#💻・modding-dev

1 messages · Page 631 of 1

daring fern
#

SMODS.calculate_effect({message = 'message'}, card)

white hull
#

ah wonderful, thank you

weary merlin
#

this is probably a stupid question with some less elegant ways to implement it,
but what would be a concise way to check if the player's joker slots contain at least 1 instance of a joker with a certain key

daring fern
dapper sun
#

how do i get if a card is debuffed?

daring fern
dapper sun
#

ty

#

how do i make something happen before all joker calculates? also, would a hook or patch be more fitting

#

i wanna add a juice_card_until thingy to my mechanic but i don't wanna add it manually into each joker i use said mechanic with

#

(my upgrade mechanic thing)

#

wait

#

ik a mod i could reference that's done something like this

#

nvmd i just looked at that code and that doesn't help

dapper sun
#

okay i think it's eval_card

stoic void
dapper sun
#

what am i doing wrong 😭

local ec_ref = eval_card
function eval_card(card, context)
    local ec = ec_ref(card, context)
    return ec
end```
dapper sun
stoic void
#

I love how thats the instant reaction

daring fern
dapper sun
#

ty

white hull
#

so i did this to make a certain joker always spawn as negative, but it also does it in the collection. how do i make it not do that in the collection?

#
set_ability = function(self, card, initial, delay_sprites)
    card:set_edition("e_negative", true)
end,
normal crest
#

Actually that might not work if set_ability is called before the card is placed in an area

white hull
#

doesn't become negative at all

normal crest
#

Break it in what way

#

Okay yeah, try making it in an event

dapper sun
#

okay, now it's making the card shake a not-so-normal amount

local oldevalcard = eval_card
function eval_card(card, context)
    local g, post = oldevalcard(card, context)
    
    if (card.config.center.slime_upgrade and card.config.center.slime_upgrade:can_use(card)) then
        juice_card_until(card, function() return not G.RESET_JIGGLES end, true)
    end
    
    return g, post
end```
normal crest
#

That happens when juice_card_until is called multiple times

daring fern
dapper sun
#

how should i correctly handle this then

normal crest
#

Pick a context for when you want it to happen

dapper sun
#

?

#

ok i'll try it

#

thanks

grand sage
#

how do i make this work everytime i load my mod with this code it says attempted to load a nil value

frosty rampart
#

you're using the load file function wrong, but you don't need to manually load image files anyway

#

you do need to have the images separated into a 1x and 2x version in the assets folder, but the game will automatically load everything properly placed in the assets folder

grand sage
slim ferry
#

just put the AltTexture in the check for the mod

weary merlin
#

what might be preventing a soul card from creating my custom legendary joker

#
SMODS.Joker {    --Archibald 
  key = "archibald",
    
    loc_txt = {
        name = "Archibald",
        text = {
            "Disables the price scaling of",
            "{C:green}Rerolls{} in the shop",
            "{C:inactive}(Minimum cost of {C:money}$1{C:inactive}){}"
        },
        unlock={
            "{E:1,s:1.3}?????"
        }
    },
    
    rarity = 4,
    cost = 20,
    blueprint_compat = false,
    
  pos = { x = 5, y = 0 },
  soul_pos = { x = 5, y = 1 },
    atlas = "jimbos",
        
    unlocked = false
}
local enlightenment_comedian_oldcalculatererollcost = calculate_reroll_cost
function calculate_reroll_cost(skip_increment)
  if (next(SMODS.find_card('j_en_comedian_archibald')) and G.GAME.current_round.reroll_cost > 0) then
        return enlightenment_comedian_oldcalculatererollcost(true)
  end
  return enlightenment_comedian_oldcalculatererollcost(skip_increment)
end
grand sage
loud citrus
#

Is there anything I can look to help me show dynamic text on a joker using loc_vars?

solid salmon
#

hey guys what are unscored cards identified as

#

like other_card is played cards

faint yacht
#

context.cardarea == 'unscored'

solid salmon
#

how do i destroy em

faint yacht
#

context.destroy_card and context.cardarea == 'unscored' and context.other_card, return {remove = true}

weary merlin
# solid salmon how do i destroy em

may i interest you in

calculate = function(self, card, context)
  if context.destroy_card and context.cardarea == "unscored" and not context.blueprint then
    return {
      remove = true
    }
  end
end
#

and tbh i find 100% destroy rate to be a bit OP

#

50% seems much more realistic

solid salmon
weary merlin
#

oh neat

solid salmon
#

it only works for 3 hands then it dies

weary merlin
solid salmon
#

neat

weary merlin
#

would anyone know why this doesn't work?

unlocked = false,
locked_loc_vars = function(self, info_queue, card)
  return { vars = { 18 } }
end,
check_for_unlock = function(self, args)
  return args.type == 'discover_amount' and #G.P_CENTER_POOLS.Spectral <= args.spectral_count
end
#

crashes when i try to load the game, despite it following the same format as vanilla rewritten does for the cartomancer unlock

weary merlin
#

i'm gonna try using the achievement criteria since that's an overlap here

#
check_for_unlock = function(self, args)
  return G.DISCOVER_TALLIES.spectrals.tally/G.DISCOVER_TALLIES.spectrals.of >= 1
end```
so this works fine but crashes upon profile reset, attempt to index field DISCOVER_TALLIES
solid salmon
#

how do i increase hands and discards for the current blind

daring fern
solid salmon
#

k

weary merlin
white hull
#

how would i do something when a joker is being destroyed i.e. by madness/dagger?

warm solar
#
for k, v in pairs(G.P_CENTERS) do
    if v.set == 'Joker' then
        if (not v.mod) then
            G.GAME.banned_keys[k] = true
        end
    end
end

how would i change this deck apply into only accepting jokers from a single mod, as it accepts all modded jokers right now.

normal crest
#

should do if v.original_mod and v.original_mod.id == "modid" then

feral tree
#

how do i detect if you've bought a spectral card in a G.E_MANAGER:add_event?

wispy falcon
#

How would I get the current position of the card in it's own calculate?

feral tree
#

this?

#
            for i = 1, #G.jokers.cards do
                if G.jokers.cards[i] == card then
                    my_pos = i
                    break
                end
            end```
wispy falcon
#

Let me try

#

Yes, that works. Thank you :D

warm solar
#

the original joker still shows up for some reason though

obsidian spear
rich pollen
#

Is there anything out there that implements like, a divide mult or divide chips score modifier???

versed swan
#

xmult = 1/(dividing amount)

rich pollen
#

You know what that makes sense

#

But how does that show up on the joker description?

#

Does it provide a divide symbol or do I have to format it myself

versed swan
#

you gotta format it yourself

#

something like {C:white,X:mult}/#1# {}Mult or something

rich pollen
#

Making a risk of rain 2 full content mod

obsidian spear
rich pollen
#

I am not the one to help lols

warm solar
#

how do you play a sound without delay when you're also changing the mult/chips

loud summit
#

hi how do you play the juice up anim on the blind score

keen quest
#

How would the code look like if I want the joker to activate on any hand except a specific one

#

like something like "Gains +10 mult if a played poker hand is not a straight"

loud summit
#

look at ortalab

daring fern
keen quest
#

thank you 🙏 🙏 🙏

mystic river
#

the only way to block Jimbo entirely is to ensure some other joker can always appear

daring fern
#

obsidian spear
#

How do I get the loc_txt of a joker?

daring fern
obsidian spear
#

tyyyyyy

vale grove
#
        calculate = function(self, card, context)
        
        if context.initial_scoring_step then 
            local old_mult = mult * 2
            local old_chips = hand_chips *2
            mult = mod_mult(old_mult) 
            hand_chips = mod_chips(old_chips)

            return {
            message = "Doubled!",
            pitch = 1,


            }
        end
    end,

i have this that doubles the base chips and mult, how do i make it keep doubling as the round goes on (and make it reset at the end of round)
(so a lvl 1 high cards becomes 2 - 10 4 -20 8 -40 etc)

daring fern
vale grove
#

i copied this from another joker i have and it works so i didnt really ask questions tbh

daring fern
vale grove
daring fern
vale grove
vale grove
#
    config = {
        extra = {
            multiplier = 0
        }
    },

    loc_vars = function(self, info_queue, center)
        return { vars = { center.ability.extra.multiplier } }
    end,

    calculate = function(self, card, context)
        if context.before then
            card.ability.extra.multiplier =
                card.ability.extra.multiplier + 1
        end

        if context.end_of_round or context.main_eval then
            card.ability.extra.multiplier = 0
        end

        if context.initial_scoring_step then
            local multiplier = card.ability.extra.multiplier

            return {
                card = card,
                Xmult_mod = 2 ^ multiplier,
                Xchip_mod = 2 ^ multiplier,
                message = "Doubled",
                colour = G.C.MULT
            }
        end
    end
``` this doesnt do anything
#

        if context.initial_scoring_step then
            local multiplier = card.ability.extra.multiplier
            local Xmult_mod = 2 ^ multiplier
            local Xchip_mod = 2 ^ multiplier

            return {
                card = card,
                mult = mult * Xmult_mod,   
                hand_chips = Xchip_mod,
                message = "Doubled", 
                colour = G.C.MULT
            }
        end

however this one doubles the mult (idk the correct way for chips so that one doesnt) but the multiplier stack doesnt work (everything same as above)

subtle storm
#

Hello, I have an issue with a shaders that i've created for an edition. i don't understand why i have that beacause i don't have a mouse_screen_pos variable in my shader.

solid salmon
#

would this work (btz_gokus is an objectType)

vale grove
solid salmon
#

then do

#

chips = chips * XChip_mod

solid salmon
#

What about writing down every member of that object type?

normal crest
#

does your object type have only jokers

solid salmon
#

Yes

vale grove
subtle storm
wintry solar
#

You need to use the galactic variable in your shader or delete it iirc

subtle storm
#

where am i supposed to use it

normal crest
#

I think your variable may need to be named galactic rather than galaxy

normal crest
# solid salmon Yes

you can loop through G.jokers.cards and check if joker.config.center.pools.btz_gokus

faint yacht
#

...just check if the given center actually has pools.

normal crest
#

forgot about that, so if (joker.config.center.pools or {}).btz_gokus

vale grove
#

how do you disable the standard message of adding mult or chips?

static valley
#

How would I keep track of jokers that have been sold or destroyed

#

not like the number, I mean I wish to keep track of the 2 most recent jokers/consumables/cards that have been sold/destroyed

ocean sinew
#

is there a variable of how much cards got sold this run?

slim ferry
#

how can i get if a card has been discovered or not?

solid salmon
#

for i = 1, G.jokers.cards do

ocean sinew
#

how do I do soul layer

stoic void
high agate
#

how come sound = 'key' and play_sound() result in completely different volumes

vernal halo
#

is the mod "balatro goes kino"compatible with cryptid?

high agate
#

former seems to be much quieter than the latter

vernal halo
#

found it

vale crow
#

Is there a way to make it so when playing a hand, instead of using a poker hand's score, to add up the chips and mult of each poker hand that composes the played hand?
For example when playing a Full House, instead of doing 40X4, it uses the chips and mult of High Card, Pair, Two Pairs, Three of a Kind and Full House making it 5+10+20+30+40 X 1+2+2+3+4.
Obviously a mod that would do such a thing should change the poker hand's scoring values to balance things.

wet valley
#

Hi, I'm trying to make a mod to procedurally generate Jokers, here's what I got so far (textures are mostly for testing purposes for now)

#

However I'm running into a few issues

#

One being the annoying little border that gets added to the outline of different Sprites

#

And the other is the tilt not being properly applied from the parent card

harsh belfry
#

oh hell nah we got JokNFT

wet valley
#

That is not the intent but unfortunately feels similar

spiral mural
#

how do i have unmodifiable values in a joker (as in other jokers can't value manipulate them)

umbral zodiac
pallid bobcat
umbral zodiac
#

or if you only want certain values the standard for that is an “immutable” table, similar to the “extra” table

spiral mural
#

thanks lily

wet valley
#

Otherwise I'm also rendering them with the center as the parent

#

Oh wait draw major

#

I didn't read that part my bad

frosty rampart
#

balatro is in a 2d engine, the shader pipeline and speicfically the dissolve shader is what simulates the 3d effect

spiral mural
#

how do i select a random consumable pool

#

nvm found it G.P_CENTER_POOLS.Consumeables

wet valley
#

Now I only have the remaining issue of borders around sprites, if anyone knows what causes that?

#

Could it be due to my png atlas being weird?

#

Or is it something to do with rendering

#

I had that issue on a previous mod as well where I created a custom deck skin

#

Here's another example of the issue

wet valley
#

I see the issue is what I expected

sage crater
#

should this part in vanillaRemade have parenthesis for the function?

versed swan
#

That is valid Lua syntax, parentheses are optional

#

Especially for SMODS.create_card since it only takes one parameter of data type table

sage crater
#

that's crazy

#

but good to know

tidal hemlock
#

how do you use variables in jokerforge? and how do you display them visually?

frosty rampart
#

the jokerforge thread in #1209506514763522108 or the jf discord server (linked in that thread somewhere iirc) is probably a better place to ask

tidal hemlock
frosty rampart
tidal hemlock
#

nvm forgot the space lol

frosty rampart
#

yea lol

sage crater
#

what area should this playing card have to go to my deck (Also, I have an emplace function afterwards to send it to my hand. Is this right)?

chrome widget
#

Area shouldnt be a string literal

#

You can use SMODS.add_card instead to automatically emplace it somewhere

daring fern
#

warm solar
#

how do i make a joker that, when sold, replaces all held jokers with their specific counterpart jokers?

daring fern
warm solar
loud summit
#

how does in_pool work for backs

#

how would i prevent it from spawning a specific vooucher

vale zinc
#

How do I pass a given card's table as an argument to SMODS.add_card()?

daring fern
daring fern
vale zinc
#

Without drawing it to hand.

daring fern
loud summit
#

is there a context for entering a shop

daring fern
loud summit
#

oh

#

its not on the wiki

frosty rampart
#

yea the calculate functions wiki page is woefully outdated
eremel's working on rewriting it, just give him some time

loud summit
#

ok

#

also how does the in_pool function work for decks

vale zinc
# daring fern `copy_card(card)`

I've got this code excerpt from something that creates a copy of the player's deck when the Blind is selected, but it doesn't work.

local mirror_card = copy_card(card_to_mirror, nil, nil, G.playing_card)
mirror_card:add_to_deck()

I'm basing it on Ortalab's Rouge Rose.

loud summit
#

i want to make reroll surplus not appear when my deck is used and taking ownership of it seems excessive

warm solar
vale zinc
#

@daring fern, can I pass copy_card(card) as an argument to SMODS.add_card()?

#

And how does SMODS.add_card(card) differ from card:add_to_deck()?

daring fern
vale zinc
# daring fern `SMODS.add_card` creates a card, emplaces it, and adds it to deck, `Card:add_to_...
set_blind = function(self)
    ease_hands_played(self.config.extra.mod_hands)
    
    local list_of_mirror_cards = {}
    for _, card_to_mirror in pairs(G.deck.cards) do
        G.playing_card = (G.playing_card and G.playing_card + 1) or 1
        local mirror_card = copy_card(card_to_mirror, nil, nil, G.playing_card)
        mirror_card.ability.LAPSEMS_world_mirror = true
        list_of_mirror_cards[#list_of_mirror_cards + 1] = mirror_card
    end
    
    for i = 1, #list_of_mirror_cards do
        G.E_MANAGER:add_event(Event({
            trigger = 'after', delay = 0.05,
            func = function()
                SMODS.add_card(list_of_mirror_cards[i]) -- This line produces a crash.
                return true
            end
        }))
    end
    
    self.original_deck_size = G.GAME.starting_deck_size
    G.GAME.starting_deck_size = #G.playing_cards
    G.deck:shuffle('bl_lapsems_final_mirror')
end,
#

Rewrote it a bit, and it crashed without giving an error message.

set_blind = function(self)
    ease_hands_played(self.config.extra.mod_hands)
    
    local list_of_mirror_cards = copy_table(G.deck.cards)
    for _, card_to_mirror in pairs(list_of_mirror_cards) do
        G.playing_card = (G.playing_card and G.playing_card + 1) or 1
        card_to_mirror.ability.LAPSEMS_world_mirror = true
    end
    
    for i = 1, #list_of_mirror_cards do
        G.E_MANAGER:add_event(Event({
            trigger = 'after', delay = 0.05,
            func = function()
                SMODS.add_card(list_of_mirror_cards[i])
                return true
            end
        }))
    end
    
    self.original_deck_size = G.GAME.starting_deck_size
    G.GAME.starting_deck_size = #G.playing_cards
    G.deck:shuffle('bl_lapsems_final_mirror')
end,
#

Tried the first batch of code that I posted, and it does produce an error message when it crashes the game.

daring fern
# vale zinc Tried the first batch of code that I posted, and it *does* produce an error mess...
set_blind = function(self)
    ease_hands_played(self.config.extra.mod_hands)
    local function better_copy_card(card, new_card, area)
        if not card then return nil end
        local area = area or (new_card and new_card.area) or card.area or G.jokers
        local cardwasindeck = new_card and new_card.added_to_deck or nil
        local copy = copy_card(card, new_card)
        if new_card and cardwasindeck then copy:remove_from_deck() end
        if card.playing_card then
            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
            copy.playing_card = G.playing_card
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, copy)
        end
        if (new_card and cardwasindeck) or not new_card then copy:add_to_deck() end
        if not new_card then area:emplace(copy) end
        return copy
    end
    for k, v in pairs(G.deck.cards) do
        better_copy_card(v).ability.LAPSEMS_world_mirror = true
    end
end
vale zinc
#

Also, this is what Rouge Rouse uses:

local card = SMODS.add_card({set = 'Base', area = G.deck, suit = suit, rank = rank})
card.ability.rouge_rose = true
vague crest
#

currently trying to discard certain ranks after hand is played, in a fashion similar to The Hook. I've narrowed it down to this specifically crashing it when it runs but the error log isn't giving me anything to go off of, just that the highlighted bit crashes

#

says attempt to index local 'card', a nil value

daring fern
vague crest
#

what does that mean in this context? i was under the assumption that one of these is a list of cards (queue) and one of them is just the array of highlighted cards

#

tried refactoring it to be more like the vremade hook and still same issue,

#

more of the code if it helps

#

it might be struggling to give selected card the value?

daring fern
vague crest
#

oh shit that worked great! thanks

spice scroll
#

just spent like ages troubleshooting cause localthunk misspelled hierophant in the code

maiden phoenix
wet valley
#

SDM_0 THE LEGEND

#

I have some ideas, but the graphical part is so fun that I might focus on that first for a bit

#

I'm a sucker for procgen

maiden phoenix
stiff locust
#

im going to try rotating a joker again

#

but where is the rotate

#

everyone just said smods.drawstep last time i asked and there's nothing in the documentation for angle

pale holly
#

OKay so two things :
Is there a way to change the spawn rate of a voucher or a consumable if you own a joker ?
I know i could use something like if next(SMODS.find_card("j_splash")) then to check if a joker is present but i wouldn't know about the rest

mystic river
#

there's not a built in function to my awareness
you may have to patch something in somewhere

pale holly
mystic river
#

is get_weight valid on vouchers and consumeables? the documentation is really unclear on this

#

yeah i don't think it is
only modifiers, vouchers, and rarities (but not cards within the rarity)

#

seems like a feature worth adding someday

pale holly
#

well, weight is about spawn rates right ?
maybe it could work out ?
i guess right now the only really easiest way would be to do a special pool for it ?

#

oh wait

#

in pools

#

what if i try to play with the weight ?

something among the lines of


in_pool = function(self, args)
if next(SMODS.find_card("j_splash")) then
    return true
else
  return false
end
end,

#

the card couldn't spawn unless the joker is present

#

i guess it's worth to see if it does work in that logic

#

though

#

HOLY FUCK IT ACTUALLY WORKS

#

I made a quick test with planet cards, in that case there's only pluto since it's the default card and i've all planet cards in my consumable slots

#

and here i've added splash from the code and now the consumable spawns

rigid pebble
#

you can do this in vanilla

#

real fun

#

very hard tho

pale holly
#

I mean i guess ?

rigid pebble
#

perkeo

#

and with tarots too

pale holly
#

I just wanted to make so my consumable wouldn't appear unless a very specific joker is in the joker slots

rigid pebble
#

you can make an infinite money chain if you thin pool down to emporor and hermit

pale holly
#

oh yeah,

#

i mean my goal here was just to see if my code to make a consumable appear only if a joker is present to work or not

rigid pebble
#

that would be a good seeded run

pale holly
#

and right now

#

it does

rigid pebble
#

cool

pale holly
rigid pebble
#

i want infinite money

#

i might be the first too...

pale holly
#

sure

rigid pebble
#

i can beat a million

#

surely

mossy anchor
#

fellow linux players what was the balatro mod directory again

#

as payment ill give PeggleSetup.exe

pale holly
mossy anchor
#

yk theres a way easier way to say /home/(your username) right

pale holly
#

Perhaps

mossy anchor
#

also its ~/.local/share/Steam/steamapps/compatdata/2379780/pfx/drive_c/users/steamuser/AppData/Roaming/Balatro/Mods/ for me

#

~

pale holly
hollow mango
#

i'd like to create an unlock for an enhancement. if im not mistaken, enhancements can't do unlocks, right? I remember trying at one point, at least...

i could pretty easily do some trickery and swap the sprite and description using loc_vars, which would make it look like it was locked. but how would I do an unlock popup like using unlock_card? would I have to make the UI myself, or is there something else I can do?

delicate pivot
#

I've asked this before, but maybe someone else will know what to do. I'm trying to overwrite the base game's blank card sprite so it is either accepting a new sprite in its place or make it invisible (whatever is easier). I can provide an example/photo to explain what I mean if anyone is confused. I already the new sprite made, but I don't know how to overwrite the sprite.

wintry solar
#

Using Malverk?

dusty fractal
#

how would i make a joker return a different string when its in the collection

#

i have a randomized hand type when you encounter it but i want it to explain that in the collection

hollow mango
dusty fractal
#

sweet thanks

#

is there a list of the valid areas

hollow mango
#

i dont know of one off the top of my head

dusty fractal
#

i imagine its somewhere in the code but

hollow mango
#

its def in the code yeah

dusty fractal
#

kk sweet

hollow mango
#

maybe G.shop_jokers or smth

dusty fractal
#

im trying to just find the one thats for the dictionary

#

cus it' dbe a lot safer to use an if statement to check that

#

edge cases

hollow mango
#

i'm digging through the code rn and i see G.your_collection

#

which is being indexed so i assume its a table of some kind that contains cardareas

dusty fractal
#

G.DISCOVER_TALLIES.jokers

#

it seems like it iterates through this?

#

which is weird

#

but im thinking that might just be some sort of tallying method

#

thats just implemented weird

hollow mango
#

possibly

wintry solar
#

Maybe I should implement alternate collection loc vars like blinds have 🤔

dusty fractal
#

thats what i was thinking yeah

hollow mango
#

maybe...

#

ive run into this situation more than once (but usually i just work around it instead of implementing anything into the joker to actually do it)

dusty fractal
#

i tried to implement it with the collection loc_vars shit

#

but it didnt work and i was like

#

'huh. thats weird'.

hollow mango
#

lol

dusty fractal
#

it seems like checking if card.area == G.your_collection doesn't do anything

#

which is weird since it definetly is handled as an area

hollow mango
#

no cuz its a table of card areas

#

you have to index a particular one

dusty fractal
#

ohhhhh lmao

hollow mango
#

u could just iterate and test them all

#

and thatd do it

#

i assume its one cardarea per row

dusty fractal
#

could also jus look through the joker one

#

but then

#

that'd not work with the 'mods'' part of the mod would it

#

hmmm

#

where it show sall the additions

#

sweet

hollow mango
#

SUCCESS!

#

mission accomplished

wispy falcon
#

Why does the Card with this Edition never trigger? Or more specific, how do I only make it trigger when it is it's turn?

wintry solar
#

You should be able to do card.area.config.collection iirc

dusty fractal
#

fair

#

now i want to make it only show in inactive color if its in the collection

#

time for evil code

spice scroll
#

real quick how do i make the text wiggle inside a joker text box

#

i thought it was v:1 but that isnt workin

normal crest
#

i think it's E:1

spice scroll
#

fire tyy

#

whered my reactions go..................

normal crest
elder rune
#

Where in the code does mult and chips get multiplied together

normal crest
#

but not 100% sure

elder rune
#

I swear I have checked like everywhere but eh ill see again

#

yeah I think I found it

tired kestrel
#

but I have not selected which.

#

although I do have an ipad which I ahve not installed balatro on it.

normal crest
#

you need to pick one of those there

tired kestrel
#

I'll go ahead and pick theo nes of the devices I have

#

and I can react soemhow now

static valley
#

how do I check if you ended a round using your most played hand?

river grail
#

oh yea ive been meaning to ask
@tired kestrel how do you change the balatro background into a different shader again? ive been wanting to do that for my end except the background would change based on a bunch of parameters (like how high you score, or if a certain shop is active)

tired kestrel
# river grail oh yea ive been meaning to ask <@860812270946353163> how do you change the bala...

I think you have to basically make splash.fs or background.fs and basically add in the shader you wanted. But you also have to make sure to sue the mix and set it to 1 so that way while the oriignal background is used without error you can basically set the other one to the max to show the background you desire.

The last part is basically having to configure about how you want it to make it. cause if you do't do modifications you'll get like the basic one since right now the brightness is handled by the splash.

#

I don't know if there'd be a proper tutorial

#

or if I would ever make a proper tutorial as it seems advanced to do but you have to like learn about how shaders work

river grail
#

right

#

i'll look into it

tired kestrel
tired kestrel
# river grail i'll look into it

alright. though even though I only did this for my Drac-amet mod but there's a bit more to go through. But yeah I wish you luck and maybe hopefully there is a better way to replace the vortex in more easier way

vale zinc
static valley
#

and... now it does nothing...

frosty rampart
#

yea end_of_round runs for context.individual too
add and not context.individual and it should be fixed i think?

static valley
#

yea it's not doing anything

#
    -- Dragoon
    SMODS.Joker{
        key = "dragoon",
        atlas = "comedy_mythical_jokers",
        pos = { x = 1, y = 0 },
        soul_pos = { x = 2, y = 0 },
        unlocked = false,
        blueprint_compat = true,
        rarity = "comedy_mythical",
        cost = 30,
        config = { extra = { exp_mult_gain = Comedy_checkDifficulty(0.05, 0.1), exp_mult = 1 } },
        loc_vars = function(self, info_queue, card)
            return { vars = { card.ability.extra.exp_mult_gain, card.ability.extra.exp_mult, colours = {ComedyColors.EMULT} } }
        end,
        calculate = function(self, card, context)
            if context.end_of_round and (G.GAME.last_hand_played == G.GAME.current_round.most_played_poker_hand) and not context.individual then
                card.ability.extra.exp_mult = card.ability.extra.exp_mult + card.ability.extra.exp_mult_gain
                return { message = localize { type = 'variable', key = 'a_exp_mult', vars = { card.ability.extra.exp_mult } } }
            end
            if context.joker_main then
                return {
                    exp_mult = card.ability.extra.exp_mult
                }
            end
        end
    }

here's the code if it can help with fixing anything

slim ferry
#

try context.main_eval instead of not context.individual

#

also fyi that most played hand value resets per ante iirc

#

since its only used for the ox

#

all other things use a for loop to find the most played hand

static valley
mellow marsh
#

yall am i dumb is there a typo here i can't see

#

every other joker loads fine

tranquil gull
#

that seems wrong

mellow marsh
#

thats odd

normal crest
#

then you'll have an actual crash log

#

or remove the message from assert

slim ferry
#

fyi, SMODS.load_file returns two things

#

both the file as a function and an error if one arises

mellow marsh
#

ahh okay, ty both

slim ferry
#

so you probably want to be doing

local file_data, err = SMODS.load_file(path..".lua")
if err then error(err) end
normal crest
#

yeah that's better than what I said

slim ferry
#

cryptid also does this for its recursive loader

mellow marsh
#

fwiw the wiki only mentions a single return value for load_file, i suppose that should be amended sometime

#

(though it then mentions love.filesystem.load, which would probably yield the correct return results if i had checked that)

static valley
#

trying to make it so that if you have 3 very specific jokers, it combines them into a fourth very specific joker

-- in a function that essentially hooks into Game:update(dt)
    -- checking if you have all dragoon parts
    local dragoonParts = {"j_comedy_dragoon_claw", "j_comedy_dragoon_body", "j_comedy_dragoon_wings"}
    if Comedy_containsAll(Comedy_checkForJokers(dragoonParts), dragoonParts) then
        Comedy_fuse_jokers(Comedy_checkForJokers(dragoonParts), create_card(nil, G.jokers, nil, nil, nil, nil, "j_comedy_dragoon", 'mythical_obtain'))
        check_for_unlock { type = 'comedy_spawn_mythical' }
    end

-- in utils.lua
-- util function to check if you have a specific list of jokers equipped
-- will be used especially for stuff like Mythical Joker creation
function Comedy_checkForJokers(jokers)
    local output = {}
    if type(jokers) ~= 'table' then return {} end
    if not G.jokers or not G.jokers.cards then return {} end
    
    for _, joker in ipairs(jokers) do
        if joker and joker.config and joker.config.center and joker.config.center.key then
            local id = joker.config.center.key
            if next(find_joker(id)) then table.insert(output, joker) end
        end
    end
    return output
end

-- destroys a joker
function Comedy_destroy_joker(joker)
    if joker then
        G.E_MANAGER:add_event(Event({
            trigger = 'after',
            delay = 0.15,
            func = function()
                if joker and not joker.removed then
                    joker:start_dissolve({ G.C.SPECTRAL, G.C.WHITE })
                    joker:remove_from_deck(true)
                    G.E_MANAGER:add_event(Event({
                        trigger = 'after',
                        delay = 0.5,
                        func = function()
                            if joker and joker.area then joker.area:remove_card(joker) end
                            return true
                        end
                    }))
                end
                return true
            end
        }))
    end
    delay(0.6)
end

-- will destroy the input jokers, and create the output joker
function Comedy_fuse_jokers(input, output)
    -- makes sure both args actually exist
    if not input then return end
    if not output then return end

    if type(input) ~= 'table' then return end
    for _, joker in ipairs(input) do
        Comedy_destroy_joker(joker)
    end
    if output then
        SMODS.add_card(output)
    end
end

-- checks two tables
function Comedy_containsAll(t1, t2)
    local set = {}
    for _, v in ipairs(t1) do set[v] = true end

    for _, v in ipairs(t2) do
        if not set[v] then return false end
    end
    return true
end

It doesn't do anything when I have all of the necessary jokers. Is there any place that I might have messed up
-# doing this in a game:upadate hook because if I had each individual piece check in the add_to_deck, it might accidentially create 3 copies of the thing

tranquil gull
#

ooooooooh yea i broke sth Bad

slim ferry
#

it doesnt really do anything anyway

slim ferry
#

you definitely should change that function

static valley
#

i was about to ask

slim ferry
#

since currently all its doing is checking the keys of inputted cards and then checking if theres a joker with that key

#

which will be the case 99% of the time

#

also the function also seems a bit redundant, for the fusion check you could just do if next(SMODS.find_card("j_comedy_dragoon_claw")) and next(SMODS.find_card("j_comedy_dragoon_body")) and next(SMODS.find_card("j_comedy_dragoon_wings"))

#

and for the fusion you can then do it like this instead

SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_claw"))
SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_body"))
SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_wings"))
SMODS.add_card{ key = "j_comedy_dragoon", area = G.jokers }
static valley
# slim ferry and for the fusion you can then do it like this instead ```lua SMODS.destroy_car...
-- will check if you have the requirements to fuse the jokers
-- mainly for mythical shards
function Comedy_fusionCheck(parts)
    if (not parts) or (type(parts) ~= 'table') then return false end
    local canFuse = true
    for _, part in parts do
        if not SMODS.find_card(part) then
            canFuse = false
        end
    end
    return canFuse
end
    -- checking if you have all dragoon parts
    local dragoonParts = {"j_comedy_dragoon_claw", "j_comedy_dragoon_body", "j_comedy_dragoon_wings"}
    if Comedy_fusionCheck(dragoonParts) then
        Comedy_fuse_jokers(dragoonParts, "j_comedy_dragoon")
        check_for_unlock { type = 'comedy_spawn_mythical' }
    end

I went and did this now, and the second I booted up the game, I got a crash

slim ferry
#

youre missing pairs/ipairs

#

in the for loop

static valley
#

oops

#

i sometimes forget that I'm not coding in python or java

#

so...

#

I got it to work

#

but now when you have the 3 things, it will keep making an endless supply of the Dragoon until after the dragoon parts have been destroyed, but only because it caused an error

slim ferry
#

did you forget to return true in the event

static valley
#

so even if you didn't have the 3 pieces, it will just keep creating an endless amount

slim ferry
#

SMODS.find_card at least returns an empty table

#

so you need a next

#

you should also probably set a flag while the fusing is happening so it doesnt keep happening until the destruction animation finishes

static valley
slim ferry
#

probably in the update hook when fusion starts

#

and then check if the flag isnt set before doing fusion

#

you could also just handle fusing in the add_to_deck for each of the jokers actually

#

so you dont have to worry about it running repeatedly

static valley
slim ferry
#

no

vale crow
#

which context. should I use for before cards are scored but after the contained poker hands are put into context.poker_hands?

slim ferry
#

add to deck only runs when you obtain the card

#

which would only do something on the last part you obtain

vale crow
slim ferry
#

why wouldnt it work

#

theres nothing about that that wouldnt work there

frosty rampart
#

if you're trying to add chips/mult, use context.initial_scoring_step instead
but otherwise yea context.before should be perfectly fine

vale crow
#

When using it, context.before is before a score reset step

frosty rampart
#

yea that's intended behavior

#

use context.initial_scoring_step if you need to modify any scoring

slim ferry
#

that is not related to the specific calculate yueah

frosty rampart
#

(resetting the score after context.before allows e.g. the level up from space joker to actually apply to the played hand)

vale crow
#

Thanks, I've tried initial_scoring_step but apparently context.poker_hands is not populated

#

or I'm doing something wrong

wintry solar
#

show your code

vale crow
#

I want to add mult for every poker hand contained, I'm currently testing it before making it a joker

function SMODS.current_mod.calculate(self, context)
if context.initial_scoring_step then
local nbph = 1

    if context.poker_hands then
        for _, h in ipairs(context.poker_hands) do
            nbph = nbph + 1
        end
    end

    return {mult= 10*nbph}
end

end

wintry solar
#

context.poker_hands isn't an integer indexed table

#

so ipairs wont do anything to it

#

you want something like this

for _, hand in pairs(context.poker_hands) do
  if next(hand) then nbph = nbph + 1 end
end
vale crow
#

Thanks! But what is the underlying structure of poker_hands?

wintry solar
#
{
  ['Pair'] = {{Card, Card}, {Card, Card}, {Card, Card}},
  ['Three of a Kind'] = {{Card, Card, Card}},
  ['Flush'] = {},
 -- etc
}
#

I believe that is how a three of a kind would look

vale crow
#

There's no ['High Card'] ?

wintry solar
#

every hand is always present

#

I just didn't type high card

vale crow
#

Ok Thank you very much!

#

It works!

static valley
# slim ferry no
    SMODS.Joker{
        key = "dragoon_claw",
        atlas = "comedy_mythical_jokers",
        pos = { x = 0, y = 0 },
        soul_pos = { x = 0, y = 0 },
        unlocked = true,
        blueprint_compat = true,
        rarity = "comedy_mythical_shard",
        cost = 10,
        config = { extra = { xmult = 2 } },
        loc_vars = function(self, info_queue, card)
            return { vars = { card.ability.extra.xmult, localize('j_comedy_dragoon')['name'] } }
        end,
        add_to_deck = function(self)
            if Comedy_hasJokers({"j_comedy_dragoon_claw", "j_comedy_dragoon_body", "j_comedy_dragoon_wings"}) then
                G.E_MANAGER:add_event(Event({
                    trigger = 'after', delay = 0.5, blocking = false,
                    func = function()
                        SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_claw"))
                        SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_body"))
                        SMODS.destroy_cards(SMODS.find_card("j_comedy_dragoon_wings"))
                        SMODS.add_card{ key = "j_comedy_dragoon", area = G.jokers }
                        check_for_unlock { type = 'comedy_spawn_mythical' }
                        return true
                    end
                }))
            end
        end,
        calculate = function(self, card, context)
            if context.joker_main then
                return {
                    xmult = card.ability.extra.xmult
                }
            end
        end
    }

for some reason even if it does have all 3 when the third one is added to the deck, it will not do anything

dusk cargo
#

How do I make my deck block everything added from different mods (excluding my mod)

mystic river
#
apply = function(self, back)
  for k,v in pairs(G.P_CENTERS) do
      if v.original_mod and v.original_mod.id ~= "your_mod_id" then
          G.GAME.banned_keys[k] = true
      end
  end
end

depending on the timing of things, you might have to put it in an event to make it wait til G.GAME.banned_keys actually exists

wintry solar
static valley
# wintry solar what does your hasJokers function look like?
function Comedy_hasJokers(jokers)
    if (not jokers) or (type(jokers) ~= 'table') then return false end
    local hasJokers = true
    for _, joker in ipairs(jokers) do
        if not next(SMODS.find_card(joker)) then
            hasJokers = false
        end
    end
    return hasJokers
end
wintry solar
#

I believe the add to deck function is called before the card is added to the area, so this function will never be able to find the card that is calling it

#

try just checking for the other 2 cards

dusk cargo
mystic river
#

yep
the only things not in G.P_CENTERS are blinds and tags, iirc

dusk cargo
#

Thank you!

static valley
frosty rampart
#

create the joker in an event

solid salmon
#

how do i use "is a pair" as a context (not contains)

frosty rampart
#

context.scoring_hand will be a string containing the name of the hand that it actually counts as
use that in whatever timing you have

vale zinc
#

context.scoring_name == <poker_hand>

dusk cargo
#

Does anyone know the problem with this

daring fern
dusk cargo
#

Where?

daring fern
# dusk cargo Where?

if context.debuff_card and (context.debuff_card:is_suit('Spades') or context.debuff_card:is_suit('Clubs'))

solid salmon
vale zinc
#

A question of my own: just what can you pass as an argument to SMODS.add_card()?

vale zinc
# solid salmon wdym?

I ask 'cause I'm creating a Showdown Blind that gives the player a copy of their current deck, which I based on Ortalab's Rouge Rose.

#

Here's what Rouge Rose uses to assemble the original deck:

local suits = {'S','C','D','H'}
local ranks = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'}
for _, suit in ipairs(suits) do
    for _, rank in ipairs(ranks) do
        G.E_MANAGER:add_event(Event({
            trigger = 'after', delay = 0.05,
            func = function()
                local card = SMODS.add_card({set = 'Base', area = G.deck, suit = suit, rank = rank})
                card.ability.rouge_rose = true
                return true
            end
        }))
    end
end
solid salmon
#

you could check wraith

#

wait no

#

wrong card

vale zinc
#

Cryptid, you mean? I was told much the same.

solid salmon
#

ankh

#

the spectral

vale zinc
#

But it doesn't work when I pass a card (in table form) to SMODS.add_card().

solid salmon
#

oh

#

i dont really know anything about copying cards

vale zinc
#

Is there anyone here who might?

solid salmon
daring fern
vale zinc
solid salmon
#

is there a way to get the level of a played hand

static valley
#

how do I get exponential mult to work without having to use/require Tailsman?

solid salmon
#

or like

#

not played

vale zinc
daring fern
solid salmon
#

hey guys

#

how do i get the level of pair

vale zinc
mystic river
static valley
# daring fern `mult_mod = (-mult)+mult^number`

this ended up happening:

INFO - [G] 2025-12-11 18:56:14 :: ERROR :: StackTrace :: Oops! The game crashed
main.lua:2020: [SMODS ComedyGold "include/utils.lua"]:467: attempt to perform arithmetic on global 'chips' (a nil value)
vale zinc
# mystic river yes

You and @daring fern, that did correctly clone the deck, but now the cards won't go away! (This was likewise adapted from Rouge Rose.)

disable = function(self)
    if not G.GAME.blind.disabled then
        LAPSEMS.disable_blind_reset_mult()
        self:defeat()
        
        for _, card in pairs(G.hand.cards) do
            if card.ability.world_mirror then
                card:shatter()
            end
        end
        G.STATE_COMPLETE = false
        G:update_draw_to_hand()
    end
end,
defeat = function(self)
    for _, card in pairs(G.deck.cards) do
        if card.ability.world_mirror then
            card:shatter()
        end
    end
    for _, card in pairs(G.discard.cards) do
        if card.ability.world_mirror then
            card:shatter()
        end
    end
    G.GAME.starting_deck_size = self.original_deck_size
end
static valley
solid salmon
#

how do i make a joker spawn mercury

daring fern
static valley
daring fern
vale zinc
loud summit
#

how would you have a context for when a steel card is activated

daring fern
frosty rampart
#

don't forget and not context.end_of_round

loud summit
#

oh theres no way to outside of just checking if youre holding a steel card?

frosty rampart
#

yea there's no post_trigger for playing cards like there is for jokers

loud summit
#

uhh how would you check if its debuffed then

frosty rampart
#

context.other_card.debuff

loud summit
#

thx

daring fern
loud summit
#

oh

#

thats handy

solid salmon
#

guys this joker isnt appearing ingame what did i do wrong

mystic river
#

is it in the collection

spiral mural
#

discovered equals false

#

make it true unless you want a unlock method

#

if you want a unlock method make one smh

mystic river
#

you're thinking about unlocked

#

discovered just means it shows as "Undiscovered Joker" until you find it

spiral mural
#

blundering

dusk cargo
#

I want to set up jokers that have an alternate joker. And then joker where selling it replaces those jokers with the alternate jokers if they are held in your hand. Is this possible?

dusk cargo
vale zinc
#

It looks like G.P_CENTER_POOLS doesn't have the table of all possible poker hands. Where are they kept?

harsh belfry
#

other answer works too

vale zinc
#

The other answer froze my game.

harsh belfry
#

though different structure and SMODS.PokerHands gives you the initial hand stats

daring fern
vale zinc
harsh belfry
#

and allows you to screw with calc

vale zinc
#

Nevermind, I ran it again and it didn't freeze.

harsh belfry
vale zinc
#

How do I localize G.GAME.last_hand_played? Running localize(G.GAME.last_hand_played) merely gives "ERROR".

harsh belfry
dusk cargo
#
if context.selling_self then
    for k, v in pairs(G.jokers.cards) do
        if counterpartjokertable[v.config.center.key] then
            v:set_ability(counterpartjokertable[v.config.center.key])
        end
    end
end

Does anyone know how to set this up?

feral tree
#

how do i update the text for G.GAME.chips to fit the actual number?

spice scroll
#

does anyone have the documentation for how remove_card works cause im apparently misusing it

daring fern
spice scroll
#

yep

#

someone else just told me using it doesnt destroy the card?

daring fern
spice scroll
#

what would i use for destroying cards then

daring fern
spice scroll
#

hmm, im trying to remove every other card, and im just iterating through cards[i], tho

#

can i still reference a card by its position in the card area

harsh belfry
#

cards[i] is a card

#

you can remove it

spice scroll
#

ok so remove doesnt take an argument then

harsh belfry
#

no

#

you just call it on a card

#

like that

spice scroll
#

so itd be G.jokers.cards[i]:remove() then

harsh belfry
spice scroll
#

alright thank you

copper perch
#

I'm having an issue with a joker of mine where when you sell it, it crashes the game for some reason. Below is the error and code

        if context.joker_main and not context.blueprint then
            if card.ability.retriggers >= 13 then
                local eval = function(card) return not card.REMOVED end
                juice_card_until(card, eval, true)
            end
        end
        if context.selling_self then
            if card.ability.retriggers >= 13 then
                SMODS.add_card ( {key = "j_DRY_Sithe_NEO" } )
            end
        end
normal crest
copper perch
# normal crest Are you calling SMODS.has_enhancement somewhere

yes

    calculate = function(self, card, context)
        if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') and not context.end_of_round then
            if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
                card.ability.retriggers = card.ability.retriggers + 1
                return {
                    repetitions = card.ability.extra.repetitions,
                }
            end
        end
loud citrus
#

dose anyone know of a modded joker who's effect uses two separate poker hands in it's ability?

timid parrot
#

What for?

loud citrus
#

i'm reworking seance to trigger after having played a flush and a straight, but i don't know the loc_vars well enough to make the extra value work

timid parrot
#

Should be the same as seance? Just with more and different entries

#

Tho even still, I’m confused. Do you mean a flush and a straight between two different plates hands?

loud citrus
#

this is my current setup in the loc_vars

#

config = {extra = {poker_hand = 'Straight Flush'}}
i don't know how i would have split this into straight and flush so i did this instead

timid parrot
#

Not sure why you’re passing in self.ability.hand_tracker at all

loud citrus
#

to update the card text

timid parrot
#

But that doesn’t make sense in the vars

#

Those are the text replacement entries

loud citrus
#

so how would i do it? because i do want to replace the text

frosty rampart
#

you literally just need to remove self.ability.hand_tracker from the return statements

#

and then in the localization itself, put #1# where you want those strings to go

loud citrus
#

like that?

frosty rampart
#

yep

vale zinc
#
local pokerhands = {}
for k,v in pairs(G.GAME.hands) do
    if SMODS.is_poker_hand_visible(k) then
        pokerhands[#pokerhands + 1] = v
    end
end
chosen_hands = {}
while #chosen_hands < card.ability.extra.hands do
    hand_to_add = pseudorandom_element(pokerhands, 'c_lapsems_skaro')
    if not LAPSEMS.contains(chosen_hands, hand_to_add) then
        chosen_hands[#chosen_hands + 1] = hand_to_add
    end
end
for i = 1, #chosen_hands do
    SMODS.smart_level_up_hand(card, chosen_hands[i], false, card.ability.extra.levels) -- This line produces a crash, "attempt to index a nil value". What do I do?
end
loud citrus
# frosty rampart yep

so every time i hover over the card in my collection. the game crashes, ask if you need the full crash log

#

even after the change

daring fern
vale zinc
normal crest
copper perch
normal crest
copper perch
#

no, I copied and pasted what it gave me...suppose I'll check the other enhancements though

loud citrus
#

these parts of my code crash the game when i hover over seance, when removed it defaults back to the original extra value... what would i need to change to fix the crashes?

normal crest
#

card.ability.extra.hand_tracker instead

loud citrus
normal crest
#

Did you start a new run

loud citrus
#

i'm looking through the collection

normal crest
#

is there a crash log

loud citrus
normal crest
loud citrus
normal crest
#

can you send the full code

loud citrus
normal crest
#

Have you ever gotten it to not crash

#

after putting a config

ivory citrus
#

hello

loud citrus
#

loc_vars and the config part itself has been my road block

ivory citrus
loud citrus
#

move the card.ability.extra.fuerza = 0 above the return, you don't need to return the value, hope that helped :)

copper perch
# normal crest Is that the only place? Cus the crash log says that you're passing nil to has_en...

Just to show all instances of has_enhancement

1. 
        if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') and not context.end_of_round then
            if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
                card.ability.retriggers = card.ability.retriggers + 1
                return {
                    repetitions = card.ability.extra.repetitions,
                }
            end
        end

2 & 3 (another card).
        if SMODS.has_enhancement(context.other_card, 'm_steel') then
            for k, v in pairs(G.I.CARD) do if v.config and v.config.center and v.config.center.key == 'm_steel' then v.ability.h_x_mult = 3 end end
        end
        if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') then
            return {
                repetitions = card.ability.extra.repetitions
            }
        end
normal crest
ivory citrus
normal crest
loud citrus
#

is there a way you think i can get around this?

copper perch
normal crest
normal crest
loud citrus
copper perch
# normal crest Then yeah that's wrong, context.other_card only exists in certain contexts, like...

thats weird then, cause it works on the one prior. I have below

    calculate = function(self, card, context)
        if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') and not context.end_of_round then
            if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
                card.ability.retriggers = card.ability.retriggers + 1
                return {
                    repetitions = card.ability.extra.repetitions,
                }
            end
        end

and

    calculate = function(self, card, context)
        if SMODS.has_enhancement(context.other_card, 'm_steel') then
            for k, v in pairs(G.I.CARD) do if v.config and v.config.center and v.config.center.key == 'm_steel' then v.ability.h_x_mult = 3 end end
        end
        if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') then
            return {
                repetitions = card.ability.extra.repetitions
            }
        end
normal crest
#

Wdym one prior?

#

The other two has_enhancement calls check if context.repetition before trying to access context.other_card

copper perch
#

ohhhhhhh, okay

#

so what could I do to make the enhancement call work on the 2nd???

#

and more importantly, how would 2 jokers affect each other in such a way?? I guess it could be that it transforms into the other

normal crest
#

I'd say first just try removing that 2nd part entirely and see if that fixes it. I'm assuming you were testing while having both jokers tbh

copper perch
#

Nope, I only had one, but one transforms into the other when selling which may be why it triggered upon selling

normal crest
#

Oh. Is the joker you spawn when selling the one with the missing context check

#

If so yeah that is definitely why

copper perch
#

nope, still returns a nil somewhere it says

normal crest
#

What'd you change

copper perch
#

wait, I'm dumb and forgot to save...hold on lol

#

I got rid of the bit with doing a check for enchants only, I'll let ya know how it goes

#

okay, that did solve it

#

so I gotta figure out how to phrase below so it works

    calculate = function(self, card, context)
        if SMODS.has_enhancement(context.other_card, 'm_steel') then
            for k, v in pairs(G.I.CARD) do if v.config and v.config.center and v.config.center.key == 'm_steel' then v.ability.h_x_mult = 3 end end
        end
normal crest
#

Do you want to make all steel cards give only 3 mult instead

copper perch
#

yes

#

I have it on an add to deck but only applies to the ones in hand, not all in the deck

normal crest
#

I'm super tired and I don't wanna think, so I'm gonna give you the easiest but worst way of doing it. Loop through G.playing_cards in update, check if steel and change

copper perch
#

I can also save for tomorrow if you want, I have no deadlines and am just doing this for fun lol
Knowing the problem will help a TON at least

loud citrus
#

result of my labor, card will at least shake, though no actual value tracking :(

soft pier
#

actually the craziest logic problem so far

#

wild cards made this incredibly difficult

dim forum
#

did the mult with suit cards get changed (lustly greedy etc)

#

can't open GitHub rn

tired kestrel
#

I need help trying to make an unlock based on the edition you bought. appernetly I tried many times to make it work but somehow sometimes it worked even without polychrome or it doesn't work.

#

I tried lovely patch and functions but none of them worked.

#

or did work

#

just not the way I thought it would supposed to be.

loud citrus
#

eary game that is

dim forum
#

I mean 15 mult on a flush hearts is cool for checkered players

tired kestrel
#

can anyone help with the unlock funtion or how it work?

loud citrus
#

i can't help but this might

loud citrus
dim forum
#

yeah fair point

loud citrus
#

WAIT, rework to give CHIPS

#

no i forgot about the arrow

#

oops lol

#

if they are for early game, i could make them give mult on play instead of score >:)

#

but that could restrict some builds... this needs to be carefully approached

tired kestrel
#

help

#

I tried with using tables but nope

#

I think I broke it

tired kestrel
#

I tried but for some strange reason it didn't work in my favor somehow and I probably need help with this

wet valley
obsidian spear
#

totally not like i gave up my own

pale holly
#
    local original_get_new_boss = get_new_boss
    
SMODS.Joker {
    key = "jam_sybil",
        loc_txt= {
        name = 'Jam Sybil',
        text = {    "",
    },},
    atlas = 'regaliadeck',
    pos = { x = 3, y = 2 },
    rarity = 2,
    cost = 5,
    pools = {["pseudoregamod"] = true},
 
    
    unlocked = true,
    discovered = false,
    blueprint_compat = false,
    eternal_compat = true,
    perishable_compat = true,
    
    --- the function
    config = { extra = {}},
        loc_vars = function(self, info_queue, card)
        return {vars = {}}
    end,
    

function get_new_boss(self)
  --if G.GAME.always_spawn_cymbal_boss_memory == true then
  if G.GAME.always_spawn_cymbal_boss_memory then
    return 'bl_cymbal_boss_memory'
  end
  return original_get_new_boss(self)
end,

add_to_deck = function(self, card, from_debuff)
G.GAME.always_spawn_cymbal_boss_memory = true
    end,
    
    remove_from_deck = function(self, card, from_debuff)
G.GAME.always_spawn_cymbal_boss_memory = false
    end,
}

seriously what am i doing wrong, set the local outside but now it's something else

ashen drift
pale holly
#

so i should but the entirely get_new_boss function outside ?

ashen drift
#

yes

#

because it's actual code and not any arguement for SMODS.Joker

stiff locust
#

is there a way to check what joker calls a function (such as get_id() )

ashen drift
#

and thus should be run seperately

#

can't you just hook card:get_id

pale holly
stiff locust
ashen drift
#

oh yeah true

stiff locust
#

i need to know what joker is calling the function

ashen drift
#

hm

stiff locust
#

im considering a few things but if I want this idea to be future proof id need to like

#

get that info or lovely patch every instance of get_id to also return the joker's info when calling it

pale holly
# ashen drift what?

setting the function outside will give me something like

    local original_get_new_boss = get_new_boss

    function get_new_boss(self)
  --if G.GAME.always_spawn_cymbal_boss_memory == true then
  if G.GAME.always_spawn_cymbal_boss_memory then
    return 'bl_cymbal_boss_memory'
  end
  return original_get_new_boss(self)
end

SMODS.Joker {
    key = "jam_sybil",
        loc_txt= {
        name = 'Jam Sybil',
        text = {    "",
    },},
    atlas = 'regaliadeck',
    pos = { x = 3, y = 2 },
    rarity = 2,
    cost = 5,
    pools = {["pseudoregamod"] = true},
 
    
    unlocked = true,
    discovered = false,
    blueprint_compat = false,
    eternal_compat = true,
    perishable_compat = true,
    
    --- the function
    config = { extra = {}},
        loc_vars = function(self, info_queue, card)
        return {vars = {}}
    end,

add_to_deck = function(self, card, from_debuff)
G.GAME.always_spawn_cymbal_boss_memory = true
    end,
    
    remove_from_deck = function(self, card, from_debuff)
G.GAME.always_spawn_cymbal_boss_memory = false
    end,
}

with only G.GAME.always_spawn_cymbal_boss_memory being there to activate the said code

ashen drift
#

no idea but card:get_id might be run a lot of other times from non-joker places

#

which might be jank

stiff locust
#

mmh

ashen drift
#

maybe try another way to implement the feature?

#

what are you trying to do, btw

stiff locust
#

i want the gimmick of my new project mod to be that you can modify the mentioned ranks of jokers

pale holly
# ashen drift ye

well i guess i better try, at least it won't run with syntax now it seems

stiff locust
#

like cloud nine could be changed to another rank for example

ashen drift
#

cant you just modify the joker's ability.extra?

stiff locust
#

it would be feasible to manually implement this on my jokers and the vanilla ones, but the feature would be pretty annoying to implement on modded jokers

stiff locust
#

almost every rank checking joker hardcodes the rank checking

ashen drift
#

oh yeah some people make that shit hardcoded

#

which is so ass

stiff locust
#

everyone does it

ashen drift
#

it makes value manip so hard

ashen drift
stiff locust
#

well ur not supposed to change the rank value normally

#

like what if it becomes 4.5

#

now your joker is broken

#

thats why we hardcode those

ashen drift
#

thats not your joker's fault, though

#

its fully on the value manip which should be better implemented

stiff locust
#

it is if you didn't round the value

#

the value manip can't interpret what value you used for what

ashen drift
pale holly
# ashen drift ye

thanks, it does work now, i keep getting the same blind as long as i've the card

stiff locust
#

anyway i would have no way to modify anything hardcoded which is the majority

#

so it would be nice to be able to intercept and modify the rank checks

ashen drift
#

maybe try hooking the function that actually changes ranks?

#

i wouldnt know though

stiff locust
#

no the function that gets ranks is get_id

#

i would need jokers to return their info in get_id to be able to do this

#

which I could patch get_id to allow, but that would still require people to manually add it to their jokers 🤔

#

that is probably the easiest method

ashen drift
#

oh yeah fuck i forgot the question

daring fern
# stiff locust that is probably the easiest method
local key, i = nil, 0
while not key do
    i=i+1
    local name, value = debug.getlocal(2, i)
    if not name then break end
    if type(value) == 'table' then
        if name == 'self' then
            if Card.is(value, Card) then
                key = value.config.center.key
            elseif value.key then
                key = value.key
            end
        elseif name == 'card' then
            key = value.config.center.key
        end
    end
end
```?
stiff locust
#

what does it do

daring fern
stiff locust
daring fern
stiff locust
#

shiiit

#

fr?

#

where would I run that

daring fern
stiff locust
#

i went to try and use a gif

#

unfortunately they are still blocked

pale holly
#

Is there a way to make a boss blind not appear trough the regular ways ?

#

If i set the min_requirement to a high value like 999 that should do it no ?

ashen drift
#

try setting in pool

pale holly
#

oh so just a

in_pool = function(self, args)
    return false
end,

should work then riight ?

ashen drift
#

should be

pale holly
#

Yes it works thanks

candid acorn
#
            if voucher.args then
                insert(tempPool, voucher)
            end
        end```
#

idk why the game does this when i try do to it

#

i have a voucher in the area

daring fern
candid acorn
normal crest
# candid acorn

this crash is due to a pseudorandom_element call you have in Empowered.lua

#

oh I see, you're passing an empty table to it, presumably tempPool

pastel badge
#

my game crashes whenever i play a high card

#

and when i turn the volume to 0 it doesnt crash

candid acorn
#

bruh

#

i think i changed it to be good but it was giving the exact same error and i thought it was the same thing again

#

anyways back to my coding of doom and despair

normal crest
pastel badge
#

you just made me realise thats the wrong chat 💔

candid acorn
normal crest
#

uhm, I don't think so

#

what do you mean by it can be scaled

#

like getting more than 1 does something?

candid acorn
#

yes

normal crest
#

if so you'll probably just have to manually make a list of allowed vouchers to duplicate

#

or the opposite, a list of blacklisted vouchers

candid acorn
#

yes but that kinda leaves a gap for modded ones

normal crest
#

vouchers just don't have that kind of information on them

normal crest
candid acorn
#

yea youre right ill do it that way

normal crest
#

i mean vouchers

candid acorn
#

tysm

#

lets go back to crashing the game

normal crest
#

o7

wet valley
#

I figured out shaders for hue shifting each separate joker part

wet valley
#

I only focused on the graphical side and I have yet to figure out exactly how they're gonna generate effects

left sonnet
#

Hey folks, does anyone know if extern MY_HIGHP_OR_MEDIUMP number time; is updated every frame in mods? I've ported over a Shadertoy shader to Balatro but it seems to be stationary, I use it by itself as well as with sin

clear ocean
wet valley
strong plume
#

Hey, I want this tag to only trigger when you use a consumable, doing nothing until then (Like how the double tag does nothing until you get another tag)

Anyone know what I'm doing wrong? Rn it doesn't crash, but it also never triggers either

#

(this is how it looks more scrolled down, if that helps)

wet valley
#

HAHAHAH

tired kestrel
#

How do I make it that it says "Applied to all previous stakes" instead of "Applys gold stake"

stoic void
#

Thats from vanilla remade

#

put that in a en-us.lua file

#

and have that in a localisation folder

tired kestrel
stoic void
#

you probably should

tired kestrel
#

also I also should also make a localization of all the stuff I've written into

stoic void
#

yeah

#

probably

sturdy compass
#

For further context (not the game term), the first screenshot is using a mod calculate object, where Maximus in this case is SMODS.current_mod. Mod calculate is a very nice tool to have once you learn it exists. The loop is the most important part, as this is how tags are typically applied. The type will be the context you’ll look for. In your case, probably type = ‘using_consumable’, and you’d probably run this under the traditional if context.using_consumeable then check. The second screenshot is a tag’s apply code where you will check for context.type == ‘using_consumable’

tired kestrel
#

since I'm doing localize is there a way to reuse this?

granite jay
#

What would be the best way to translate this to a Joker?

#

Cos I wanna make a joker that turns into one of four specific jokers when blind is defeated

broken rivet
#

is there a context that happens after playing cards are scored but before context.joker_main

mellow marsh
#

trying to make a joker that copies abilities of both adjacent jokers... i feel like this code is correct but it does not seem to be working?

#

the printed effects table looks to indeed be a proper list of effects (jolly joker and regular joker used here for testing)

#

granted, i'm referencing doodle from all in jest for this code, and last i played a run with it that joker didn't work either i think lol

#

ah merge_effects is just yielding nil here hm

#

oh it's supposed to receive a single table listing the effects, rather than passing the effects in as arguments directly

#

i feel like that is not documented correctly?

loud summit
#

is it possible to tell if a card triggered another joker

silver flame
#

Hey everyone, sorry to bother you again but I updated my mod with more jonklers and got this wierd crash message

#

the joker I had was supose to make a negative food joker when blind is selected but the game just crashed

slim ferry
#

code?

slim ferry
#

or context.other_context.card for some contexts

gilded narwhal
#

Hey now that the joker atlas for my mod is getting REALLY big, it's starting to slow down load time quite a bit. I don't really feel like checking but if I wanted to optimize for loading time, would it be more efficient to split it into multiple atlases?

#

Idk why it would, just figured id ask

silver flame
slim ferry
#

and the object type?

silver flame
#

object type?

slim ferry
#

the pool

silver flame
slim ferry
#

the pool in the joker should not have an extra mod prefix

silver flame
#

oh, all the other jokers have that problem cause thats just how joker forge does things and that wasn't caused problems

slim ferry
#

complain in the joker forge discord

#

they have a bug reports channel

dapper sun
#

how do i check for an exact hand (instead of containing a hand)

daring fern
dapper sun
#

ty

ivory citrus
#

i tried move the card.ability.extra.fuerza = 0 to diferent part but still no working

daring fern
ivory citrus
#

Thanks, very grateful

slim ferry
#

try it and see i suppose

gusty compass
#

what would i be doing wrong here

dapper sun
#

is there an faster way to test things than restarting the game every time i change something

slim ferry
#

Not really

#

You can use alt f5 to instantly restart the game i guess

dapper sun
#

oh ok

#

thanks

#

that does help actually

dusk cargo
#

Is the card id for ace, A?

#

Nvm.

dapper sun
#

anyone know why pressing the button crashes the game?

-- Shop thingy :)
function create_UIbox_becca()
    return create_UIBox_generic_options({
        no_back = true,
        contents = {
            UIBox_button({ button = "elle_rebecca.exit_shop", label = { "Exit" }, minw = 5, colour = G.C.RED })
        }
    })
end

-- Button Callbacks
G.FUNCS.elle_rebecca = {
    -- Leave shop
    exit_shop = function(e)
        if not e then return end
        G.FUNCS.exit_overlay_menu()
    end
}```
dapper sun
vague crest
#

how could i check if a joker is the first one of that specific joker in my joker slots? specifically to fix a bug that happens with part of the code if you have two or more of them, i wanna disable that part of the code if it isn't the first instance of that joker

daring fern
loud summit
#

hey so how do you directly set the # of chips and mult mid hand

#

ive tried doing it in a event and not and the next calculation still acts as though it wasnt set

vague crest
#

this worked perfectly tysm!!

loud summit
loud summit
#

bbbbut vanillaremade explicitly says to

loud summit
daring fern
loud summit
#

how is that different to just setting mult directly

#

also do you return it in the table or

dapper sun
#

yea it goes in the return table

loud summit
#

oh

#

is there a mult_chips too

daring fern
daring fern
loud summit
#

oh right

#

so chip_mod/mult_mod supports negative values but is otherwise identical to mult?

dapper sun
loud summit
#

(and doesnt send a message)

daring fern
loud summit
#

mult doesnt support negatives tho

dapper sun
#

regular mult/chips also support negatives

#

yes it does

loud summit
#

????? its done nothing when i tried before

daring fern
dapper sun
daring fern
dapper sun
#

oh i'm blind :)

#

G.FUNCS[self.config.button](self)

loud summit
#
        if context.before and not context.blueprint and
            SMODS.pseudorandom_probability(card, "nflame_mcbedrock", 1, card.ability.extra.chance) then

            card.ability.extra.chip = card.ability.extra.chip + hand_chips
            card.ability.extra.mult = card.ability.extra.mult + mult

            return { mult_mod = -mult, chip_mod = -hand_chips, message = localize("k_upgrade_ex") }
        end
``` ok so the mult mod seems to do literally nothing, not even change the scoring number
dapper sun
#

oh i think i see the problem

#

i don't think i can "elle_rebecca.exit_shop"

loud summit
#

wait is hand_chips and mult set during before?

daring fern
loud summit
#

so how would i change it before the first card is scored

daring fern
loud summit
#

thanks

#

when exactly does that fire

daring fern
loud summit
#

thx :D

#

how is it different to context.before

daring fern
loud summit
#

is that the only diff

faint yacht
frosty rampart
# loud summit is that the only diff

yea pretty much
although it's directly after context.before, so e.g. a space joker to the right of something with context.initial_scoring_step would still fire off before the joker you're making

loud summit
#

hmmm

#

so context.before for like anything that doesnt affect this hand

#

and context.initial_scoring_step for anything that does

frosty rampart
#

yep

loud summit
#

ok

#

also.

#

mod_mult() vs returning mult_mod, which one should i use??

daring fern
loud summit
#

aaalr

#

so just return { mult_mod = newmult - mult } basically

#

where you want to set it to newmult

daring fern
loud summit
#

ok cool

dapper sun
#

i don't understand ui i think

function create_UIbox_becca(card)
    return create_UIBox_generic_options({
        no_back = true,
        contents = {
            {n = G.UIT.R, config = {align = "cm", padding = 0.1, nodes = {
                {n = G.UIT.T, config = {align = "cm", padding = 0.1, colour = G.C.GOLD, text = card.ability.extra.test}}
            }}},
            UIBox_button({ button = "elle_rebecca_exit_shop", label = { "Exit" }, minh = 0.6, minw = 10, colour = G.C.FILTER })
        }
    })
end```
primal robin
dapper sun
#

oh i'm blind lmao

#

ty

primal robin
#

np

dapper sun
#

how do i get a shadow to appear under my node?

{n = G.UIT.R, config = {align="cm", outline=1, padding=.15, r=.1, emboss=.5, hover=true, shadow=true}, nodes = {```
#

(the one with an outline)

ivory coral
#
print(count)
print(card.ability.extra.levelreq)
print(count / card.ability.extra.levelreq)
print(math.floor(count / card.ability.extra.levelreq))
print(math.floor(count / card.ability.extra.levelreq) ~= 0)
print('WHAT')

am i going insane or is the math genuinely just not mathing

#

what do you mean 0 ~= 0

daring fern
ivory coral
#

i do
could be that but i dont recall talisman breaking this when i first coded it

#

ok yeah its talisman
figures, how is it breaking it though

#

count and levelreq are both always just normal numbers, did they change math.floor somehow?

daring fern
ivory coral
#

actually, count is affected by G.GAME.hands[hand].level its probably that

#

ok putting a to_big() around count did it
whoops
thanks lad

vale zinc
#

Could any of you say why this doesn't automatically debuff the rightmost Joker during this Boss Blind? I adapted the code from Bunco's The Wind, which disables the leftmost Joker instead.

local LAPSEMS_original_game_update = Game.update
function Game:update(dt)
    --[[
    This is utilized by The Blood.
    --]]
    if G.GAME and G.GAME.blind and G.GAME.blind.name == 'bl_lapsems_blood' and G.jokers and G.jokers.cards then
        if not G.GAME.blind.disabled then
            for i = 1, #G.jokers.cards do
                if i == #G.jokers.cards then
                    G.jokers.cards[i].ability.bl_lapsems_blood_chosen = true
                else
                    G.jokers.cards[i].ability.bl_lapsems_blood_chosen = nil
                end
            end
        else
            for i = 1, #G.jokers.cards do
                G.jokers.cards[i].ability.bl_lapsems_blood_chosen = nil
            end
        end
    end
    
    LAPSEMS_original_game_update(self, dt)
end
daring fern
vale zinc
daring fern
vale zinc
#

...But now the debuff persists after the Blind is defeated.

daring fern
vale zinc
daring fern
vale zinc
spiral mural
#

cards don't auto debuff

#

the 2nd value has to be truthy to undebuff

#

btw

vale zinc
spiral mural
#

have you ever

#

coded before???

vale zinc
#

Yes!

spiral mural
#

tell me

#

what does the word "truth" imply

vale zinc
#

Nevermind your astonishment at my not grasping these things. What do I do instead?

spiral mural
#

booleans exist

#

false is one half

#

true is the other half

#

in lua, everything but false and nil is truthy (counts as true)

#

therefor just shove true in there

vale zinc
#

But I already used SMODS.debuff_card(joker, true, 'bl_lapsems_blood') to apply the debuff to begin with!

spiral mural
#

oh wait i think

#

sorry im stupid

vale zinc
#

Do I swap the true for nil instead?

spiral mural
#

false reads better

#

so use false

vale zinc
#

I did.

spiral mural
vale zinc
daring fern
vale zinc
# daring fern Code?

I followed @spiral mural's instruction.

disable = function(self)
    for i, joker in ipairs(G.jokers.cards) do
        joker.ability.bl_lapsems_blood_chosen = nil
        SMODS.debuff_card(G.jokers.cards[i], false, 'bl_lapsems_blood')
    end
end,
spiral mural
#

shove in a print statement (and have debug+ installed) and see if its even running

daring fern
vale zinc
# daring fern Do you also have that in `defeat`?
disable = function(self)
    for _, joker in ipairs(G.jokers.cards) do
        joker.ability.bl_lapsems_blood_chosen = nil
        SMODS.debuff_card(joker, false, 'bl_lapsems_blood')
    end
end,
defeat = function(self)
    return self:disable()
end,
local LAPSEMS_original_game_update = Game.update
function Game:update(dt)
    --[[
    This is utilized by The Blood.
    --]]
    if G.GAME and G.GAME.blind and G.GAME.blind.config.blind.key == 'bl_lapsems_blood' and G.jokers and G.jokers.cards then
        if not G.GAME.blind.disabled then
            for i = 1, #G.jokers.cards do
                if i == #G.jokers.cards then
                    G.jokers.cards[i].ability.bl_lapsems_blood_chosen = true
                    SMODS.debuff_card(G.jokers.cards[i], true, 'bl_lapsems_blood')
                else
                    G.jokers.cards[i].ability.bl_lapsems_blood_chosen = nil
                    SMODS.debuff_card(G.jokers.cards[i], false, 'bl_lapsems_blood')
                end
            end
        end
    end
    
    LAPSEMS_original_game_update(self, dt)
end
spiral mural
vale zinc
daring fern
vale zinc
daring fern
vale zinc
subtle hawk
#

Why is the UI aligning like that. Turned on the outline on the ROOT node specifically to see that it's going outside the create_UIBox_generic_options for some reason??

subtle hawk
pastel kernel
#

I'm using cryptlib for thislua {"{C:attention}All jokers owned, cards in deck, and consumables owned{} gain {C:attention}x#1#{}values"}

#

how do i affect cards in deck and consumables

tired kestrel
#

Guys I have a question when it comes to like applied stakes, when you try to make the text into like "Applies to all previous stakes"?

#

other than having to manually do locazlize ports.

tired kestrel
#

I tried localize in en_us but that didn't work.

#

I think it worked now.

wintry solar
#

It’ll add the applied line for you iirc

tired kestrel
#

I see. though right now I kinda wished there'D be a way for loc_text to replace the applied gold stake to whatever previous stakes you had

#

but now I have to basically do the whole localization thing in motion espeically having the custom deck_locked things

#

eremel do you have an idea on how custom deck_locked worked in general?

wintry solar
tired kestrel