#đŸ’»ăƒ»modding-dev

1 messages · Page 55 of 1

shell tangle
hushed cradle
#

you need to put the check box and the 'example' test in a seperate columns, and have those columns in a row

#

probably

shell tangle
#

This is very scuffed. And I have that.

#

Actually, maybe I don't have the colums themselves in a row.

#

No, I do.

#
{n = G.UIT.R, config = {r = 0, align = 'tm', minw = 4, minh = 0}, nodes = {
            {n = G.UIT.C, config = {r = 0, align = 'tl', minw = 0.8, minh = 3}, nodes = {
                {n = G.UIT.R, config = {r = 0, align = 'tm', minw = 0, minh = 0.8}, nodes = {
                create_toggle{label = '', active_colour = G.C.SO_2.Clubs, scale = 1, w = 0, shadow = true, ref_table = config, ref_value = 'Testing'}}},
            {n = G.UIT.C, config = {r = 0, align = 'tr', minw = 3, minh = 3}, nodes = {
                {n = G.UIT.R, config = {r = 0, align = 'tm', minw = 3, minh = 0}, nodes = {
              {n = G.UIT.T, config = {text = 'Example', align = 'tm', scale = 0.5, colour = G.C.UI.TEXT_LIGHT}}}}}}
          }}}},```
mellow sable
#

I’m really not qualified to help with that lol

#

And I still need to add things to it (like another box and colors to check if the info matches)

hushed cradle
mellow sable
#

(And pages for both multiple checks in a run and more mods than can fit on screen)

hushed cradle
#

for the joker retrigger api stuff

#

i have the lovely patches

#

in a toml

#

and the lua file

#

do i need more?

#

my code for this joker is literally identical to boredom apart from it just checks if each joker sell value is less than the one that retriggers them

mellow sable
hushed cradle
#

ah is that where it went

mellow sable
#

Because I made some changes to it

hushed cradle
#

i tried looking for the stuff on the git and couldnt find it

#

ill give that a go

#

thanks

mellow sable
mellow sable
hushed cradle
#

you are beautiful

#

i cant even put into words how i feel rn

zealous glen
#

math is beautiful

zealous glen
wintry solar
#

Try swapping where you use rows and columns

hushed cradle
#

<3

shell tangle
wintry solar
#

Can you send me a screenshot rather than text? My mobile editor wraps lines and it’s awful to read ui code

shell tangle
wintry solar
#

I think it’s needs to be structured as a row with two columns inside, where each column contains one of the elements

#

I’d add a align=‘cl’ on the row too, with align=‘cm’ on the columns

#

I think

shell tangle
#

So much better already, thanks.

wintry solar
#

Could throw a box in there to space it out too

shell tangle
#

Next is that I want to make Extra feel like it's attached to the bottom of the option cycle, any idea here?

shell tangle
wintry solar
#

Put some negative padding on the row it’s in and reduce the text scale

#

Oh, putting padding on the toggle label would space it further away too

shell tangle
#

You can do negative padding?

wintry solar
#

Yeah it’s a bit funky though

#

I’ve had inconsistent results with it

shell tangle
#

Alright, looks closer together, still needs more tweaking, but definitely a step in the right direction. Should be able to figure it out from here, thanks so much.

#

Glory to the User Interface Wizard.

wintry solar
#

Look forward to seeing what this will be used for!

zealous glen
hushed cradle
#

sure

#
calculate = function(self, card, context)
        if context.retrigger_joker_check and not context.retrigger_joker then
            if context.other_card.sell_cost < card.sell_cost then
                return {
                    message = localize('k_again_ex'),
                    repetitions = card.ability.extra,
                    card = card
                }
            end
        end
    end,```
zealous glen
#

Thank you

#

Is the API a PR for Steamodded?

hushed cradle
#

yeah

hushed cradle
#

im gonna have to add some more checks to my code because it retriggers stuff like gros michel chance to break lol

#

but the core functionality is there

crisp elbow
#

Does anyone know how you could potentially get a like, "ID" of a joker? If they're stored like numerically at all somehow in the game's code

zealous glen
#

There are keys

#

which you have to define for Steamodded anyways

crisp elbow
#

true

zealous glen
#

If you want to find every Joker with a key, Steamodded provides SMODS.find_card

crisp elbow
#

I was more thinking of trying to implement something similar to the Spindown Dice from Isaac where it would be a consumable that would change the Joker numerically up or down on use

#

but idk if that specically will be possible if it's just based on keys rather then like numeric positioning if that makes sense

zealous glen
#

The Jokers are loaded into the collection in order

crisp elbow
#

đŸ€” true

zealous glen
#

Though with different mods it could be inconsistent

mellow sable
#

You can take ownership of Gros Michel if you don’t want your mod to do that

zealous glen
crisp coral
crisp elbow
#

Are modded jokers automatically assigned an order on load?

#

I would assume so myself

zealous glen
#

Yesn’t

#

It’s the order they’re loaded in

#

But they aren’t necessarily loaded in the same order all the time

#

It depends on the specific mod’s implementation, and other mods being installed or not

#

But usually you’ll have vanilla and modded content segregated

#

And again segregated per mod

crisp coral
#

complicated way to say priority and alphabetical order

zealous glen
#

But it’s not alphabetical

crisp elbow
#

It would mostly be based on priority first and then alphabetical second tho

zealous glen
#

Not really

#

There’s nothing alphabetical about it

#

It’s injection order

frosty dock
#

within the same mod, it uses the order they're registered in in code

zealous glen
#

Which may or may not be consistent

frosty dock
#

it usually is

zealous glen
#

If the user injects using pairs for example

#

It’s not consistent

frosty dock
#

yeah sure but that's not what you're supposed to do anyways

zealous glen
#

I agree but people do it anyways

#

I use ipairs with a table that both lists the Jokers in order and has non-integer keys holding Booleans to decide if the Joker is added or not

#

I got it from Autumn

frosty dock
#

I meant that as in, you don't need a convoluted loader for your modded objects like cryptid has

zealous glen
#

so I use Myst’s convoluted loader for nothing

#

smh my head

frosty dock
#

just split your files up with SMODS.load_file and call the constructors directly

#

there's no need for the indirection

zealous glen
zealous glen
# crisp coral ?

I think I looked at your mod for a reference on how to use NDS.load because I didn’t understand Cryptid

#

It might’ve been another one

#

I have since updated while looking at Cryptid tho

frosty dock
#

the way you use NFS.load is that you don't, you let steamodded do it now

#

else you get useless stack traces

crisp coral
#

i did use NFS.load, but all jokers were in order of listed?

frosty dock
#

they should always be, but that wasn't my point

crisp coral
#

unrelated question, how the hell do you update these dynatexts on demand

zealous glen
#

@frosty dock what's the Steamodded alternative now?

crisp coral
#

SMODS.load_file

zealous glen
#

why is my connection so bad

zealous glen
crisp coral
#

did you really need to ping me

#

i'm looping through all the dynatexts and updating them but for some reason they aren't redrawn

zealous glen
crisp coral
#

you pinged me one minute after i posted that

#

i'm still in the channel, yk

zealous glen
#

I had this to update the color of Hands and Discards

#

also this

crisp coral
#

okay nevermind that, i just needed to pass true to first_pass

stray warren
#

How do I set the sell_cost of a joker to 1 when it is spawned? I tried card:set_cost() but that calculates the sell_value based on the cost of the joker every time and then adds the extra values specified.

zealous glen
#

You can do what set_cost does but directly change the sell value

stray warren
#

Yeah, but when something like Gift Card is in effect, it calls the original set_cost and adds the sell value based on editions and whatnot, basically overwriting what I wrote

zealous glen
#

maybe hook into set_cost then

stray warren
#

Oh, I could probably hook into it like you said and do a if self.ability.name == x check

zealous glen
#

I do this

stray warren
#

Yeah ok. Let me try that. Thanks

zealous glen
#

@frosty dock SMODS.load_file doesn't let me set up custom messages smh my head

frosty dock
#

wdym custom messages

zealous glen
#

VictinsCollection :: Failed to load "..joker_name.." with error "..error

frosty dock
#

oh you totally can

#

it returns a function the same way NFS.load would

#

or an error message if it failed to load

zealous glen
#

Oh I misread then

#

So this works

#

?

frosty dock
#

yeah

zealous glen
wintry solar
#

Do you have the right level set in the steamodded config?

frosty dock
#

steamodded has a log level setting now (in Mods > config)

#

by default it only shows info and higher

zealous glen
#

huh

stray warren
#

Is there a prefix on modded joker name values? This code works when Blueprint is in the name area, but not my modded Joker's name.

crisp coral
#

no, but don't use name, use center keys

stray warren
#

Oh, I see now with the debug message. The name value is literally just it's full prepended key.

#

So do I still use self.ability.name or is there a different way to access it?

zealous glen
#

uh look at SMODS.find_card maybe

red flower
#

it's self.config.center.key

zealous glen
stray warren
#

oh, should I use that function instead?

zealous glen
#

No that one just finds Jokers by the key

#

or Consumeables

#

But it uses card.config.center.key

hushed cradle
#

is there a function called whenever the deck is modified that i can hook smth to?

zealous glen
#

Modified how

hushed cradle
#

like any change to the deck

zealous glen
#

what's a change to the deck

hushed cradle
#

check_for_unlock might be the way to go

#

like if you add/remove a card, change suits, change ranks

#

enhancements, seals

zealous glen
#

Only adding and removing cards is changing the deck

#

The rest isn't

#

And there are hooks for those two

hushed cradle
#

okay by my definition of changing the deck then

zealous glen
#

which is why I asked

#

But keep in mind cards are added and removed from the deck when debuffed

wintry solar
#

You could hook into use consumable too

hushed cradle
#

yeah ik

hushed cradle
#

think thats the best way

zealous glen
#

I don't think you can catch every modded effect

stray warren
#

Ok, so I got this code to work for the Joker, but if there're any other Jokers that modify its sell value, it still overwrites it. I think I know why, but I can't for the life of me think of an alternative, other than hardcoding specific joker names to work with it (Which I want to avoid)

-- set_cost hook for Wish You Were Here
local set_cost_ref = Card.set_cost
function Card.set_cost(self)
    if self.config.center.key == "j_pape_wish_you_were_here" then
        if self.ability.extra_value == 0 then
            self.sell_cost = 1
        else
            self.sell_cost = self.sell_cost + self.ability.extra_value
        end
    else
        set_cost_ref(self)
    end
end
hushed cradle
#

im gonna hook to the check_for_unlock

#

because use consumable, emplace, and remove all call that anyway

stray warren
#

Yeah, that's what i've been basing this logic off of

#

And I know why Gift Card is resetting the Joker's sell value, I just can't think of an alternative way to implement it

stray warren
#

Ok, so from my understanding (which is probably wrong lol) Gift Card is calling set_cost(), and it doesn't match up with the if statement in my set_cost() hook, so it goes to the original function (in my else statement). In there, it calculates the original sell_value based on half the cost to buy (which I set to 6 in the joker config) which is 3. Then it calculates the edition bonuses and adds the extra_value provided by gift card with the previous extra costs applied

zealous glen
#

I mean, then your if statement is the issue, no?

shell tangle
#

I now understand the appeal of UI.

stray warren
#

Yeah, it is when a Joker other than my Joker calls set_cost(). I could add all the jokers that add sell_value to that if statement with ors, but I wanted to prevent that so as to work with other modded jokers

wintry solar
stray warren
#

which i guess is only gift card in this case lol

zealous glen
#

Unless you coded your if condition wrong, it should go directly to it

wintry solar
zealous glen
#

That's what I do

#

In fact

#

Your implemention is bad because it doesn't change the cost of the Joker if it works

#

So e.g. other effects can't change its cost

#

(Tags, etc.)

shell tangle
# wintry solar Do they do anything yet?

They do cycle through config, but I use an opt_callback to save the cycle changes that calls this code,

G.FUNCS.Balu_cycle_save = function(args)
  local test = args.cycle_config.ref_value
  config[test] = args.cycle_config.current_option
end

Unsure if there's a better way.

stray warren
zealous glen
hushed cradle
#

`why is that not

#
function update_new_moon()
    local suits = {}
    local suit_order = {
        Spades = 1,
        Hearts = 2,
        Clubs = 3,
        Diamonds = 4,
    }
    local values = {}
    local value_order = {
        ['Ace'] = 1,
        ['King'] = 2,
        ['Queen'] = 3,
        ['Jack'] = 4,
        ['10'] = 5,
        ['9'] = 6,
        ['8'] = 7,
        ['7'] = 8,
        ['6'] = 9,
        ['5'] = 10,
        ['4'] = 11,
        ['3'] = 12,
        ['2'] = 13,
    }
    for k, v in pairs(G.playing_cards) do
        if v.ability.effect ~= 'Stone Card' then
            suits[v.base.suit] = (suits[v.base.suit] or 0) + 1
            values[v.base.value] = (values[v.base.value] or 0) + 1
        end
    end
    local common_suit = {'Spades', 0}
    local common_value = {'Ace', 0}
    for k, v in pairs(suits) do
        if v > common_suit[2] then
            common_suit = {k, v}
        elseif v == common_suit[2] then
            if suit_order[k] < suit_order[common_suit[1]] then
                common_suit = {k, v}
            end
        end
    end
    for k, v in pairs(values) do
        if v > common_value[2] then
            common_value = {k, v}
        elseif v == common_value[2] then
            if value_order[k] < value_order[common_value[1]] then
                common_value = {k, v}
            end
        end
    end
    new_moon.debuff = {
        suit = common_suit[1],
        value = common_value[1],
    }
end```
#

ik the code itself is horrible

zealous glen
hushed cradle
#

but idk why G.playing_cards is nil

zealous glen
zealous glen
hushed cradle
#

during a run

zealous glen
#

when is it called

hushed cradle
#
local check_for_unlock_ref = check_for_unlock
function check_for_unlock(args)
    check_for_unlock_ref(args)
    if G.STAGE == G.STAGES.RUN then
        update_new_moon()
    end
end```
zealous glen
#

I think check_for_unlock is called before you enter a run

hushed cradle
zealous glen
# hushed cradle

Oh you want it to update dynamically when you add a card to your deck?

hushed cradle
#

yeah

zealous glen
#

I don't think that's a good idea

hushed cradle
#

when i leave and re etner the run it breaks

zealous glen
#

Make it work like Ox

hushed cradle
#

nah i want it work like this

stray warren
#

I guess one way I could fix it is by setting the Joker's cost to 1 initially and then if its available to buy in the shop only THEN temporarily set it to the correct cost value.

zealous glen
zealous glen
shell tangle
wintry solar
#

You can set the table you want to modify as the actual reference

shell tangle
#

As the ref_table, and leave ref_value blank?

wintry solar
#

Let me just put my kid to bed and then I’ll show you

zealous glen
#

although I need to make it works with Editions I guess

#

Does SMODS.Edition have a cost value for vanilla and modded Editions?

#

They do, but I'm not sure how to access it

stray warren
#

Oh, nice. So your code sets the placeholder Joker's sell value to 1 and then it never gets reset?

hushed cradle
#
local game_update_ref = Game.update
function Game:update(dt)
    game_update_ref(self, dt)
    if self.playing_cards then
        update_new_moon()
    end
end```
#

fixed it :)

zealous glen
#

Then 2, etc.

stray warren
#

what is the initial cost in your joker definition?

zealous glen
#

Idk

stray warren
#

like, to purchase it in the shop

#

that's my real issue; it keeps referencing that value when doing the calculations

zealous glen
red flower
stray warren
#

Yeah, so I want it to cost $6 in the shop, but when its purchased, set it to 1

#

Problem is that value is directly referenced in the set_cost function

zealous glen
#

I don't think changing the cost would matter

#

Because the minimum cost is 1 anyways

#

so even though I put 0 it would be updated to 1

#

So the value it uses is never the value I put

#

But the result doesn't change

zealous glen
stray warren
#

Hmm. Can I see your code? That seems exactly what I want lol

zealous glen
# zealous glen

@stray warren but swap the order of 0 or self.ability.extra_value

#

that was a silly error

zealous glen
frosty dock
#

(yes that means poker hands are merged)

zealous glen
#

but again do it after you call the original function

frosty dock
#

okay so these warn messages are really annoying

#

maybe I should get rid of them

stray warren
#

I could've sworn I tried that before, but oh well

zealous glen
frosty dock
#

that's the mod id

stray warren
#

There's no predefined --- PREFIX: so it's the first four

zealous glen
#

Not vict

stray warren
#

Yeah, it's only 3 digits, so it's the full mod_id

frosty dock
#

yeah it takes the mod ID, not the name

zealous glen
#

oh

#

I thought it used the name

frosty dock
#

it's the first 4 chars of the mod ID in lowercase, so it'll just be the first 3 if it's only 3 chars long

zealous glen
#

By the way

#

why is it called a prefix when it's usually an infix

#

smh my head

frosty dock
#

as to not make keys overly long?

mellow sable
#

If that was added recently I also think it breaks the Royal flush example

stray warren
frosty dock
#

it's just the default

#

your own prefix can be as long as you need it to

mellow sable
#

👍

frosty dock
#

but actually I do need to fix the royal flush example

zealous glen
mellow sable
#

I thought you meant forcing prefixes to be 4 or less characters

mellow sable
frosty dock
#

I just merged the new poker hand API

primal robin
#

Is Reverie mod only for 0.9.8 Steamodded?

hallow forge
#

for now

primal robin
#

Well, time to downgrade, just to make sure my mod is working fine water

frosty dock
#

so clean

#

actually I should make the 'royal' part of it its own PokerHandPart just to demonstrate

static juniper
#

I was reading through your Example Joker Mod as a newbie mod creator (and it's really well put together, even if I still have questions, which I'll have to discover myself), and I found this line. Are King and Ace supposed to have the same id or is this a typo?

frosty dock
#

actually maybe not

shell tangle
static juniper
#

Makes sense. Thanks!

wintry solar
frosty dock
#

small correction, ref_value = 'test_1'

wintry solar
#

nah my table uses test1 #based

#

they should be in quotes though, that is true

zealous glen
#

Wait all this work and I just remembered it's meant to ignore Edition changes to sell value lol

shell tangle
wintry solar
#

what did you put in your cycle definition?

frosty dock
shell tangle
#

It had ref_table = config which was the current path stuff, and ref_value = 'cycle_test'. Options were options = {'Testing', 'Testing 1'}, thouugh I did try it without the options first, and it just had nil.

hushed cradle
#
loc_vars = function(self, info_queue, card)
        return {vars = {self.debuff.value .. 's', self.debuff.suit}}
    end,

    collection_loc_vars = function(self)
        return {vars = {self.debuff.value .. 's', self.debuff.suit}}
    end,```
#

uh

#

loc vars works

#

colletion loc vars doesnt

frosty dock
#

1.0.0b-DEVELOPMENT?

#

why are you overriding the balatro version

hushed cradle
#

uh

#

that is not me

#

i think

#

well i mean it must be

#

but

#

oh i think its saturn

#

is that an issue?

frosty dock
#

it might be if it used 0.x versioning since the game does some logic with that on startup

#

but it's just bad practice

hushed cradle
#

its not smth i added to saturn myself

#

but ill bare that in mind

#

oh do i have to pass colours to blinds?

#

i was wondering if i could change the colours

shell tangle
wintry solar
#

just testing some stuff

#

been a few days since I played with option cycles

frosty dock
hushed cradle
#

is there an example mod i can read to see how

frosty dock
#

where that color is HEX('DF509F')

hushed cradle
#

thank you

#

might be worth putting that on the wiki, unless it is and im blind in which case sorry

frosty dock
#

oops, it is not

#

I'll add it rn

wintry solar
#

@shell tangle use opt_callback = 'test_framework_cycle_callback'

#

that will adjust your ref_table correctly

shell tangle
wintry solar
#

no

#

this is in source code

#

I knew I'd seen thunk use a ref_table in an option cycle

frosty dock
#

base game function actually

wintry solar
#

just needed to find it again

#

thanks vscode regex search 🙂

shell tangle
#

Any thoughts on a lovely patch to make it the default opt_callback?

hushed cradle
#

is there an easier way to pass it a completely diff loc text than this

#
 loc_txt = {
        name = 'New Moon',
        text = {
            '#1# #2# #3# #4#',
            '#5# #6##7##8#',
        },
    },```
wintry solar
hushed cradle
#

not really

#

i want a completely different text

#

All (most common rank) ... is too long and looks bad imo

frosty dock
#

loc_vars can return a key i think

#

if i made that work for blinds

zealous glen
zealous glen
#

I have some fake text which I look for so I can create custom boxes and text

frosty dock
#

doesn't look like I did lmao

zealous glen
#

like adding a Credits box to Jokers

hushed cradle
#

even if it is scuffed

shell tangle
wintry solar
#

uhhh good question

unkempt ridge
#

Is there a debug line of code for outputting a message? Like, just so we can debug if part of a play is going thru

shell tangle
#

sendDebugMessage().

wintry solar
#

I think it's going to be easier to just not use this built in function and write a new one

shell tangle
#

Back to what I had, then.

wintry solar
#

I would do something like this.

config = {
  test = {
    options = {A, B, C},
    value = 1
  }
}

create_option_cycle({current_option = config.test.value, options = config.test.options, ref_table = config.test, ref_value = 'value', opt_callback = 'callback_func'})

G.FUNCS.callback_func = function(args)
  args = args or {}
  if args.cycle_config and args.cycle_config.ref_table and args.cycle_config.ref_value then
    args.cycle_config.ref_table[args.cycle_config.ref_value] = args.to_key
  end
end
#

I believe this will work

shell tangle
#

Just to prevent crashes if the table doesn't exist yet, or?

wintry solar
#

just an example of what the table could look like

shell tangle
#
G.FUNCS.Balu_cycle_save = function(args)
  local ref = args.cycle_config.ref_value
  config[ref] = args.cycle_config.current_option
end
``` Here's mine which has been working, but, I obviously haven't put it under any stress testing yet.
wintry solar
#

yeah that'll work

#

I suppose I wrote mine as a more generalised case

#

you could use mine on any option slider

shell tangle
#

I also have my options located within the create cycle function, rather than in the config area.

wintry solar
#

yeah that's fine too

#

interestingly, having them in the config area would allow them to by dynamic too

shell tangle
#

Complete side note, how is an info_queue thing structured again?

frosty dock
#

array of tables that have a set and key

stray warren
#

does context.cards_destroyed not work?

wintry solar
#

context.remove_playing_cards

stray warren
#

oh. I saw on a different thread that it was context.destroying_cards

#

But that context doesn't work on Jokers or consumables, does it? I'm currently looking through your post, so sorry if that's already answered

wintry solar
#

I don't think there's a check for destroying those

#

base game can't destroy them, right?

stray warren
#

Well Madness can destroy Jokers, but I don't think consumables can be destroyed

wintry solar
#

oh true

stray warren
#

And I don't even know where to begin to add new contexts sadge

wintry solar
#

what are you trying to do?

static juniper
#

Is there a way to get the total chips scored by a hand at the end of a hand?

stray warren
#

and i guess consumables if there was a mod that added that

wintry solar
#

uhhh you could maybe hook Card:start_dissolve and check for card.getting_sliced and run a calculate joker there with a new context

stray warren
#

Let me try that

#

I may have done something wrong; is getting_sliced a child of self in this function?

local start_dissolve_ref = Card.start_dissolve
function Card.start_dissolve(self, dissolve_colours, silent, dissolve_time_fac, no_juice)
    start_dissolve_ref(self, dissolve_colours, silent, dissolve_time_fac, no_juice)

    if self.getting_sliced then
        self:calculate_joker({destroying_cards = true})
    end
end
#

or am I calling calculate_joker incorrectly?

zealous glen
#

Betmma does, I know other people have but I don’t remember all of them

wintry solar
#

function Card:start_dissolve

#

then remove self from the function definition

#

actually, does that even matter?

stray warren
#

Are you talking about the . or :? I've seen it used interchangeably in multiple different mods

stray warren
zealous glen
zealous glen
wintry solar
#

checking getting_sliced also isn't perfect to be fair

zealous glen
#

When will SMODS add this custom context v_v

stray warren
#

Would I even need a getting_sliced check, since if it's dissolving it's probably been destroyed anyway? Or am I missing something

zealous glen
stray warren
#

oh yeah duh

zealous glen
#

Cards are only not dissolved when they’re shattered and exploded I think

#

Maybe exploding cards also dissolves them I forget

stray warren
#

Oh, so my implementation wouldn't work for glass cards

wintry solar
#

but they should have context.remove_playing_cards

#

so you can just check for either

zealous glen
#

Not quite

#

You can destroy glass cards in other ways

#

And they’re shattered instead

#

I think it’s inconsistent but I don’t remember

wintry solar
#

they still call that context iirc

zealous glen
#

But only if they’re destroyed by the Glass card’s effect I think

wintry solar
#

that sounds wrong

stray warren
#

Surely cryptid has a context for it

zealous glen
#

Also remember to add a key to your custom contexts

wintry solar
#
local start_dissolve_ref = Card.start_dissolve
function Card:start_dissolve(dissolve_colours, silent, dissolve_time_fac, no_juice)
    if self.getting_sliced then
        for i=1, #G.jokers.cards do
            G.jokers.cards[i]:calculate_joker({destroying_cards = true, destroyed_card = self})
        end
    end

    start_dissolve_ref(self, dissolve_colours, silent, dissolve_time_fac, no_juice)

end
#

I think this is what you need

stray warren
#

So I would check for that context or remove_playing_cards

wintry solar
#

yeah

#

probably needs to throw a check in somewhere to make sure the card that is calculating isn't being destroyed, although I guess that depends on the effect

stray warren
#

Yeah, I actually noticed that and added it in there. Let me see if this works đŸ€ž

zealous glen
#

Don’t forget to test selling cards

stray warren
#

Ok, selling cards doesn't trigger it, and it gives mult when cards are destroyed; although it only gives mult once, no matter how many cards are destroyed

wintry solar
#

how did you destroy the cards?

stray warren
#
        if (context.destroying_cards or context.remove_playing_cards) and not context.blueprint then
            if context.destroyed_card ~= card then
                card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
                return {
                    message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult_mod } }
                }
            end
        end

I destroyed playing cards with the hanged man and a joker with Madness

wintry solar
#

check for context.removed and then the size of it

#

it contains all the removed cards

#

the context.destroyed_card should only ever contain one card

stray warren
#

Yeah. It should call calculate joker on each card destroyed, right?

wintry solar
#

yes

#

but the default ones on playing cards call it once on the whole set of destroyed cards

stray warren
#

oh so that's where the context.removed comes into play

wintry solar
#

yeah

stray warren
#
if (context.destroying_cards or context.remove_playing_cards) and not context.blueprint then
            if context.destroyed_card ~= card then
                if context.removed then
                    for i=1, #context.removed do
                        card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
                    end
                end

                return {
                    message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult_mod } }
                }
            end
        end
wintry solar
#

you can remove the for loop by doing card.ability.extra.mult + (#context.removed * cart.ability.extra.mult_mod), but looks good

stray warren
#

Oops, forgot to modify the mult when a Joker is destroyed. But thank you, it all seems to be working as expected now

wintry solar
#

I wonder if card.ability.extra.mult + ((#context.removed + #context.destroyed) * cart.ability.extra.mult_mod) would work

stray warren
#

Let me try it lol

#

Well it wouldn't though, because if only a Joker is destroyed, context.removed would be nil, right?

wintry solar
#

yeah, I'm not sure how doing # on a nil object works

#

it might error, or it might be 0

zealous glen
#

You can throw a or 0

#

Or maybe or {}

#

Actually don’t all cards have a remove_from_deck? Or only Jokers?

wintry solar
#

I think it's just jokers, but it calls when debuffed anyway

#

is this better than using tooltips?

zealous glen
zealous glen
wintry solar
#

the current labels are in tooltips on hover

zealous glen
#

Oh when you hover over the option?

wintry solar
#

yeah

zealous glen
#

Either works I think

#

If you add more options you can add back the tooltips

stray warren
#

I split it up into two distinct if statements. Do you see any issues with this?

        if not context.blueprint then
            if context.destroying_cards then
                if context.destroyed_card and context.destroyed_card ~= card then
                    card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
                    card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult_mod}}})
                end
            elseif context.remove_playing_cards then
                if context.removed then
                    card.ability.extra.mult = card.ability.extra.mult + ((#context.removed or 0) * card.ability.extra.mult_mod)

                    card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_xmult', vars = {card.ability.extra.mult_mod * (#context.removed or 0)}}})
                end
            end
        end
#

ew, formatting broke

wintry solar
#

is that supposed to be a_xmult?

stray warren
#

nope, nice catch

#

Actually, I'll probably just make it say Upgrade! like some base jokers do

#

and first argument has to be card and not self

#

Actually, not sure what's causing that

wintry solar
#

I imagine it always calls the removed_playing_cards context, so you'll need to check that context.removed isn't nil

stray warren
#

hmm, that's not it. I added this line if context.removed and context.removed ~= nil then and it's still showing that

#

but those mean the same thing, right?

wintry solar
#

it just doesn't get called if it's empty anyway

#

can I see the entire calcualte function?

stray warren
#
calculate = function(self, card, context)
        if not context.blueprint then
            if context.destroying_cards then
                if context.destroyed_card and context.destroyed_card ~= card then
                    card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
                    card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult_mod}}})
                end
            elseif context.remove_playing_cards then
                if context.removed and context.removed ~= nil then
                    card.ability.extra.mult = card.ability.extra.mult + ((#context.removed or 0) * card.ability.extra.mult_mod)

                    card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult_mod * (#context.removed or 0)}}})
                end
            end
        end

        

        if context.joker_main then
            if card.ability.extra.mult > 0 then
                return {
                    mult_mod = card.ability.extra.mult,
                    card = card,
                    message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
                }
            end
        end
    end,
wintry solar
#

(#context.removed or 0) change this to just #context.removed

stray warren
#

Still doing it. should I put card_eval_status_text in its own conditional?

wintry solar
#

throw a #context.removed > 0 instead of the nil check?

stray warren
#

That did the trick. Thanks!

#

I understand contexts and how to create them a lot better now

wintry solar
#

when creating them you just need to make sure you're passing through everything that might be useful

unkempt ridge
#

Need a bit of assistance with this Jonklers code
From what we understand we kinda messed up and are having em read every single card that's played and, affecting every card that's played. Instead of just, reading once and doing it once.
Unsure how to set it so that it only Does it per the card that it is? Since, it also crashes if we play something like a two pair with kings and two's. (Probably because the rank isn't supposed go any lower than 2)

Any help would be appreciated ^^

shell tangle
#

Try switching the for k, v in pairs (G.play.cards) do to context.other_card instead?

unkempt thicket
#

how do you check if played hand contains a certain hand?

shell tangle
shell tangle
unkempt thicket
#

if the scored hand contains another hand

shell tangle
#

At a quick look, Trousers just checks for either Two Pair or Full House,

wintry solar
#

I think you can use context.before for this

#

@unkempt ridge

shell tangle
wintry solar
#

poker_hands contains all the valid poker_hands that are contained in the hand

shell tangle
#

Didn't know. Should update my example mod, because the runner in it is using scoring_name.

unkempt ridge
shell tangle
#

They are, but you aren't necessarily using context.individual in any way, it's just repeating the code 5 times, because it's checking context.individual for each card.

#

You can still check for G.play.hand in context.before, I'm pretty sure, though.

unkempt ridge
shell tangle
#

You'd probably want to switch to context.before for that, then, since the checks for context.indivdual is, I think the step right after the chips of the card are given.

unkempt ridge
#

swapping context.individual with context.before doesn't trigger the cards, just skips over it

shell tangle
#

What is the new code?

unkempt ridge
shell tangle
#

Grabbed from my context.before checking joker,

    -- Check for Spades in played hand.
    if context.cardarea == G.jokers and context.before and not context.blueprint then
      local suit = ""
      for k, v in ipairs(context.scoring_hand) do
        if v:is_suit('Spades') then card.ability.extra.broken = true end
      end
    end```
#

Ah, it's because context.other_card is unique to context.individual, so you need to switch back to the for loop method.

#

Also, will say that G.play.hand, I'm pretty sure will use all cards, including non-scored cards, so maybe switch to context.scoring_hand as well.

wintry solar
#

Go and read the calculation breakdown I linked and see if that helps you understand contexts and what information you have available with them, it seems like you’re basing your knowledge off something else?

unkempt ridge
#

This might just be our own skill issue

shell tangle
# unkempt ridge We've been using your post as a breakdown since we started this mod lol

Will say that the guide is kind of indigestible at first, just because it's a lot of steps, but, yeah, once it starts clicking, everything makes sense.
You've figured out where context.individual gets triggered and where context.other_card is used now, but that's too far ahead for what you want to do.
So go back a few steps, and see what you can do with context.before.

wintry solar
#

Yeah this seems like you want the effect to happen before scoring, which is a big hint for context.before (similar logic for after too)

#

All the in between ones are a bit fiddly

unkempt ridge
#

We need a flow chart for this stuff tbh lol

shell tangle
#

Would probably be a good idea.

wintry solar
#

I mean it would be a pretty dull flow chart, it’s just a linear evaluation

unkempt ridge
#

Maybe more like a timeline then lol

wintry solar
#

But that’s what my guide is, it’s just not in beginner friendly terminology at the moment

shell tangle
#

I do think a flow chart would work, just because it can be easier for some to see it visually with arrows, than piece it together in order through text.

wintry solar
#

I’ll get round to rewriting it at some point

shell tangle
#

Without the descriptions of what the parts do, I think the flowchart would feel similar to a more legible table of contents/glossary, of sorts, which I do think would help out people just starting out with it.

unkempt ridge
#

Good(?) news is it's doing all the cards only once now, so retriggers aren't gonna be affected
Tho the scoring is still of issue. We're not sure if it's because of the code snippits at 42-66? Because they're in the event manager maybe.

static juniper
#

How do you add a vanilla tooltip to a joker?

#

Right now all I want is to add the Lucky Card tooltip to a Joker that makes cards Lucky

hushed cradle
#
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
{
    // Take pixel color (rgba) from `texture` at `texture_coords`, equivalent of texture2D in GLSL
    vec4 tex = Texel(texture, texture_coords);
    // Position of a pixel within the sprite
    vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;

    tex.a = 0.5 * tex.a;

    number one = sneaky.x / sneaky.x;

    // required
    return dissolve_mask(tex*colour*one, texture_coords, uv);
}```
#

i have no idea what im doing with shaders tbh

#

i watched a 15 min yt vid

#

does anyone know where im going wrong here?

#

i just want to reduce the alpha

unkempt ridge
#

Actually frick that might be impossible (or out of our skillset)
If the way the calculation triggers work is true, then the scoring_hand is already populated even before the context.before
So, only way to affect it would be to modify scoring_hand somehow during that step

hushed cradle
#

can you hook smth to the button callback for when you press play hand

#

use calculate joker to figure out if it should

#

then do it

#

no idea what youre actually trying to do but it looks cool

unkempt ridge
#

Yknow what close enough
'It's a feature'
Gonna change the card description to say it'll do it after score is calculated

static juniper
#

I'm trying to make an effect that gains chips whenever an 8 is scored, a la Wee Joker, and I have everything except the Upgrade message that pops up on the joker. I tried copying the Wee Joker code for the message, and it crashed my game. Any help?

    card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
    return {
        extra = {focus = self, message = localize('k_upgrade_ex')},
        card = self,
        colour = G.C.CHIPS
    }
end```
rain imp
#

Where is Blind fight UI being called? I know that somewhere in UI_definitions.lua, but search by G.UIDEF gave nothing useful (or is it called by a different function?)

hushed cradle
#

i think replace self with card

static juniper
#

Crash report for the record

hushed cradle
#

you replaced focus = self with focus = card to right?

#

im not really sure then

static juniper
#

(I only changed the card = self to card = card)

hushed cradle
#

nws

#

once you sent the error message w juice_up causing an issue i thought it was for sure the focus bit

unkempt thicket
#

how do you get the amount of cash-out money?

rain imp
#

What function pulls the Blind UI up and down? I have found the one that calls for it in game.lua:2349 (which is inside of function Game:start_run(args)), as well as the declaration of it in UI_definitions.lua:1210, but those are not hooked to the beginning or an end of the fight, where is it then? Search by folder gave only the 5 that are in game.lua

#

Ones in game.lua also kill the UI on run end, but nothing more of it

crisp coral
rain imp
#

Thanks!

static juniper
#

I keep getting this error message whenever I try to boot up the game. What can I do to fix this?

static juniper
rain imp
#

But from what I can guess you saved a custom sprite in a weird, unreadable for Balatro way

#

Did you?

frosty dock
#

nope, that's an out of memory crash

static juniper
#

Might be it, but I haven't touched my custom sprites for a while. I'll remove it to test it anyway.

frosty dock
#

it should go away if you close some programs running on your machine

rain imp
#

bruh

opal spade
#

it seems to happen a lot if steam is trying to sync ur balatro with the cloud

#

at least for me when debugging my mods

static juniper
tepid egret
#

yup its already been done

hushed cradle
#

steamodded tech support do you know much about shaders?

wintry solar
#

What do you need?

hushed cradle
#

im literally only trying to change the alpha lol

#

but it wont do it for some reason

#

and also when i try and use time in any of my shaders it doesnt seem to update

#

this is supposed to be transparent

#

or translucent actually

#
{
    // Take pixel color (rgba) from `texture` at `texture_coords`, equivalent of texture2D in GLSL
    vec4 tex = Texel(texture, texture_coords);
    // Position of a pixel within the sprite
    vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;

    tex.a = tex.a * 0.5;

    number one = sneaky.x / sneaky.x;

    // required
    return dissolve_mask(tex*colour*one, texture_coords, uv);
}```
#

i watched one 15 min yt video so i dont think im qualified for using these things

wintry solar
#

Time should be shadername.r

#

Let me just check is the new shader stuff got merged too

hushed cradle
#

oh so i cant just use time

wintry solar
#

I’d need to check some of my shaders out hold on

hushed cradle
#

nws

wintry solar
#

For the alpha put override_base_shader = true on your shader object

#

shadername.y + time is what I use

hushed cradle
#

that worked thank you

#

i clearly didnt read the wiki page thoroughly enough

wintry solar
#

I don’t think those are in the wiki

#

The override thing is new

hushed cradle
#

oh yeah

#

thank you even more then

#

i wouldve never figured out what was wrong

wintry solar
#

Oh there’s probably a shadow one you want to add too

hushed cradle
#

a shadow shader?

#

like shader for the shadow

wintry solar
#

ignore_shadow = true

#

Yeah because you’re playing with transparency you can see the shadow through the card

hushed cradle
#

ah right yeah

#

thanks

languid mirage
#

wiki probably doesn't even have shaders section

wintry solar
#

I think I covered them in the edition wiki briefly

hushed cradle
#

edition mentions a few things

#

the example mod was too confusing for my small brain

wintry solar
#

The example mod isn’t great tbh, stupid made some fixes to it but it was hastily thrown together for internal testing mostly, it was never designed for other people to use as an example

opal spade
#

is there any simple way to change the visual effect/text when redeeming a voucher

rain imp
#

Text - probably via localisation, which is pretty easy

maiden phoenix
#

You can prob also override the atlas and pos for sprite

rain imp
#

The effect though is in shaders\voucher.fs, which is its own can of worms. It is not a texture on an atlas, it is a shader fully scripted in this file

opal spade
#

i meant as in the behaviour of the voucher going to the middle of the screen and saying "[name] redeemed"

rain imp
#

Oh, that is an event that is changable

#

Can't tell where exactly though

opal spade
#

ok doing some investigating its a part of card:redeem, now i just need to check whether theres an easy way to change the event that happens

rain imp
#

What you need to change is in

                top_dynatext = DynaText({string = localize{type = 'name_text', set = self.config.center.set, key = self.config.center.key}, colours = {G.C.WHITE}, rotate = 1,shadow = true, bump = true,float=true, scale = 0.9, pop_in = 0.6/G.SPEEDFACTOR, pop_in_rate = 1.5*G.SPEEDFACTOR})
                bot_dynatext = DynaText({string = localize('k_redeemed_ex'), colours = {G.C.WHITE}, rotate = 2,shadow = true, bump = true,float=true, scale = 0.9, pop_in = 1.4/G.SPEEDFACTOR, pop_in_rate = 1.5*G.SPEEDFACTOR, pitch_shift = 0.25})
                self:juice_up(0.3, 0.5)
                play_sound('card1')
                play_sound('coin1')
                self.children.top_disp = UIBox{
                    definition =    {n=G.UIT.ROOT, config = {align = 'tm', r = 0.15, colour = G.C.CLEAR, padding = 0.15}, nodes={
                                        {n=G.UIT.O, config={object = top_dynatext}}
                                    }},
                    config = {align="tm", offset = {x=0,y=0},parent = self}
                }
                self.children.bot_disp = UIBox{
                        definition =    {n=G.UIT.ROOT, config = {align = 'tm', r = 0.15, colour = G.C.CLEAR, padding = 0.15}, nodes={
                                            {n=G.UIT.O, config={object = bot_dynatext}}
                                        }},
                        config = {align="bm", offset = {x=0,y=0},parent = self}
                    }
            return true end }))```
, mainly UI description
opal spade
opal spade
#

true but ive already made up my mind on just tackling on a second event for this instead of trying to messing with the initial one

wintry solar
#

you can always ping me for ui questions

primal robin
unkempt thicket
#

how do you get the amount of cash-out money?

maiden phoenix
rain imp
#

And I guess G.GAME.current_round.dollars = config.dollars specifically

#

It may be just a part of the sum though

regal wolf
regal wolf
zealous glen
regal wolf
#

it depends on the use case

#

but yeah, it is mainly for hooking

zealous glen
#

ye but the way they asked an injection seemed more applicable

regal wolf
#

ah, i didnt read the whole thread, just skimmed

languid mirage
olive shoal
#

dvd screensaver?

languid mirage
wintry solar
olive shoal
#

unrelated - ive been working on some thing and have been wondering on an actual good way to implement it user wise. i made some spectrals which modify poker hands in a specific way for each spectral on use to put it, but im torn on how it should actually like, select which hand to modify in a way that you actually get to pick which one to modify w/o it being extremely easy to pick the bestest one ever, like how opening a spectral or tarot pack only gives u a limited amount of options so you cant just immediately add red seals and insane enhancements to ur best cards immediately

#

my initial idea was "using it modifies the next hand played" but then i feel like its too easy to pick which one gets modified. other ideas include last hand played (but i think that has the same problem), hand for next planet card (breaks with cryptid i think and also takes 9 years to use), and uhm random hand played (bad). if anyone can come up with any idea of how said spectrals should select which hand in an actually intuitive way thatd be phenomenal, im so lost rn

primal robin
wintry solar
#

đŸ€·â€â™‚ïž

#

I haven’t looked at any animation stuff

#

I believe @zealous glen has though?

lament fjord
#

@regal wolf Saturn still causes the ERROR localization string issue

regal wolf
#

from the devlop branch

lament fjord
#

Pull from develop branch?

#

Okay I'll try that

#

Same results

regal wolf
#

saturn doesnt do anything with localizations

regal wolf
#

I dont have the same issue lol

lament fjord
#

Mods menu of steamodded

languid mirage
#

maybe not latest steamodded

lament fjord
#

Actually is latest steamodded

languid mirage
#

I meant for djynasty

#

I can see the version on your ss

#

you have no other mods that could break it, right?

lament fjord
unkempt thicket
#

how do you make a basic tag that opens a certain booster pack?

regal wolf
#

odd

lament fjord
#

(What was it doing, anyways? Just copypaste straggler?)

zealous glen
#

You can move things manually or try to use existing functions that move them

#

Take a look at how the Blind Selection UI moves when you reroll a boss or how a Blind UI moves in on the top left after you select a Blind, those are my best guesses for suggestions, unless you have something specific in mind

lament fjord
#

Also Saturn seems to interact badly with Steamodded's tag collection viewer

primal robin
zealous glen
#

But if you do it manually, use an ease Event

primal robin
#

Sounds useful

regal wolf
primal robin
zealous glen
#

Joker idea:

Chimera
If played hand has three or fewer cards, each scoring card has every rank and suit

#

Actually it should be scoring hand so that not every three cards form a 3OAK

opal spade
#

messing around for fun, I think I got a fun idea but idk how I could balance it better

#

(not written on the card but the effect always happens last to ensure the hand that triggered the effect doesn't score)

zealous glen
#

I wouldn’t word it that way, I think, but I’m not sure how I would word it

#

I think debuffing the hand like Psychic is better but then it doesn’t score at all

opal spade
zealous glen
#

Not everything needs to be inside calculate

#

And in fact not everything is

#

Golden Joker, Pareidolia, etc.

zealous glen
zealous glen
edgy reef
#

If it debuffed the hand then you wouldn't get use of 90% of scaling jokers (only ones trigger though debuffed hands and context.after) which would make this joker very much not worth being rare.

#

Unless this isn't intended to be beneficial to you.

zealous glen
#

I mean it is an extra hand

#

You can think of it sometimes as an extra discard

edgy reef
#

I still costs a hand to play.

zealous glen
#

I mean that’s what an extra hand does

opal spade
#

worth*

zealous glen
#

I think it might but I couldn’t think of a better wording that kept it

#

I think even debuffing the hand it’s as good as Burglar

static juniper
#

Trying to use an atlas to sprite my jokers for the first time. I put Jimbo as a placeholder, but why are they so small?

zealous glen
static juniper
zealous glen
#

The game uses 1x sized assets and 2x sized assets

static juniper
#

Oh, is that why there's two folders?

zealous glen
#

I think you just have the same 1x assets twice

static juniper
#

I was really confused why there were two of them

opal spade
#

assets in the 2x folder are twice the resolution

static juniper
#

So these sprites need to be 142x190?

zealous glen
#

Only in the 2x folder

static juniper
#

It works now, thanks!

opal spade
zealous glen
#

How about

When you play a hand with 2 or fewer scoring cards, +1 hand and ?

opal spade
#

footage with old description but it's mechanically the same as the current one

zealous glen
#

Also that feels Legendary worthy

zealous glen
#

I had thought it was just a flat +1 like the Voucher

#

(Handy? Grabby?)

opal spade
#

grabber

zealous glen
opal spade
zealous glen
#

Ah you’re looking specifically for cards that don’t score

opal spade
#

ye

zealous glen
opal spade
#

honestly now that you pointed that out idk why I used if instead of when

zealous glen
#

I know YGO uses “if” for similar triggered effects

#

(It’s more complicated)

#

But I think regarding the English language it’s how people conceptualize these kinds of cause-and-effect phenomenons

zealous glen
primal robin
#

Adding a limit like "3 times per round" would be nice i think

opal spade
#

I've considered adding limits to it like "the first played hand" or "the last hand of the round", the former turns it into a drunkard with extra steps, but the latter is one of the things I'm considering

#

making it so the power to cycle the entire deck forces you to play your strongest hand kinda makes sense

#

one of the problems with adding such limits though is that it adds more text onto a card that barely fits 3 lines

primal robin
#

Dagger exists

zealous glen
#

Ultimately you can choose if you want to stay close to Balatro standards or stray further away

#

I think if you have the forced X0 Mult you’re already straying away

primal robin
#

Also, if you place Jimbo after Kirigiri-san, does it adds +4 mult after x0?

zealous glen
opal spade
zealous glen
# opal spade I'm all ears

It needs a bit of work still but:

When you play your final hand of round, if it has no face-down cards, +1 hand and draw your next cards face-down

#

So the detective becomes the player trying to find out what they drew

zealous glen
# opal spade that's actually rlly clever

I like the idea of face-down synergy. Me and at least like 3 other people have had the idea of making scoring face-down cards give xMult. But I think they need enablers

If you want to move further from your original idea, maybe something along these lines would work

opal spade
zealous glen
#

is it one of those white schwarma games

opal spade
zealous glen
#

The second google result is a Reddit post saying “the official Danganronpa card game”

opal spade
zealous glen
#

Tbf it seems to have been released only in Japan probably

opal spade
#

the game the original card is from is kinda like town of salem and the original effect is "when using your ability (investigation), you can use an investigation item as a free action"

#

which is why the whole cycling the deck using hands thing

zealous glen
#

I think if you use face-down cards it could be any hand

#

Although I prefer encouraging the player to play face-down cards

opal spade
#

bcos you'll eventually run out of face up cards

zealous glen
#

That’s why I said it could be any hand

opal spade
#

splendid

zealous glen
opal spade
#

stone synergy

zealous glen
#

I guess that’s true

#

I was trying to avoid it upgrading hands so I wonder how that would work

opal spade
#

it being a shortcut/four fingers for 3oak isn't really that big of a deal imo because 3oak as a hand is just ok

zealous glen
#

Yeah but I don’t want it to make just any three cards into 3OAK

#

At least 3 Stone cards to 3OAK requires some effort

#

I think this effect is about Uncommon in terms of strength, though I could see Rare for wackiness

opal spade
#

seems like an uncommon to me

zealous glen
#

ye

static juniper
#

Is it possible to change the size of a Joker's hitbox like with Half Joker, Square Joker, Photograph, and Wee Joker?

zealous glen
#

Yes

static juniper
#

How does one do that?

zealous glen
#

Take a look at how those Jokers do it

tepid sky
#

What coding language is mostly used for balatro modding?

#

I want to get into modding my self and i got a great idea i want to add

zealous glen
#

Lua

tepid sky
#

Ty

#

Anything else worthy of note?

zealous glen
#

The Steamodded wiki

static juniper
#

Looking at the code for resizing Jokers, and I found the code that does it in the Card:set_sprites and Card:set_ability functions, but I don't know how to recreate that for my own cards...

tepid sky
#

I'll check tmr! Thanks 🙏

static juniper
#

I tried to use the code for photograph to manipulate my Joker's size, but I'm pretty sure I'm doing it wrong since nothing's happening (and I have no idea what I'm doing). Here's what I put in my Joker

    if (card.discovered or self.bypass_discovery_center) then 
        self.children.card.scale.y = self.children.card.scale.y/1.2
    end
end,
set_sprites = function(self, card, front)
    if (card.discovered or self.bypass_discovery_center) then 
        H = H/1.2
        self.T.h = H
    end
end,```
frosty dock
#

that should be crashing the game, most likely

static juniper
#

Well it doesn't, it just does nothing

frosty dock
#

I'm pretty sure your selfs need to be replaced with card

static juniper
#

All of them?

frosty dock
#

all of them within the functions, of course

#

though if it does nothing, that means it's not being run at all

#

can I see the surrounding code?

static juniper
#
    key = "lucky_penny",
    rarity = 1,
    discovered = true,
    pos = {x = 0, y = 0},
    cost = 3,
    config = {extra = {mult = 15, chips = 90, odds = 2}},
    loc_vars = function(self, info_queue, card)
        return {vars = {card.ability.extra.mult, card.ability.extra.chips, card.ability.extra.odds, (G.GAME.probabilities.normal or 1)}}
    end,
    loc_txt = {
        name = "Lucky Penny",
        text = {
            "{C:green}#4# in #3#{} chance of {C:mult}+#1#{} Mult.",
            "Otherwise, {C:chips}+#2#{} Chips."
        }
    },
    set_ability = function(self, card, initial, delay_sprites)
        if (card.discovered or card.bypass_discovery_center) then 
            card.children.card.scale.y = card.children.card.scale.y/1.2
        end
    end,
    set_sprites = function(self, card, front)
        if (card.discovered or card.bypass_discovery_center) then 
            H = H/1.2
            card.T.h = H
        end
    end,
    calculate = function(self, card, context)
        if context.joker_main then
            if pseudorandom('lucky_penny') < G.GAME.probabilities.normal/card.ability.extra.odds then
                return {
                    mult_mod = card.ability.extra.mult,
                    message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult}}
                }
            else
                return {
                    chip_mod = card.ability.extra.chips,
                    message = localize{type = 'variable', key = 'a_chips', vars = {card.ability.extra.chips}}
                }
            end
        end
    end,
    atlas = "lucky_penny"
}```
#

It still does nothing

#

(The sprite stuff I mean, everything else works fine)

stray warren
#

Is there a Joker anybody knows of that works with enhancement gates (for reference)?

crisp coral
#

mystjokers' scratch card is gated behind lucky cards iirc

static juniper
stray warren
stray warren
static juniper
stray warren
#

fr (Stack Overflow comes to mind)

stray warren
static juniper
#

Although I'm now having a problem where when a save with the joker is loaded, this happens to the sprite

stray warren
#

I think I saw something about using the load function on the joker to fix that

#

At least that's what i saw on the Steamodded wiki

static juniper
#

Yeah, I couldn't figure out how to use load properly. I tried this but it led to the above image

    local W, H = G.CARD_W, G.CARD_H
    local scale = 65/71
    card.children.center.scale.y = card.children.center.scale.x
    H = W
    card.T.h = H*scale
    card.T.w = W*scale
end,```
stray warren
static juniper
#

65 is the width of my joker and 71 is the total width of all jokers

stray warren
#

Ok. So I need to calculate the width of my joker and put it there. I notice your Joker is a circle, but mine is a small rectangle (Other Joker for scale) so I'm just trying to figure out the logic for calculating this scale

static juniper
stray warren
#

All art credit goes to PaperMoon, I can't draw anything to save my life

static juniper
#

Maybe I should also get an artist lmao

stray warren
#

Btw, what'd you put in your set_sprites function?

static juniper
#

I don’t have one

stray warren
#

weird. My texture gets super tiny when I put what you wrote

#

Yeah, I got the hitbox where I want it, just the texture is super small lol

static juniper
#

Did you put the double sized textures in the 2x folder?

stray warren
#

Yeah, they're 2x

static juniper
#

Idk then đŸ€·

stray warren
#

This is what I have to get the hitbox where it is now

    set_ability = function(self, card, initial, delay_sprites)
        local W, H = card.T.w, card.T.h
        local w_scale, h_scale = 33/71, 43/95

        card.T.h = H*h_scale
        card.T.w = W*w_scale
    end,
static juniper
#

Maybe it’s because you’re missing the middle line?

stray warren
#

It squished

static juniper
#

Are you using the atlas to get your sprite?

stray warren
#

Yeah, I am. So I did this code, and I got the height to look right. The x, not so much lol

    set_ability = function(self, card, initial, delay_sprites)
        local W, H = card.T.w, card.T.h
        local w_scale, h_scale = 33/71, 43/95

        card.children.center.scale.y = card.children.center.scale.y * h_scale
        card.children.center.scale.x = card.children.center.scale.x * w_scale

        card.T.h = H*h_scale
        card.T.w = W*w_scale
    end,
static juniper
#

I didn’t use the main atlas to get this sprite. I used a completely separate atlas to specify a different sprite size

stray warren
#

I think it has to do with the sprite being in the middle of the 71x95 area defined

#

I'm gonna try moving it all the way to the left

lusty epoch
#

move it to top left

#

a few cryptid jokers that do this have their sprites at top left so maybe that will help

static juniper
#

Okay I managed to make it not bug out when reloading by doing this

    card.T.h = card.T.h * 65/95
    card.T.w = card.T.w * 65/71
end,
set_sprites = function(self, card, front) 
    card.children.center.scale.y = card.children.center.scale.y * 65/95
    card.children.center.scale.x = card.children.center.scale.x * 65/71
end,
load = function(self, card, card_table, other_card)
    card.T.h = card.T.h * 65/95
    card.T.w = card.T.w * 65/71
end,```
#

(Though it does bug out weirdly at the moment when you add it from the debug menu, but that's a non-issue)

stray warren
#

Moving to top left worked. Also, I added two pixels to the calculated width and height to account for the 1px transparent border on the regular joker sprites to get it aligned perfectly

tepid sky
stray warren
#

It will be a part of the Paperback mod (once I get around to implementing it) so check that out if you wish

tepid sky
#

It honestly seems like this coding isn't that hard...

#

But my idea that i want to implement kinda isn't a new joker?

#

Its far, far worse

mellow sable
#

cursed balatro images

unkempt thicket
mellow sable
nocturne garnet
#

wtf am i not getting

wintry solar
#

That’s not how to reference the shader key, it needs to just be ’holographic2’

primal robin
#

Skibidi Trolge

opal spade
#

the blueprint compat makes it still able to cycle the deck but i feel like having that synergy between two rares is fine

#

also because you wont be able to see the cards ur throwing away half the time nvm i forgot playing cards flips them lol, although you'd still have to play them to see them so

stray warren
#

Ok, so let me see if I've got this right. You can't hook into functions that aren't in a class, so you have to do a lovely patch in those instances?

opal spade
#

i think you can hook into them just fine

stray warren
#

How would I do it? This code is syntactically incorrect, and its referencing itself

local level_up_hand_ref = level_up_hand
function level_up_hand(card, hand, instant, amount)
    level_up_hand_ref(self, card, hand, instant, amount)

    -- Do stuff
end
frosty dock
#

that should work

#

the thing with Lovely patches is more that you can't hook into the middle of functions

#

it's not self referential, theka reference keeps pointing to the original

#

oh wait the self is wrong

#

you don't need self here

stray warren
#

It's saying undefined global 'self' and that amount doesn't fit in the arguments for level_up_hand. It's thinking self is a passed-in parameter

frosty dock
#

yeah just get rid of it?

#

there's no self in that function

stray warren
#

oh yeah. it's not a class

#

or in a class, I should say

frosty dock
#

In fact you cna always have the same incoming and outgoing arguments if you just avoid the colon syntax sugar

stray warren
#

Ok, so this code should do what I think it will, right?

local level_up_hand_ref = level_up_hand
function level_up_hand(card, hand, instant, amount)
    level_up_hand_ref(card, hand, instant, amount)

    -- Do stuff
    calculate_joker({level_up_hand = true})
end
frosty dock
#

Class:func() is just Class.func(self)

solid crag
#

Hey folks! I was wondering how easy or complicated it is to learn how to make custom decks for the game? I have zero programming experience of any kind, so I'm just wondering if this is the kind of thing I could pick up in a day or 2 of learning or if it would take a more extended period of time to work out?

glass scaffold
#

Stick by the Steamodded wiki and you'll be able to do a few things

#

This channel will help you along the way too

stray warren
#

It seems like it called calculate_joker just fine, but can't access the config for the card

frosty dock
#

what are you even calling calculate_joker on?

#

you should loop over G.jokers.cards

stray warren
#

When a hand gets leveled up, I want my Joker to do something

hallow forge
#

you aren't calling anything

stray warren
#

Oh, I see

hallow forge
#

calculate_joker must be done with an actual joker

stray warren
#

And in that loop, check if that Joker's name is my joker, call calculate_joker

hallow forge
#

no need

#

just pass the context

#

all jokers should check for contexts

stray warren
#

Cool, shouldn't make that mistake again. Thanks!

tidal edge
#

what is the line of code that would add a certain amount of money to my balance

hallow forge
#

ease_dollars()

tidal edge
#

wouldnt that just change the money value to something specific

#

not add to it

hallow forge
#

No, it adds

tidal edge
#

ok

tepid sky
#

nice

#

i was always wondering what the currency was called in the game

slow ocean
#

jollars

tidal edge
#

do you prelude it with anything

#

or does this itself add money

#

without anything before it

opal spade
#

it adds money

hallow forge
#

The function itself adds money

opal spade
#

it adds (retracts) money by a specified amount while doin the animation and playing the sound

night pagoda
#

Has anyone tried to open a booster pack after other booster pack is opened?

limpid flint
#

?

night pagoda
#

I'm getting either booster pack layered on top of the shop, or it does this after finishing:

night pagoda
#

I want to open a booster pack right after skipping it

#

Or rather, so the pack opening is triggered by skipping

#

nvm, I think I figured it out

zealous glen
# opal spade implemented this

I think the wording needs work still but cool! Also I think it might be okay if it worked for any hand but I’m not sure

#

In any case, keeping the effect, maybe:

If final hand of round has no face-down cards, +1 Hand then draw cards face-down

olive shoal
#

this is awesome

opal spade
opal spade
zealous glen
opal spade
#

ye but being specifically on the last one gives a more explicit push into that direction

zealous glen
#

I think “final hand” could be a bit unintuitive for players when you can play the final hand repeatedly, but I wouldn’t change the wording

glossy stone
#

DANGANORNAPOABDKSOAJSNK?????

#

MY INTEREST IS PIQUED

night pagoda
#

I'm trying to make an ability to reroll booster packs (via Voucher)

But there's a thing that I can't figure out: currently, after the pack is done opening, it requires one tick of being outside of pack to get back again, because otherwise it puts me in empty limbo instead of shop/game. This one tick triggers tags and other stuff, causing some nasty things to happen.

Any ideas? Maybe I can somehow open the next pack immideately without going into the shop/game?

#

This is my code currently (it is from lovely patch but I put it in an empty file for better visibility):

hushed cradle
#

im so confused

#

the colourblind one literally has mult_mod

#

but is still giving chips

#

would it be calculated in joker on joker effects?

crisp coral
#

is there any way to make an uibox not block objects below it?

#

ig i'll ping the uiboxmancer @wintry solar

wintry solar
#

visibility or click?

crisp coral
#

click

#

the part below the attention text uibox can't be clicked

zealous glen
#

For example, from High Card mod I made my own Joker that plays a hand over and over

#

So it required a bit more fine-tuned control of how the game updates the states

night pagoda
#

the issue is that I need at least one tick of being in the shop, if there's no that tick I appear in an "empty" state

wintry solar
#

uhhh, I'm pretty sure the mouse knows all of the elements, so it's just finding a way to ignore the text one

night pagoda
#

after closing the pack

crisp coral
#

how does that work

zealous glen
#

I think you’re changing states for a single tick

#

I am saying to not do that

night pagoda
#

yup, I just don't know what to do to get there

#

I can hook alright, but have no idea which thing exactly

zealous glen
#

Again there’s probably a update_name_of_state function

#

All the vanilla ones are in the same file

#

Try searching uh update_hand_played maybe?

#

Actually I think all of them are called in sequence in Game:update

#

Just make sure it will work for the Steamodded packs

night pagoda
#

the way I'm doing it now accounts for the steamodded packs

zealous glen
#

But this should be hookable if it’s like replaying a hand

crisp coral
#

oh got it! just needed to add args.AT.states.hover.can = false

zealous glen
#

And that works for Steamodded packs

night pagoda
#

can't find such function, I think states are simply switched by rewriting

#

without a function

zealous glen
#

Again look for Game:update

night pagoda
#

I'm still confused, because I can't inject in *_PACK state because that's not really what I need, the thing that needs replacement can be any state (not only shop), tags can open booster packs outside of it. Rerouting so it doesn't go to the shop after reroll won't solve every other state

zealous glen
#

Just reset the Booster pack state

#

Also update_hand_played definitely exists

night pagoda
#

it does

#

but I don't see how that helps tbh

zealous glen
#

They’re all in game.lua as expected

#

The booster pack ones are there too

night pagoda
#

yup

#

I have no idea what to do with them, still

zealous glen
#

For example, for Tarot Pack, try cleaning up what it creates and set G.STATE_COMPLETE = false

#

it might also help to look at the function that advances the state, since this one doesn’t seem to do it automatically

#

I think that would be G.FUNCS.end_consumeable

night pagoda
#

Wait, but If I do G.STATE_COMPLETE = false for the Tarot Pack it will just simply lock it from loading

#

end_consumable I use already, yep

night pagoda
#

G.STATE_COMPLETE makes the state load, after it loads it gets set back to false automatically

#

seems irrelevant to the problem

zealous glen
night pagoda
zealous glen
#

Look at update_arcana_pack

#

You’re looking at the wrong state update func to on

#

Also

night pagoda
#

it's the one you told me lol

zealous glen
#

If you read just before

#

You’ll see it changes states first

#

Which is why it sets it back to false

zealous glen
#

So I just told you the name of one I remembered

#

Because I knew the rest were in the same file

night pagoda
#

ahhh okay