#💻・modding-dev
1 messages · Page 623 of 1
like i don't think there's any distinct difference in loading the file vs having the contents of that file directly in the main file
what's your goal
so i have a lua script to generate the spritesheets automatically
and i wanted to also make it calculate the pos offset and use it in the object pos's
but i dont want it to regen the spritesheets when the game starts (mosty because the raw files are only on my harddrive)
don't put that script somewhere where the mod will automatically load it? or rewrite the way your mod loads files to avoid the script
oh wait i could just check if SMODS is set right?
oh yea you could do that
oke wow i was overthinking it :D
what would i call to retrieve the number of vouchers currently purchased in a run?
#G.vouchers.cards
(note that this is the number of vouchers the player currently owns, which is subtly different from the number of vouchers purchased if there are mods installed that can give you vouchers without directly buying them or make the player lose vouchers. e.g. cryptid does both via the Trade spectral card)
also for mod wide globals that shouldnt be used outside of it
is it ok to add it to SMODS.current_mod.whatever
yes but i think it's better to use your own table so you don't accidentally clash with an smods mod object field
also keep in mind those don't get saved
so smods.current_mod.foo.x
its fine it gets regenned every boot
Iterate over G.GAME.used_vouchers and count then.
is there any way to do something like midas touch but with an edition?
i tried just replacing m_gold with e_foil but uh
it did some very strange things until it eventually crashed
given the fact it turned the sprites into jimbo i want to say the problem is that e_foil only works on jokers
but im not sure how to change that
use set_edition, not set_ability
set_ability only works for enhancements, not editions
ah alright
Yo guys how do i change the texture of one specific joker?
what would i use in localization to add the side panel for edition descriptions
override the graphic at the joker's index on its respective atlas
I attempted this.
i dont know lua... how do i do that i am tryna create my own custom pack
oh thanks man
What do you mean the side panel?
like when you hover on a tooltip and it creates something to the side of the tooltip explaining a term
i want to do that for ml_negative_desc
(yeah I had an idea of like trying to use patches to replace the screen colors and also the introduction colors)
Yo man is there a way to change the texture of one specific joker rather than using the jokers entire menu in malverk
local seal_them = Card:get_seal()
function Card:get_seal()
local ret = seal_them()
return ret
end
```Is my hook for :get_seal is good
I can't figure out how to make that a certain seal can also be consider as a red seal
I decided to try and see how it would look with other mods as I have yet to make that splash and background as an option yet.
No, ```lua
local oldgetseal = Card.get_seal
function Card:get_seal(bypass_debuff)
local g = oldgetseal(self, bypass_debuff)
return g
end
oh right i forgot about bypass debuff
anyway this isn't really possible with how get_seal works, you need it to behave like is_suit
You mean like quantum seals?
Oh cause I figured it out with enhancement but I wasnt knowing if it was possible for seal cause get_seal doesnt have an argument tu specify the seal
yea it works with enhancements because smods has a whole quantum enhancements setup
yeah
denominator is not in your config
Do you think that smods can make a thing that make seal like enhancement like a SMODS.get_seal(card, key) can be very cool
just know all my questions and pleas for help are going to great things
idk abt the code side but is it conceptually possible to "predict" the next ante's boss blind? since its not technically random
like if i wanted a joker that could "predict the future" and see next ante's boss blind, or the next card youre gonna draw or something like that
yes, i know people have made similar things that predict e.g. the contents of a booster pack
and misprint already predicts the next card you're gonna draw
also not sure about the code side but there was a conversation about it in here recently
alr i can dig, thanks!
Likely not
Oh 🥲
I mean if you want me to add this I can
Yes, I am the person being referred to with predicting booster packa
Sure thing, and oh! which reminds me did you get a chance to look into the texture issues of the two shaders?
No I have been indisposed (see: depressive episode). Let me get up and I can look at them today
im sorry 🫂
Alright-y then. and sorry to hear about that. and also I'll look at what happened.
would this be used to run upon opening a spectral pack? some of this stuff isn't obvious in the documentation so i have to guess a bit
calculate = function(self, card, context)
if context.open_booster and not context.blueprint then
if card.kind == "Spectral" then
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.gain
end
end
if context.joker_main then
return { vars = { card.ability.extra.Xmult } }
end
end,
you're nearly there, but you should be checking if context.card.kind == "Spectral"
and you're returning the xmult wrong in the joker_main section, it should be return { xmult = card.ability.extra.Xmult }
oh bet i might ask you how that works at some point if thats okay
@weary merlin in case this got buried too quickly
No, it's context.card.config.center.kind
trying to run an unlock if the player has bought 5 vouchers by ante 4, this crashed my game
unlocked = false,
check_for_unlock = function(self, args)
if args.type == 'round_win' and args.ante < 4 and #G.GAME.used_vouchers >= 5 then
return true
end
end,
Log?
Also it's #G.vouchers.cards
attempt to compare nil with number
Try using G.GAME.round_resets.ante instead of args.ante
on a different joker i'm working on i need an unlock condition for when the player loses against a finisher blind
any way to also allow this to pass upon buying a voucher?
check_for_unlock = function(self, args)
if args.type == 'round_win' and G.GAME.round_resets.ante < 4 and #G.vouchers.cards >= 5 then
return true
end
end,
this is broken too haha
loc_txt = {
name = "Voucher Joker",
text = {
"Each {C:attention}voucher{}",
"redeemed this run",
"gives this Joker",
"{X:mult,C:white} X#1# {} Mult",
"{C:inactive}(Currently {X:mult,C:white} X#2# {C:inactive} Mult){}"
},
unlock = {
"Buy {E:1,C:attention}5{E:1,C:attention} Vouchers{} by Ante 4"
}
},
config = { extra = { xmult = 0.5 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, 1 + card.ability.extra.xmult * #G.vouchers.cards } }
end,
attempt to index field vouchers (a nil value)
you need a nil check for G.vouchers because it might not exist (e.g. if you open the collection on the main menu)
if G.vouchers is nil you should set a default value
G.vouchers and #G.vouchers.cards or 0
More of a Lua question than anything, but if I have the following table:
local mu = {1="test", 2="test", 4="test", 5="test"}
And I iterate with for c,str in pairs(mu), will the order be 1 -> 2 -> 4 -> 5?
Dangit afk
No, it would crash.
you could test this very easily by putting print(c) in the body of the for loop
i don't think it would? it's pairs, not ipairs
It would be {[1]="test", [2]="test", [4]="test", [5]="test"}
I'm asking bc i can't test it rn :( at work
the internet is really cool :3 https://onecompiler.com/lua
OneCompiler's Lua online editor helps you to write, compile, debug and run Lua code online.
anyways no you won't get a consistent order out of that
if you want one make there not be holes or use some sort of default value that isn't nil to fill the holes
i mean you May or May Not get a consistent order out of it but writing code that expects a consistent order from that table is incorrect
(also, this uses 5.4, not 5.1/luajit. they don't follow the same spec)
close enough for most usecases in my experience
im pretty sure mycompiler uses 5.2 which will have an implementation closer to luajit but still different
not the ordering that pairs returns
Damn, I see
please elaborate, I've been wondering about balatro's pairs ordering for a bit
Hi, I'm doing my first mod I don't really understand an error that I'm recieving
essentially, pairs boils down to the next function which takes the table and greedily looks for the next value after a specific one (which using pairs the "specific one" is always the last one yielded by the iterator)
the values are always in some order, but since associative arrays are not objectively ordered by their keys the order that key/value pairs are returned by next is completely undefined
I'm trying to create a joker that reactivates foil cards, but it just doesnt work
as far as luajit is concerned, pairs does actually return key/value pairs in order of the key for normal arrays
but it could technically return them in any order if it wanted to, like if it decided it would be faster to store the array part in the hashmap part (which it is allowed to do)
so you should use ipairs and a holeless array when you need to see things in a consistent order
🤔
What do you mean reactivates foil cards?
do you have a source for any of the luajit stuff? I found documentation for lua's internals, but not for luajit
enjoy reading this abysmal code
like, retrigger
yeahhhhh I was hoping I didn't have to 😭
if context.repetition and context.other_card.edition and context.other_card.edition.foil then return {repetitions = 1} end
onecompiler my beloved
c devs readability challenge (impossible 100)
Ok thanks, it's really similar to what I have. btw what does the context.repetition exactly do?
okay well I can confirm you're at least partially right, next does seem to rely on both an array part and a hash part
is there a general "when this joker is removed" context
not a context, a separate remove_from_deck function
ah ok
It is used to check how many times a playing card should be retriggered.
what arguments does it have
that's the context during which you can return repetitions (retriggers)
ok thx
thx, however, it still doesn't work, and the error it gives isn't even from my mod
oh uh
):
you need to do card:juice_up(x,y)
inside the return?
no hold on lemme look
Code?
do you have any return {..., card = self}?
yes indeed
Don't, use card = card instead
Remove card = self
ohhh
or just remove it yeah
may i recommend
https://github.com/nh6574/VanillaRemade/blob/main/src/jokers.lua
I'm trying to run a function that resets the player's profile but it doesn't work
can someone help me
this is the code:
local function reset_profile(n)
n=n or G.SETTINGS.profile
print("current profile:",n)
print("profiles:",G.PROFILES)
love.filesystem.remove(n..'/'..'profile.jkr')
love.filesystem.remove(n..'/'..'save.jkr')
love.filesystem.remove(n..'/'..'meta.jkr')
love.filesystem.remove(n..'/'..'unlock_notify.jkr')
love.filesystem.remove(n..'')
local _name = nil
if G.PROFILES[n].name and G.PROFILES[n].name ~= '' then
_name = G.PROFILES[n].name
end
G.E_MANAGER:clear_queue()
G.FUNCS.wipe_on()
G.PROFILES[n] = {}
G.SAVED_GAME = nil
G.DISCOVER_TALLIES = nil
G.PROGRESS = nil
G.FILE_HANDLER.force = true
G:load_profile(n)
G.PROFILES[n].name = _name
G.FUNCS.wipe_off()
return n
end
it resets the player stats however the cards unlocked and discovered aren't reseted for some reason
pretty sure this is already a vanilla function (though I cant check rn)
I.e. one of the functions that is run when you click the button that resets your profile
It's
G.SAVED_GAME = nil
G.E_MANAGER:clear_queue()
G.FUNCS.wipe_on()
G.E_MANAGER:add_event(Event({
no_delete = true,
func = function()
G:delete_run()
local _name = nil
if G.PROFILES[G.focused_profile].name and G.PROFILES[G.focused_profile].name ~= '' then
_name = G.PROFILES[G.focused_profile].name
end
if delete_prof_data then G.PROFILES[G.focused_profile] = {} end
G.DISCOVER_TALLIES = nil
G.PROGRESS = nil
G:load_profile(G.focused_profile)
G.PROFILES[G.focused_profile].name = _name
G:init_item_prototypes()
return true
end
}))
at button_callbacks.lua
G.FUNCS.load_profile
what's that?
what vanilla jokers would look like when made using SMODS
better to take those as examples rather than the vanilla code
ohh, that's really usefull
How do I make a joker that changes the music? I've been searching in the yahimod files because it has a joker that does that, but I couldn't find it
something like this but return next(SMODS.find_card("j_midprefix_key")) and math.huge or false
ok thx
how can i make the backside of custom jokers reflect modified transparent pixels?
i got one voucher-shaped that i need a custom backside for
Sorry, it doesn't work, any ideas?
well idk where you made your SMODS.Sound
it just needs to go in there
and how do I make a joker activate that
okay, thanks
when you return in the first condition it doesn't reach the second one
... how do i fix
that would do the same thing but in reverse
change the logic so you don't return until the end
...
idk check out a boolean logic tutorial
no
well yeah actually
you would need something like pseudorandom_element({"Tarot", "Spectral"}, "seed") but it's a bit harder if you want it weighted
i dont want it weighted
hi everyone
im attempting to load a custom image in the likes of yahimod (as in i got the code straight from yahimod)
specifically just
when a certain joker activates
it puts an image on screen
so far I havent gotten it to load, but its not crashing so im happy about that
here's the code, if any of you would like to help
return {
xmult = card.ability.extra.Xmult
}
end
if context.post_trigger then
G.macorner = 1
end
end,
}
local drawhook = love.draw
function love.draw()
drawhook()
local function loadThatImage(fn)
local full_path = (clo.path .. "customimages/" .. fn)
local file_data = assert(NFS.newFileData(full_path),("Epic fail"))
local tempimagedata = assert(love.image.newImageData(file_data),("Epic fail 2"))
return assert(love.graphics.newImage(tempimagedata),("Epic fail 3"))
end
if G.macorner then
if clo.macorner == nil then
clo.macorner = loadThatImage("Macorner.webp")
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
clo.macorner,
200 * _xscale * 2,
100 * _yscale * 2,
0,
_xscale,
_yscale
)
end
end```
oh i saw two different pseudorandom checks so i though you did
but i guess they're the same
i wasnt able to find anything on the wiki for this
but im sure its out there somewhere
Is there a way to prevent a type of card enchantment from appearing in standard packs?
one that you made or a vanilla one
I made the enchantment
Got it, thank you
does anyone know an alternative to get_id() which works with custom ranks?
No, Card:get_id() works for custom ranks.
you can also use card.base.value
you can check for has_no_rank
and they will not be relevant once quantum ranks come out :3
Great thx
can you store a card reference in another card's config?
basically
a "treasure hunt"
a random card in the deck is assigned as the "treasure"
if that card is scored, give the money and consume the consumable that started this hunt since it hangs about in your consumable slots
No, just store the sort_id
i see i see
whats the function for checking whether a card is a consumable again?
card:foo()
or whatever
how do i check agian
card.ability.consumeable
I know I've been here with this card before but I am confused...I'm going for a loyalty card-like joker, where it makes either a Cavendish or a Gros Michel and I'm having troubles resetting my variable cooking_process and it ticking down again. It does it once then stops and I'm unsure why
if context.joker_main then
card.ability.extra.cooking_process = (card.ability.extra.every - 1 - (G.GAME.hands_played - card.ability.hands_played_at_create)) % (card.ability.extra.every + 1)
card.ability.extra.xmult = 1 + ( #SMODS.find_card("j_gros_michel") + #SMODS.find_card("j_cavendish") ) * card.ability.extra.xmult_gain
if card.ability.extra.xmult > 1 then
return {
xmult = card.ability.extra.xmult
}
end
if not context.blueprint then
if card.ability.extra.cooking_process == 0 then
local eval = function(card) return card.ability.extra.cooking_process == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
end
if card.ability.extra.cooking_process == card.ability.extra.every and not context.blueprint then
if #G.jokers.cards < G.jokers.config.card_limit then
if SMODS.pseudorandom_probability(card, "DRYDina", 1, card.ability.odds, "DRYDina") then
SMODS.add_card ( {key = "j_cavendish" } )
return {
message = 'Potassium.', colour = G.C.YELLOW
}
else
SMODS.add_card ( {key = "j_gros_michel" } )
return {
message = 'Order up!', colour = G.C.YELLOW
}
end
end
end
end
hi I'm new to balatro moding and I'm trying to make a tarot card play a music when use, but it just crash saying that the delta time is at a "nil" value. can someone help me. the following screen shot about my code has only the "use" function and the path.
it should be play_sound("modprefix_music1") not just play_sound("music1")
so put [prefix]_ before it, depending on what you pput the prefix of your mod as in the json file
once you have the food cards it returns for xmult and never does what is below that condition
I see...
my prefix is call FreakedFleapit, does it mean is should be call play_sound ("FreakedFleapit_music1")
if that's what you set the prefix to, then yes
you should probably shorten it tbh
you use the prefix very often so having a shorter one is a lot more convenient
noted, thank you
Followup then, why does this one work??
if context.joker_main then
card.ability.extra.birdbrain = (card.ability.extra.every - 1 - (G.GAME.hands_played - card.ability.hands_played_at_create)) % (card.ability.extra.every + 1)
if not context.blueprint then
if card.ability.extra.birdbrain == 0 then
local eval = function(card) return card.ability.extra.birdbrain == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
end
if card.ability.extra.birdbrain == card.ability.extra.every then
return {
chips = card.ability.extra.chips
}
end
end
because that return is at the end of the block
it can do the rest of that code you just pasted because it comes before the return
okayy, so I need to put my return at the bottom of the other one and it should work...?
no because the other conditions also return
you need to either combine the returns or change the logic a bit
personally i would create the jokers in context.before and only apply the xmult in joker_main
How does context.before work? Never had to use that one so I'm clueless
basically the same way joker_main does but it happens earlier
timing-wise it happens at the same time as when space joker levels up the played hand
okay
sorry again but after your help it seem to have the same problem, in this case here the new function and the json file with the prefix because I think it could be my json file but I just don't know
The sound key has music in it so it is counted as music but you're playing it as a sound.
should it then be a music_track or something close to it
Correct me if I did something wrong but something like this?
if context.joker_main then
card.ability.extra.cooking_process = (card.ability.extra.every - 1 - (G.GAME.hands_played - card.ability.hands_played_at_create)) % (card.ability.extra.every + 1)
card.ability.extra.xmult = 1 + ( #SMODS.find_card("j_gros_michel") + #SMODS.find_card("j_cavendish") ) * card.ability.extra.xmult_gain
if card.ability.extra.xmult > 1 then
return {
xmult = card.ability.extra.xmult
}
end
if not context.blueprint then
if card.ability.extra.cooking_process == 0 then
local eval = function(card) return card.ability.extra.cooking_process == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
end
end
if context.before then
if card.ability.extra.cooking_process == card.ability.extra.every and not context.blueprint then
if #G.jokers.cards < G.jokers.config.card_limit then
if SMODS.pseudorandom_probability(card, "DRYDina", 1, card.ability.odds, "DRYDina") then
SMODS.add_card ( {key = "j_cavendish" } )
return {
message = 'Potassium.', colour = G.C.YELLOW
}
else
SMODS.add_card ( {key = "j_gros_michel" } )
return {
message = 'Order up!', colour = G.C.YELLOW
}
end
end
end
end
Are you trying to change the music when the consumable is used?
yes. When the consumable is use the music already playing need to change to the new music. in this case it's the "music1"
"attempted to index a nil value at line 412"
lua indexing starts at 1 btw
only
card.ability.extra.xmult = 1 + ( #SMODS.find_card("j_gros_michel") + #SMODS.find_card("j_cavendish") ) * card.ability.extra.xmult_gain
if card.ability.extra.xmult > 1 then
return {
xmult = card.ability.extra.xmult
}
end
should be in joker_main
No, use pseudorandom_element
Sorry I keep asking, but this then?
if context.joker_main then
card.ability.extra.xmult = 1 + ( #SMODS.find_card("j_gros_michel") + #SMODS.find_card("j_cavendish") ) * card.ability.extra.xmult_gain
if card.ability.extra.xmult > 1 then
return {
xmult = card.ability.extra.xmult
}
end
end
if context.before then
card.ability.extra.cooking_process = (card.ability.extra.every - 1 - (G.GAME.hands_played - card.ability.hands_played_at_create)) % (card.ability.extra.every + 1)
if not context.blueprint then
if card.ability.extra.cooking_process == 0 then
local eval = function(card) return card.ability.extra.cooking_process == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
end
if card.ability.extra.cooking_process == card.ability.extra.every and not context.blueprint then
if #G.jokers.cards < G.jokers.config.card_limit then
if SMODS.pseudorandom_probability(card, "DRYDina", 1, card.ability.odds, "DRYDina") then
SMODS.add_card ( {key = "j_cavendish" } )
return {
message = 'Potassium.', colour = G.C.YELLOW
}
else
SMODS.add_card ( {key = "j_gros_michel" } )
return {
message = 'Order up!', colour = G.C.YELLOW
}
end
end
end
end
yeah
alright, I'll run a test
Perfect, you honestly fixed 2 problems in 1 so thank you :D
what would be the difference /genq
pseudorandom works just fine
is balatro just like
not allowed to work in quarters
i want to do X1.25 mult but it always rounds up to X1.5
no it can
then how would i do it D:
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:is_face() then
return {
xmult = card.ability.extra.Xmult
}
end
end
}```
that seems fine
are you restarting the run
yep
i have had this problem with most things i try to do quarters with
like i had a legendary that gained a quarter of a cards sell value in XMult
but it always did half instead
i think your lua interpreter is cursed
What’s your mod list?
i have debugplus and lovely
and my mod i guess
thats it
Weird
[[patches]]
[patches.pattern]
target = '=[Cryptid "lib/overrides.lua"]'
pattern = "function calculate_reroll_cost(skip_increment)"
position = "after"
is this how you would do this
=[SMODS Cryptid
i seeee
(also if you're doing a patch after the first line of a function it might be a better job for a hook)
i mean true but
ive been working on my own mod and i have no prior coding experience other than this mod 😭 and this is the code for my joker (Medusa: On final hand of round, turn all scoring cards to stone. For every stone card scored, this joker gains x0.2 mult)
a notable issue i have is that the first card changes, yet it doesn't give chips as a stone, but will trigger the upgrade as if being triggered as a stone
i would check midas mask
https://github.com/nh6574/VanillaRemade/blob/0d158691dc9aac5664bca0e09e531d93519fba04/src/jokers.lua#L2112
Are there versions of G.GAME.hands_played and card.ability.hands_played_at_create that can apply to blinds played?
G.GAME.hands_played is a global
for the other one there isn't afaik
you would need to count them manually
Ah, I see
is there a function to add an extra card to a booster pack?
G.GAME.modifiers.booster_size_mod
https://github.com/Steamodded/smods/discussions/919
And G.GAME.modifiers.booster_choice_mod for more choices.
then no
because its something you can trigger inside of one
you can probably add to the cardarea but idk if that handles everything
im able to edit G.GAME.pack_size , but modifying G.GAME.pack_choices doesnt do anything :(
...I mean, technically, adding to the G.pack_cards is possible...
wait other way around
pack_choices works, pack_size doesnt
Just that you won't be respecting the pool of the pack itself by default.
yeah you would need to add to that area using the booster's create_card if you want it to be part of the pack
makes sense because the size is calculated at the beginning
what function do i call for that again?
context.card:create_card() just crashes because the method doesnt exist
context.card.config.center:create_card()
but idk if it works for vanilla cards
boosters*
probably not
oh but smods takes ownership so maybe
isnt doing anything in vanilla or modded boosters
would i also need to add whatever it returns to G.pack_cards
local card
local _card_to_spawn = context.card.config.center:create_card(context.card, #G.pack_cards.cards+1)
if type((_card_to_spawn or {}).is) == 'function' and _card_to_spawn:is(Card) then
card = _card_to_spawn
else
card = SMODS.create_card(_card_to_spawn)
end
G.pack_cards:emplace(card)
Yes.
okay that fixed it, now its not upgrading on scored stone cards
i fix tomorrow
Know I kinda asked this earlier but how would I be able to subtract 1 from every for every blind played and not every hand played? Know hands played is a global but I would need to keep track of blinds.
card.ability.extra.cooking_process = (card.ability.extra.every - 1 - (G.GAME.hands_played - card.ability.hands_played_at_create)) % (card.ability.extra.every + 1)
<@&1133519078540185692>
return {
descriptions = {
Back={},
Blind={},
Edition={},
Enhanced={},
Joker={},
Other={},
Planet={},
Spectral={},
Stake={},
Tag={},
Tarot={},
Voucher={},
},
misc = {
achievement_descriptions={},
achievement_names={},
blind_states={},
challenge_names={},
collabs={},
dictionary={
b_consumabletypekeywithoutmodprefix_cards = 'Consumable Cards'
},
high_scores={},
labels={},
poker_hand_descriptions={},
poker_hands={},
quips={},
ranks={},
suits_plural={},
suits_singular={},
tutorial={},
v_dictionary={},
v_text={},
},
}
thanks
how do i fix this
what is this exactly, i'm not up to speed on what you're trying to do here
consumable badge
idk if you can see ut
but it says errir
k_consumabletypekeywithoutmodprefix = 'Consumable'
yea that should be it
for a second i was gonna say you do need the mod prefix but i have prefix_config set to true in my consumable type lmao
thanks
in dictionary too?
Yes.
thanks
Sorry for so many questions tonight, I took a break from coding my mod and everything is slipping lol
With that said, how would I go about changing the variable clove_xmult every hand played and it not changing every time I hover over the card? I want it to be able to display what xmult it currently is too in the description of the card. I have that now, it just changes whenever I hover over it
loc_vars = function(self, info_queue, card)
card.ability.extra.clove_xmult = pseudorandom('DRY_Clove', card.ability.extra.min, card.ability.extra.max)
return {
vars = {
card.ability.extra.clove_xmult
}
}
end,
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.clove_xmult
}
end
end
Put it in context.before in calculate instead of loc_vars
And I'd still be able to return that into my Joker's description, even if it returns in context.before?
Yes.
Alright, thank you
Its returning a nil at the moment
calculate = function(self, card, context)
if context.before then
card.ability.extra.clove_xmult = pseudorandom('DRY_Clove', card.ability.extra.min, card.ability.extra.max)
return {
vars = {
card.ability.extra.clove_xmult
}
}
end
if context.joker_main then
return {
xmult = card.ability.extra.clove_xmult
}
end
end
Remove the return {vars = {}} also you need to set clove_xmult be something initially in your config.
So this?
config = {
extra = {
clove_xmult = 1,
max = 10,
min = 1
}
},
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
atlas = "DRY_Jokers",
pos = { x = 8, y = 0 },
cost = 5,
calculate = function(self, card, context)
if context.before then
card.ability.extra.clove_xmult = pseudorandom('DRY_Clove', card.ability.extra.min, card.ability.extra.max)
end
if context.joker_main then
return {
xmult = card.ability.extra.clove_xmult
}
end
end
Yes.
Still nil
how do you apply hologram shader to a card
You still need loc_vars
would I put it after the calculate so that clove_xmult has already been randomly changed thanks to the pseudorandom?
or would I just have to settle that 1st call won't be random but every one after will?
No, the order doesn't matter.
Why is there a {} around the second one?
oh i dont need it?
deleted it, new error
Code?
use = function(self, card, area, copier)
for i = 1, card.ability.extra.count do
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
card:juice_up(0.3, 0.5)
local types = {
function() SMODS.add_card({ set = 'Joker' }) end,
function() SMODS.add_card({ set = 'Tarot' }) end,
function() SMODS.add_card({ set = 'Planet' }) end,
function() SMODS.add_card({ set = 'Spectral' }) end,
function() SMODS.add_card({ set = 'Standard' }) end
}
local choice = pseudorandom_element(types, 'everything')
choice()
return true
end
}))
end
delay(0.6)
end,
can_use = function(self, card)
return true
end
Standard is not a set.
shit
same crash methinks but without standard
What does your localization file look like?
Move the c_bd_defaultprint table into the mistarot table.
how would one make it so that when a joker scores, if whats returned is just a number with no index that it'll use a variable in the joker?
patching obviously
where would the file for scoring of jokers be
where is the file in the game that is for scoring
specifically from jokers
no the first part
what do you mean whats returned
in the calculate function?
which returns a number instead of a table?
am i reading it right
I want to be instead of
return {
mult = 4
}```
to be
```lua
-- In the joker
scoring = "mult"
-- later
return {
4
}
unless you can return a variable name instead
scoring = "mult"
-- ... later in the joker ...
local ret = {}
ret[scoring] = 4
return ret
you have to construct the return table a bit more tediously, but in exchange, you can change scoring to chips or dollars or whatever
cant you do return {[card.ability.extra.scoring] = 4}
just armchair coding here but i think if i understand it correctly you could do
[scoring] = 4
yea now that i think about it you can do the bracket stuff inside the table itself fine lol
my bad
bro went straight to patching 💔
Making a Joker that has a chance to retrigger specifically only steel cards, yet it does not seem to be working (or I'm extremely unlucky with my 1/2's)
loc_vars = function(self, info_queue, card)
local probabilities_normal, odds = SMODS.get_probability_vars(card, 1, card.ability.odds, "Sithe")
return { vars = { probabilities_normal, odds, card.ability.retriggers } }
end,
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(card, 'm_steel') then
if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
return {
repetitions = card.ability.extra.repetitions,
retriggers = card.ability.retriggers + 1
}
end
end
end
Yes, it's context.other_card not card in SMODS.has_enhancement also remove retriggers = card.ability.retriggers + 1
the thing is that I need to keep track of the retriggers, I'm doing something with that at a later point with this joker
No, you don't because it's not doing anything.
it works now
but do you have any idea on how to apply the hologram shader into a card
The plan is to be able to sell the card when retriggers hits a certain point to get another Joker instead, so I will later down the line so its best to do it now...unless it screws something up?
you aren't actually incrementing retriggers
draw = function(self, card, layer) card.children.center:draw_shader('hologram',nil, card.ARGS.send_to_shader) end
thanks
it just will always retrigger steel cards one more time than the retriggers value you saved in the joker initially
do i put this inside of soul_pos or
ahhh, so how would I keep track of retriggers then?
No, retriggers doesn't do anything in a return.
outside of the return, right above it, just put card.ability.retriggers = card.ability.retriggers + 1 (assuming that you actually put retriggers just directly in the config table and not in the extra table)
No, you should use SMODS.DrawStep instead if you want it on the soul.
i see
got it, thank you
thanks
the localization is gone now
okay so what's wrong here?
calculate code
-- earlier
local scoring = G.tlj.WeightRnd(G.tlj.scoring)
print("Num ",scoring)
scoring = G.tlj.scoring[scoring]["r"]
print("scoring", scoring)
-- loc txt
loc_txt = {
name = G.tlj.adj[math.random(1, #G.tlj.adj)].. " ".. G.tlj.animals[math.random(1, #G.tlj.animals)],
-- good enough for now ^^
text = string.sub(scoring,0,1) ~= "x" and "{C:"..scoring.."}+5{} ".. scoring or "{X:"..scoring..",C:white}+5{} ".. scoring
},
-- calc (short for calculator)
calculate = function(self, card ,context)
if context.joker_main then
return {
[scoring] = 5
}
end
end
ignore name of the loc_txt sinceits irrelevant
text should be a table.
ihml
i was too locked in on one thing
okay different problem, scoring = G.tlj.scoring[scoring]["r"] can sometimes return nil?
G.tlj.scoring = {
{r="chips",w=2},
{r="xchips",w=0.1},
{r="mult",w=2},
{r="xmult",w=0.5},
{r="dollars",w=1},
}```
scoring table
G.tlj.WeightRnd = function(weightTable) -- wightedTable will have a table of tables that have values and weights
local totalWeight = 0
for _, weight in pairs(weightTable) do
totalWeight = totalWeight + weight.w
end
local Random = math.random(1, totalWeight)
local currentWeight = 0
for item, weightData in pairs(weightTable) do
currentWeight = currentWeight + weightData.w
if Random <= currentWeight then
if item then
return item
else return G.tlj.WeightRnd(weightTable)
end
end
end
end
weighted random
INFO - [G] oh shit | failed to load Scripts/JokerGenerator.lua | Reason: [SMODS TooLilJkrs "Scripts/JokerGenerator.lua"]:33: attempt to index a nil value
does the lua version balatro use old and cant return functions
there should be no reason for it being nil, i've checked the prints, and aparently item is nil 🤷♂️
after the G.tlj.scoring[scoring] line?
since G.tlj.WeightRnd returns a number
which is the index
What is being printed?
INFO - [G] Num 3
INFO - [G] scoring mult
INFO - [G] AAAA | made number 1
INFO - [G] Num 5
INFO - [G] scoring dollars
INFO - [G] AAAA | made number 2
INFO - [G] Num 3
INFO - [G] scoring mult
INFO - [G] AAAA | made number 3
INFO - [G] Num 3
INFO - [G] scoring mult
INFO - [G] AAAA | made number 4
INFO - [G] Num nil
INFO - [G] oh shit | failed to load Scripts/JokerGenerator.lua | Reason: [SMODS TooLilJkrs "Scripts/JokerGenerator.lua"]:33: attempt to index a nil value
aaaa is printed at the end of creation
local scoring = G.tlj.WeightRnd(G.tlj.scoring)
print("Num ",scoring)
scoring = G.tlj.scoring[scoring]["r"]
print("scoring", scoring)
line that prints
I think it should be math.random() * totalWeight instead of math.random(1, totalWeight)
ig ill try it
oh okay!
seems to work
How would I change the xmult of steel cards with a joker? I have a variable with the new xmult but unsure what to do with it
You mean all the xmult of existing steel cards and steel cards that will exist in the future?
yes
me when i'm bored but don't want to work on my mod so i code an entire solitaire variant minigame for the debugplus console
is it possible to make info_queue contains dynatext
i'm 63% sure you have to go a step above info_queue and use whatever it uses
but again thats only 63% sure that's barely passing i'm not very confident in that statement
i only need the text node anyways
its nothing crazy
Why do they look like NFTs but much better because they ain't scams?
i see
Yes, I have done this
(actually I'm pretty certain N' was the one who did this)
These patches, to enable main_start nodes in edition loc_vars:
https://github.com/BarrierTrio/Cardsauce/blob/main/lovely/corrupted_display.toml
And this code:
https://github.com/BarrierTrio/Cardsauce/blob/main/items/editions/corrupted.lua
Is there anyway to dynamically update ante_scaling mid run?
Yes.
You modify G.GAME.starting_params.ante_scaling
How would I make a card jiggle like invisible when its 2 rounds are done? I'm assuming its juice_card_until but I'm unsure
Yes, it is juice_card_until
Alright, thanks
No I just need to figure out how to place a joker after one is sold...once again kinda like Invis but its a determined Joker
currently have
remove_from_deck = function(self, card, from_debuff)
if card.ability.extra.retriggers >= 13 then
SMODS.add_card ( {key = "j_DRY_Sithe_NEO" } )
end
end,
but returns a nil every time
No, it would be context.selling_self in calculate
Thanks again :)
Okay, 1 final issue it seems. My counter here is a bit wonkey. It retriggered cards 3 times, yet its at 6
card.ability.retriggers = card.ability.retriggers + 1
Code?
loc_vars = function(self, info_queue, card)
local probabilities_normal, odds = SMODS.get_probability_vars(card, 1, card.ability.odds, "Sithe")
return { vars = { probabilities_normal, odds, card.ability.retriggers } }
end,
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') then
if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
card.ability.retriggers = card.ability.retriggers + 1
return {
repetitions = card.ability.extra.repetitions,
}
end
end
if context.joker_main and not context.blueprint then
if card.ability.retriggers >= 13 then
local eval = function(card) return not card.REMOVED end
juice_card_until(card, eval, true)
end
end
if context.selling_self then
if card.ability.retriggers >= 13 then
SMODS.add_card ( {key = "j_DRY_Sithe_NEO" } )
end
end
end
The variable retriggers starts at 0, if that means anything
Try putting the card.ability.retriggers = card.ability.retriggers + 1 in a func in the return.
how would I go about that (sorry I'm so clueless)
Would something like this work?
if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
return {
repetitions = card.ability.extra.repetitions,
retrigger_counter = function(self,card, context)
card.ability.retriggers = card.ability.retriggers + 1
end
}
end
holy huge man
thanks alot
girl*
FUCK
calculate = function(self, card, context)
if context.retrigger_joker_check and not card.ability.triggered then
card.ability.triggered = true
return {
repetitions = card.ability.extra.repetitions
}
end
if context.end_of_round then
card.ability.triggered = nil end
end
any idea why this doesnt work
those look cool
tyy!! ^^
the idea of a misprint tarot card in general would be pretty cool\
i have yet decided on what effects they should have either way
may i lay some suggestions?
sure
my definition for these was bugged tarots
since i was also thinking about that right
and code wise holy shit, its gonna be complicated
@shell timber this is what im trying to do
try printing some stuff, maybe checking if context.retrigger_joker_check ever goes off
and eval card.ability.triggered if possible
how would i do that again
print?
before the if statement (yea with debugplus ur screen is filled) but its important to see if it exists
print("String" or smth that can be a string)
nil and true and false can be made strings by print
if you wanna print a table do tprint() its a balatro only thing tho
should be good
uuh, nah
calculate goes every time smth happens, so like constantly, enter a shop calculate play hand calculate card counted calculate
hey y'all, when attaching an attention text or uibox to major (eg. major = G.ROOM_ATTACH), where within the table is its position stored?
where do i put it then
you should like do
calculate = function(self, card, context)
print(context.retrigger_joker_check, not card.ability.triggered) -- So then the prints will have a bunch of nil, but one has to be true eventually, and not blah blah is so we can see if thats the problem
if context.retrigger_joker_check and not card.ability.triggered then
card.ability.triggered = true
return {
repetitions = card.ability.extra.repetitions
}
end
if context.end_of_round then
print("reset triggered on ", card.label)
card.ability.triggered = nil
end
end
you should find the way cards have their name since im just smth chair coding
cant remeber the word
armchair*
i personally (since i cant read alot) put alot of comments so i can under stand what im looking at
might be just me but whenever i see a code filled with a bunch of comments i just think of AI writing it
probably because they scraped all documentations on the internet
thats only if theres emojis
true
i just cant read so i require it 😭
i'll kinda black out, go back read my code and like
vomit or smth idk
and i've made several 300 line scripts that work (ish)
so i constantly think im making bad not neat code
@lament agate lmk what the prints are, ima be a minute brb
what a name, uuh
nope
odd
oh, in if context.end_of_round then add in and card.ability.triggered
but uhh
that means that retrigger_joker_check doesnt exist
where did you get this from?
from specifically cryptid?
from new smods
i have a funny feeling thats added by cryptidlib
check version
1016c
maybe download from src
the big blue code button since that one is on like 1118a
but is buggy*
im asking ruby hold on
ruby's definitely far above me in balatro coding
she hasnt answered yet
rip
wait shit
you have lua installed. not smods/balatro
so it'll flag it
since its a slightly changed lua
i also have balatro and smods in my workspace
still not how it works
needs to be an extension that manages lua
wait
like how quantum enhancement and stuff
https://github.com/Steamodded/smods/wiki/The-Mod-Object look for it here
oh
it does need to be enabled
OMG THE FUCKIN THING I NEEDED RETRIGGER_JOKER WAS IN BASE SANFGHBAERY HNUFIJHUGGJWEGSF
I spent 2 days looking how to add it
asking everyone
and no one said that
so annoying
alright hold on
do i need to put both?
this is for not reading the vremade wiki smh
fine ill solve your riddles
3:
calculate = function(s, c, ctx)
if ctx.post_trigger and ctx.other_context.joker_main then
SMODS.calculate_effect(ctx.other_ret, ctx.other_card)
end
end
No, that doesn't include retriggers.
if context.post_trigger doesn't fire on retriggers make a bug report at https://github.com/Steamodded/smods/issues
No, I mean it should score and be retriggered, then it should rescore and be retriggered again, like if you used SMODS.score_card on a playing card.
Hello, i'm having issue with my joker, that when you sell a showman, the joker gain +1 xmult but i can't get it to work, can sombody help me please?
sell_joker = function(self, card, context)
if context.card and context.card.ability.name == "Showman" then
if not context.blueprint then
card.ability.extra.x_mult = card.ability.extra.x_mult + card.ability.extra.x_mult_mod
return {
card = card,
message = localize('k_upgrade_ex'),
colour = G.C.RED
}
end
end
end,
calculate = function(self, card, context)
if not (context.individual or context.repetition) and context.other_joker and context.other_joker.ability.name == "Showman" and self ~= context.other_joker then
shakecard(context.other_joker)
return {
message = localize{type='variable',key='a_xmult',vars={card.ability.extra.x_mult}},
colour = G.C.RED,
x_mult = card.ability.extra.x_mult
}
end
end,
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.x_mult }, key = self.key}
end
}
want to make an erosion-like that gives discards based on cards in deck instead of mult
what context do i use to get it to live-update when cards are added or removed?
the loc works of course, but
what the hell do i put in the calculate i got no clue its completely empty rn 😭
context.playing_card_added and context.remove_playing_cards
ty
if context.selling_card and context.card.config.center.key == 'j_ring_master'
Also sell_joker doesn't exist.
i have to place all that's in my sell_joker fonction in the calculate?
Yes.
thanks!
And is there something wrong with my en-us.lua localization file? cause it doesn't shows the description of my joker, (Sorry i'm asking a lot of questions)
return {
descriptions = {
joker = {
j_tsmc_theshow = {
name = "The Show",
text = {
{
"Each Showman gives {X:mult,C:white} X#{x_mult}# {} Mult.",
"When another Showman Joker is {C:attention}sold{}",
"incrases by x1",
"{C:inactive}(Currently {C:x_mult}+#1#{C:inactive} x Mult)",
}
},
}
}
},
misc = {
-- do note that when using messages such as:
-- message = localize{type='variable',key='a_xmult',vars={current_xmult}},
-- that the key 'a_xmult' will use provided values from vars={} in that order to replace #1#, #2# etc... in the localization file.
dictionary = {
a_chips="+#1#",
a_chips_minus="-#1#",
a_hands="+#1# Hands",
a_handsize="+#1# Hand Size",
a_handsize_minus="-#1# Hand Size",
a_mult="+#1# Mult",
a_mult_minus="-#1# Mult",
a_remaining="#1# Remaining",
a_sold_tally="#1#/#2# Sold",
a_xmult="X#1# Mult",
a_xmult_minus="-X#1# Mult",
}
}
}
Yes, it's Joker not joker
Thanks you!
i have this config thingy for my mod which changes what is displayed on some stickers, but how do i reload it without having to restart the game to apply the effects, is that possible?
like i have this in every joker that has the sticker:
set_ability = function(self, card, initial)
SMODS.Stickers.flags_stats_afghanistan:apply(card, true)
end,
and then in my localization file
i have flags_stats_afghanistan = make_flag_stats('Afghanistan'),
and there's this function above the return {...} in the localization file:
local function make_flag_stats(country)
local additional = {}
if FLGTRO.config.show_hidden_stats then
additional[#additional+1] = 'Intentional Homicides {C:inactive}(per 100K people){}: {C:attention}' .. data[country][data_keys.homicides] .. '{}'
end
if FLGTRO.config.show_other_gdp_stats then
additional[#additional+1] = 'GDP per capita: {C:attention}' .. data[country][data_keys.gdp_per_capita] .. '{}'
additional[#additional+1] = 'GDP growth {C:inactive}(annual %){}: {C:attention}' .. data[country][data_keys.gdp_growth] .. '{}'
end
if FLGTRO.config.show_all_stats then
table.insert(additional, 'Access to electricity {C:inactive}(population %){}: {C:attention}' .. data[country][data_keys.electricity_access] .. '{}')
[[minimized]]
local text = {
'Population: {C:attention}' .. data[country][data_keys.population] .. '{}',
'GDP {C:inactive}(US$){}: {C:attention}' .. data[country][data_keys.gdp] .. '{}',
'Inflation {C:inactive}(annual %){}: {C:attention}' .. data[country][data_keys.inflation] .. '{}',
'Forest area {C:inactive,s:0.9}(% of land area){}: {C:attention}' .. data[country][data_keys.forest_area] .. '{}',
'CO2 Emission: {C:attention}' .. data[country][data_keys.co2] .. '{}',
}
for _, v in ipairs(additional) do
text[#text + 1] = v
end
return {
name = country,
text = text
}
end
wtf is this an enconomy simulator in balatro
lmao
I'd figure I try to ask something again here. Does the Texture Pack mod called Malverk allow you to change the textures for the playing cards? Like the cards in your hand? I am making a texture pack and I don't know if you can change them or not. If it is not possible, is there a way to do this differently?
And I don't mean like Friends of Jimbo, like the textures for all the cards
No, that's done using deckskins
that's a base SMODS feature
they're like friends of jimbo, but they can change the textures of all playing cards, not just face cards
So I could do it through SMODS or DeckSkins, do you know which is easier?
deckskins is SMODS
Oh ok, I'll try that, thanks. Does it interfere with Malverk at all?
nope
anyone...?
But if someone were to install it, they would have to install the Malverk pack and then the deckskin, right? Just making sure, I am going to open a repository for it. Thanks again!
you could reload the localization, but that's usually an indicator you should be using localization variables instead
Like put it all in one folder to install? I didn't know that. It just needs the dependencies I see. That makes sense now. Neato
?
what are localization vars ;-;
ohh those
but like it shows/hides certain stuff in the sticker. the config doesn't simply "change" the values
i would use the key parameter to change to another description or use generate_ui if the logic is more complicated
🥺 it's the same for almost 2 years
how do you get a factorial of something
depends whether you want the exact value or an approximation
ty
one is much cheaper than the other
exact ig
idk
wait does talisman have factorial?
then approx. is prol fine
let me check
I appreciate the correction
nvm talisman doesn't have this
i saw it in some codebase maybe cryptlib or vallkarri
will this work?
function fact(n)
local result = 1
for i = 2, n do
result = result * i
end
return result
end
it'll work
IM SORRY
also how can I make a function in say ./functions/utils.lua and then access it from another script
everything runs in the same space so you can write function something() somewhere and call something() in an entirely different file
what most people do is have a single global for their mod and put all the functions in that
oh
like MyMod = {}?
and then MyMod.function something()?
MyMod.something = function() but yes
oh ok
i think there is a better way to do this ;-;
config = { extra = { mult = MC.factorial((G.playing_cards and (#G.playing_cards) or 52)) } },
loc_vars = function(self, info_queue, card)
return { vars = { MC.factorial((G.playing_cards and (#G.playing_cards) or 52)) } }
end,
calculate = function(self, card, context)
card.ability.extra.mult = MC.factorial((G.playing_cards and (#G.playing_cards) or 52))
if context.joker_main and not context.blueprint then
return {
mult = card.ability.extra.mult
}
end
end
also i have big numbers like 100
will that function from earlier lose precision, or will it be fine.
maybe i should use the bigint lib?
it won't lose precision until you hit infinity at which point yeah it'll lose precision
if it loses precision
if you want to use factorials you should be using talisman
if you want to use factorials you should be using talisman
how would i use talisman in this case?
function fact(n)
local result = to_big(1)
for i = 2, n do
result = result * to_big(i)
end
return result
end
and i would keep this? @hardy viper
it works
it could be rewritten to calculate the factorial less but it's fine if it's based on how many cards there are
ye
also what's the hidden bool property do in an smods game object
i think i asked this before
but i forgot;-;
also how do i create a specfic joker
-# for a consumeable
makes an object soul-like, it only spawns as a rare replacement for other cards of its set
vanillaremade wiki probably has a page for this
waow hi lily
congrats on your very postpartum gender reveal party
hello
so it defines how rare it is to spawn (technically?)
ah
no it just defines if it is rare to spawn
soul_rate controls the percent rate of a card to spawn (used best alongside hidden otherwise it’ll also spawn normally)
is soul_rate, 0-1?
soul_rate have no effect without hidden iirc
iirc soul_rate w/o hidden makes it spawn like hidden in packs but also be spawnable by consumable generation but i could be wrong
0.003 (default soul rate) = 0.3%
accoring to code it cant because without hidden card is not added to legendary pool
so this is fine?
key = 'test',
set = 'Spectral',
pos = { x = 0, y = 0 },
soul_pos = { x = 1, y = 0 },
soul_rate = 0.01,
hidden = true,
soul_set = 'Tarot',
yeah i was gonna say the vremade shouldnt be there lol
ye i realized
does anyone else want to participate https://discord.com/channels/1116389027176787968/1441421150319149249 
<@&1133519078540185692> scam bot
Oh
Right when I send that message they get sniped
funny idea
they were a lil' late in modding-chat 🤷♂️ /hj
I dont have a character tho, so i cant really
you don't need one?
i can even just screenshot your pfp
and it'll be the Gud joker
or consumeable or blind, etc.
and then you can think of any ability
someone said ultrakill for theirs 🤷♂️
which sucks becuase then most ideas go to those 2 first
what? you don't need to do anything other then think of the ability?
oh
Abilities are hardest for me
ah..
I could do code or art easier
well im doin that 
and this isnt my invitation to do so
yup
if you have any random/OP/weak asf ability, just lmk
also ddoes anyone know how I can increase every config value of the, per se, leftmost Joker? (specifically multiply the values)
check cryptlib
ok im coming back to this, its an off by one error
#G.playing_cards hasn’t updated yet in these contexts, so when it fires it uses the old deck size, not the current one, as the cards havent actually been added/removed yet
is there a different context that fires slightly later?
no but in that case cant you just add them
both contexts have the cards added or removed
Does anyone have any good examples on how to implement custom challange rules?
Likely yes
Can you link it?
do I use Cryptid.manipulate_value()?
My entire mod I guess
okay uh
next issue
some things like DNA… are updating #G.playing_cards at this point in the context
so now im double counting them
why does dna update it but not cryptid? 
Cryptid's code is occasionally a nightmare
tbh the code for the cryptid spectral is still a nightmare because its placed in the tower of booleans that is Card:use_consumeable
yeah
in which case how the hell do i account for it
I haven't noticed it in regular gameplay, but occasions where I've failed to update G.playing_cards for a modded card I notice it sometimes doesn't fully update until the next draw
It's also possible it's handled elsewhere
Though off the top of my head I don't know where
THank you!
i need an accurate number of how many cards are in the deck, including the newly added cards and excluding newly destroyed cards, whenever a card gets added or destroyed
how the heck do i get an accurate number if vanilla itself is inconsistent about when to update #G.playing_cards
Does the joker Erosion have the same problem?
no, because its +mult only actually triggers when a hand is played, it seamlessly hides the problem
and it calculates it on the fly
i cant calculate it on the fly i have to store the value
since im not doing something that only impacts scoring
I'm trying to find what file stuff like extra_blind_active custom modifiers is; do you know what file it's on? @chrome widget
Doing just this isn't helping hah
That's all in the API this runs off actually https://github.com/Kekulism/Arrow/blob/main/api/hooks/blind.lua
It has a whole system for creating extra blind effects
ohhh it's in a different api, thank you
Yeah sorry, the blind stuff is handled by Arrow. However the rest of the challenges do implement some custom rules here and there
I'll poke around more, thanks!
??
i just want to multiply all values of a joker by x1.01 ;-;
🥀
For example the Fanquisitw Corpse challenge has rules for pinning all jokers and making eternal all jokers but the leftmost joker eternal, which is implemented in CardArea:align_cards() in inclides > hooks > CardArea.lua
Unfortunately there's not a lot of framework for challenge rules. Even in vanilla, a lot of challenge rules are just kinda slotted in in various parts of code and not centralized anywhere
So you're gonna have to hook/patch a lot
Maybe that'd be a fun thing to add to my API, some centralized handling for them to change values
dude, anyone? 😭
-# i kinda have to go in 30 that's why i'm asking sm ;-;
I've got a function for that
Yeah
Basically, call this function and pass in card.ability as the table and your mod as 1.01
--- Recursively modifies number values in a table given a multipliative mod, or a reset table and comparator conditions to reset from.
--- If no parameters but a table are provided, the function returns a deep copy of all non-object values
--- @param table table A table to modify.
--- @param mod number | nil A modifier value (such as 0.5 or 2). Default is 1
--- @param reset_table table | nil Table to reset directly comparable values from based on comparator
--- @param compare string | nil A comparator to determine when to reset ('pos', 'neg', or 'dif', default is 'neg')
--- @return table # A modified copy of the given table
recursive_mod = function(table, mod, reset_table, compare)
local val_type = type(table)
local mod_copy = nil
if val_type ~= 'table' then
-- modify number values
if val_type == 'number' and (not reset_table or type(reset_table) == 'number') then
-- default value
mod_copy = table * (mod or 1)
if not compare then
compare = 'neg'
end
-- reset if a reset table is provided
if reset_table and ((compare == 'neg' and table < reset_table)
or (compare == 'pos' and table > reset_table)
or (compare == 'dif' and table ~= reset_table)) then
mod_copy = reset_table
end
return mod_copy
end
-- weird scenarios with a table mismatch
return table
end
-- recursive to arbitrary depth
mod_copy = {}
for k, v in next, table, nil do
if (k == 'order' and type(v) == 'number') or (type(v) == 'table' and v.is and (v:is(Card) or v:is(Cardarea))) then
-- don't copy certain values
mod_copy[k] = v
else
if mod and mod ~= 1 and type(v) == 'number' and (k == 'x_mult' or k == 'Xmult' or k == 'x_chips' or k == 'Xchips') then
if v == 1 then
mod_copy[k] = math.max(0, recursive_mod(0, mod, reset_table and reset_table[k] or nil, compare))
else
mod_copy[k] = math.max(0, recursive_mod(v - 1, mod, reset_table and reset_table[k] or nil, compare))
end
else
mod_copy[k] = recursive_mod(v, mod, reset_table and reset_table[k] or nil, compare)
end
end
end
return mod_copy
end,
-# thanks lol
It also has extra functionality that can be used to reset a table based on the original center which I use sometimes
oh cool
My counter here is a bit wonkey. It retriggered cards 3 times, yet its at 6
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') then
if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
card.ability.retriggers = card.ability.retriggers + 1
return {
repetitions = card.ability.extra.repetitions,
}
end
end
do and context.individual if it's for 1 card.
also what is card.ability.retriggers?
3?
in config i mean
by default
I start it at 0
does it only repeat 1 time the first time?
which to what i see, it looks like you're doing that.
so add that check
and that may or may not fix the issue
its for every steel in hand, so I'mma say no
well...
i mean you are doing it ONCE (the repetition) for each card
that's what i meant
just try it atleast
okay, makes sense
So like this?
if context.repetition and context.cardarea == G.hand and SMODS.has_enhancement(context.other_card, 'm_steel') and context.individual then
if SMODS.pseudorandom_probability(card, "Sithe_steel_retrigger", 1, card.ability.odds, "Sithe_steel_retrigger") then
card.ability.retriggers = card.ability.retriggers + 1
return {
repetitions = card.ability.extra.repetitions,
}
end
end
Yeah
alright :)
Also, I'd check Cryptid for 'Clicked Cookie', that may be a good start :)
oh nice
Also update here, does not work sadly
Its not retriggering the steels anymore
wait wait, I think I figured it out. It does the initial hit whenever the card hits the chance to retrigger, then when it does it goes up again because the probability is still in the range, so its adding again
Unsure what to do with that info though-
wait so doing MC.manipulate_values(self.ability, self.ability.extra.x) will make the self card multiply by the self card's config extra x (which is x1.01) right?
Not it's config (which is on the prototype) but on the ability table,n which are its instanced values
wha?
However I'd recommend storing the factor somewhere else, because by doing this, it will also multiple the factor itself by 1.01
Because it's within a table under the ability table
but isnt MC.manipulate_values(self.ability, self.ability.extra.x) just MC.manipulate_values(self.ability, 1.01)
oh wait do i do G.jokers.cards[1] (and the others) for the table arg
I don't know the circumstance this is being used in
But you do the .ability table for whatever card object
I would not recommend doing it on the highest level card table
events?
I’m 95% sure this is because it triggers in end of round calls too
Really?? Weird...how would I fix that?
and not context.end_of_round
Yippee, it works! Thank you
now I just need to figure out how to change the xmult all current and future steel cards have with a joker
everything is fucked
IM STILL GETTING THE SAME SOUND ERROR
WHAT AM I DOING WRONG
WHAT AM I DOING WROOOOOOOOOOOOOOOOOOOOONGGGGGGGGG 😭 😭
THE PATHS ARE ALL CORRECT
WHY AM I GETTING BAD ARGUMENTS
SCREAMS
,,,,,,,,,,,wait
make sure you dont get fooled by windows hiding file extensions
because its off by default and i will explode microsoft hq everytime for that
anyone have a lead how I could do this? I wanna do it without needing to make a new enchantment for a better steel card but seems its my only option rn
for k, v in pairs(G.I.CARD) do if v.config.center.key == 'm_steel' then v.ability.h_x_mult = number end end and hook Card:set_ability
I'm assuming this would be in calculate and under joker_main?
No, when you want to change it.
on spawn in
so add to deck probably would be best huh
Yes.
So like this?
add_to_deck = function(self, card, from_debuff)
for k, v in pairs(G.I.CARD) do if v.config.center.key == 'm_steel' then v.ability.h_x_mult = card.ability.steel_xmult end end
end,
how do i make it say a message when used (e.g. "Evolved!")
i know i have to use attention text, but i dont know where
Yes.
No, SMODS.calculate_effect({message = 'Evolved!'}, card)
so would this work?
You could move the sound into the SMODS.calculate_effect by also specifying sound = 'hatch_mega' as part of the table where message is.
its returning a nil value
What is?
the code you gave me, it gives a nil somewhere in that line
?
SMODS.calculate_effect({message = 'Evolved!', sound = 'hatch_mega'}, card) also move it out of the event.
wait yeah, that makes more sense
For forcing Flush as part of current poker hand, do I use context.evaluate_poker_hand or do I hook get_flush(hand)?
Whole error if you'd like
if context.evaluate_poker_hand then
table.insert(context.poker_hands['Flush'], context.scoring_hand)
end
for k, v in pairs(G.I.CARD) do if v.config and v.config.center and v.config.center.key == 'm_steel' then v.ability.h_x_mult = number end end
Be careful with forcing hand types though, you’ll need to make sure the table of cards you assign to it is the correct size
SMODS.four_fingers will be involved.
thats something at least, not crashing on spawn in anymore but still gives 1.5x
...will it update the scoring hand type if Flush ends up the highest by order though? 🤔
Are you testing with steel cards that already existed before getting the joker?
no, my bad. Spawning the joker then making the steels. I'll check the other way now
okay, does work with old steel cards but not new ones
hmm, it works but its not what i want
for starters id want it to shatter, not dissolve
secondly, i dont want the message to be normal, it's supposed to be like wheel of fortune's "nope"
jokerforge used to support that but now they dont for some reason????
i want it to work like this
if context.evaluate_poker_hand and context.poker_hands then
local minh = SMODS.four_fingers('flush')
local schand = context.full_hand or {}
if #schand < minh then return end
local isallstone = true
for i, v in ipairs(schand or {}) do
if not SMODS.has_enhancement(v, 'm_stone') then isallstone = false; break end
end
if isallstone then
table.insert(context.poker_hands['Flush'], context.scoring_hand)
end
end
Doesn't seem to update the scoring name by order.
I GOT IT! Just had to put it in before
Use Card:shatter() instead of Card:start_dissolve()
-# Probably would be easier for me to hook get_flush(hand)...
if G.GAME.hands[context.scoring_name].order > G.GAME.hands['Flush'].order then return {replace_scoring_name = 'Flush'} end?
Will that respect higher order hands should those be present?
-# Also apparently triggers 3x...
Put the last event in the use
You forgot the }))
which line
114
this looks right but i cant tell
i dont know what im doing
im genuinely lost
ITS JUST A SIMPLE CONSUMABLE HOW CAN IT BE THIS HARD 😭
Send the full code.
this is one hell of an error
https://youtu.be/n3TFdNQv5Ao?t=38 i want it to match this
the mega evolution test zip file
this is the lua file i used for the mega evolutin test
The event is still not in the use function also you are not returning true
No, you removed the can_use function.
o h hm
The last one.
can i bother you for a moment?
Yes.
better if we go to #🎙・server-chat
Was easier for me to just hook get_flush and do my checks there if said Joker is present. 😅
Welp I made a new joker. and I'm gonna have you all have to guess what this is referencing.
its an nes joker 😨
Yeah, but which game is it?
idk
apparently the issue is at line 90
It's Planet not planet
ah
thx
Since no one had found out, I'll tell you this spoiler:
||Casino Kid||
hey! are there resources to make mods on talisman?
talisman doesn't have many docs sadly, what do you need to know
I have modded balatro but never with talisman so I just wanna start and see if it's any easier
ohh talisman is not a modding api
Talisman just makes making mods more annoying
it's a mod for high numbers that needs special compatibility basically
yes I know but many mods have dependencies on talisman so I assume they're working with it
it's not easier or harder, it's just busy work
talisman basically allows for ^mult
and Xchips as I saw
that's in smods
then google just lied lol
it used to be only talisman but a long time ago
First add this string to your code
to_big = to_big or function(x) return x end
then on comparison of number-valued variables, wrap the numbers on both sides with the to_big function:
-- x,y are numbers
if x <= y then ... end
-- Turn into:
if to_big(x) <= to_big(y) then ... end
That's it, that's making compatibility with Talisman
so basically as long as it's not an absurd e100e100e100 score type mod I'm fine without talisman
No, not all of them, only some of them.
well, there are some precautions that all mods need to take if people are playing your mod with talisman. i recommend not worrying about them until necessary but here's the info for that
https://github.com/nh6574/VanillaRemade/wiki#why-do-i-get-attempt-to-compare-number-with-table-when-talisman-is-installed
edited post
praying rn that one of those forks of talisman that doesnt make lua whine abt comparing differently typed values will be merged into main
it will eventually
(i genuinely do not understand this design choice for lua - operator metamethods work with differently typed values, there shouldn't be a reason for comparison metamethods to not work with differently typed values)
its just not stable atm from what ive heard
ok so the code is moreorless solid, just one small question - how do i have the joker have an edition with it? i want to give it the divine edition
like permanently or just to test it?
permanently
i want it so every divine joker has a forced divine edition
and that it cant have its edition changed
makes sense
i think ive figured it out?
set_ability = function(self, card) card:set_edition('e_modprefix_key') end and hook Card:set_edition
nope i have not figured it out
please help me
what is hooking
?
ok so from what I got, its either:
A some messed up code in my booster packs
or B: some messed up code in my editions
ok nevermind i fixed it
can someone help me find the missing bracket
What is the card id for an ace?
14
No, move it out of the event.
Thanks
its fine i think ive figured it out
i have a new error now
i made a new edition with a shader that i commissioned @terse merlin for
hi