#💻・modding-dev

1 messages · Page 592 of 1

left sonnet
#

Hi, sorted out my initial issue, just did a nil check to set it to 0 if it's nil, going to now swap it to a local

queen meadow
#

how bad is this

daring fern
#

No, you could check if a message was called during the seal calculation or if it returned anything.

stuck ore
#

If I wanted to give money when a joker triggers would "dollars = card.ability.extra.dollars" be correct? It currently doesn't seem to be giving money when it triggers

left sonnet
stuck ore
#

Sorry I should have specified, this is for returning the value not setting it to be a new value

left sonnet
#

Then that should be chill, yeah

stuck ore
#

idk it isn't working for me annoyingly

#

config = { extra = {mult = 10, chips = 30, dollars = 3, type = 'Three of a Kind' } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult, card.ability.extra.chips, card.ability.extra.dollars, localize(card.ability.extra.type, 'poker_hands') } }
end,
calculate = function(self, card, context)
if context.joker_main and next(context.poker_hands[card.ability.extra.type]) then
card:juice_up(1,0.5)
return {
mult = card.ability.extra.mult,
chips = card.ability.extra.chips,
dollars = card.ability.extra.dollars
}
end

#

Not sure where the issue for the money part is

#

the mult and chips trigger fine though

unborn mountain
#

Hi people, seeing that you all know a lot about modding can someone tell me what everything means and how to begin?

stuck ore
# unborn mountain Hi people, seeing that you all know a lot about modding can someone tell me what...

STEAMODDED 1.0.0
A tutorial on how to make a modded Joker.

https://github.com/art-muncher/Example-Mod -- EXAMPLE MOD
https://github.com/Steamopollys/Steamodded -- STEAMODDED
https://github.com/WilsontheWolf/DebugPlus -- DEBUGPLUS
-----------------------------------------------------...

▶ Play video
#

I recommend this a neat starting off point

#

Theres another more recent video they made but they go over different things

unborn mountain
#

Thanks, i will look into this with that video

stuck ore
keen atlas
#

<@&1133519078540185692>

left sonnet
#

Hey, is there a way to check the cards in a played hand in context.before? I want to sync up the sound it plays and the message it displays, but the way I have it at the moment - checking for aces as it scores them - the sound plays instantly because the game already found them in an instant, and then the message displays after the hand is scored, whereas I would like to have both play together before the hand is scored. Naturally context.scoring_hand doesn't seem to work because the hand has not been "played" yet

slim ferry
#

add sound = <sound key> to the return

left sonnet
slim ferry
#

no

left sonnet
#

Then I already have, I'll screen record the current outcome

unborn mountain
#

What program do you guys use for the coding?

slim ferry
#

visual studio code

unborn mountain
#

arl thanks

rotund sable
gilded goblet
#

any reason why context.using_consumeable fails if the card ur checking is the only card that is being used?

faint yacht
#

Oddly enough, having a bit of fun with JokerDisplay compat progress.

unkempt thicket
#

Why is context.money_altered printing an inconsistent amounts of times, 1st item $5 and prints once, 2nd item $4 and prints twice, 3rd item $5 and prints five times.

gilded goblet
lavish elm
#
card.ability.extra_value = card.ability.extra_value * 2
card:set_cost()

why this not increase sell value

daring fern
lavish elm
#

ok thx

gilded goblet
daring fern
gilded goblet
#

yea that's somewhat what i assumed was happening 🥀

#

good to know ty

lavish elm
#

how to modify sell value of joker?

#

other than extra_value

ocean sinew
lavish elm
#

ok thx

left sonnet
#

Does the video not work for anyone else

gilded goblet
#

it works

left sonnet
#

Just me then, that's fine

#

Anyways, right now the sound plays immediately as the hand is scored, whereas the message only drops after the 2nd scored Ace. Is there a way to have the message play right before the hand starts scoring like the sound does?

#

Vid started working as I was typing smh

#

Think I found something, one sec

lavish elm
#

how to check if wheel of fortune fails/succeed?

left sonnet
#

Gonna try this

card_eval_status_text(self, 'extra', nil, nil, nil, {
    message = "CHAT IS THIS REAL?", colour = G.C.MULT, instant = true})
play_sound('kain_LeBronScream')
faint yacht
#

SMODS.calculate_effect({message = 'aeiou', sound = 'modkey_name'}, card)?

unkempt bronze
#

A joker in my mod is supposed to turn a random card in hand into a spade at the end of a round, but it's not

#

anything to fix?

vestal yew
#

hey gang, i have a joker that's not loading, any clue why?

#

other jokers in the same place are working fine, this one just wont load properly

unkempt bronze
#

Hmm, have you put it in an altas?

vestal yew
#

it goes through and loads each file in the objects/jokers folder

unkempt bronze
#

then idk

daring fern
unkempt bronze
slim ferry
#

i dont imagine thats what you want to do

unkempt bronze
#

Out in spades, no one can hear you win

daring fern
# unkempt bronze
if context.end_of_round and context.main_eval then
    local _card = pseudorandom_element(G.hand.cards, 'seed')
    SMODS.change_base(_card, 'Spades')
end
vestal yew
#

or wait

vestal yew
#

yeah it is, right? so i take the first file_names_jokers value, plug it into path, plug that into load_joker which loads it, then go to the next one and do the same thing

#

let me try swapping the order and see what that does

#

ok yeah its just the dudehole joker thats not loading

#

the order doesnt matter

left sonnet
# faint yacht `SMODS.calculate_effect({message = 'aeiou', sound = 'modkey_name'}, card)`?

Gave this a try and I'm running into the same issue I did before, but I forgot how to solve it 😅 "resources/sounds/kain_LeBronScream.ogg. Does not exist."

SMODS.Sound{key = "LeBronScream", path = "LeBronScream.ogg"}
...
SMODS.calculate_effect({message = 'CHAT IS THIS REAL?', sound = 'kain_LebronScream'}, card)

I believe this is correct, my prefix is 'kain'

faint yacht
#

sound = 'kain_LeBronScream'

#

b > B

left sonnet
#

Dude I'm actually so blind, that's twice today

#

Thank you

vestal yew
left sonnet
#

There we go, my first fully functional joker

#

Only took most of my day

left sonnet
faint yacht
#

-# 'twas the same for me back when I wanted to mod Balatro because I found the Talisman sounds cool as fuck.

left sonnet
vestal yew
#

ali do you have any clue abt mine? :3

faint yacht
vestal yew
#

yeah

faint yacht
#
local file_names_jokers = {
  'bowlatro',
  'dudehole'
}

local folderpath = 'objects/jokers/'
for _, v in pairs(file_names_jokers) do
  local file = folderpath .. v .. '.lua'
  assert(SMODS.load_file(file))()
end
vestal yew
#

i got the loading to work by just copy/pasting my working joker (bowlatro) code into it so its smth wrong with the original dudehole.lua code specifically

faint yacht
#

If it doesn't load, but doesn't crash, then the loading itself may not have target the file - verify the path and filenames.

vestal yew
#

gotcha thanks

pale holly
#

    loc_txt = {
        name = "Hurry Deck",
        text = {
    "Winning Ante is {C:attention}6",
    "Shop's items cost {C:attention}twice more{}",
    "Start run with {C:money}$25{},",
    "{C:attention}{T:v_seed_money}{}",
    "and {C:attention}{T:v_money_tree}{}"
        }
    },
}

Tried to use the {T:key} to add the voucher description but i guess i've done it wrong ? Can someone help please ?

winter flower
#

it’s {C:attention,T:v_seed_money}text or var{}

pale holly
#

Ah alright, thanks !

#

Is it nomal it won't work with my custom vouchers ? I set the prexif and everything

    loc_txt = {
        name = "Complete Focus Deck ",
        text = {
    "Winning Ante is {C:attention}10",
    "Standard Packs are banned",
    "Start with the {C:attention, T:v_cymbal_slide}Slide{}",
    "and {C:attention, T:v_cymbal_solarwind} Solar Wind{}"
        }
    },
}```
analog spoke
#

why is every joker idea I have end up more complex to code than the last lol, it doesn't matter how complex I think it'd be, it ends up more complex lol

#

flower-pot style effect which makes it so that if you discard exactly 4 cards, 1 of each suit, [effect happens]

#

apparently flower pot's code is like a full damn novel in length tho lmao

#

;-;

sturdy finch
pale holly
#

well it sure sounds like a requiremend, individual checking of the suit, checking if 4 cards,

analog spoke
#

mmmm, yeah, I think what I need is... to swap the "scoring hand" bit for a discard somehow... also, the effect I want is gonna need a way to destroy the discarded cards lol (it's sorta like a mix of trading card and flower pot lol)

left sonnet
#

Alright gang, last thing for today. Making a challenge to start with my new Joker. The name is there and the challenge appears in Challenges, but my custom rule and my joker don't appear. I have put both in curly brackets just to be sure, and now I'm getting a "card.lua:279: attempt to index local 'center' (a nil value)" error. Could anyone toss me in the right direction?

--Challenges
SMODS.Challenge{
    key = 'kain_outside',
    loc_txt = {
        name = "I Like Yer Dog Mate"
    },
    rules = {
        custom = {
            {id = "ch_c_kain_walk"},
        },
        modifiers = {
        }
    },
    jokers = {
        {id = "kain_outside"},
        eternal = true
    },
}
Localization file:
return {
    misc = {
        challenge_names = {
            kain_outside = "I Like Yer Dog Mate",
        },
        v_text = {
            ch_c_kain_walk = {
                "Join {C:mult}Kain{} on a {C:attention,E:1,s2}walk"
            }
        },
    },
}
faint yacht
#

'j_kain_outside'?

left sonnet
pale holly
lavish elm
#
if context.after and context.cardarea == G.play and SMODS.pseudorandom_probability(card, "xmpl_epik_face_hand", 1, card.ability.seal.extra.odds1) then
            for i = 1, #G.hand.cards do
                SMODS.destroy_cards(G.hand.cards[i])
            end
            return{
                message = "EPIK PRANK",
                sound = "xmpl_bruh"
            }
        end
if context.after and context.cardarea == G.play and SMODS.pseudorandom_probability(card, "xmpl_epik_face_self", 1, card.ability.seal.extra.odds2) then
            SMODS.destroy_cards(card)
            return{
                message = "EPIK OUTRO",
                sound = "xmpl_vine"
            }
        end

why does the first condition activate but the second one doesn't?

faint yacht
#

return stops execution of code afterwards.

lavish elm
#

ok thx

left sonnet
lavish elm
#

context.destroy_card and SMODS.pseudorandom_probability(card, "xmpl_epik_face_self", 1, card.ability.seal.extra.odds2)
like this?

faint yacht
#
if context.destroy_card and context.cardarea == G.play and SMODS.pseudorandom_probability(card, "xmpl_epik_face_self", 1, card.ability.seal.extra.odds2) then
  return { remove = true }
end
lavish elm
#

ok thx alot

#

ok now the first condition is no longer working

#

ok I think that the reason is bc it is destroying itself before the context.after activates it doesn't activate the first one

#

ok fixed the problem by changing from context.after to context.final_scoring_step

real night
#

how do you modify the values that editions give

#

like how would you make holo +15 Mult

rocky plaza
real night
#

how the Fuck do i use it

rocky plaza
#

SMODS.Edition:take_ownership(key, {})

#

where the table is all the elements that u want to override

atomic edge
#

hey guys can someone tell me in which file the shop is coded?

real night
#

no i mean like

#

take ownership in general

rocky plaza
#

example here

real night
#

ohh

#

okay time to make edition planets

rocky plaza
# real night ohh

also as you'd expect
the first arg is the full key of the object without the object type prefix

real night
#

okay god damn

#

take ownership is cracked

#

how didnt i notice this before

wind steppe
#

Why isnt it with the object type prefix anyways

frosty rampart
#

because it's already a function call on the object type (i.e. SMODS.Joker:take_ownership will only ever be taking ownership of jokers)

rocky plaza
rocky plaza
wind steppe
#

i suppose that makes sense

rocky plaza
#

but yeah its easy for one to miss if they dont know the exact verbage

real night
#

also im considering reworking trash bin to be "+1 mult for every card discarded this round"

#

its just like

#

actually unique

#

a bit

left sonnet
atomic edge
#

is there a mod that adds a new button to the shop?

languid aurora
#

iirc ortalab adds a flipside button

atomic edge
#

thanks

real night
#

wait

#

let me just check the source code

faint yacht
#

e_foil?

real night
#

where are the editions

#

in the source code

#

okay found them

#

how the fuck do i access foil's chips

#

🥀

gilded goblet
#

game.lua ctrl+f: e_foil

real night
#

so would SMODS.Edition:take_ownership(foil, {G.P_CENTERS.e_foil.config.extra = G.P_CENTERS.e_foil.config.extra + card.ability.chips}) work

faint yacht
#

-# That sure would be perma.

real night
#

oh wait yeah thats permanent

#

shit

faint yacht
gilded goblet
#

+-50 🔥

faint yacht
#

If you want to modify the chips of Foil on a card w/o affecting others, do card.edition.chips, where card is the Joker or playing card.

real night
#

i wnat to like

#

level the entire edition up for the run

faint yacht
#

Keep track of the "level" and modify the chips in set_edition hook?

real night
#

fuck i have never worked with hooks

willow ember
#

hi guys

#

newbie modder here, never worked with lua, thought i'd mess around with the joker forge tool. I was trying to make a life is strange inspired card that basically prevents death, resets the blind and deck and hands and discards, as a rare card. this works once per round thats not a boss blind

#

joker forge has a prevents death effect but it auto wins the run

#

can i implement something like this with the site or do i have to get my hands dirty with lua

real night
loud summit
#

how do you check if a hand has been played this round

rocky plaza
#

tldr hooks let u execute code before and or after a function is called

gilded goblet
#

yuh

willow ember
#

¯_(ツ)_/¯

rocky plaza
rocky plaza
gilded goblet
#

shoutout n'

rocky plaza
#

N' the goat

real night
#

i dont know What to Do.

rocky plaza
#

not at my pc rn so im not sure what parameters are available on set_edition

faint yacht
#

function Card:set_edition(edition, immediate, silent, delay) end

rocky plaza
#

surely u'd just define
G.edition_levels = {}
by hooking G.start_run

#

and then when a edition planet is used,
add the editions key to a table and set it to 1 if the key maps to nil, otherwise increase the mapped value by 1

real night
#

no i mean like

#

i still dont get how tf do actually do hooks at all

rocky plaza
#

basically

  • store a reference to the original function you want to hook
  • override the function by defining a function with the same name and arguments as the original
  • make sure you call the original via the reference somewhere in the overriding definition EXACTLY ONCE
  • make sure to return a value if the original function returned something
real night
#

i dont

#

ugh im stupid

mental nacelle
#

For some reason the 'test' object in this doesn't have an ability table?

    class_prefix = 'md',
    set = 'OpalModifier',
    discovered = false,
    unlocked = true,
    atlas = 'OpalModifiers',
    pos = {x = 0, y = 0},
    config = {},
    required_params = {'key'},
    pre_inject_class = function(self)
            G.P_CENTER_POOLS[self.set] = {}
    end,
}

OPAL.Modifier{ -- Test
    key = "test",
    name = 'Test Modifier',
    atlas = 'OpalModifiers',
    pos = {x = 0, y = 0},
    config = {}
}```
rocky plaza
rocky plaza
#

i think the is_suit and is_face hooks would probably be the most helpful to look at

#

get_id is also the simplest hook in there

#

ya know im surprised i actually havent needed to do a lovely patch at all

faint yacht
#

-# ...was gonna send a complete hook...

gilded goblet
#

is there a way to "force-update" a tooltip box? im changing a center's config with lua but it still shows the old value on the card

twilit tundra
#

trying to make a consumable that opens multiple standard packs, however it keeps freezing the game on being used

            for i = 1, math.min(card.ability.boosters, 20) do
                G.E_MANAGER:add_event(Event({
                    trigger = "before",
                    func = function()
                        if (G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then return false end
                        local key = "p_standard_normal_1"
                        local booster = Card(
                                G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2,
                                G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2,
                                G.CARD_W * 1.27,
                                G.CARD_H * 1.27,
                                G.P_CARDS.empty,
                                G.P_CENTERS[key],
                                { bypass_discovery_center = true, bypass_discovery_ui = true }
                        )
                        booster.cost = 0
                        booster.from_tag = true
                        G.FUNCS.use_card({ config = { ref_table = booster } })
                        booster:start_materialize()
                        return true
                    end,
                }))
            end
        end,```

the "if (G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then return false end" part is definitely not being done correctly, but... how *do* i get it to only fire off the second and third pack events *after* you're out of the first pack? (without this line it tries to open all three packs at the same time, which is... also bad.)
#

wait uh

#

i removed a bunch of mods and now its behaving differently (fuck i shouldve done this first)
its just doing the same "open all three packs at once" thing instead of freezing

so this still isn't the way to do it

#

uh. how do i correctly only open one pack at a time.

ocean sinew
twilit tundra
#

i want them opened... one at a time

ocean sinew
#

I think you can check if G.pack_cards exists and If not open one

twilit tundra
#

so if G.pack_cards?

ocean sinew
#

Yeah

#

not sure though

#

but maybe it'll work

gilded goblet
ocean sinew
#

If It doesn't work check If there's any card in G.pack_cards and If there's not open booster

twilit tundra
#

why the fuck did that open the booster in the shop screen.

atomic edge
#

hey guys can someone confirm that ortalab adds a new button to the shop? because someone said it does and i cant find any info on it

gilded goblet
#

let me check bruh

#

i think they lied bro

atomic edge
#

oh

#

do you maybe know any other mods that add a button to the shop?

frosty rampart
#

entropy adds a new button after boss blinds only

atomic edge
#

thank you

#

if you remember can you tell me if it has to meet a condition like a voucher/joker or something or does it always show up

twilit tundra
#

always shows up

stone dagger
#

Hello, I have a joker that creates a planet card for a random hand played at round end, I have mentioned it here before. But I'm having trouble making it blueprint compatible. Is it since it triggers at joker_main to save the hand played and then again at round end to create the card and the blueprint doesnt have the list of hands and as such the game goes boom? How do blueprint jokers work?

frosty rampart
atomic edge
#

okay thanks

twilit tundra
# ocean sinew I think you can check if G.pack_cards exists and If not open one

good news, that works

bad news:
what the fuck is going on

current code:

            for i = 1, math.min(card.ability.boosters, 20) do
                G.E_MANAGER:add_event(Event({
                    trigger = "before",
                    blocking = false,
                    func = function()
                        if ((G.STATE == G.STATES.SMODS_BOOSTER_OPENED) or G.pack_cards) then return false end
                        local key = "p_standard_normal_1"
                        local booster = Card(
                                G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2,
                                G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2,
                                G.CARD_W * 1.27,
                                G.CARD_H * 1.27,
                                G.P_CARDS.empty,
                                G.P_CENTERS[key],
                                { bypass_discovery_center = true, bypass_discovery_ui = true }
                        )
                        booster.cost = 0
                        booster.from_tag = true
                        G.FUNCS.use_card({ config = { ref_table = booster } })
                        booster:start_materialize()
                        return true
                    end,
                }))
            end
        end```
#

i. feel like im missing some things here

#

why are boosters so cursed

#

i want to not make the game do things twice at the same time

atomic edge
#

i dont know if im stupid or what but i cant find the button or get it to show up i even looked at videos of other people on youtube and it doesnt show up for them either can someone who has it installed pls screenshot it so i can at least see what it looks like?

twilit tundra
twilit tundra
#

won't appear on ante 1

atomic edge
#

oh man thank you so much

#

i was looking for it at ante 1 and 8

twilit tundra
atomic edge
#

man you are a life saver

twilit tundra
#

ty

twilit tundra
atomic edge
#

i would love to but im fairly new here too so i dont have much experience im sorry

stone dagger
#

Sorry I asked for help in the middle of this thread so it kinda didnt go well

#

do you guys know how I could make a joker blueprint compatible?

#

more exactly if a joker saves values and then the blueprint copies it how does blueprint access those values?

#

becase im just getting nil

stone dagger
#

Current working blueprint version

if context.joker_main then
            card.ability.extra.hands_table[#card.ability.extra.hands_table + 1] = context.scoring_name
            card.ability.extra.hand = pseudorandom_element(card.ability.extra.hands_table, self.key)
        end

        if context.end_of_round and context.cardarea == G.jokers then
            
            if G.consumeables.config.card_count < G.consumeables.config.card_limit then
                
                card.ability.extra.hands_table = {}

                local planet = Get_hand_planet(card.ability.extra.hand)

                return {
                    message = 'Found ' .. planet.name,
                    func = function()
                        G.E_MANAGER:add_event(Event {
                            trigger = 'after',
                            delay = 0.4,
                            func = function()
                                if G.consumeables.config.card_limit > #G.consumeables.cards then
                                    play_sound('timpani')
                                    SMODS.add_card { key = planet.key }
                                end
                                return true
                            end
                        })
                    end
                }

            end
            
        end
#

previous version:

if context.joker_main then
            card.ability.extra.hands_table[#card.ability.extra.hands_table + 1] = context.scoring_name
        end

        if context.end_of_round and context.cardarea == G.jokers then
            
            if G.consumeables.config.card_count < G.consumeables.config.card_limit then
                
                local rand_hand = pseudorandom_element(card.ability.extra.hands_table, self.key)
                
                card.ability.extra.hands_table = {}

                local planet = Get_hand_planet(rand_hand)

                return {
                    message = 'Found ' .. planet.name,
                    func = function()
                        G.E_MANAGER:add_event(Event {
                            trigger = 'after',
                            delay = 0.4,
                            func = function()
                                if G.consumeables.config.card_limit > #G.consumeables.cards then
                                    play_sound('timpani')
                                    SMODS.add_card { key = planet.key }
                                end
                                return true
                            end
                        })
                    end
                }

            end
            
        end
wind steppe
#

what function would i hook to do something when exiting the run

twilit tundra
#

it should just be opening the booster

willow scroll
#

i diw rtie a function that lets you pretend that anything is a booster pack and open that with 0 problems*

*1 problem but i think ive thought of a way to fix it so it doesnt require global mod calculate dejanking

twilit tundra
#

👀

red flower
willow scroll
#

would thee want it

twilit tundra
#

i would i think

#

would also like it to properly open multiple boosters in sequence
as all ive done is either only open one but still have booster particles, or open all 3 at the same time

willow scroll
#

its main purpose is so you could do the open anything anywhere as a booster pack without both the open function and the state system freaking out

#

i dont think it does sequential stuff well

#

but give me like 20 mins and ill hand you the function in whatever state i get it to since i need sleep anyway

willow scroll
#

okay smods wiki documentation with the hail mary?

#

god damn it works

#

pseudo_open no longer uses any global calculate jank 🙏

willow scroll
#

youll have to tinker

twilit tundra
#

fuck

willow scroll
# twilit tundra fuck

okay sadly i forgot that this actually needs a small lovely patch to function, but otherwise its decently self contained albeit very jank
i quickly jotted some comments down so you can understand it a bit quicker

willow scroll
# willow scroll okay sadly i forgot that this actually needs a small lovely patch to function, b...
[[patches]]
[patches.pattern]
target = '''functions/button_callbacks.lua'''
pattern = '''
if card.ability.set == 'Booster' then
      G.CONTROLLER.locks.use = false
      G.TAROT_INTERRUPT = nil
    else
'''
position = "at"
payload = '''
if card.ability.set == 'Booster' or card.config.pseudo_open then
      G.CONTROLLER.locks.use = false
      G.TAROT_INTERRUPT = nil
    else
'''
overwrite = true
match_indent = false

the lovely patch in question (may or may not follow best patching practices)

#

god i really need to make my code cleaner

unkempt bronze
#

Say, anyone here do custom cards?

plucky berry
#

yes

#

[SMODS _ "src/utils.lua"]:2703: handname 'napoli_Trentuno' not found!
I'm getting this crash even though my hand key and the localizations match, anyone can help?

#

did not have this problem adding other poker hands

plucky berry
#

i am maybe an idiot if that is the problem

gaunt folio
#

what am i doing wrong here? Im trying to make it act like a timed negative

jolly shadow
hallow slate
#

How do I get my mod's config file? Like for making a config tab for my mod

red flower
#

SMODS.current_mod.config

#

you want to save that somewhere

gaunt folio
#

this other edition works but i jsut dont know

jolly shadow
gaunt folio
#

nvm figured it out

tranquil gull
versed swan
#

Scoring_Calculations is goated as fuck

#

I'm using it for two mods to replace previous implementations of new scoring parameters, and things are so much more easier to deal with

#

thank you for your work

versed swan
#

I'm trying to implement a stake that makes cards have a chance to get a sticker, but the stake just makes every card have the sticker. Here's the code I have for the stake and sticker:

SMODS.Sticker {
    key = "stickernana",

    needs_enabled_flag = true,
    should_apply = function (self, card, center, area, bypass_reroll)
        return (
            G.GAME.modifiers.enable_stickernana
            and not card.ability.eternal
        )
    end,
    rate = 0.3,
    sets = {
        Joker = true
    },

    calculate = function(self, card, context)
        ...
    end
}
SMODS.Stake {
    key = ...,
    applied_stakes = { "gold" },
    modifiers = function ()
        G.GAME.modifiers.enable_stickernana = true
    end,
}
daring fern
versed swan
#

problem now is that the stake doesn't apply any previous stakes, and doesn't apply banana sticker at all

#

...oh wait

#

hold on lemme check other code, might be related to sticker ownership taking

#

nvm, it's not

final jewel
latent perch
#

yeah I could see how that may crash

#

unhighlight_all() is called while you're still iterating over G.hand.highlighted

#

unhighlight_all() modifies G.hand.highlighted

final jewel
#

oh

#

wait I'll try

#

but its weird since it crash when I win the round

#

its not that but it make the code better

final jewel
#

ok I found that aether joker made it crash but It never happen i'll investigate

rigid solar
#

how does SMODS actually check which version is superior to which lol

#

does it check individual number by individual number (aka it sees 1 < 9 and it doesn't work)? mr_bones

shell timber
#

it's probably alphabetical yeah

red flower
rigid solar
#

yeah ok

rigid solar
#

also for example, if a mod goes from 9.xx to 10.xx, i figure it'll also say 9 > 1 and so the older version will be seen as compatible? but I don't think anyone puts a 0 before the 1st number in the version so 🤔
pokermon's eventually gonna have this problem lol

red flower
rigid solar
#

oh ok

#

so it's only anything that comes after the - that's in alphabetical order?

red flower
#

afaik yes

rigid solar
#

good to know

stuck ore
#

Is "repetitions = card.ability.extra.repetitions" the correct writing for returning a repitition because It doesn't seem to be working for me

red flower
stuck ore
#
            if context.cardarea == G.play and context.individual then
                for _, other_card in ipairs(G.play.cards) do
                    if context.other_card:get_id() == 12 then
                        card.ability.extra.queen_count = card.ability.extra.queen_count + 1
                    end
                end
            end
            if context.repetition and context.cardarea == G.play then
                if context.other_card:get_id() == 12 then
                    return {
                        repetitions = card.ability.extra.repetitions,
                            message = "Retrigger",
                            colour = G.C.Orange
                    }
                end
            end
        end, ```
#

Basically the idea is to only retrigger the queens if there is exactly two queens in the played hand

queen crescent
#

do queens actually have that id tho

red flower
red flower
queen crescent
#
print("like this")
stuck ore
#

gotcha

queen crescent
#

vessel: you were supposed to obey me

e_mult:
careful joker positioning:
literally any consumable that can strip eternal:

red flower
stuck ore
#
    eternal_compat=true,
    atlas = 'jokers',
    pos = {x = 3, y = 1},
    rarity = 3,
    config = { extra = { queen_count = 0, repetitions = 1 } },
    loc_vars = function(self, info_queue, card)
    return {vars = {card.ability.extra.queen_count, repetitions = 1}}
    end, ```
#

This is the config

#

I will say in debug it mentioned something about a lack of repitions being listed internally when the card scored

#

Sorry new keyboard so I typo often

queen crescent
#

a yellow warning thingy?

#

no repetitions found?

stuck ore
#

Sounds yes one sec

#

SECOND

queen crescent
#

ayo

#

anyway

ive had that happen yet the joker retriggered things just fine lol

red flower
#

it's when you don't return repetitions in a repetition context

stuck ore
#

"Found effect table with no assigned repitions" or something like that

red flower
stuck ore
#

wait

queen crescent
stuck ore
#

omfg

#

are you kidding me

#

Yes, thank you, I literally would've kept trying endlessly

#

resetting the run worked

red flower
#

if you change the config you need to get a new instance of the joker, but usually it's better to restart the run just in case

stuck ore
#

Will inscribe that into my brain, thank you a bunch

mental nacelle
#

badge_colour doesn’t seem to work for an extension of SMODS.Object

daring fern
hushed field
#

I'm sure I'm pretty close to figuring it out, as I just have to do a better job reading the mod badge code, but does anyone know the way to get the ID of a joker/card's source mod?

red flower
#

card.config.center.original_mod.id

hushed field
#

You're a champ, N

faint yacht
#

-# I still want to do that "putting 'Blind' in 'Blind run'" mod after these antics. 😂

stuck ore
#

btw does 'colour = G.C.Purple' work for making messages purple or can Balatro only do certain colors?

queen crescent
#

if you want to do custom colors youll need to do V: or lovely patch

red flower
#

there's a list of colours but G.C.PURPLE should work

red flower
queen crescent
#

i had a custom currency in my roadmap

but i know fr fr that this one requires a lovely patch

red flower
#

yes but you can also do C: without patches

vernal seal
#

quick question: does big and small blinds have object key? keys in sense like "v_grabber"

vernal seal
thorn basin
#

sorry for the late response but "options" must contain the objectType pool's key or "type_key" must contain that?

red flower
thorn basin
#

ah oof

red flower
#

it should be a table like { options = {...} }

#

it doesn't take an object type either

thorn basin
red flower
#

because it was not programmed to lol

#

objecttypes are not that widely used and most people just use them for jokers

thorn basin
#

oh, I see

#

welp, I must get rid of the ObjectType I did for those enhancements

red flower
#

i mean you can keep it

#

you can get the list easier by iterating G.P_CENTER_POOLS.objecttypekey

thorn basin
#

aight

wintry solar
#

you should be able to just put options = SMODS.ObjectTypes.key.cards I think

thorn basin
#

I tried using the consumable but it did nothing the first time, when I used the second one this error message appeared

red flower
thorn basin
#

or what part of it

red flower
#

it should be something like SMODS.poll_enhancements( { type_key = "seed", guaranteed = true, options = { "m_prefix_key", "m_prefix_key2" } } )

thorn basin
glass scaffold
#

this isn't applying Eternal to the Jokers

red flower
thorn basin
#

oh, so one defines when to generate one and another defines which one to generate

red flower
#

yeah

plucky berry
#

is there a way to code a poker hand part for a 3 card flush?

daring fern
plucky berry
#

i'm struggling with checking for suit

thorn basin
glass scaffold
daring fern
thorn basin
# red flower yeah

ok so uh, small update now something really peculiar happens when I use the consumable:
basically it creates a card of with the random enhancement applied to it and then destroys it.
I tried using "card.ability.max.highlited" instead of "card" but it gives me error as it is just a number variable.
What should I use to get the selected cards to apply the random enhancement?

plucky berry
#

i mean

#

i don't need to change base flush entirely

daring fern
plucky berry
#

wait so how do i implement it

#

into my poker hand

red flower
daring fern
analog spoke
#

sorry, thandfkjnkfsnkjfdn I am tired lol, just woke up, one second, I'll give further info lol

#

essentially, I'm trying to make an effect which is kinda a hybrid of both trading card and flower pot, where if you discard exactly 1 card of each suit, in a 4 card discard, they'll all be destroyed and you'll gain money in return

I am not sure how I'd exactly swap out the played hand for a discard effect like that however ndfskjnsdfkjsd

faint yacht
#
if context.pre_discard and G.hand.highlighted[1] and #G.hand.highlighted == 4 then
  ... -- suit table here.
  for i = 1, #G.hand.highlighted do
    ... -- do the base suit check with this loop.
  end
  for i = 1, #G.hand.highlighted do
    ... -- do the 'any suit' check with this loop.
  end
  -- put the final if with the suit counts and result here.
end
solemn shuttle
#

how does one refer to a SMODS.Gradient color in loc_vars or card desc text

liek would i add it to return{ vars = { colours {etc}}} in loc_vars and then use as {V:1}text{} or could i just refer to it by name as in {C:etc}

solemn shuttle
#

not sure HOW to refer to it either lol

red flower
#

{C:modprefix_key} should work

#

in loc_vars it would be SMODS.Gradients.modprefix_key

analog spoke
solemn shuttle
#

wsh being the prefix and essence being the key in SMODS.Gradient

red flower
#

yeah
you don't need both if you're not using V:

analog spoke
faint yacht
#

You didn't replace context.scoring_hand parts.

analog spoke
#

oh, lmao 😭 dfnsd sorry, one second lol

analog spoke
#

it still crashes sadly it seems ndkjsnfksdjf :<

faint yacht
#

#G.hand.highlighted[i] > G.hand.highlighted[i]

analog spoke
faint yacht
#

#table is length of table.

#

...as long as table has table[1], table[2] and so on in order... as long as there's not a break in that.

analog spoke
#

ahhh, I see, so, what I'm doing there basically is "digit length of xth digit of the table" which, just, doesn't make sense to the code lol

faint yacht
#

Length of the table element.

analog spoke
#

ok, so, it works now dfnsdfj, well, almost, except for one aspect, the cards aren't being destroyed yet, otherwise, it seems everything is working dfnksdf

faint yacht
#

If the conditions pass, on one hand, you can pass the cards to SMODS.destroy_cards(G.hand.highlighted)... on the other, you can, once again, iterate over G.hand.highlighted, but this time, tag them, like G.hand.highlighted[i].black_lotus_destroy.

Then, in a separate context check for if context.discard and context.other_card and context.other_card.black_lotus_destroy then, you can return { remove = true }.

analog spoke
#

mmmmm, interesting interesting

#

I somehow only just realized from this that I could be making my own contexts for things lol, not sure what I'd use it for yet, but it sure could lead to some interesting stuff mayhaps

#

I think I wanna do the 2nd option here, for the sole reason that I'm thinking perhaps maybe making it so the money is gained per removed card instead of being all at once could be an interesting thing, perhaps I could make a mime style joker at some point which retriggers discard effects, if that'd even be possible lol

faint yacht
#

I have 9 Jokers that respond to custom contexts.

analog spoke
analog spoke
#

doesn't even have a joker tag lol

faint yacht
#

If the Flower-Pot-like conditions pass, iterate over the G.hand.highlighted and set G.hand.highlighted[i].black_lotus_destroy, yes.

analog spoke
#

mmm, I see, I see, I think I'm getting it

faint yacht
#

Then

if context.discard and context.other_card and context.other_card.black_lotus_destroy then
  context.other_card.black_lotus_destroy = nil
  return { remove = true }
end

as context.discard iterates over each discarded card individually.

analog spoke
#

so, is this what was meant?

#

I may've wildly misinterpreted lol

faint yacht
#
if suits['Hearts'] > 1 and suits['Diamonds'] > 1 and suits['Spades'] > 1 and suits['Clubs'] > 1 then
  for i = 1, #G.hand.highlighted do
    G.hand.highlighted[i].black_lotus_destroy = true
  end
end
analog spoke
#

mmm, I see, I think I get it, maybe

#

(sorry for being stupid lol, I am like this frequently lmao)

#

I'll try this lol

faint yacht
#

Just remove the setting of that variable out of the suit checks.

#

And no worries... my initial antics here were more or less the same when I started.

solemn shuttle
#
    key = "essence",
    colours = {
        HEX('EB00C4'),
        HEX('A60056'),
        HEX('CF2B80'),
    },
    cycle = 10,
    interpolation = 'trig',
}```
#

-# the gradient code for reference if that matters too

analog spoke
slim ferry
#

how does the additional text for perma-bonuses on cards work? i figured out that i had to hook SMODS.localize_perma_bonuses, but how do i get the game to actually pass in the variables for a perma bonus into specific_vars

faint yacht
#

The if context.discard part is supposed to be outside of the if context.pre_discard.

analog spoke
final jewel
#

Question : how do I modify the blind size mid blind I'm trying to do a seal that reduce it but when I play the seal it just get stuck in the playing phase without doing anything

faint yacht
#

One can contain them all.

solemn shuttle
#

🗣️

red flower
solemn shuttle
# red flower can i see the actual joker description and code
    key = "essence",
    colours = {
        HEX('EB00C4'),
        HEX('A60056'),
        HEX('CF2B80'),
    },
    cycle = 10,
    interpolation = 'trig',
}

SMODS.Consumable({
    set = "Tarot",
    key = "tar_awesome",
    pos = {
        x = 1,
        y = 2
    },
    loc_txt = {
        name = "The Awesome",
        text = {
            " ",
            "{C:inactive}It would be so cool...{}",
            " ",
            "{C:green}1 in 100{} chance for either",
            "{C:dark_edition}The Soul{} or {C:wsh_essence}The Essence{}"
        }
    },
    config = { extra = {  } },
    atlas = 'nixconsume',
    cost = 2,
    discovered = true,
    loc_vars = function(self, info_queue, card)
        info_queue[#info_queue + 1] = { key = 'c_soul', set = 'Spectral' }
        info_queue[#info_queue + 1] = { key = 'c_wsh_essence', set = 'Spectral' }
        return { vars = { colours = { SMODS.Gradients.wsh_essence } } }
    end,
    use = function(self, card, area, copier)
        if pseudorandom('itwouldbesoawesome') < 1 / 100 then -- yeah it's fixed odds lol
            if math.random(0, 1) == 1 then
                SMODS.add_card({
                    key = "c_soul",
                })
            else
                SMODS.add_card({
                    key = "c_wsh_essence",
                })
            end
        end
    end,
    can_use = function(self, card)
        return true
    end
})```
analog spoke
solemn shuttle
#

ik you said you dont need both but i was tryna figure out what you had meant by that too admittedly like which shoujld i use ig?

#

ive been tryna tinker

faint yacht
#
if context.pre_discard ...

end
if context.discard ...

end

under one calculate.

red flower
analog spoke
solemn shuttle
#

yeah i had tried that too and it gave the same crash

red flower
analog spoke
red flower
solemn shuttle
#

yeah

solemn shuttle
#

confusion, effectively [or so im guessing]

#

given the gradient and consumable im referencing share a name

#

ty 😭

red flower
#

thats not the issue

red flower
solemn shuttle
#

OH

#

i see

faint yacht
#

...why the self.config and not card.ability? Replace the if G.GAME.chips block with just return true.

final jewel
#

cause its a seal

#

the seal reduce the blind size by 1%

daring fern
final jewel
#

G.GAME.blind.chips = math.floor(G.GAME.blind.chips * (1 - card.ability.seal.extra.reduce / 100))
like that

final jewel
#

if G.GAME.chips - G.GAME.blind.chips >= 0 then
G.STATE = G.STATES.HAND_PLAYED
G.STATE_COMPLETE = true
end_round()
end

and this block isnt necessary ?

final jewel
#

its stuck again

faint yacht
#

Show the "full" calculate.

next timber
#

is there any way to make the 'hitbox' of a consumable or consumabletype smaller? i have a consumable type that has a lot of free space at the top and bottom and id like for them not to be clickable there

final jewel
next timber
#

nvm just found the docs for pixel_size

faint yacht
#

...remove trigger and delay lines? Or just copy paste my entire hook and edit the values accordingly?

final jewel
#

its not that

faint yacht
#

...oh, you are not return true in the first event add.

final jewel
#

oh shoot

#

if its that I am a zebra

#

I AM A ZEBRA

#

Ali the GOAT

faint yacht
hollow horizon
#

Hi! Is there a way to check for system time? Like I'd like for function to work only for e.g at 17:30 and else to return false. Is it possible?

daring fern
hollow horizon
#

great, thanks

next timber
#

why can't i set the display_size on an undiscovered sprite? i have an atlas for consumables that are less than the size of a full card but i find i still have to use display_size to stop them stretching, and for some reason it doesn't seem to work on SMODS.UndiscoveredSprite

errant arrow
#

im trying to make an upgradable joker (via consumables) but i don't know how much mult, chip, or both, modifiers the joker should start with.

i have it set to 10 upgrades right now, but i don't know how to start with the values

slim ferry
#

oh wait

#

nvm

hollow horizon
#

how do I debuff jokers in blind?

slim ferry
#

same as any other card

#

except check for context.debuff_card.area == G.jokers

hollow horizon
#

thx

next timber
#

currently scraping the balatro modded wiki looking for mods with weird consumable shapes to see how they manage lol

crystal perch
#

weird bug i'm having where SMODS.destroy_cards(card, true, true, true) doesn't make it immediate or skip the animation

rare torrent
#

how do i make it retrigger glass cards instead of face cards?

        if context.repetition and context.cardarea == G.play and context.other_card:is_face() then
            return {
                repetitions = card.ability.extra.repetitions
            }
        end
    end,```
next timber
daring fern
rare torrent
#

yeah that worked thank you!

hollow horizon
#

can I make a blind retrigger cards with specific seal?

slim ferry
#

yeah, same way a joker or something would do it

#

blinds can use calculate in all the same ways

hollow horizon
#

oh ok

rare torrent
#

back again, now im trying to make a joker that makes face cards undebuffable, but this isn't working for some reason

    if context.setting_blind then
        for _, c in ipairs(G.deck.cards) do
            if c:is_face() then
                c:set_debuff(false)
            end
        end
    end
end```
slim ferry
#
if context.debuff_card and context.debuff_card:is_face() then
  return {
    prevent_debuff = true
  }
end
rare torrent
#

that worked thank you!

hollow horizon
#

is calculate = function(self, card) G.GAME.dollars = G.GAME.dollars - 1 end, a right way to charge 1$ for every played card just like in The Tooth?

slim ferry
#

ease_dollars(-1)

hollow horizon
#

or will it trigger just once for played hand?

slim ferry
#

also you forgot the context check

hollow horizon
hollow horizon
slim ferry
#

the tooth loops over G.play.cards in context.before for the money stuff

#

also you should probably look at vanillaremade the tooth if youre doing basically the same effect

hollow horizon
#

sure, I'm only using smods api, so yeah... I'll look for it thanks

next timber
#

Does anybody know how I can set the display_size of an UndiscoveredSprite? just doing display_size = {w=67,h=68} seems to not be doing anything

faint yacht
#

-# ...does UndiscoveredSprite even support display_size..?

next timber
#

clearly not

#

which is. annoying

slim ferry
#

the docs dont mention it

#

so i dont think so

next timber
#

is there any way of getting it the right size or am i royally screwed

willow scroll
faint yacht
next timber
#

woa alphabet cards are 57x81?

#

freaky

jolly shadow
next timber
#

ok no i guess alphabet cards are standard sized. yay

#

time to patch i guess

#

hang on. i have no fucking clue how to do that

#

guess i should try anyways

jolly shadow
#

🥀

next timber
#

ok just remembered setting the overlay sprite does nothing ebcause im not using an overlay sprite

#

this isnt working

gusty compass
#

Where can I find the hand size as a variable again?

slim ferry
#

G.hand.config.card_limit

gusty compass
#

Alr

next timber
topaz berry
#

I was wondering if there was a method that returns a boolean if card is a joker.

slim ferry
#

card.ability.set == "Joker"

topaz berry
#

thank you

plucky berry
#

help with planet descriptions not showing up?

topaz berry
#

making a joker that does something else when sold, is there to prevent a card from being sold, instead of just copying the joker when sold?

topaz berry
#

gotcha thank you

hollow horizon
#

Hi, will that work for checking the seal on played cards?

frosty rampart
violet void
#

Has anyone else had a problem with stack overlow after duplicating a Joker with a custom button (above/below Sell)?

rotund sable
winter flower
#

how do i make it so that the background is set to a different colour until a condition is set

violet void
slim ferry
#

why arent you just using copy_card

violet void
#

I'm not calling this function directly, but using Ankh leads there (or using DebugPlus duplicate hotkey)

#

and I can't figure out why the custom button is the culprit

hollow horizon
#

I have no idea why won't this joker ever trigger... Any help?

slim ferry
#

can you also show the seal definition

hollow horizon
#

but it doesn't do anything even if there are no such seals on any cards

frosty rampart
#

don't put the _seal suffix in the seal's key itself, it should just be key = "kazakh"

#

the way you have it now, you'd need to reference "misiek_kazakh_seal_seal" in some places

hollow horizon
#

yeah I do have it like that, the seals work just fine

rare torrent
#

how do i remove stickers from all jokers?

hollow horizon
#

the joker also subtracts -0.2 per every card with seal but doesn't trigger what's inside context.joker_main at all

wicked leaf
#

ACTUALLY working on my first mod

tranquil cypress
#

fire

mild bronze
mild bronze
wicked leaf
#

its a poptart

granite jay
#

How do you make jokers trigger when other jokers trigger?

true jasper
#

From the smods wiki

if context.post_trigger then
{
    cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
    post_trigger = true,
    blueprint_card = context.blueprint_card, -- if applicable
    other_card = card, -- the card that triggered
    other_context = context, -- the context the trigger happened on
    other_ret = ret -- the return table from the trigger
}
sturdy compass
#

post_trigger is also an optional feature that you need to activate

granite jay
#

Ah ok

#

Cos I'm tryna make a joker that gains mult when cards, jokers and consumables are triggered, then resets when the joker itself is triggered after giving it's mult.

granite jay
broken rivet
#

is it possible to have a deck start in a different game state? i'm aiming for a custom one but i'll just say i want it to start in the shop as an example

wintry solar
#

Yeah, should be able to patch into the run start stuff and change something like that

sturdy compass
broken rivet
#

at least it seems like it

wintry solar
#

Can you not just set the state after that?

broken rivet
#

i tried doing it in the deck object, didn't work though that might've been because it also starts you with 2 buffoon tags

granite jay
#
calculate = function(self,card,context)              --define calculate functions here
        if context.joker_main and context.cardarea == G.jokers then
            if card.ability.extra.mult > 0 then
                local effects = {
                    {
                        mult = card.ability.extra.mult, 
                        colour = G.C.MULT
                    },
                    {
                        message = localize('k_reset'),
                        colour = G.C.MULT
                    },
                }
                card.ability.extra.mult = 0
                return SMODS.merge_effects(effects)
            end
        end
        if not context.blueprint then
            if (context.post_trigger and not context.joker_main) or context.using_consumeable or (context.individual and context.cardarea == G.play) then
                card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
                return {
                    extra = {focus = card, message = localize('k_upgrade_ex')},
                    card = card,
                    colour = G.C.MULT
                }
            end
        end
    end,

The joker triggers twice when playing cards or consumables are used and I suspect it's to do with the joker triggering itself. Anyone know a fix?

raven lake
robust sable
#

im getting this same issue but every time i find someone else talking about it they get 0 replies

#

why is this the worlds most ignored problem

#

not one reply? not one hint?

solemn shuttle
#

is there a way to specifically retrigger a consumable's effect

#

like if its a held-in-area effect or otherwise

#

i was considering checking how whoprint [yahimod] works with jokers and try to repurpose it with consumables

#

as i want it to be for a specific Set too

tepid crow
#

I probably should've looked at this code earlier, cuz I don't think I would ever be able to reproduce using this code.
It might be multiple parts of your mod interacting in weird unexpected ways? If you manage to make a single file mod that you can make crash you can probably solve it

chrome widget
#

Yeah I'll have to narrow it down

tepid crow
#

ye

chrome widget
#

It's not unsolvable, it'll just be boring to fix because the crash log is spectacularly unhelpful

granite jay
#

BTW how do you check how many joker slots there are?

solemn shuttle
#

wait no thats

#

total jokers owned

#

hangon

#

G.jokers.config.card_limit

#

this is the total joker slot count

granite jay
#

thx

solemn shuttle
#

np lol

queen meadow
#

is there a trigger for when a voucher is redeemed?

granite jay
#
get_xmult = function()
        local my_pos = 1
        if #G.jokers.cards then
            for i = 1, #G.jokers.cards do
                if G.jokers.cards[i] == card then
                    my_pos = i
                    break
                elseif i > #G.jokers.cards then
                    break
                end
            end
        end
        
        local joker_count = G.jokers.config.card_limit or 5
        local x_mult = (((1-card.ability.extra.x_mult_mod) * (joker_count-my_pos)) / (joker_count - 1)) + 1

        if x_mult < 1 then
            x_mult = 1
        end
        return x_mult
    end,

    get_xmult_gradient = function()
        local joker_count = G.jokers.config.card_limit or 5
        local x_mult = (card.ability.extra.x_mult_mod - 1) / (joker_count - 1)
        return x_mult
    end,

    calculate = function(self,card,context)              --define calculate functions here
        if context.joker_main and context.cardarea == G.jokers then
            return {
                x_mult = card.get_xmult(),
                colour = G.C.MULT
            }
        end
    end,

    loc_vars = function(self, info_queue, card)          --defines variables to use in the UI. you can use #1# for example to show the chips variable
        return { vars = {card.get_xmult(), card.ability.extra.x_mult_mod, card.get_xmult_gradient()}, key = self.key }
    end

The game crashes when I try to call the functions, anyone know how to call them?

#

nvm put the function in config and called it through that

solemn shuttle
#

how would one adjust the amount of cards avilable in a booster pack mid run

#

ie with a voucher

sturdy compass
#

I believe there's a global var you can access to do that

#

G.GAME.modifiers.booster_choice_mod

solemn shuttle
#

oh wait 👀

#

wait does this influence All packs tho

sturdy compass
#

Yes

solemn shuttle
#

im specifically tryna adjust the ones for one specific type

#

could that still work or memon_thonk

frosty rampart
#

you can probably dig through the smods code to see how the global modifier works, and then make a copy of it that only applies to the specific type

solemn shuttle
#

hmmm

#

alr then ty lol

granite jay
#
SMODS.Joker{
    key = "deltah",
    config = { 
        extra = {x_mult_mod = 5},
    },

    calculate = function(self,card,context)
        if context.joker_main and context.cardarea == G.jokers then
            local my_pos = 1
            local joker_count = 1
            
            for i = 1, #G.jokers.cards do
                if G.jokers.cards[i] == card then
                    my_pos = i
                    break
                elseif i > #G.jokers.cards then
                    break
                end
            end
            
            local x_mult_gain = get_deltah_x_mult(my_pos, G.jokers.config.card_limit, card.ability.extra.x_mult_mod)
            return {
                x_mult = x_mult_gain,
                colour = G.C.MULT
            }
        end
    end,

    loc_vars = function(self, info_queue, card)          --defines variables to use in the UI. you can use #1# for example to show the chips variable
        local joker_count = 5
        local my_pos = 1
        if G.jokers then
            joker_count = G.jokers.config.card_limit
            for i = 1, #G.jokers.cards do
                if G.jokers.cards[i] == card then
                    my_pos = i
                    break
                elseif i > #G.jokers.cards then
                    break
                end
            end
        end

        local x_mult = get_deltah_x_mult(my_pos, joker_count, card.ability.extra.x_mult_mod)
        local x_mult_gradient = (card.ability.extra.x_mult_mod - 1) / (joker_count - 1)
        return { vars = {x_mult, card.ability.extra.x_mult_mod, x_mult_gradient}, key = self.key }
    end
}

local function get_deltah_x_mult(position, slots, x_mult_mod)
    local x_mult = (((1 - x_mult_mod) * (slots-position)) / (slots - 1)) + 1
    if x_mult < 1 then
        x_mult = 1
    end
    return x_mult
end```
Game crashes when I try to call the local function
#

Anyone know why that happens?

twilit tundra
gaunt folio
#

how can i make this repeat the joker or playing cards? It replays playing cards but doesnt do so for a joker

#

the joker repeats the playing cards, which is neat too but not my intended effect

frosty rampart
#

context.repetition is only for playing cards

#

you need to enable the retrigger_joker optional feature and then use context.retrigger_joker_check (and don't use the cardarea or main_scoring checks)

#

if you only want to retrigger the joker that the edition is on, then you'll need to check if card == context.other_card

gaunt folio
#

alright

solemn shuttle
#

is there a similar method like this for consumables

#

whether it’s a held-in-area effect or basically a “double-effect” on use

frosty rampart
#

uhhh i don't think so
at least not anything as simple as returning repetitions is for joker or playing card retriggers

#

unless maybe held-in-area consumables count for the retrigger joker check?

solemn shuttle
#

the Held In effect is manly what I’m thinking about so

#

id have to check ig

frosty rampart
#

at worst you can copy the code for the retrigger joker check and set it up to run a new context for retriggering calculating consumables instead

gaunt folio
#

kw idk how to make it retrigger the joker if its a joker and playing card if its a playing card but ngl

#

the concept of making the joker retrigger cards is kinda fun so

desert ore
#

can SMODS.blueprint_effect copy multiple jokers at once?

frosty rampart
desert ore
#

oh sweet thank you

whole linden
#

Howdy im uh new here and need help with the tailsman mod for balatro if anyone will help me

wicked leaf
#

how do you add an extra sidebar button to a joker?

#

it HAS to be a lovely patch but I cant find any examples

violet void
wicked leaf
#

yeah basically

#

I found some examples in the entropy hooks

#

i might be able to use that

violet void
#

I also managed to do it but it crashes the game when the Joker is duplicated ç-ç

wicked leaf
#

Another question, how can I get the least played hand? I know how to get the most played but not the least played

violet void
wicked leaf
#

ill try to figure that out

#

im not too versed in lua

#

but it cant be too different from java

#

and im pretty good at java so

violet void
wicked leaf
#

akyros

violet void
#

gonna check it out too

wicked leaf
#

im confoused

#

do I need to set up the local myself

violet void
stuck ore
#

G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + card.ability.extra.dollars return { message = "$".. card.ability.extra.diamonds_count .."", colour = G.C.MONEY, extra = { dollars = card.ability.extra.dollars * card.ability.extra.diamonds_count, func = function() G.E_MANAGER:add_event(Event({ func = function() G.GAME.dollar_buffer = 0 return true end })) end
is this good for granting money on trigger because it doesn't seem to do anything. I know I can use ease_dollars() but doing that has this weird delay with the messages and the money is gained instantly and I don't really like it, any suggestions?

#

nvm there was an issue I missed, this works just fine

wintry swallow
#

Here's the code from the original shakecard function, after changing the name to mod_shake card:

function mod_shakecard(self) --visually shake a card
G.E_MANAGER:add_event(Event({
func = function()
self:juice_up(0.5, 0.5)
return true
end
}))
end

hushed field
#

If you add your code between three backtics on each side, it'll auto format! ` these thingies

#

Self in this case is going to be empty! I see what you're trying to do, but just shaking a card luckily doesn't need all of this shell code around it. You can comfortably replace every instance of mod_shakecard in your code with a direct call to juice_up()!

#

Could you link the tutorial your following btw? I'm wondering if it might be older!

wintry swallow
#

Welcome to the second edition of Balatro Modding 101 tutorial.
Steammodded upgraded their logic so i re-made this tutorial!

In this beginner-friendly guide, I'll walk you through the steps to get started with modding in Balatro. Whether you're looking to install mods created by others or dive into making your very first mod, I've got you covere...

▶ Play video
wintry swallow
#

Like this?

hushed field
#

No, haha, those are quotation marks. The backtic (`) is next to the tilde (~) on your physical keyboard, or on a phone probably also next to the tilde!

wintry swallow
#

oop

hushed field
#

No worries, probably the most common mistake made, haha

#

Are you familiar with VanillaRemade, by the way?

wintry swallow
#

No, I don't have too much coding experience, I just love Balatro and wanted to make my own mod so I'm learning as I go

wintry swallow
#

wait

#

wrong section of code

#

this one

hushed field
#

But yeah, I'm not sure why you'd need a separate event call to shake the card, as juice up accounts for that. I'll grab a link to vanillaremade, and try and find an example of juice_up being used in a joker there!

wintry swallow
#

It's now crashing because of where I'm putting the backtics I guess? I'll take a look at VanillaRemade and try to recreate from there

hushed field
#

Oh, wait, sorry, I'm fully misunderstanding, haha

#

no, the backtic aren't necessary to add to your actual code!

#

They're for when you share code on discord!

wintry swallow
#

OH

hushed field
#
    G.E_MANAGER:add_event(Event({
        func = function()
            self:juice_up(0.5, 0.5)
            return true
        end
    }))
end```

so it looks like this, which is a bit easier to parse, haha
wintry swallow
#

ok i also misunderstood, my bad

wintry swallow
hushed field
#

Oh yeah sorry, haha. I got distracted way too quickly

wicked leaf
#

im doing smth wrong here and idk what

hushed field
wintry swallow
#

Thanks! I'll try and report back!

faint yacht
wicked leaf
wicked leaf
hushed field
#

https://github.com/nh6574/VanillaRemade/blob/main/src/jokers.lua#L442

This is the code for the reimplementation of Ceremonial Dagger. If you're very new, it might be a bit daunting, but main thing is that, as you can see. The juice_up in these cases are all called in events, but that is to make specific animations line up. Having a generic, separate event for juice_up can be a bit cumbersome for when you're stacking other visual animations, as they would each happen separately, while you may want them to happen all at once!

GitHub

Contribute to nh6574/VanillaRemade development by creating an account on GitHub.

faint yacht
#

Also, other_card should be context.other_card.

wicked leaf
#

got it got it

hushed field
wintry swallow
#

ah

queen meadow
#

how can i make this not happen

hushed field
#

You can set it up to only return something if the value is > 0

queen meadow
#

got it

wintry swallow
#

So, the only thing I'm unclear on is how to show the assets of jokers

#

I have the asset made, in 142x190, and 71x95

faint yacht
#

Former goes under assets/2x, latter - assets/1x.

#

The game automatically switches between the two in vanilla.

wintry swallow
#

i did that... let me try a different method rq

hushed field
#

Did you also set them up with an Atlas?

wintry swallow
#

ok so i DO need to do that? there is not an atlas in VanillaRemade

hushed field
#

Yeah, for new assets you would need to!

#

VanillaRemade uses the existing art, though I get why that's kinda confusing

wintry swallow
#

DOG COME ON

#

i dont understand what the issue is, it's the EXACT code format from vanillaremade

red flower
#

may i see the code

wintry swallow
#
    key = "test_stoat",
    path = "j_test_stoat.png",
    px = 71,
    py = 95
})```

```SMODS.Joker {
   ``` key = "stoat",
    pos = { x = 0, y = 0 },
    rarity = 1,
    blueprint_compat = true,
    cost = 1,
    config = { extra = { chips = 10, mult = 2 }, },
    loc_vars = function(self, info_queue, card)
        return { vars = { card.ability.extra.chips, card.ability.extra.mult } }
    end,
    calculate = function(self, card, context)
        if context.joker_main then
            return {
                chips = card.ability.extra.chips,
                mult = card.ability.extra.mult
            }
        end
    end,
}

end```
red flower
#

that end in the last line shouldn't be there

wintry swallow
#

??????? alright then???? ill try

#

THATS THE TICKET

ashen drift
#

do seals' calculate functions not run when theyre held in hand?

#

because this is just not printing anything

red flower
ashen drift
#

okay

#

okay it prints fuck now but doesnt actually print shit

daring fern
ashen drift
#

so do i loop through G.hand?

daring fern
wintry swallow
#

Dog I'm gonna crash out.

ashen drift
#

fuck im actually stupid 🤦‍♂️

wintry swallow
ashen drift
#

i dont even need a check im actually so stupid

#

agbilrgargbu thanks

#

my brain is not spinning

#

is there not an in pool function for seals?

wintry swallow
#

can someone explain what's wrong with this????? the name and description are not showing up..........

ashen drift
wintry swallow
ashen drift
#
return {
   descriptions = {
      Joker = {
         j_prefix_key = {
            name = "Name",
            text = {"text"}
         }
      }
   }
}```
daring fern
ashen drift
#

its not showing up on the lsp or the wiki apparantly

wintry swallow
red flower
ashen drift
#

ah alright

#

thanks

atomic edge
#

does anyone know what part of the code hides the shop when opnening a bosster/redeeming a voucher etc.

wicked leaf
#

idk what im doing wrong

#

im upset

#

theres nothing there

last oracle
#

, is used to separate table contents

ashen drift
#

i also reccomend you get the lua lsp plugin

#

it can show you grammatical coding errors and warnings alike

last oracle
#

This is vscode propaganda

#

Code on paper

#

Reject modernity

wicked leaf
#

there are a bunch of lsp plugins

#

mostly for roblox

ashen drift
#

just search lua

#

this one

wicked leaf
#

got it

wicked leaf
#

just using card causes a nil error

#

not sure WHAT card im supposed to target

atomic edge
#

how can i change the position of the effect description (it shows up above the card and i want it to be to the left)

tepid crow
#

can you explain why? thunk made the effect descriptions appear in certain orientations depending on the card position for a reason

atomic edge
#

because i have a custom card area

#

that is above the deck

#

and when i hover the cards in the area

#

the whole description is not visible

#

because it comes above the card

tepid crow
#

Ah, fair enough

red flower
#

hook Card:align_h_popup

atomic edge
#

thank you

red flower
#

there are no highlighted cards in context.before

wicked leaf
#

level up the least played hand (before the hand is scored)

#

im checking vanillaremade code for reference but that only has level_up = true and its not helping me

tepid crow
red flower
#

to level up another hand you can do

return {
     level_up = true,
     level_up_hand = key
}

but i dont see the logic in your code to get the least played hand

#

@wicked leaf

wicked leaf
#

im just really confused cuz im just copying code to loop through all the hands and check that the one played is less than the rest

red flower
#

can i see the code?

wicked leaf
wicked leaf
red flower
wicked leaf
#

the problem is that SMODS.smart_level_up_hand has a "card" argument

#

why would you need that

#

what's the point

#

i dont know what to put there

red flower
#

the card

wicked leaf
#

WHAT card

ashen drift
#

the card provided in the calculate function id assume

wicked leaf
#

you dont level up cards

red flower
#

it's for animations

ashen drift
#

i think its just for displaying messages? im not sure i havent used it

wicked leaf
#

I tried doing this but it crashes my game

red flower
#

you provide the card doing the effect

#

self is not a card

#

card is the card

wicked leaf
#

im gonna try again

#

this is like. my first or second time trying balatro modding and it confuses me

#

yep, crashes

#

isnt context.before the context right before scoring?

red flower
#

yes

wicked leaf
#

idk what im doing wrong then

red flower
#

can you post the full log

wicked leaf
red flower
#

oh

#

it's "Three of a Kind"

willow scroll
#

yoooo new smods wiki page

#

bless

ashen drift
#

woah

wicked leaf
#

alright this should work

#

that should level up the hand im about to play

red flower
#

context.before is after the cards are moved to G.play

#

use context.scoring_name

#

instead of text

ashen drift
#

ooo internal documentation

wicked leaf
rain seal
#

im working on a mod rn and i need more colors for the desc what are all the colors pls i need ts

wicked leaf
ashen drift
#

just check everything in G.C

wicked leaf
#

Joker is usually where the contexts are

ashen drift
#

or use HEX("hex code value")

rain seal
#

thx

ashen drift
#

mb im stupid

#

💔

wicked leaf
#

alright im gonna try to use the code from obelisk to make the actual effect

red flower
#

there's an example for most played hand on the vanillaremade wiki

wicked leaf
#

MOOODS

#

THIS MAN IS INTERRUPTING MY TEA TIME

#

thank you

atomic edge
#

is there a mod that allows you to reload the game so you dont have to turn it off everry time you change something?

wicked leaf
#

I thought changing it from >= to <= would make it the least played but apparently not

#

I am stuck again

willow scroll
#

how would i make it so a sticker ignores whether the card its applied on is debuffed or not?

red flower
atomic edge
#

oh nice thats exactly what i needed

red flower
wicked leaf
gilded goblet
#

is there a way i can change a tarot's "effect" value without messing with its config? here i changed card.ability.max_highlighted to 1 but that still doesn't limit it to just one card

i'm assuming it has something to do with card.ability.consumeable? if i change card.ability.consumeable.max_highlighted to 1, it works, but it's then gonna be like that for every future card :/

wicked leaf
#

it should have value manipulation stuff

hollow horizon
#

Can I pin a joker but to the right instead of to the left?

red flower
hollow horizon
#

I see, alright

gilded goblet
#

ty

wicked leaf
#

(Cryptlib is just cryptid features in a library separate from cryptid)

daring fern
gilded goblet
#

oh wow that works, ty! i dont fully understand why rn but i will look into it soon

daring fern
broken rivet
#

is it possible for another joker to prevent a joker from triggering

broken rivet
#

i guess

#

i wanted a joker that either retriggers a joker or causes it to fail entirely

zealous glen
#

Last time I asked I don’t think there was, but that was months ago

broken rivet
#

though tbh that'd also probably cause a lot of crimson bean-esque bugs

lilac trail
#

I play mobile, but plan to buy the steam version pretty soon. I know LUA programming pretty well. How do you recommend I get started modding?

broken rivet
#

jokers that sorta "prime" themselves in context.before for example could break

#

might be a better idea to just not do it

violet void
broken rivet
#

i have

#

i know cryptid's repulsor boss blind does something similar but that's also cryptid and i would ideally not want to reference cryptid code

lilac trail
#

Does balatro have a mod loader at this point in time?

broken rivet
#

smods

lilac trail
#

thanks. and a modding api?

broken rivet
#

also smods

dreamy thunder
#

how would i place this button behind the card

daring fern
broken rivet
#

last time i tried modifying context.other_ret it seemed to just do nothing

daring fern
broken rivet
#

it was for a cryptid joker that makes chips jokers use the next highest operator, so i was trying to do stuff like replacing chips with xchips

broken rivet
#

i found a way to do it with an SMODS.calculate_individual_effect hook that works better anyway though

broken rivet
unkempt thicket
broken rivet
unkempt thicket
broken rivet
broken rivet
daring fern
glass scaffold
#

Odd request, but:

How do I randomly spawn a Joker between 2 mods?

daring fern
rocky plaza
#

how would one replicate the visual effect of Card:start_dissolve without actually destroying the card?

daring fern
frail parcel
#

is this how i do boss blinds debuffing

daring fern
frail parcel
#

could you give a example

wicked leaf
#

trying to get the least played hand, but the card seems to be triggering with all of them

daring fern
# frail parcel could you give a example
calculate = function(self, card, context)
    if context.debuff_card and (context.debuff_card:get_id() == 2 or context.debuff_card:get_id() == 3 or context.debuff_card:get_id() == 5 or context.debuff_card:get_id() == 7 or context.debuff_card:get_id() == 14) then
    return {debuff = true}
end
frail parcel
#

thx

daring fern
wicked leaf
#

well yeah, that's what it says to do for the MOST played

#

instead of > im doing <

#

theoretically that should do the least played

slim ferry
#

yeah because every play count will be bigger than -1

#

so it works for most played

daring fern
wicked leaf
wicked leaf
slim ferry
#

you want to start at a play count bigger than every other hand

wicked leaf
#

ohhh i see

wicked leaf
#

give me a second

slim ferry
#

just add a check that hand.played ~= 0

wicked leaf
#

should it be AND or OR

slim ferry
#

and

wicked leaf
#

maybe this'd do?

slim ferry
#

since you want to check if its less played than the current hand AND if its not 0

#

yeah

wicked leaf
#

I mean I want it to trigger if the number IS zero

slim ferry
#

huh

wicked leaf
#

Otherwise you're gonna spend all run trying to trigger the card

slim ferry
wicked leaf
#

I want it to check that its the least played hand
unless its zero, in such case, it triggers regardless of it

slim ferry
#

so

daring fern
twilit tundra
#

isnt that just the equivalent of checking for the least played hand?

or do you not want to trigger it off of a tie for least played otherwise

#

since by definition hands played 0 times are tied for least played

wicked leaf
#

I do want it to trigger on tied cards yeah

#

but im not sure if it'll do it with this code

#

ill test it

twilit tundra
#

oh wait do you mean you aren't counting unplayed hands in this so if a hand has been played 1 time and theres unplayed hands its still fine?

wicked leaf
#

ok so basically hold on

daring fern
wicked leaf
#

yeah exactly

#

if the played hand is 0

#

level it up anyways

#

this is the card

wicked leaf