#💻・modding-dev

1 messages · Page 97 of 1

placid frigate
#

what more information do you need, the whole error message or my code?

gritty valley
gritty valley
#

Lemme see the calculate function for the broken joker

placid frigate
#
      if context.after and not context.blueprint then
      for index, card2 in ipairs(context.full_hand) do
        if card2:is_suit("Hearts") then
            Card:start_dissolve(card2)
            card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_mod
           end
        end
      end
      if context.joker_main and card.ability.extra.Xmult >= 1 then
        return {
        message = localize{type='variable',key='a_xmult',vars={card.ability.extra.Xmult}},
        X_mult_mod = card.ability.extra.Xmult,
        card = card
        }
      end
    end
}```
gritty valley
#

That might be the issue

placid frigate
#

let me try

gritty valley
#

it should be self.config.Xmult_mod

placid frigate
#

so self.config.Xmult_mod instead of card.ability.extra.Xmult_mod

gritty valley
#

Yes

placid frigate
gritty valley
#

Ok send me your full code

placid frigate
gritty valley
placid frigate
#

how should it be set up then?

gritty valley
placid frigate
gritty valley
#

No, the config field on your joker object is not formatted correctly. It should be like this ```lua
config = { Xmult = 1, Xmult_mod = 1 }

placid frigate
#

oh I see

#

why would you want to not use extra then

gritty valley
placid frigate
#

ok

wintry solar
#

Using extra is recommended

#

The game only copies specific values from the config table when it creates the joker, but it will copy the entire extra table always. Using the extra table will guarantee that your joker has the values you want it to have, and they can be accessed by card.ability.extra.key

gritty valley
#

Ah I didn't know that

placid frigate
#

me neither

#

so I should but { Xmult = 1, Xmult_mod = 1 } in the extra tabel

gritty valley
#

So yeah it should be config = { Xmult_mod = 1, extra = {Xmult = 1} }

placid frigate
#

why would the Xmult_mod = 1 not be part of the extra table?

gritty valley
#

As in it won't increase or decrease when the joker is in play

placid frigate
#

the base value wouldn't. I'm trying to have it where every Heart card played increases the Xmult by 1 then destroys the played heart cards (1xmult -> 2 heart cards are played -> 3x mult) almost like a mix between vampire or sixth sense

wintry solar
#

Just put them all in the extra table

#

It’s easier to remember that way and harder to screw up

gritty valley
zenith sage
#
for k, v in pairs(context.scoring_hand) do
                        print(k,v)
                    end

returns (when playing a pair)
1, nil, 2, nil
all cards are just nil all the time
what am i doing wrong

gritty valley
placid frigate
# gritty valley Send the calc func
    ---context.after is after the hand is scored
    ---not context.blueprint means this part cannot be copied by Blueprint
      if context.after and not context.blueprint then
      ---loops through every card in played hand
      for index, card2 in ipairs(context.full_hand) do
        ---check for hearts suit, card2 is the value in the current loop
        if card2:is_suit("Hearts") then
          ---destroy the card
            card2:start_dissolve()
            ---increment Xmult value by adding increase to the Xmult value
            card.ability.extra.Xmult = card.ability.extra.Xmult + self.config.Xmult_mod
           end
        end
      end```
#

do you also want the context?

gritty valley
#

Send the config field

placid frigate
#

config = { Xmult = 1, extra = {Xmult_mod = 1} },

#

just like we talked about before

gritty valley
#

That's mb

placid frigate
#

what's the difference between Xmult and Xmult_mod

gritty valley
wintry solar
#

Though I still don’t recommend not using the extra table, it should be card.ability.Xmult_mod

placid frigate
#

ok so the game stoped crashing but the mult isn't being added

#

it's giving the pop up saying it's mult

placid frigate
wintry solar
#

After the +

zenith sage
#

i think you might just need a joker_main context returning xmult = card.ability.Xmult

wintry solar
#

You need a message for the pop up text when you increase the mult, using card_eval_status_text or SMODS.eval_this

placid frigate
zenith sage
#

like

#

        if context.joker_main then
            return {
                Xmult_mod = card.ability.x_mult,
                message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.x_mult } }
            }
        end
wintry solar
placid frigate
#

config = { Xmult_mod = 1, extra = {Xmult_mod = 1} }

wintry solar
#

Generally, any values you need in your joker should be defined in the config table, and I’d recommend using the extra table within that so you can ensure they’re all copied over (like I said before, there are very specific keywords that will be copied over regardless). When you need to use them in your calculate function (or other functions, loc_vars in particular) you use card.ability.extra.blablabla

#

So when I’m creating scaling Xmult jokers, for example, I set config = {extra = {xmult = 1, gain = 0.25}} and then my scaling line would look like card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.gain. Using the extra table like this means that your joker has can set your variables to be named whatever you like, so you can be really specific with names in more advanced calculations

placid frigate
#

so the card.ability calls from config, .extra. calls from the extra table and the last part are the values you put in the tabele?

#

also note how how do you get the code parts to be the same line in discord mine keep making new lines

placid frigate
#

like this hopefully

#

ok thanks

#

ok, so I don't know what it is, but only when I do card.ability.extra.Xmult = card.ability.extra.Xmult + 1 does NOT not crash

#

but it's still not counting towards the X_mult (nor the t=chips I might add)

sage umbra
#

why is nil

teal estuary
#

isnt it card.ability.extra.X ?

nocturne garnet
nocturne garnet
#

for some reason x_mult is nil or something

teal estuary
earnest zealot
earnest zealot
#

Whoopsie

frosty dock
teal estuary
#

ooooh, cool

sage umbra
#

i ont know whats wrong

#

oh.

nocturne garnet
#

or whatever that number was

#

i forgot

pearl bane
#

is there any luaLS settings for a better modding experience (auto completion and such)? I'm using zed, so anything beyond LuaLS settings or at best a modified LuaLS binary is out of the question.

hidden timber
#
poll_question_text

Should I create a repo, where every mod for Balatro should be listed? So like an Index, which the Balatro Mod Manager could use.

Everybody would contribute to it by giving the meta-data for their mod and a thumbnail

victor_answer_votes

10

total_votes

12

victor_answer_id

1

victor_answer_text

Yes

maiden phoenix
#

Isnt an index already in the work?

tidal edge
#

wouldn't be allowed to be changed

nocturne garnet
#

oh damn

hardy viper
#

that poll made it get thought about again i guess

#

might start getting some attention once beta happens

undone sapphire
#

Does some of y’all created mods without much experience in coding ? Because I would like to create one but I wonder if it’s that difficult

teal estuary
#

i have no formal expirence in coding, in any capacity

undone sapphire
#

Oh okay !

pearl bane
#

Can a joker be spawned in a shop using debugplus?

nocturne garnet
zenith sage
#

wow yeah

#

beautiful

rough furnace
zealous glen
#

Is there documentation on how to use the RetriggerAPI?

arctic lion
#

which of these functions triggers first? obviously i only want to calculate the odds once, is there a priority to these things or is it simply based on which is higher in the code?
```lua
calc_dollar_bonus = function(self, card)
local rand = pseudorandom('JokerTest')
local pOdds = G.GAME.probabilities.normal / currentOdds
print(rand, pOdds)
end,

calculate = function(self, card, context)
    if context.end_of_round and not context.repetition and not context.individual and not context.blueprint then
local rand = pseudorandom('JokerTest')
local pOdds = G.GAME.probabilities.normal / currentOdds
print(rand, pOdds)
end

end

zealous glen
#

It's based on whatever order the game runs them in

arctic lion
#

yeah calculate would come before the screen comes up i suppose

jaunty fulcrum
#

whats the best way to figure out why im crashing all the time?

arctic lion
crisp coral
#

via the crash log

jaunty fulcrum
#

yes, I have that but my little brain doesnt understand the log

arctic lion
#

that's programming i'm afraid, logs are your best asset to root for a problem

#

you can show us but we can only take you so far

jaunty fulcrum
crisp coral
#

send the crash log here and someone might be able to help

arctic lion
#

it usually pinpoints the line or area the problem occurs

zealous glen
thick panther
#

How do you check when the game has ran through all joker abilities for a played poker hand, then execute code there before the scoring finishes?

arctic lion
#

has anyone tried dynamically changing the name/text of loc_txt yet? Or would it be easier/better to create another joker that replaces it based on if the conditions are met?

wintry solar
#

You can dynamically change them

arctic lion
nocturne garnet
#

naw prob not

rough furnace
#

no

arctic lion
#

yeah thought not kek

rough furnace
#

you can use variables if it's something simple

#

otherwise you need to make new keys and swap them

#

not sure the entire process

arctic lion
#

i think i can do something clever with loc_vars and just have it point to the same variable in there

tidal ice
#

not entirely sure what the issue is here, it has something to do with loc_vars not being able to read the config for one reason or another, it says the ability value is nil

(btw it doesnt currently reduce by 1 each hand, that is something I will add once I get this done)

#

its proably smth stupid lol

arctic lion
tidal ice
#

ah

mystic river
teal estuary
#

also, whats the lowest id a stone card can be? i found it once in the source code and never again, and it'd be easier to ask here 😭

rough furnace
#

-100 to -1000000

teal estuary
#

ty ty

zenith sage
#

im having an issue where every card is registering as nil and impossible to get info on
does anyone know why that might be

#

for example


                    for k, v in pairs(context.scoring_hand) do
                        print(k,v)
                    end

returns
1, nil, 2,nil, etc

rough furnace
#

how are you checking the print

zenith sage
#

lovely console

rough furnace
#

iirc lovely bug

zenith sage
#

ah

rough furnace
#

try print(k,tprint(v))

#

also DebugPlus's console doens't have the same bug

tidal ice
#

I basically just copied seltzer's code while editing a few things but I'm getting a crash that says something along the lines of a function needing to be a number rather than... whatever it is, it seemingly didnt give me a line where the issue is, I wish the log was saved as a text file or smth

as far as I can tell, there doesnt seem to be any syntax errors, I checked

#

for context this is a food joker that loses mult every hand

rough furnace
#

whats your config look like on your joker?

tidal ice
#
        mult = 10,
        mult_mod = 1
        }
    }
rough furnace
#

send crash

tidal ice
#

wait hang on I need to figure out where it is in the first place

zenith sage
#

mods/lovely

rough furnace
#

you can copy from the crash screen or Mods/lovely/logs

tidal ice
#

im gonna have to censor my name out of this, for some reason my user folder is my real fuckin name I need to change that

rough furnace
#

Not too sure but I think this is a you're returning something wrong in a certain context

tidal ice
#

ill see

spare nebula
#

Where can i learn to make mods?

tidal ice
#

ignore the `s

tidal ice
# spare nebula Where can i learn to make mods?

https://youtu.be/Zp-4U5TlbxY?si=cynb-VfZ89iOSI5E
this video helped me learn the basics, while looking in the base game's code and other mods helped me more

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
nocturne garnet
#

🤔

tidal ice
#

thats crazy

nocturne garnet
#

you should probably listen to the amalgam at the end....

tidal ice
#

oh yeah ive been meaning to check that out actually

wintry swallow
#

What does match_indent do exactly in patches?

rough furnace
#

makes it so when your patch is inserted it has indenting

nocturne garnet
#

it matches your indent you could say

wintry swallow
#

Ok but for the pattern I search (without regex) do I need to add the indent in the pattern string?

rough furnace
#

no

#

if your pattern matches line() then in this file

if 1 then
   if 2 then
       line()
   end
end

if match_indent is true, you get:

if 1 then
   if 2 then
       line()
       patch()
   end
end

otherwise you get

if 1 then
   if 2 then
       line()
patch()
   end
end
wintry swallow
#

Hmm weird why doesn't it find the line

rough furnace
#

is it erroring in the console?

wintry swallow
#

Oh actually, looks like steammooded has inserted something

rough furnace
#

yeah patch conflict could cause issues

wintry swallow
#

How do i figure out what the code looks like after steamodded has modified it?

rough furnace
#

look at the lovely dump

teal estuary
#

is the modifier that scales text {S:#}{}?

wintry swallow
#

Got it

#

That's easier than I thought

#

Though brittle as fuck 😄

nocturne garnet
teal estuary
nocturne garnet
#

minor misspelling mistake

#

code ruined

rough furnace
#

aren't the modifiers case insensitive?

nocturne garnet
#

i have no idea lmfao

teal estuary
#

also it feels weird if its s: for scale, but C: or X: for colouration

nocturne garnet
#

C:color, X: xmult shit

wintry swallow
#

Actually does LUA allow ternary operators inside an expression? Like does this work:
repetitions = 1 + (G.GAME.n_seal_repeats or 5)

teal estuary
#

S:# does work, using it rn

nocturne garnet
#

dang

#

didnt knwo

teal estuary
#

imagine

rough furnace
wintry swallow
#

Eh right not ternary but it's rtelative that I don't know the name of

rough furnace
#

it's a boolean operator

wintry swallow
#

Oh lol

#

Right

nocturne garnet
teal estuary
#

it is s:

#

thats.. annoying

nocturne garnet
#

i KNOW, RIGHT??

teal estuary
#

☹️

wintry swallow
#

Woo, lovely makes it possible to get Windows error message popups in Linux

frosty dock
rough furnace
#

thats just wine/proton

wintry swallow
rough furnace
#

depends on your definitojn of emulation

frosty dock
#

oh right, WINE is a recursive acronym for "WINE is not a emulator"

wintry swallow
#

I wonder if you could use patches to make R code look readable

arctic lion
#

has there ever been a joker that changes the type of a card whilst it's in your hand? a bit like how midas mask converts face cards into gold when scored, could you change the suit/rank of a card that isn't played?

#

i have no idea how i'd even start

rough furnace
#

yeah probably

frosty dock
#

surely

rough furnace
#

would take a look at how strength changes cards and then when midas mask runs and then jsut do it

wintry solar
#

I haven't done any jokers that do that (unless I have forgotten about them) but ortalab has just released zodiac cards that have a lot of hand interaction during scoring

arctic lion
#

i'll check it out

thick panther
#

How do you modify an existing joker's calculate method? I learned how to add a joker with a custom calculate method, but idk how to modify an existing one.

frosty dock
#
SMODS.Joker:take_ownership('j_joker', { -- replace with whatever key you need
  calculate = function(self, card, context)
  -- ...
  end,
})
#

add an additional argument of true at the end if you don't want the joker to get your mod badge

tidal ice
#

is there a thing such as context.after_scoring? I want this joker to do smth right after all the cards and jokers have scored, like how seltzer does

frosty dock
#

yes, it's called context.after though

thick panther
frosty dock
#

you dropped a ', but yes

thick panther
#

Okay, thank you

tidal ice
frosty dock
#

it's what seltzer uses

tidal ice
#

YES it works

#

idk what was up earlier

thick panther
#

Is there a way to calculate the mult based on the money the player has and display that in the loc_txt? GAME seems inaccessible in the config.

SMODS.Joker:take_ownership('j_greedy_joker', {

    loc_txt = {
        name = 'Greedy Joker',
        text = {
            'Multiplies {C:mult}mult{} based on how',
            'much {C:money}money{} you have. {C:money}$100{} = {X:mult,C:white}X1{}',
            'Current mult: {X:mult,C:white}X#1#{}'
        }
    },

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

    config = { extra = {
        Xmult = G.GAME.dollars / 100
    }},

    calculate = function(self, card, context)
        if context.joker_main then
            
            -- $100 = 1x mult. $80 = 0.8x mult.
            return {
                card = card,
                Xmult_mod = card.ability.extra.Xmult,
                message = 'X' .. card.ability.extra.Xmult,
                colour = G.C.MULT
            }
        end
    end

}, true)
rough furnace
#

config is ony set when your mod is first loaded

#

probably want to use update

#

see how bootsraps does it

pearl bane
#

is there a way to see the context of the joker being added to the deck?

#

(e.g. from a booster pack or bought)

rough furnace
#

not sure

#

maybe checking G.STATE

pearl bane
#

oh no I'm not doing calculate magickery

rough furnace
#

theres add_to_deck

#

if you just want to know whne it's aquored

#

oh wait

#

unless you mean deteitng when another joker is being added

wintry solar
#

what are you trying to do?

pearl bane
#

I want to set the money to 0 upon buying the joker

#

currently it sets it to -{joker value}

rough furnace
#

by buying the joker do you mean your joker or any joker

pearl bane
#

only when buying the modded joker

wintry solar
#

change the cost in set_ability

rough furnace
#

you can use add_to_deck to and remeber to chekc the from_debuff

pearl bane
#

again, it can be obtained from booster packs

rough furnace
#

also technically judgement

pearl bane
#

anything that gives jokers for free
tags, even

rough furnace
#

well tags just put them in the shop for you to buy

#

I would see what the state is

wintry solar
#

use set_ability to set the cost of the joker and then add_to_deck to set it back if it's screwing up the sell value

#

I'm pretty sure that would work

rough furnace
#

no I think they want t oset your money to 0 not the price

pearl bane
#

when does set_ability work?

rough furnace
#

when the joker is created iirc

pearl bane
rough furnace
#

if you did want it to always be free I think you can just put couponed = true in your config

pearl bane
#

at this point might as well do a lovely patch

#

it's $7 but I want it to take all remaining money

#

dollar buffer momento?

wintry solar
#

oh right

#

but it only takes money if you buy it?

pearl bane
#

yes

wintry solar
#

you can use context.buying_card

#

and then check that context.card == card

thick panther
#

Does take_ownership override all values of a Joker or only the ones you specify? For example, If I have calculate, and loc_txt in the take_ownership method, would that only override their respectful values?

pearl bane
pearl bane
wintry solar
#

no

#

just a calculate function

pearl bane
#

yeah that sounds about uncomplicated and more reasonable

rough furnace
#

looks like the game calls calcuate with buying_joker = true and your joker as the card when you buy it

#

just check if context.card == card and then its buyign you

pearl bane
#

funny how buying_card isn't even used in the main game

wintry solar
#

there are a few things like that where thunk just doesnt use them

pearl bane
wintry solar
#

here's another one

rough furnace
#

oh cool

pearl bane
#

wait why can't I see the problem

rough furnace
#

it's swapping mult and chips

pearl bane
#

wait

#

bruh so that was the swap eval type

rough furnace
#

silly knife idea, instatly destory any bought joker

pearl bane
#

scoped knife

wintry solar
#

there's also effects[ii].extra.func which executes a function you return, I don't think base game uses that either iirc

rough furnace
#

oh

#

would that be like making an instant event and doing your stuff?

#

also thers add_joker(id) which will create and add the given joker or consumable id which is technically unused

wintry solar
#

it sort of adds the event without using the event manager from what I remember

pearl bane
#

is there any docs on events?

rough furnace
#

It's used to debug spawn jokers and in some unused sandbox code

#

actually yes

wintry solar
#

oh snap I remember that

#

lets get it on the wiki

#

you happy for me to throw it on wilson?

pearl bane
#

ngl SMODS/Balatro is still fairly undocumented

rough furnace
rough furnace
#

theres a lot of balatr to document

#

and SMODS has only recently had most of it's api semi-stable

wintry solar
#

there we go

#

oh I have an edited UI one in my DMs too

rough furnace
#

The issue is everyone deep into modding baaltro is so used to reverse engineering baaltro's code, SMODS code is super easy to reverse engineer

pearl bane
#

I'm sorry btw I'm 3 days into modding or lua in general

wintry solar
#

buying_card is only from the shop iirc

tepid crow
rough furnace
#

free yes, booster I don't think so (try it and see)

pearl bane
#

ahhh
what to do then

#

ykw

worldly moss
#

how do I use add_to_deck in a deck?

frosty dock
#

I want to write up some docs, what do we need most?

worldly moss
#

like I want to add a joker to your deck on start

thick panther
#

Can loc_txt not be overrided in SMODS.Joker:take_owenership? It still defaults to the text in the localization scripts.

rough furnace
pearl bane
#

I think add_to_deck with some "flags" in config is actually better. but there's a problem of not knowing the price

rough furnace
#

like everyt function in it

worldly moss
#

this is what i've kinda thrown together in my thing

frosty dock
#

fair, we've been missing that

rough furnace
#

explain why to use it and what vanilla function it repalces

worldly moss
#

I literally just want it to add a showman with poly

tepid crow
rough furnace
#

shouldn't be (?)

frosty dock
#

it should work from what I remember

rough furnace
#

but I know how to force it to redo localization if nessicary

frosty dock
#

but using loc files is preferable anyways

wintry solar
tepid crow
#

All this unnecessary hate for localization files

rough furnace
wintry solar
#

loc files are bis

rough furnace
#

it's a shrimple as that

frosty dock
#

i won't stop you

rough furnace
#

I should switch soon

#

but for now it's easier for development

thick panther
frosty dock
#

if you're ever in a situation where you want to have localization in a mod, you won't want inline loc_txt anymore

worldly moss
#

how does taking ownership work??

rough furnace
#

see I'm more worried about getting art then localization

worldly moss
#

is it the same as it was in 0.9.8??

tepid crow
thick panther
rough furnace
frosty dock
rough furnace
#

uhh I thought the sidebar was auto populated tbh

rough furnace
#

oh also for docs the making a mod section should be removed from getting statted and be it's own page with a lot more detail

frosty dock
rough furnace
wintry solar
#

it's fancy

#

but I don't know, I'll add it back now

frosty dock
#

yeah it's just the metadata format

#

tbh we could make a full guide out of that

tepid crow
#

There is stuff missing from the custom sidebar (mostly the subheaders)

frosty dock
#

migration guide also went missing

#

but that's neither a real page nor a guide

wintry solar
#

if you haven't migrated by now you can dig through the old sidebar to find it imo

#

or maybe I can dump it ith the 0.9.8 stuff

#

or do we remove that too?

tepid crow
#

Is there any real reason for the 0.9.8 docs to still exist?

worldly moss
#

local c = G.P_CENTERS[j_ring_master] would this be the right way to get showman in a variable??

#

cause I know P_CENTERS is a table, so calling the key would work?

#

maybe>

#

?

frosty dock
#

G.P_CENTERS['j_ring_master'] almost

worldly moss
#

awww so close

frosty dock
#

needs to be a string

worldly moss
#

ah

#

I had thought since the key in the table wasn't a string it wouldn't be closed

frosty dock
#

else you're doing G.P_CENTERS[nil] most of the time which crashes the game

rough furnace
#

I think what you are looking for is SMODS.create_card

frosty dock
#

you can however do G.P_CENTERS.j_ring_master

rough furnace
#

Youre trying to give the user a card, right?

worldly moss
frosty dock
rough furnace
#

Centers are more like blueprints used to make cards

wintry solar
#

with the custom sidebar we can just leave them in the old sidebar

#

it's still accessible

frosty dock
rough furnace
frosty dock
#

arguably you just look at the code if you need that

rough furnace
#

And change the key to shoeman's

frosty dock
#

i think I'm in favor of just kicking it off the sidebar for now

worldly moss
rough furnace
#

That's the center not a card

worldly moss
#

ohh...

frosty dock
#

also i think we should get rid of the numbering of the page titles / file names

#

it's out of order with the new sidebar

rough furnace
#

Center is the information about how to make a card and card is the instance of the card in the game

rough furnace
wintry solar
#

it's an easy fix 😢

frosty dock
worldly moss
#

so this will about work?

rough furnace
#

I'm already home

frosty dock
#

fine

#

so am I

worldly moss
#

hooray!

frosty dock
#

I'd opt to leave the getting started page's name intact so the links don't break, the rest isn't as important

wintry solar
#

change them and I'll fix the links

#

do we just want the numbers removing?

rough furnace
frosty dock
#

changing the sidebar links isn't much of a concern, it might just be irritating for trying to use links posted in other places

wintry solar
#

oh that is true

#

duplicate the pages with new names balatrojoker

frosty dock
rough furnace
#

If were going to break links I say just break them and will fix them as they crop up

frosty dock
#

it's just that the getting started page has been refed a lot and is probably in a bunch of other places

#

though it just sends you to home so it's not hard to find the real page from there

#

fuck it we ball

rough furnace
#

TBH home could be the getting started page

frosty dock
#

good point

wintry solar
#

I wonder if the sidebar can have collapsible parts

frosty dock
#

cursed filename [Guide-‐-Joker-Calculation.md]

#

oh these are different -s

#

vscode displays them the same lmao

frosty dock
autumn coral
#

how do i get the rarity of a joker in G.Jokers.cards?

#

is it just G.Jokers.cards[i].rarity?

frosty dock
#

G.jokers.cards[i].config.center.rarity

autumn coral
#

thanks

frosty dock
#

1 is common, 2 is uncommon, 3 is rare, 4 is legendary

#

it's not guaranteed to be a number though, with custom rarities

autumn coral
#

yeah i know

#

i was just looking into it

#

my card rerolls all of the jokers in hand minus itself and i wanted it to keep rarity

#

pain in the ass tbh how thunk programmed it 😭

#

i had to make a huge if/else just to change it to 0.75 for uncommon and 0 for common 💀

#

because yes, create_card with 1,2,3,4 does nothing for whatever reason

wintry solar
#

rarity = (rarity == 4 and 4) or (rarity == 3 and 0.98) or (rarity == 2 and 0.75) or 0 this will change it for vanilla rarities

autumn coral
#

oh actually that's REALLY good

#

i'm fairly new to lua but that's so much more optimized

#

thanks

#

the 4 does nothing though unfortunately 😅

#

it has to have something set to true but that's alr

wintry solar
#

I don't know why I set it to 4 😆

rough furnace
#

4 is truethy

wintry solar
#

but I check later on if it is 4 for legendary stuff

autumn coral
#

it is but create_card needs to have the 3rd arg set to true to spawn a legendary and it ignores whatever the number is

#

this broke it actually

#

😭

#

wait nvm i'm just stupid

wintry solar
#

rarity == 4 as the arg is fine

autumn coral
#

yea ik

#

to my knowledge tho i still need the true statement tho iirc

#

pretty sure the arg is literally like _legendary or smf

#

coooool it works

#

i wanna keep working on the texturing for the nameplate, it kinda sucks ass lmfao

wintry solar
#

texturing the nameplate?

autumn coral
#

yeah

#

i'm working on that isaac mod

#

rn i'm on dice

#

i finished d20 yesterday, today was d4

#

also gonna try to do d6 today if i can

#

i think polyphemus will be legendary and have ^2 mult or smf

#

maybe i'll even make it exotic in tandem with cryptid or smf

velvet cargo
#

so why is the lovely mod flagged as a virus?

tepid crow
#

(ooh, nice job on moving the "Anti-virus setup" section to be first btw, whoever did that)

wintry solar
#

I wonder if we can get a chat bot in here to auto respond with that to messages that mention lovely and virus

rough furnace
#

Idk

tepid crow
#

the mods don't like bots haha

rough furnace
#

Meth should probably put the antivirus warking on the lovely downalod page

tepid crow
#

a bot that explained the cards by pulling from the wiki was suggested a couple times and denied

gaunt thistle
#

since it's been such a massive pain in the ass

#

you would think that it would become trusted given the amount of people downloading and using it

tepid crow
#

my anti-virus actually said something new last time

#

it just gave this pop-up every time I launched the game but it didn't stop/remove anything

#

(I had no exclusions on this folder/file - I did have tell win def to allow it to stop the notifications)

thick panther
#

How do you get that grey subtext for a joker? Is that just part of the text field in loc_txt?

teal estuary
#

C:inactive

weak depot
#

does anybody know why this isn't destroying cards in rank 3?

deck.apply = function(self)

    G.E_MANAGER:add_event(Event({

        func = function()

            for _, card in ipairs(G.playing_cards) do

                for _, rank in ipairs({2, 3, 4, 14}) do
                    if rank == card:get_id() then
                        card:remove()
                    end
                end
            
            end

            return true
        end}))
end
#

like this should be incredibly simple i'm so confused

gaunt thistle
#

I've figured out a fix and I would like you to test it when convenient

thick panther
#

When making the art for the back of a deck, do you setup the file the same as making joker art (71x95), or do you copy the whole enhancers.png file and add it there? If the latter, how do you make it work with other deck mods?

tepid crow
#

you do the same as what you do for joker art (make a new atlas .png that you load in)

weak depot
tepid crow
# weak depot any help?

Well it's a really weird way to set the function. Are you sure you're setting it before it gets called?

weak depot
#

i mean it's a function that's part of SMODS.Back

#

i'm confused, how would you write it?

tepid crow
#
SMODS.Back {
    key = "example",
    pos = {x = 0, y = 4},
    loc_txt = {
        name = "Example Deck",
        text = { "Text" }
    },
    apply = function(self)
        ...
    end
}
weak depot
#

yeah

#

it's in there

#

it's just a way of me divvying them into separate files

tepid crow
#

pause

#

the Back definition and the apply definition are in separate files?

weak depot
#

so this is the load file's code to load the actual thing:

for _, v in ipairs(decks_to_load) do

    --load file and call it deck_loaded for this purpose so we can modify the deck and take from it instead of just its name like with deck_name
    local deck_loaded = SMODS.load_file("source/decks/" .. v .. ".lua")()
    
    --throw an error and instead of crashing the game like an angry toddler if the deck isn't found
    if not deck_loaded then
        sendErrorMessage("Error loading file " .. v .. ".lua", "Shellular's Deck of Cards")

    else
        --set "universal" info for every deck here so i don't have to write "atlas = 'deck_atlas'" 1 quadrillion times
        deck_loaded.key = v
        deck_loaded.atlas = "deck_atlas"
        deck_loaded.unlocked = true
        deck_loaded.discovered = true

        if not deck_loaded.pos then
            deck_loaded.pos = { x = 0, y = 0 }
        end
        
        local deck_obj = SMODS.Back(deck_loaded)

        --i'm a little stupid  & don't totally know what this means but it's basically going "for each function in the file, pull function and add it to deck_obj"
        for k_, v_ in pairs(deck_loaded) do
            if type(v_) == 'function' then
                deck_obj[k_] = deck_loaded[k_]
            end
        end

        --you did it *party.wav*
        sendInfoMessage("Loaded " .. v .. " deck successfully", "Shellular's Deck of Cards")
    end
end
#

and this is the file for the deck in question's code:

local deck = {
    name = "Harlequin Deck",
    pos = { x = 7, y = 0 },
    loc_txt = {
        name = "Harlequin Deck",
        text = {
            "Start run with no",
            "{C:attention}Aces{}, {C:attention}2s{}, {C:attention}3s{}, and {C:attention}4s{}",
            "in your deck"
        },
    },
    config = {},
}

deck.apply = function(self)

    G.E_MANAGER:add_event(Event({

        func = function()

            for _, card in ipairs(G.playing_cards) do

                for _, rank in pairs({2, 3, 4, 14}) do
                    if rank == card:get_id() then
                        card:remove()
                    end
                end
            
            end

            return true
        end}))
end

return deck
thick panther
#

How do you add a custom joker at start in a custom deck? Do you use the joker's key?

local greed_joker = create_card('j_greed', G.Jokers, nil, nil, nil, nil)
                greed_joker:add_to_deck()
                G.jokers:emplace(greed_joker)
tepid crow
weak depot
#

i'm still really confused on why it doesn't destroy threes

tepid crow
wintry solar
#

You can add keys in the config to start with them too

weak depot
tepid crow
#

(I can replicate btw. That was very confusing for a sec haha)

weak depot
weak depot
tepid crow
#

no worries, it's a common trap haha

#

just iterate using index

tidal ice
#

how would I get my mod to load extra lua files in a folder in the game's directory, it doesnt seem like they do so automatically

tepid crow
#

assert(SMODS.load_file("path/to/file.lua"))() I believe

thick panther
#

How do you set the rarity of a joker? I want to set one to rare (From looking at the source, I think thats an int at 2?)

frosty dock
#

rare is 3

thick panther
#

My joker multiplies mult by how much money you have. However, its value is based on how much you have before you play your hand. So, if you play a gold seal card, the joker's mult will not reflect that when it triggers. How do I ensure that it does update correctly? Should I just use Xmult instead of the local mult?

update = function(self, card, dt)
        -- Calculate the multiplier
        card.ability.extra.Xmult = G.GAME.dollars / 100

    end,

    calculate = function(self, card, context)
        if context.joker_main then
            
            -- $100 = 1x mult. $80 = 0.8x mult.
            local mult = G.GAME.dollars / 100

            return {
                card = card,
                Xmult_mod = mult,
                message = 'X' .. card.ability.extra.Xmult,
                colour = G.C.MULT
            }
        end
    end,
earnest zealot
#

I don’t rember the specific name

frosty dock
#

G.GAME.dollar_buffer

thick panther
#

I assume its G.GAME.dollar_buffer? Would I use that in place of G.GAME.dollars in my equation?

frosty dock
#

no, you add it

#

(G.GAME.dollars + (G.GAME.dollar_buffer or 0)) / 100

thick panther
#

okay, thank you!

frosty dock
#

also you don't need the update function if you recalculate in loc_vars, there's no need to do it every frame

thick panther
#

I have it display in the text field of the Joker (Like how Joker Stensil displays the num of empty joker slots).

frosty dock
#

yeah i figured

hot drift
#

idk what im doing but this crashes when I try to open balatro with it

frosty dock
#

yes jestie, that is not proper syntax

exotic hedge
#

Do you think one would be fine with a spectral like this? I feel like It lacks a lot of detail that other spectrals have. This is my first time spriting, so I just want to know if it would be good enough to seem vanilla-ish

#

(Also would this be considered mod development? Since this is for a mod I'm making)

tidal ice
#

my joker works perfectly (yay!!!) but the only issue is that the description is incorrect, it displays the current xMult where the amount increased should be

#

and idk why that is

frosty dock
#

it could use some more depth

exotic hedge
#

forgive me for it being kinda ass since this is my first time lol

frosty dock
#

i could see the card looking like it's rotated a bit about that middle line

exotic hedge
#

like it's being warped?

#

or the entire card

thick panther
#

How do you get the on hover effect with the description of something based on what is specified on a deck's (or even joker's) text field? For example, T:m_gold shows the description for a Gold Card. How could I do that for a modded joker?

text = {
            'Start with {C:money}$100{},',
            'Deck of {C:attention,T:m_gold}Double Gold{} cards.',
            'Start with the {C:red, T:j_gree_greed}Greed Joker{}.'
        },
frosty dock
#

say you take that inner card and rotated it so one side faces more towards you

autumn coral
#

how do i create a sync table that replaces any of the game's specified songs by default with mine btw

#

the wiki is NOT specific

frosty dock
#

dunno just an idea, I'm not an artist

exotic hedge
frosty dock
#

sort of, though I was thinking of rotating about the vertical axis

autumn coral
#

oh nvm

autumn coral
#

is create_replace_sound called by SMODS.Sound:create_replace_sound or is it standalone?

frosty dock
autumn coral
#

how would that look /gen

frosty dock
# exotic hedge like this, right?

yeah, but in a different direction. here the bottom side is rotated towards you, I'm thinking rotate about the vertical axis (where the sides flip) so the left or right side is closer

frosty dock
autumn coral
#

nbm i figured it out

#

thx

frosty dock
#

{s:1.2}

autumn coral
#

does the name have to have the prefix i'm assuming?

#

the key*

frosty dock
#

or {s:whatever_number}

frosty dock
autumn coral
#

gotcha

#

wait what

#

oh

#

in the filename or in the key name

frosty dock
#

key

autumn coral
#

does it matter if i add an underscore after music

frosty dock
#

no, it just has to contain it as a substring

exotic hedge
frosty dock
#

i have a hard time seeing which way this is supposed to be rotated, but yes

#

might just be because it's out of context

exotic hedge
#

yeah i just did that really quick to see if that was what you were talking abt lol

autumn coral
#

ok so like where is there latency on my sync tracks 💀

thick panther
#

When making multiple decks, should you use just one atlas and lay the back images out next to eachother or should you use multiple atlases, with each back its own seperate file?

exotic hedge
#

@frosty dock tysm I havent warped the graphics yet but it looks SO good already

autumn coral
exotic hedge
#

now idk how to warp the graphics 😭 🙏

autumn coral
#

istg there was no delay in rx11

orchid thunder
#

what did i do wrong the local vars dont update correctly

exotic hedge
#

how would one warp the graphics on this so it looks like it's in it's correct orientation? I have no idea how to lol

#

I can imagine it but I can't do it

tidal ice
arctic lion
tidal ice
#

oop gimme a sec

#

WAIT

arctic lion
#

they're both the same

tidal ice
#

YEAH I JUST REALIZED I'm stupid lol

#

lowkey embarassing

thick panther
#

How would I debuff all suits except a specified one? I assume I would use trigger_effect in SMODS.Back as the base, but what would the if-statement look like?

tidal ice
#

where can I find documentation about how deck code works in steammodded's current version

hardy viper
#

on the smods github wiki

tidal ice
#

there only seems to be outdated documentation

hardy viper
#

?

tidal ice
balmy stump
# hardy viper ?

yeah out of the three paragraphs of create a deck, all of them are outdated.

hardy viper
#

its in SMODS.Center with the rest of the center-related things

tidal ice
#

oh

hardy viper
#

if you dont want to find outdated stuff dont look at the outdated sections

tidal ice
#

ok yeah i didnt know the center area had stuff about decks

hardy viper
#

understandable but like
maybe look first

#

and ask later

#

asking is fine though

tidal ice
#

yeah sorry

tepid crow
#

would it be a positive or a negative to separate out the centers into their own pages? 🤔

karmic kelp
#

I also wonder if it'd be beneficial to have like a page 0 that defines key terms, like what a center even is
I vaguely know from skimming this chat, but if those pages are meant to be of use to a newcomer

tepid crow
#

On that same note, can somebody please put in the docs how original_key transforms into key?
It's confusing and to understand it you need to either read steamodded's internal code or ask in #💻・modding-dev
Just being able to link to the explanation would be nice instead of having to go through the whole spiel of having to explain wtf type and mod prefixes are

humble gale
#

quick question, do custom info queues need to be in a localization file to be used?

#

cause i have one that is set to a table with name and text and im getting an info queue that says error

elder vapor
#

afaik yeah

balmy stump
#

im trying to make a deck that increases the maximum joker slots by one everytime a joker is added to hand and vice versa, but im having a hard time figuring out some of this stuff. like how can i alter joker slots, using add to hand

#

ive tried looking for refrences but i just cant find anything similar enough that i can use for this

cold peak
#

Negative jokers just modify G.jokers.config.card_limit like so

if not self.edition then
    self.edition = {}
    if self.added_to_deck then --Need to override if adding negative to an existing joker
        if self.ability.consumeable then
            G.consumeables.config.card_limit = G.consumeables.config.card_limit + 1
        else
            G.jokers.config.card_limit = G.jokers.config.card_limit + 1
        end
    end
end
self.edition.negative = true
self.edition.type = 'negative'

this is in Card:set_edition so you could probably add this code to the add/remove function

balmy stump
#

au tysm

spare nebula
#

Is it possible to get the source code on mac?

balmy stump
#

yes, by switching to windows like any sane person

spare nebula
balmy stump
#

same

remote shell
tidal ice
#

sorry for asking so many questions but I don't know whats going on here

tidal ice
tidal ice
#

ah that makes sense

crisp coral
#

and also you need to specify more contexts in context.cardarea == G.jokers

#

move the context.joker_main up to that check

balmy stump
# cold peak Negative jokers just modify `G.jokers.config.card_limit` like so ```lua if not s...

`local cardaddtodeck = Card.add_to_deck
function Card.add_to_deck(self,edition)
cardaddtodeck(self, edition)
if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
end

local removefromdeck = Card.remove_from_deck
function Card.remove_from_deck(self)
    removefromdeck(self)
        G.jokers.config.card_limit = G.jokers.config.card_limit + 1
    end`
#

can you tell me what i did wrong here?

#

the game runs but this doesnt do anything

tidal ice
cold peak
balmy stump
#

this is the full thing, the first part is working put the second part isnt doing anything as in i can play the deck put none of the code works.

`
SMODS.Back{
name = "Infinite Jokers",
key = "infD",
pos = {x = 0, y = 3},
config = {joker_slot = -4}
loc_txt = {
name = "Infinite Jokers"
text = {
"Start With Infinite Joker Slots."
},

},
local cardaddtodeck = Card.add_to_deck
function Card.add_to_deck(self,edition)
    cardaddtodeck(self, edition)
    if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
        G.jokers.config.card_limit = G.jokers.config.card_limit + 1
    end
end

local removefromdeck = Card.remove_from_deck
function Card.remove_from_deck(self)
    removefromdeck(self)
        G.jokers.config.card_limit = G.jokers.config.card_limit - 1
    end

}
`

cold peak
#

uhhh maybe because this is all inside SMODS.Back? It looks like your indentation is all off but that could be from discord formatting weird. Can you try putting 3 ` around your whole code, that'll make it a whole code block instead of each line being individual

#

You can even do ```lua to get code highlighting

balmy stump
#
SMODS.Back{
    name = "Infinite Jokers",
    key = "infD",
    pos = {x = 0, y = 3},
    config = {joker_slot = -4}
    loc_txt = {
        name = "Infinite Jokers"
        text = {
            "Start With Infinite Joker Slots."
        },
        
    },
    local cardaddtodeck = Card.add_to_deck
    function Card.add_to_deck(self,edition)
        cardaddtodeck(self, edition)
        if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
            G.jokers.config.card_limit = G.jokers.config.card_limit + 1
        end
    end

    local removefromdeck = Card.remove_from_deck
    function Card.remove_from_deck(self)
        removefromdeck(self)
            G.jokers.config.card_limit = G.jokers.config.card_limit - 1
        end
}
#

i didnt know putting everything into smodsback would be a problem kind of my first deck

#

if i move the final closing bracket to before the code starts it will work then?

cold peak
#

Yeah I don't think it goes in there, I think that will just be used to register deck to the game with its name and description and whatnot

#

The actual code will have to register whether or not you're playing with that deck

#

One sec

#

I'm thinking its going to be like the anaglyph deck

#

But I've never actually done this so if someone else has more insight that might be more useful

humble gale
#

So i have info_queuse on my one joker and only the name in the box appears, not the text.
This is how the record in en-us.lua looks like

default = {
            name = "Boss Soul",
            text = {
                "Defeat a Boss to gain a {C:legendary}Boss Soul{}"
            }
        },

and below is being called in local vars of the joker

OSIRIS.GENERATE_OSIRIS_INFO_QUEUE_BOSS = function(self,bossName,info_queue)
    local _boss
    if bossName == "" then
        _boss = OSIRIS.BOSS_TEXT_TABLE['Def']['Key']
    else
        _boss = OSIRIS.BOSS_TEXT_TABLE[bossName]['Key']
    end
    info_queue[#info_queue+1] = {set = 'OsirisInfoQueuesBoss',key = _boss}
end
#

in this case key is "default"

cold peak
# cold peak I'm thinking its going to be like the anaglyph deck

I can't find how anaglyph does its thing, but one way you might be able to get it to work is by checking in the add/remove methods what back is currently in use and then running your code if its yours, but this seems..inefficient? You might be able to find more info on adding new decks by exploring some githubs of other mods that do so

humble gale
balmy stump
#

config = {joker_slot = #G.jokers.cards+1} Like this?

hardy viper
balmy stump
#

thats not cool

hardy viper
#

i feel like it's a little misleading if it's not like that

balmy stump
#

finite joker deck

hardy viper
#

people might start a run with the deck and see the joker slots be normal and get confused

#

tbh that could be cool

#

+1 joker slots, joker slots can never change

#

it'd be bad

#

but cool

zenith sage
#

if one wanted to get / compare the editions of all played cards in a hand, what would that look like
this is what ive been trying so far, and thought because of a bug with lovely both return nil, it does successfully tell me that one does and one does not when i play a hand where that is true

if context.before then
  if next(context.poker_hands['Pair']) then
      local edition_one
      local edition_two
      for k, v in pairs(context.scoring_hand) do
          if v.edition then
              if edition_one then
                  edition_two = v.edition
              else
                  edition_one = v.edition
              end
          end
          print(edition_one)
          print(edition_two)
      end
  end

however when using edition_type it no longer works?

humble gale
tidal ice
#

yes those placeholders are from cryptid

zenith sage
#

descriptions?

balmy stump
#

kinda expected it ngl

humble gale
#

Same but worth a shot

tidal ice
zenith sage
#

oh true

exotic hedge
#

I finished the sprite today, do you guys like it?

#

lobster

zenith sage
#

lobster!!

zenith sage
#

where at least v.edition returns the correct boolean

#

so in

if not edition_one or not edition_two then
    if edition_one == edition_two then
        -- neither
        print("Neither")
    else
        -- one has an edition
        print("One",edition_one)
    end
    -- at least one parent has no edition (mixed or neither)
else
    -- both have editions (different or same)
    if edition_one == edition_two then
        -- same editions
        print("Same",edition_one)
    else 
        -- different editions
        print("Different",edition_one,edition_two)
    end
end

these guard cases, using v.edition will correctly give me "One" because one is nil (not true) and true ~= nil

#

but with v.edition_type it gives me neither because it sets both as nil even though it knows one has an edition and therefore nil == nil

#

most likely theres a better way to do this altogether, preferably without using an iterator

balmy stump
weak depot
#

does anyone have an overlay for the stake shading?

balmy stump
#

what context guide?

nocturne garnet
wintry solar
#

Don’t link that one

nocturne garnet
#

wgar

#

why not

nocturne garnet
#

ooooooooooooooooooo

wintry solar
#

Because divvy rewrote it so it’s actually readable

nocturne garnet
#

thanks divvy

zealous glen
#

I also thought the original Discord messages were fine

tepid crow
#

Tbf the original discord messages didnt really explain that much

#

It just info dumped the context properties

hardy viper
wintry solar
#

Yeah I don’t find the simulator code easy to read either but I already understand all the contexts so I’m probably not the best judge of it

#

I can add the new guide to the discord post though

tepid crow
#

Oh yeah that's probably a good idea

stuck hawk
#

Hey there, first time modder and awfully inexperienced coder heregolden_joker I'm trying to make a simple Joker that creates a Devil Tarot card when a Round starts, haven't been able to find a way for now. Is that something feasible to do with modding?

tepid crow
#

If it can be described as a combination of different base game jokers it should be relatively easy to do

stuck hawk
#

Yeah, I was trying to modify the behavior of the Cartomancer joker basically

#
                G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
                G.E_MANAGER:add_event(Event({
                    func = (function()
                        G.E_MANAGER:add_event(Event({
                            func = function() 
                                local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil, nil, 'car')
                                card:add_to_deck()
                                G.consumeables:emplace(card)
                                G.GAME.consumeable_buffer = 0
                                return true
                            end}))   
                            card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('k_plus_tarot'), colour = G.C.PURPLE})                       
                        return true
                    end)}))
            end```
#

except that instead of picking random Tarots, it should pick a Devil card. Should be something related to the 'car' tag in the function if I got it right

tepid crow
#

Pretty close

#

The 'car' refers to the seed though

tepid crow
#

You might want to take a look at SMODS.create_card, and the key you want is c_devil I think? Can't check right now

nocturne garnet
#

oh man i fucking hate ui code

#

i would rather die than do it

#

but god

#

it is

#

so fucking annoyin

hardy viper
#

@wintry solar do UIs allow infinitely recursive backwards references

#

i would imagine not?

wintry solar
#

🤷‍♂️

hardy viper
#

darn

#

was hoping youd know

wintry solar
#

what is it you're trying to do?

mystic river
# spare nebula bro im broke

linux also works and is free
though I'm not clear on whether the great apple overlords will let you install it on their hardware

hardy viper
# wintry solar what is it you're trying to do?

very unseriously attempting to create an SMODS ui library (which acts as an overhead for vanilla UI)
specifically in this instance i want to, for every single node in a UI, coerce it to an object with an smods overhead object

#

so i would need to recursively go through the ui nodes, and i would love to be able to do that with unlimited depth

frosty dock
hardy viper
#

and by unseriously i mean i dont plan on going through with it unless its actually useful

frosty dock
#

it's not obfuscated or compiled or anything

nocturne garnet
tidal edge
nocturne garnet
#

page with presets

tidal edge
#

oh ok

tidal ice
#

I honestly don't know what to do for the background, any suggestions for things I could use as inspiration?

mystic river
#

hmm, what's another optical illusion that can tile ThinkRingo

nocturne garnet
#

that escher big thingy would be cool

tidal ice
#

true

nocturne garnet
#

it'd probably be a paint to draw tho 😭

tidal ice
#

I think I'm just gonna draw walls and doors in wacky orientations like this

humble gale
#

On my on joker i keep getting an error on end of round that says 'for limit must be a number' on line 211 of state events
the only weird thing im doing in the code is calling a function from another file and the context of said function is before so idk

calculate = function (self,card,context)
        if card.ability.extra.boss ~= "" then
            return{
                message = OSIRIS.BOSS_TEXT_TABLE[card.ability.extra.boss].func(self,card,context)
            }
        end

        if context.end_of_round and not context.game_over and not context.repetition and G.GAME.blind.boss and not context.blueprint and not card.ability.extra.abilityStopper then
            card.ability.extra.boss = "The Ox" --for testing, can change later on
            card.ability.extra.abilityStopper = true
            return {
                message = "Stolen!",
                card = card
            }
        end
    end
white forum
# mystic river hmm, what's another optical illusion that can tile <:ThinkRingo:7544537763829514...

first ever message in this server only to recommend this one: https://en.wikipedia.org/wiki/Sky_and_Water_I

Sky and Water I is a woodcut print by the Dutch artist M. C. Escher first printed in June 1938. The basis of this print is a regular division of the plane consisting of birds and fish. Both prints have the horizontal series of these elements—fitting into each other like the pieces of a jigsaw puzzle—in the middle, transitional portion of the pr...

tepid crow
humble gale
#

I have a check for not context.repition in the if statment

wintry solar
#

It’s the first bit

#

It’ll trigger in every single context

tepid crow
#

Yeah the first one

tidal ice
#

I think I'm fine with this for now but I may change the colors of the bg

frosty dock
#

guys

#

what percentage of people do you think will miss this

arctic lion
#

has anyone dabbled in config files, particularly ones you can edit in-game (like with debugplus)?

gaunt thistle
arctic lion
#

i can't find documentation for creating config files specifically and my very crude config file can't be edited at runtime and isn't very user friendly

tepid crow
#

The Steamodded wiki has a page on it

frosty dock
frosty dock
arctic lion
#

ah twas hiding from me thank

#

truly a skill issue at navigating wikis and documentation

frosty dock
#

counting it as a win if 2.5x more people can read because of it

tepid crow
#

That's 5% of the community WOOOO

nocturne garnet
frosty dock
#

... what

#

that looks atrociously cramped

tepid crow
#

Looks fine to me /s

arctic lion
#

padding is afraid of him

balmy stump
#

what is calculate_joker and how do i use it?

hardy viper
#

what are u trying to do

#

because calculate_joker just, handles joker calculations for all cards

#

it doesn't have a usecase for typical things

balmy stump
#

remember the thing i was trying to do yesterday

#

that

hardy viper
#

i have no memory of this

hardy viper
#

yeah i dont think calculate_joker would be any help there

balmy stump
#

yeah im just trying anything

hardy viper
#
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
 if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
  G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
 end
 oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
#

should work

balmy stump
#

so i can feel like i got something out of wasting 8 hours trying to do this can you atleast explain what love.update and oldupd(dt) is since i havent heard of either until now

hardy viper
#

ok i may or may not have msesed that up

#

hang on let me

#

comment

tepid crow
#

how often does that function run? is that every frame?

#

cuz that seems... excessive

hardy viper
#

well yeah lol

#

we dont care about optimization here do we

#

and its like, barely anything so

#

wont make a dent

tepid crow
#

I mean no it won't have a real impact but

#

just feels inelegant

arctic lion
#

step 1. get it working
step 2. say you'll optimise it
step 3. never do

hardy viper
# tepid crow just feels inelegant

the alternative is hooking multiple functions for removing a joker, removing a joker from an area, creating a joker, moving a joker to an area, etc

#

you only need a couple of those but i wouldnt know which youd need to hook

tepid crow
#

would setting the joker slots to math.inf or whatever the lua equivalent is work? 🤔

balmy stump
#

do i put the code inside the smods.back {} or do i make a new lua file or what

hardy viper
hardy viper
#
SMODS.Back{
...
}

--code
balmy stump
#

ok i did that and this doesnt do anything

hardy viper
#

elaborate ?

balmy stump
#

loads the deck deck does nothing.

hardy viper
#

can u post the entire lua file

balmy stump
#
SMODS.Back{
    key = "infD",
    config = {joker_slot = -4},
    loc_txt = {
        name = "Infinite Jokers",
        text = {
            "Start With Infinite Joker Slots.",
        },
    },
}
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
 if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
  G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
 end
 oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
hardy viper
#

ah you removed the name

balmy stump
#

maybe because i didnt put an extra name

hardy viper
#
SMODS.Back{
    key = "infD",
    name = "Infinite Jokers",
    config = {joker_slot = -4},
    loc_txt = {
        name = "Infinite Jokers",
        text = {
            "Start With Infinite Joker Slots.",
        },
    },
}
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
 if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
  G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
 end
 oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
nocturne garnet
#

i finally did it chat

#

Disable Disable Vanilla Jokers 😭

hardy viper
#

have you considered making the buttons not right on top of each other

#

you could for sure fit like, 10 of those per page

#

if they werent so large

frosty dock
nocturne garnet
#

Enable Disable Vanilla Jokers

balmy stump
#

ok it works, im gonna see if i can make it do everything i want using this as a refrence

thick panther
#

Is there a wiki for the Balatro APIs? I know about the steamodded wiki, but is there one that focuses on the game's source?

hardy viper
#

haha i wish

tepid crow
#

game is basically undocumented apart from steamodded's own docs

thick panther
#

ah okay.

hardy viper
#

its more fun this way

teal estuary
#

documentation? for modding uses? well i never

#

who would ask for such a thing?

tepid crow
#

if you're lucky Thunk added a comment

teal estuary
#

smh

frosty dock
#

you're lucky there isn't some eloborate decompilation process you need to go through to get to the source code

#

smh

mellow sable
#

no joke, there was only one github repository that worked to decompile the source code

#

because it used a specific version of LuaJIT

nocturne garnet
balmy stump
#
local addjokerslot = Card.add_to_deck
function Card.add_to_deck()
  if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
    G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
  end
  addjokerslot()
end

Whenever i buy a card the game crashes.

frosty dock
#

but i did have the highest glitched score

#

that wasn't actually 0.9.0

#

0.9.3 iirc

tidal ice
#

anything wrong here? no crashes or anything its just not retriggering any cards

#

oh wait do I need to do context.repetition? lemme try that

#

that didnt work

teal estuary
#

iirc its repetitions = repetitions, lemme double check

#

also, card = card

tidal ice
#

right

teal estuary
#

heres one of my jokers that retriggers certain suits, so just ignore that one line

#

ah, reptitions = card.ability.extra.reptitions... maybe you could do repetitions = 1 then?

#

im not sure, i'd just use card.ability.extra...

tidal ice
#

alrighty ill try that

thick panther
#

How can you get a joker to debuff an entire suit like some of the blinds do?

tidal ice
#

I think its an issue with the chances

#

I need to check this actually

#

ok so its NOT an issue with the chances

hardy viper
# balmy stump ```lua local addjokerslot = Card.add_to_deck function Card.add_to_deck() if G...
local addjokerslot = Card.add_to_deck
function Card.add_to_deck(self, ...)
  if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
    G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
  end
  addjokerslot(self, ...)
end
#

alternatively ```lua
local addjokerslot = Card.add_to_deck
function Card:add_to_deck(...)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
addjokerslot(self, ...)
end

thick panther
#

Okay, I got the debuff part working, but is there a way to have it show the debuffs when a round starts, similar to some blinds? I figured I would move part of it to the deck code, but what do I use to check if a round has started?

calculate = function(self, card, context)

        for _, card in ipairs(G.playing_cards) do
            if card.base.suit ~= 'Hearts' then
                SMODS.debuff_card(card, true, 'testJoker')
            end
        end

    end,
tidal ice
#

still having issues
again, no crashes, its just not retriggering any cards
I temporarily commented out the chance's code just in case there was a problem with it

wintry solar
#

Are you working with a new instance of the joker or loading an old save?

tidal ice
#

loading an old save

#

is that acgtually the issue??

wintry solar
#

Probably

#

Try creating a new instance of your joker

#

The old save probably doesn’t have the repetitions in the config

tidal ice
#

ill check

#

ok so that may have actually been the problem

#

thats actually kinda funny

rough furnace
#

yeah if you change config old saves don't

#

this also means if thunk adjust values in an update old save jokers will have old values still

#

for most jokers

balmy stump
#

the simplest solution is just to only activate the code when a joker is added to the deck, how do i specify for that

thick panther
#

Is there a way to set text size and color? {C:inactive, s:0.8} colors the text gray, but doesnt resize.

rough furnace
hardy viper
hardy viper
rough furnace
#

Wait ehats going on?

balmy stump
rough furnace
#

You want a deck where you always have more joker slots?

balmy stump
#

since the game would crash long before ever reaching that number its technically infinite

hardy viper
rough furnace
#

Just use the update function to set the joker slot limit to 1 plus the number of jokers

hardy viper
#

you've been clear you don't want to do that

rough furnace
#

Why are we overriding global functions for this?

hardy viper
#

we did this

balmy stump
#

yeah okay ill just do that then, ill credit you since i didnt even write any of the code for it 😦

hardy viper
#

you don't need to credit me

#

my soul is licensed under gpl v3

thick panther
#

When I play a hand of hearts, this joker is suppose to increment its own mult by 5 per heart card played, but its getting up into the thousands, with numbers like 6,200. Is the issue how I am incrementing the mult?

calculate = function(self, card, context)

        for _, pCard in ipairs(G.playing_cards) do

            -- Debuff all non-Heart cards, except for Stone Cards
            if pCard.base.suit ~= 'Hearts' and pCard.ability.effect ~= 'Stone Card' then
                SMODS.debuff_card(pCard, true, 'lJoker')
            end

            -- Increment mult for each played Heart card
            if pCard.base.suit == 'Hearts' then
                card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.multAdd
            end

        end

        -- Add mult
        if context.joker_main then
            return {
                card = card,
                mult_mod = card.ability.extra.mult,
                message = '+' .. card.ability.extra.mult,
                colour = G.C.MULT
            }
        end

    end,
wintry solar
#

Your iterating part has no context check so runs for every single context

thick panther
#

So should the whole for loop be wrapped in context.joker_main or the inside of the for loop?

wintry solar
#

You could but there are better ways to do it, look at the joker calculation guide

balmy stump
#

attempted to index jokers a nil value

hardy viper
#

oh oops

#
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
 if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" and G.jokers then --if theres a game in progress, a deck, and the deck is the infinite joker deck
  G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
 end
 oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
balmy stump
hardy viper
#

odd

#

ill check it out when i get home

tidal ice
#

Speedrunner

arctic lion
#

how can you tell which specific pack has been opened? i can see G.booster_pack for any and G.booster_pack_meteor for celestials but i don't see any kind of variable for buffoon, spectral, cards, arcana etc.

frosty dock
#

SMODS.OPENED_BOOSTER should have the booster card

thick panther
#

Blueprint and Brainstorm label my joker as incompatible, yet they still trigger. is there a flag that needs to be enabled for them to show compatible?

thick panther
frosty dock
#

that one you can only do in the code of your calculate function

#

if not context.blueprint then

thick panther
#

Is there a way to prevent a joker from being sold at the shop, like the legendaries?

frosty dock
#

yes, it's best to use an in_pool function for that

brisk quartz
thick panther
frosty dock
#

you set it to a function that returns false

#

though it also won't spawn in the shop if you give it legendary rarity

thick panther
frosty dock
#

yes, unless in_pool is returning false

thick panther
#

Okay, thank you! Do you know if theres a way to have colored text but also change its size? I tried {C:inactive, s:0.8}, but it only changes the color, not the text size.

frosty dock
#

i think you just need to remove the space

#

{C:inactive,s:0.8} should work

hardy viper
#

inactive inherently changes text size iirc?

frosty dock
#

don't think so

hardy viper
#

oh wait that's just a color

#

been awhile since ive done text stuff lol

thick panther
frosty dock
#

the parser just doesn't understand that

tidal ice
balmy stump
# hardy viper oh wait that's just a color

using my method of changing add_to_card instead of updating every tick doesnt crash the game on the second run but when i try to add in more functions it crashes saying function arguments expected near function

hardy viper
tidal ice
#

oh right

balmy stump
#

how do i make multiple functions

#
    key = "infD3",
    name = "Mrk3",
    config = {joker_slot = -4},
    loc_txt = {
        name = "Infinite Jokers3",
        text = {
            "Start With Infinite Joker Slots.",
        },
    },
}
local addcard = Card.add_to_deck
function Card.add_to_deck(self)
  if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name == "Mrk3" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
        G.jokers.config.card_limit = #G.jokers.cards + 1
        G.jokers.config.card_limit = G.jokers.config.card_limit + 1

  end
  addcard(self)
end

local removecard = Card:remove_from_deck
function Card:remove_from_deck(self)
  if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name == "Mrk3" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
        G.jokers.config.card_limit = #G.jokers.cards
  end
  removecard(self)
end

#

it crashes on the second function but works normally when i delete it

hardy viper
#

not Card:remove_from_deck

balmy stump
#

oml

hardy viper
#

you can only use the colon when you're actually calling the function. also, self is implied when you do Card:remove_from_deck()

#

Card.remove_from_deck(self)
is the same as
Cars:remove_from_deck()

balmy stump
thick panther
#

How do you add money with a joker? I thought it was dollars?

if context.joker_main then
            
            -- Double money
            local dMoney = G.GAME.dollars * 2

            return {
                card = card,
                dollars = dMoney,
                message = '+$' .. dMoney,
                colour = G.C.MONEY
            }

        end
balmy stump
#

right now the second function is crashing because of index self nil value whether or not i specify self

balmy stump
#

it works

pearl bane
#

so uh, is extra_value the value of the card or the, well, extra value of it?

#

as in, the value gained

frosty dock
#

added sell value, like from gift card

pearl bane
#

hmmm

frosty dock
#

actual sell value is sell_cost iirc

pearl bane
#

isn't that the sell price?

frosty dock
#

yeah what else do you mean

pearl bane
#

nah I'd rather just add the base price than calculate and round down/up the sell price

#

also, couponed is for when a card is gained for free through tags, right?

rough furnace
#

theres a function to calculate sell cost iirc

frosty dock
#

yeah Card:set_cost(). again real sell value is stored in card.sell_cost

rough furnace
#

I would probably use the sell cost just cause mods may screw with stuff in ways you can't predict

#

liek I have a joker that spawns jokers who's sell cost is forced to 0

#

but they still have base cost for example

pearl bane
#

are they flagged as couponed? if not, I think you should add it egg

frosty dock
#

that's not what couponed does though

rough furnace
#

no the sell cost is 0 not the buy cost

#

(these jokers can't appear in the shop)

frosty dock
#

couponed cards still sell for a positive price

pearl bane
#

you know what, this is too much magickery; I'll just use events to set money to 0 after the card is in the deck

rough furnace
#

you can use add_to_deck to run code when added to deck

pearl bane
#

ok, so I have a joker that sets money to 0 when bought, the code is this:

-- snip
    add_to_deck = function(self, card, from_debuff)
        if not from_debuff then
            local dollars = G.GAME.dollars
            ease_dollars(-dollars)
-- snip (do stuff with dollars)

and it set money to -{j price}

#

about time I explained myself lol

#

how do I avoid this?

rough furnace
#

does ease_dollars(0) work?

#

I fiorget how ease_dollars works again

thick panther
frosty dock
#

yeah it's relative to current money

pearl bane
#

Imma try using lovely to inject an extra exact argument into ease_dollars

rough furnace
#

if you don't care about the effect you can just do G.GAME.dollars = 0

pearl bane
#

I do

#

that's the problem

teal estuary
#

this might be a stupid question but what defines how many chips a card gives? like, if i wanted to make aces score 12 chips instead of 11, what would i call in a joker to change it 🤨

rough furnace
pearl bane
#

should I?

frosty dock
#

try putting it in an event

pearl bane
#

cuz it still shows 0

rough furnace
#

this feels like it's being called multiple times

frosty dock
#

no, imo it feels like it's setting to 0 before the shop price is paid

pearl bane
#

yeah so I might be able to do it with events