#💻・modding-dev
1 messages · Page 525 of 1
It's pretty weird like I have this joker that do'es the same thing
I also had no clue that was a context 😭
all the blind functions have contexts now basically
although it would be nice to have the docs for them :3
is there a function i can hook to change the cost of anything you have to buy
card:set_cost?
soonTM
no yeah that looks like something messing with set_ability
yeah
I mean, set_ability creates a new instance of the ability, does it not? Why would it copy values?
i dont recall if set_ability or copy_card but one of those keeps the values of the original
i mean, copy_card does but i dont remember if it's set_ability's doing
the problem is not that theyre being reset, its that they're being upgraded
I wonder, does it carry over the ability table before or after the set_ability call?
Its like they are being rounded but their is only 2 digits so thats make 0 sense
If it’s before, that’s probably why and is a fundamental error in base code lmao
yeah probably
.
I want the buttons (and area) to draw above every other area so they don't collapse with consumables f.e.
I've tried increasing draw_layer but all it does is disappear
Pokerleven.create_UIBox_bench_area = function()
local t = {
n = G.UIT.ROOT,
config = { align = 'cm', r = 0.1, colour = G.C.CLEAR, padding = 0.02 },
nodes = {
{
n = G.UIT.O,
config = {
object = Pokerleven.ina_bench_area,
draw_layer = 1
}
},
}
}
return t
end
where are you defining the area?
self.ina_bench_area = CardArea(
0,
0,
self.CARD_W * 4.95,
self.CARD_H * 0.95,
{
card_limit = 4,
type = 'joker',
highlight_limit = 1,
}
)
Pokerleven.ina_bench_area = G.ina_bench_area
where
hooked inside Game:start_run
before or after the reference call
local game_start_run_ref = Game.start_run
function Game:start_run(args)
self.ina_manager_area = CardArea(
0,
0,
self.CARD_W * 1.9,
self.CARD_H * 0.95,
{
card_limit = 1,
type = 'joker',
highlight_limit = 1,
}
)
Pokerleven.ina_manager_area = G.ina_manager_area
self.ina_bench_area = CardArea(
0,
0,
self.CARD_W * 4.95,
self.CARD_H * 0.95,
{
card_limit = 4,
type = 'joker',
highlight_limit = 1,
}
)
Pokerleven.ina_bench_area = G.ina_bench_area
game_start_run_ref(self, args)
is this the consumable area or the manager area
The consumable
Is there something for changing the sprite of a joker, when a requirement is met?
This is the hole code of start_run
local game_start_run_ref = Game.start_run
function Game:start_run(args)
self.ina_manager_area = CardArea(
0,
0,
self.CARD_W * 1.9,
self.CARD_H * 0.95,
{
card_limit = 1,
type = 'joker',
highlight_limit = 1,
}
)
Pokerleven.ina_manager_area = G.ina_manager_area
self.ina_bench_area = CardArea(
0,
0,
self.CARD_W * 4.95,
self.CARD_H * 0.95,
{
card_limit = 4,
type = 'joker',
highlight_limit = 1,
}
)
Pokerleven.ina_bench_area = G.ina_bench_area
game_start_run_ref(self, args)
Pokerleven.ina_manager_uibox = UIBox {
definition = Pokerleven.create_UIBox_manager_area(),
config = {
align = 'cmi',
offset = { x = 2.3, y = 3.5 },
major = self.consumeables,
bond = 'Weak'
} }
self.ina_bench = UIBox {
definition = Pokerleven.create_UIBox_bench_area(),
config = { align = 'cmi', offset = { x = 0, y = -5 }, major = self.jokers, bond = 'Weak' }
}
end
card.children.center:set_sprite_pos({x = x, y = y})
i mean this is my exact same code haha
But that isn't for putting a different sprite, is it?
not a different atlas if thats what you mean
for a different atlas it's more complicated
I now feel like a moron for not making my cardarea init stuff a hook
Time to change that! 
Well it happens also with new buttons that I have created
They appear behind any area
i fixed that issue with the draw_layer = 1
I want a joker to change it's sprite for a requirement met. Like for example if the player has only one hand left or the joker activates
so idk what the problem is
yeah
thats what i sent
you would put it in the same atlas and change the pos
so sad
That's all?
yes
I'm gonna try it, thank you :)
Maybe isn't the area itself and the buttons are the problem?
the sell custom button
maybe
alright if i want to have a spectral card have a 0.3% chance to replace a playing card in a standard pack, what would be the best approach?
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
if context.other_card:get_id() == 14 then
return {
x_mult = card.ability.extra.acemult,
}
end
local chance = pseudorandom('susies_idea')
if chance < G.GAME.probabilities.normal / card.ability.extra.aceodds then
SMODS.add_card{ set = "Base", rank = "A", enhancement = "m_steel", edition = "e_polychrome", seal = "Red" }
end
end
end```
why does this not give xmult
are u using the latest SMODS version?
i don't get pseudorandom
I want it to give me a number between 1 and 5
and then do something based on that
how can i do that
pseudorandom("seed", 1, 5) i think
yeah but then how do i get the number it generated
it's a function call, and it returns the number it generated
local number_generated = pseudorandom("seed", 1, 5)
Well I tried setting draw_layers to the button also but nope
it took me 3 months to find the solution myself so good luck
^
☠️
set the soul_rate to 0.3 and then set the soul_set to Standard(?)
not really sure of the soul_set variable exactly, but thats how you get it to generate in other packs
Bump
depends on the event
for preventing death i think you would need to patch the code that does that
Uuuggggghhhhhhh yay, more patches
I'll try to see if I can figure out patching for this, ty
Are there any examples of this config for UI?
instance_type: set the layer that the current node is drawn on, either:
NODE, MOVEABLE, UIBOX (w/o attention_text), CARDAREA, CARD, UI_BOX (w/ attention_text), ALERT, or POPUP
These are ordered from lowest to highest layer.
maybe thats what I need
you can just try them out
Today I learn the difference between Xmult and x_mult
i did and it made stuff render over other stuff i didn't want
there's none?
instance_type is a sub config parameter right?
it's a parameter for the uibox's config
So something like this right?
lua self.ina_bench = UIBox { definition = Pokerleven.create_UIBox_bench_area(), config = { align = 'cmi', offset = { x = 0, y = -5 }, major = self.jokers, bond = 'Weak', instance_type = "UI_BOX" }, }
Photograph too??
yeah
this does not work?lua calculate = function(self, card, context) if context.individual and context.cardarea == G.play then if context.other_card:get_id() == 14 then return { Xmult = card.ability.extra.acemult } end local chance = pseudorandom('susies_idea') if chance < G.GAME.probabilities.normal / card.ability.extra.aceodds then SMODS.add_card{ set = "Base", rank = "A", enhancement = "m_steel", edition = "e_polychrome", seal = "Red" } end end end
what's the goal and what's not working
Gives acemult when an ace is scored
Finally
1 in 10 chance to also spawn random red seal steel polychrome ace during scoring any card
then you need to return at the end after you add the card
what did u do
Wdym
instance_type = "ALERT" },
Maybe you can use UI_BOX also as its above cardarea
when you return from a function it ends
so if the card is an ace it won't try to add
So let me try to comprehend that
The only function I see in here is in calculate
When you return from a function it ends
So
Ok I got nothing
So I also have to add a return end in the pseudorandom thing?
or do i try to fit it in?
you need to move that if condition to the end
yes
Now I have a different problem, why does multiplying 1 by xmult stay at 1?
This happened with susie
Spinel
And even photograph
i dont get what you mean
Why does xmult not affect a poker hand with the base mult of 1?
no idea
Photograph is a vanilla joker, it should work
that seems like a mod messing with calculation
i would ask ruby
oops all 6s works
you're using old probability
Wdym by unriggable?
use the new probability system
oh rigged probably uses the new system yeah
Oh yeah you can probably just replace it with the fix_probability context
the cryptid sticker
Oh if it's cryptid idk if it's updated to use it yet
Rigged sticker makes all probabilities guaranteed
yeah you should update to the new probability method
I don’t remember what it is
don't test with rigged sticker it might not work yet
I'm aware old cryptid probability rigging was jank as all fuck
tutorial there
Oops all 6s works tho
Oops is hardcoded
are you on the latest smods
oops all 6s is hardcoded to work for back compat
Yes
Ough not looking forward to doing Cryptid compatibility tbh
my mod is just not compatible :3
Bone to pick with cryptid and talisman for being so popular and getting in early, making other mod compatibility expected
If Cryptid (not talisman) isn't compatible with your mod it's cryptid's fault
local new_numerator, new_denominator = SMODS.get_probability_vars(card, numerator, demoninator, 'identifier')
what do i write in place of identifier
also do i keep numerator and denominator as such?
demoninator
demon-inator
identifier should probably be the seed string you are using
your numerator and denominator respectively should be there
yes
im having trouble finding how function SMODS.debuff_card(card, debuff, source) works. can someone explain how to usedebuff and source?
so probably 1 and card.ability.extra.odds
return {vars = {G.GAME.probabilities.normal, card.ability.extra.aceodds, card.ability.extra.acemult}}
no
am i blind as hell where is this
new_numerator, new_denominator, and card.ability.extra.acemult
so in this case, card, numerator, denonimator, 'susies_idea'
utility functions in smods wiki
probably add your mod prefix to that
not required but it is good practice
busterb_susies_idea omfg i'm gonna bang my head against the wall that is a mouthful
numerator and denominator there should be 1 and card.ability.extra.aceodds if that wasn't clear
i may be blind, thank you
wait wtf
you should shorten your mod prefix
seven characters is far too much
anybody know why SMODS.load_file isn't working?
it doesn't throw any errors when loading but the jokers can't seem to find the atlases despite me calling for it to load
wrap it in assert
this
loc_vars = function(self, info_queue, card)
local new_numerator, new_denominator = SMODS.get_probability_vars(card, 1, demoninator, 'busterb_susies_idea')
return {vars = {new_numerator, new_denominator, card.ability.extra.acemult}}
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
local chance = pseudorandom('busterb_susies_idea')
if chance < G.GAME.probabilities.normal / card.ability.extra.aceodds then
SMODS.add_card{ set = "Base", rank = "A", enhancement = "m_steel", edition = "e_polychrome", seal = "Red" }
end
```
it returns a function you need to call by adding () at the end
you still need to fix the actual chance
when i do that it crashes
but the loc_vars is good
then your atlas file is wrong
no there's definitely a file there and the code worked previously when it was just in main
pseudorandom('busterb_susies_idea',2)?
well I'm sorry but something is wrong on your end
post the crashlog
assert(SMODS.load_file("content/atlases.lua"))()
Is there a guide on patches I can read?
line 21 is the load_file btw
read the guide please
that looks like it cant find the file
ther just returns that
it looks like it cant read it
yeah the path is wrong
does this file actually exist as a readable lua file in the right place
oh wait one moment
i may have been editing it in the wrong place 💀
nope i moved it to roaming and it still errors out
let me do something
okay i figured it out
i made the seed an identifier...
my VSC was open in the wrong filepath so i was unknowingly editing the incorrect files
looks like i gotta change my workspace preset
seed should also be busterb_susies_idea
oh wait no the loc_vars is still wrong
demoninator should be your denominator for the probability
so then replace demoninator with card.ability.extra.aceodds
like in here?
return {vars = {acechance, aceodds, card.ability.extra.acemult}}
replace aceodds with card.ability.extra.aceodds?
no in the probability vars thing
SMODS.get_probability_vars(card, 1, card.extra.ability.aceodds, 'busterb_susies_idea')
yup
local chance = pseudorandom('susies_idea')
if SMODS.pseudorandom_probability(card, 'susies_idea', 1, card.extra.ability.aceodds, 'busterb_susies_idea') then
and then your return should be return {vars = {new_numerator, new_denominator, card.ability.extra.acemult}}
how about this?
Why does this happen?
if context.before and context.cardarea == G.jokers then
card.ability.extra.card_amount = 0
for _, c in ipairs(context.scoring_hand) do
if context.other_card.edition and context.other_card.edition.key == "e_foil" then
card.ability.extra.card_amount = card.ability.extra.card_amount + 1
end
end
end
if context.joker_main and context.cardarea == G.jokers and card.ability.extra.card_amount > 0 then
return{
chips = card.ability.extra.chips * card.ability.extra.card_amount
}
end
end,```
changed it to acechance and aceodds in the local
replace susies_idea with busterb_susies_idea
there's no other_card in context.before
is the new_numerator and new_denominator also acechance and aceodds
yes
replace context.other_card with c and card with c in context.before
It didn't work in joker_main either though
yeah thats fine then
seed and identifier use the same key 💔
other_card is also not in joker_main
this info is in the documentation
hold on a moment
what are you trying to do
because it looks like permabonuses might be the answer to your problem
thats intended
what do i do here now
local chance = pseudorandom('busterb_susies_idea')
get rid of that
the age of pseudorandom is dead
final
loc_vars = function(self, info_queue, card)
local acechance, aceodds = SMODS.get_probability_vars(card, 1, card.extra.ability.aceodds, 'busterb_susies_idea') return {vars = {acechance, aceodds, card.ability.extra.acemult}}
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
if SMODS.pseudorandom_probability(card, 'busterb_susies_idea', 1, card.extra.ability.aceodds, 'busterb_susies_idea') then
SMODS.add_card{ set = "Base", rank = "A", enhancement = "m_steel", edition = "e_polychrome", seal = "Red" }
end```
No, I want the Joker to give 15 chips per foil card played/scored
this is for every card played?
for every card scored but sure
played or scored
pick one
scored
guess i'll have to change my other chance joker peacock
in context.individual check if the cards foil and increase card.ability.extra.card_amount (like youre doing in the for loop)
Is putting vouchers and boosters in consumable slots possible
i believe you can just emplace them there
Oh shit really?
also make sure to use not context.blueprint for context.individual
like this too?```lua
loc_vars = function(self, info_queue, card)
local polychance, polyodds = SMODS.get_probability_vars(card, 1, card.extra.ability.odds, 'busterb_peacock_polychrome')
return {
vars = {
card.ability.extra.SA2XChips,
card.ability.extra.SA2XMult,
card.ability.extra.SA2Mod,
polychance,
polyodds
}
}
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
local is_polychrome = context.other_card.edition and context.other_card.edition.polychrome
if is_polychrome then
card.ability.extra.SA2XChips = card.ability.extra.SA2XChips + card.ability.extra.SA2Mod
card.ability.extra.SA2XMult = card.ability.extra.SA2XMult + card.ability.extra.SA2Mod
card_eval_status_text(card, 'extra', nil, nil, nil,
{ message = localize("k_upgrade_ex"), colour = G.C.PURPLE })
return { card = card }
else
if SMODS.pseudorandom_probability(card, 'busterb_peacock_polychrome', 1, card.extra.ability.odds, 'busterb_peacock_polychrome') then
context.other_card:set_edition({ polychrome = true }, true)
card.ability.extra.SA2XChips = card.ability.extra.SA2XChips + card.ability.extra.SA2Mod
card.ability.extra.SA2XMult = card.ability.extra.SA2XMult + card.ability.extra.SA2Mod
card_eval_status_text(card, 'extra', nil, nil, nil,
{ message = localize("k_upgrade_ex"), colour = G.C.PURPLE })
else
end```
blueprint doesnt have those values to scale
yup
your joker_main is fine just remove the extra conditions
how would one go about retriggering jokers? i'd check cryptid's code but i was advised against it xd
first you have to enable it
retrigger_joker = true,
}```
Our crossmod joker 🥀
put that at the top of your main file
the background is a little too bright
Will fix later
How do I know if I'm inside a blind?
That’s not how blueprint works
in calculate?
oh shit rlly?
Nop. In a can_use. I want to disable a button inside blinds
and the line in question is
local acechance, aceodds = SMODS.get_probability_vars(card, 1, card.extra.ability.aceodds, 'busterb_susies_idea')
Yeah, blueprint basically just makes the other joker calculate again and display its messages on blueprint
apparently it's attempting to index field 'extra'
G.hand and G.GAME.blind.in_blind returns true if and only if youre in a blind
card.ability.extra not card.extra.ability
am i dyslexic
I think I did it wrong... Now the Joker does nothing at all
if context.before and context.cardarea == G.jokers then
card.ability.extra.card_amount = 0
end
if context.individual and context.cardarea == G.jokers then
for _, c in ipairs(context.scoring_hand) do
if context.other_card.edition and context.other_card.edition.key == "e_foil" then
card.ability.extra.card_amount = card.ability.extra.card_amount + 1
end
end
end
if context.joker_main then
return{
chips = card.ability.extra.chips * card.ability.extra.card_amount
}
end
end,```
and for actual joker repetition?
i assume it would be something like context.joker_main and context.repetition but idk
Okay, cardarea checks are only for when you are trying to find a different card to evaluate, like a played card, so delete the one with the context.before and change the one with individual to G.play
However
depends on what jokers you're trying to retrigger
For this joker I wouldn’t use context.individual at all
You just need to iterate over context.scoring_hand within your joker main check and keep a local count of the number of foil cards
another joker from this one
you gotta be more specific
So what now?
shits undocumented so i have to go off of cryptid and only cryptid
lmao ok
they said they wanted it to be scored not scoring though
jokers next to this one
that implies retrigger synergy
N do you have all my new doc screenshots saved or something
Doesn't seem to work. I can still use the button inside a blind
G.FUNCS.can_toggle_bench_card = function(e, area, button_name, active_colour)
if area.config.card_count >= area.config.card_limit and G.GAME.blind.in_blind then
e.config.colour = G.C.UI.BACKGROUND_INACTIVE
e.config.button = nil
return false
else
e.config.colour = active_colour
e.config.button = button_name
return true
end
end```
why isn't that in the wiki page? /genq
Those are the same thing?
G.hand and
eremel hasnt finished the page yet
yeah I tried that too
to me that implies retrigger synergy?
doesn't work either
vague wording ig
THE PROBABILITY WORKS
hm. hold on let me test something
holy shmoly is that eremel hi eremel
Hello dilly
i hope you fare well this day
i just got talismogged 😭
I do fare well I hope you also fair well
So what should I try now? context.individual or something else?
im doing alright, because people were hating on my codebreakers checksum i have now implemented sha-256 to it so it should be alot less possible to break it
joker_main, like eremel said and use c instead of context.scoring_card like unusedparadox said
What’s the actual desired effect
I want the Joker to give 15 chips per counted foil card from the scoring cards of the played hand
so no retrigger synergy?
What does that mean? I'm so confused right now
Then use joker main
retriggers. like the vanilla balatro feature that retriggers playing cards. like hanging chad.
those retriggers
if a foil card is retriggered, should it add +15 chips again
Wasn't the problem
did you find a way to do it?
still doesn't work 🙁
if a card gets triggered twice, it should count twice imo
can you use it outside of blinds
yeah use context.individual then
Probably best to make a custom cardarea and do it that way
Not really a good way to do it as far as i can tell
also do you want this to reset or not
im currently trying to create a consumable that spawns the last sold joker
does this function actually check if you can press the button
Man I'm an Idiot. It was area.config.card_count >= area.config.card_limit **OR ** (G.hand and G.GAME.blind.in_blind) not AND
getting a problem where one of my functions for registering items errors out at line 7 where it's attempting to call a nil value. all the files & paths exist and are named properly and are loaded into main, so i don't understand the issue
It should reset every blind
It now works, thanks
also i would like to mention that i stole some of this code from Paperback mod, which it works in
keep the last sold joker's key somewhere and create it when the consumable is used
where's counterfeit joker
G.GAME should do?
i forgor
commenting out counterfeit joker made it work
i may be an idiot
it says it in the log btw
wait is card.rank from G.playing_cards not the same as the rank?
i have to create a function that checks what happens each frame?
the rank is card.base.value
i should really get better at reading the error logs 😔
no????
i see, thank you
Hey Dilly, you interested in being a mod playtester?
If I want to add an uibox to the right of the deck, what is the major? G.deck?
This was the idea but i dont get how to create the function
do you know what a hook is
Im not really familiar with the lang
Ill check it
does anyone here want to explain hooks?
https://forums.kleientertainment.com/forums/topic/129557-tutorial-function-hooking-and-you/ this guide is not great but its better than nothing
In LUA, it is a very important concept to understand that everything is a variable and all variables may be edited in runtime. This includes functions. With modding other peoples' LUA files, like Klei's basegame code, you may find yourself wanting to run your code before or after the original fun...
Ty, appreciate 🙏
essentially hooking is just storing a function as a variable under a different name, then overriding it by creating a new function with the exact same name
then in your new function somewhere call (and return if necessary) the original function with the new name and the original arguments
And now you have the power to do stuff before and after the function is called
Ty man
i.e
local start_run_hook = Game.start_run
function Game:start_run(args)
start_run_hook(self, args)
G.GAME.glass_broken = G.GAME.glass_broken or {}
end
If I set up two music tracks with SMODS.Sound, where Music 1 has conditions A and B and Music 2 has conditions A, B and C, and I have conditions A, B and C currently fulfilled (making Music 2 play), does that actively stop Music1 or does it keep "playing" in the background? If condition C goes away and Music 1 comes back, will it start from the beginning or will it be midway through as if it was playing the whole time?
this will create a new variable saved to G.GAME after the run is started
So if i have to get the last joker sold ill have to create a hook and create a new variable (for example G.GAME.last_joker_sold) that stores the id of the last sold joker?
yeah
And then i can use this new variable when in the consumable code
yep
gotta do a nil check tho to make sure that a joker has been sold before
Ye ofc
yeah, had to do something similar where i stored all broken glass cards
that was painful to figure out tho
I've been having trouble with this setup. If I activate the enable_fast_music setting it switches to the 2nd track, but when I deactivate it and it goes back to the 1st track it doesn't start at the beginning. It's like if it's just muting one and unmuting the other instead of restarting the tracks. I also tried setting different priority values, but it didn't do much. Am I missing something?
vol = 0.6,
pitch = 0.8,
key = "music_middle_normal",
path = "middleNormal.ogg",
select_music_track = function()
return (G.GAME.selected_back.name == 'The Middle Deck' and G.GAME.blind and not G.GAME.blind.boss and not G.shop and not ProjectMoonMusic.config.enable_fast_music) and 0 or false
end,
})
SMODS.Sound({
vol = 0.6,
pitch = 1.0,
key = "music_middle_normal_f",
path = "middleNormal.ogg",
select_music_track = function()
return (G.GAME.selected_back.name == 'The Middle Deck' and G.GAME.blind and not G.GAME.blind.boss and not G.shop and ProjectMoonMusic.config.enable_fast_music) and 0 or false
end,
})```
Ty for the helpful advices
are the two tracks supposed to sync with each other? if not, set sync = false
If I want to create a new Sprite for a G.UIT.O. Should I use SMODS.Sprite? And how does it work?
how do i create a joker that does something when a glass card is clicked
No, you use the normal Sprite() object
And how does that work? Can I reference an atlas from it?
How do you use card.children.center:set_sprite_pos({x = x, y = y})? Like when and what for?
Oh my God, I missed that in the wiki. Thank you!
Yes, just look for uses of it in the vanilla code, it’s pretty straightforward
how do i do the effect of a legendary joker and have the art seperate from the back
just add a soul_pos parameter in the joker that points to the floating sprite location in the atlas
alright
local px = G.ASSET_ATLAS["barrier"].px
local py = G.ASSET_ATLAS["barrier"].py
local atlas = G.ASSET_ATLAS["barrier"]
local sprite = Sprite(0, 0, px, py, atlas, { x = 0, y = 0 })```
something like this?
Idk why i'm getting a nil exception from barrier atlas if I do create it
For the Memory Card joker, which memory card do you want me to recreate?
3
3
2
Dreamcast (Classic Gray, Jimbo as profile icon)
how do i make a joker do something when a glass card is clicked
idk if thats a checkable function icl
what actually is G.I.CARD? i see it a lot in the files, is it just all cards currently in play?
How do i make a joker animated?
With the update function updating his sprite manually
Do discovery bypasses just not take the card name into account???
is there no discovered = true for consumeables?
How do I change the sprite of a Joker mid-game?
There is but that alone was being weird (I tried it before adding these clauses). Imma try try it with
Still nope
update function
I have a solution for it but I heard SMODS is planning on adding animation support for other types of cards
bump
What is the update function?
And can I put requirements there? Like if I want it to change after activating, for example
yeah
mb
there is this
you should be able to do something with the function that highlights/unhighlights cards when you click on them. id imagine you have to do fancy hook stuff and then make a context for it in SMODS.calculate_context
yea that's not even super fancy, all you'd do in the hook is calculate the custom context and then pass it off to the old version of the function
^
Does someone have a guide or video that explains the update function?
update function triggers every frame
it's literally just a function that runs every frame
thats the only thing about it
you can do whatever you want in it, it's just a quick way to have something happen if you need to be checking the condition constantly
that set_sprite_pos function you were asking about earlier will change the sprite
How?
you put in the { x = [something], y = [something] }, and it changes the card's sprite to whatever that position is in its atlas
i'm having trouble making jokers retrigger :(
And how do I set it in the atlas? I've never did that, I just used path = "something.png"
getting error "Found effect table with no assigned repetitions during repetition check"
I understand what it means, but I don't know what am I doing wrong
Ok bruh I should not have had to patch that in myself 😭
i don't think that's something you can do? your joker code has atlas = 'something', does it not?
im changing it to a blind, is it easier to do with a blind?
if a glass card is selected/clicked, it game overs you
Yes. Is there a difference or why?
youd have to hook the click function regardless to detect clicks i think
i havent worked with hooks before
okay simple explanation
so your joker has an atlas then. the set_sprite_pos will select a card from the image that your joker started taking its art from
I'm confused. What does that mean?
show me your joker code
basically what you do is you make a copy of the function that you want to hook in another variable,
then, you can edit the function you want to hook as long as you call the original function within it (youre basically just adding code into the original function)
for example this hook that i made once:
what
first line is copying SMODS.poll_enhancement (the original one)
and then everything after is just
key = "final_push",
path = "j_SPACEHOLDER.png",
px = 71,
py = 95
})
SMODS.Joker{
key = "final_push",
config = { extra = { xchips = 2 } },
pos = { x = 0, y = 0 },
rarity = 3,
cost = 8,
blueprint_compat = true,
eternal_compat = true,
unlocked = true,
discovered = true,
effect = nil,
atlas = 'final_push',
soul_pos = nil,
calculate = function(self, card, context)
if context.joker_main and G.GAME.current_round.hands_left == 0 then
return {
xchips = card.ability.extra.xchips
}
end
end,
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xchips }, key = self.key }
end,
}```
the actual code of the hook
where eventually the old function gets called
so the original stuff still happens
here im using it to modify the arguments that get put into the function
your atlas is final_push, which uses the image j_SPACEHOLDER.png. if you call the set_sprite_pos function in the update function of your final_push joker, then you can set final_push's sprite to any card that you have in the j_SPACEHOLDER.png image
but you can do basically anything
im so confuzzled 😭🙏
uhhhhh,,,,,,,,,,,,,,,,,,,,,
im sorry 😭
D:
but ill just give an example see if that helps
Hey, does anyone happen to know how to make a custom voucher that does the same shit as tarot/planet merchant/tycoon?
I checked the source code and it seems it is reading from a hardcoded table I cannot modify.
(because it is locally stored in the function)
But I want to change it from j_SPACEHOLDER.png to something else, like j_something.png. Is that possible?
examplefunction_old = examplefunction
function examplefunction(argument1, argument2) --example hook!
--everything you want to do BEFORE the original function goes here
local ret = examplefunction_old(argument1, argument2)
--everything you want to do AFTER the original function goes here
return ret
end
does this help at all?
not as far as i'm aware. if the card images are related, they should be in the same atlas for organizational purposes anyway (e.g. have all your jokers in one single atlas)
okay
So I can't change the image mid-game in any way?
no. but you shouldn't need to, because you can just pick a different part of the image to display
the game is designed for an atlas to contain a bunch of sprites in one image
So I could make a bigger image (with both images in it) and just position it differently?
yes. that is exactly what i've been saying
I didn't know that, sorry
Helo
Thank you so much though! I'm going to try it now
Does anyone know how to port my mod to mobile?
modding rule 4
what?
Sorry, I forgot that rule.
Is there any way to change the tooltip on uiboxes?
n = G.UIT.C,
config = {
align = "cm",
colour = { 0.3, 0.3, 0.3, 0.5 },
r = 0.1,
minw = 2,
padding = 0.05,
outline = 1,
outline_colour = G.C.BLACK,
hover = true,
tooltip = { title = "Barriers" }
},```
what do i need to do to have an effect activate on the first scoring card of the first hand of the round if the hand matches a rotating hand type variable (as with to-do list)?
im trying to use
if context.cardarea == G.jokers and context.joker_main then
if context.scoring_name == G.GAME.current_round.pokervar_hand and (G.GAME.current_round.hands_played == 0) and context.other_card == context.scoring_hand[1] then
as well as :
if context.cardarea == G.jokers and context.joker_main then
if context.scoring_name == G.GAME.current_round.pokervar_hand then
if (G.GAME.current_round.hands_played == 0) then
if context.other_card == context.scoring_hand[1] then
but it isnt working
context.other_card doesn't exist in context.joker_main,
but you don't need that check at all, you can just use context.scoring_hand[1] directly
oh shoot
is there a table that contains all the rarities?
Another quick question regarding card.children.center:set_sprite_pos({x = x, y = y}) How do I know what x and y?
look at your atlas image
the top-left sprite in it is x = 0, y = 0
from there its just a grid of coordinates
So I just take a guess till I get it right?
you can look at the spritesheet for the coordinates
down 1 sprite is +1 y and right 1 sprite is +1 x
What spritesheet?
Oh, I'm stupid... I didn't know it's called that
isn’t it literally SMODS.Atlas
I meant that it's called a sprite sheet
How would a joker destroy the cards between the cards selected for Hanged Man?
is there a context for creating consumables?
do you mean obtaining them
obtaining in every form except buying
but I guess i can exclude buying from shop and it'd be the same
G.consumeables afaik
not misspelled
when a consumable is added, it does call context.card_added, but not cardarea = G.consumeables
but I think I can work with that
yes. but it's consumeables in the game code
How could I track and level up unplayed hands each round?
I feel stupid asking this but why is my joker getting invisible when I set the sprite pos to something other than x = 0, y = 0?
the documentation may not be perfect, but in this case you can see that context.before gets the name of the scoring hand in context.scoring_hand. https://github.com/Steamodded/smods/wiki/Calculate-Functions
so you can track the scored hands in a subtable in card.ability.extra, then iterate through SMODS.PokerHands at the end of the round and level up all the hands that you didn't track. and then reset the table of scored hands afterwards so that the next round starts fresh
how is your image set up, what are you changing the sprite pos to, and did you change the px or py settings in the SMODS.Atlas (you shouldn't have)
good evening chat
This is my image (I left space underneath for the other 2 Sprites I'm still working on). I'm changing the sprite pos to the top left corner of the right card (x = 72, y = 0) and I didn't change anything in atlas except for the path to this image
sprite pos isn't the pixel position, it's the sprite position. you should set it to (x = 1, y = 0)
But how does it know what of it a sprite is?
Hello, there is no example regarding the use of assert
calculate = function(self, card, context) if context.cardarea == G.scored then if context.other_card:get_id() == 13 or context.other_card:get_id() == 11 then message = 'Queen!' and assert(SMODS.change_base(played_card, "12"))
Whenever i try to get this joker to work, i get either error of context other_card being not recognised, or error about change_base lacking cards
It works now, thank you again
G.scored doesn't exist.
The issue is nil value in "'other_card" as of right now
to answer this, that's what the px and py in the atlas definition do. by setting px = 71, py = 95, the game knows that that atlas contains sprites that are 71x95 pixels
woah, what does this do, if i may ask
Makes sense
This was recommended to me here, I try to make a joker that changed jacks and kings into queens
assert should function like strenght in this regard
How do you change the edition of a card?
holy shit. jestrogen
specifically, a consumable
my mod has jestosterone which does the opposite lmao
if context.individual and context.cardarea == G.play and (context.other_card:get_id() == 13 or context.other_card:get_id() == 11) then
assert(SMODS.change_base(context.other_card, nil, "Queen"))
end
^ your issue wasn't the assert, but the context checks beforehand
paperback has both lmao
great minds think alike
so it was checking the hand value before hand was played
what is the fix to that for the future?
No, it was trying to get the id of a card that doesn't exist.
read up on the contexts in here (a non-exhaustive list is at the bottom)
https://github.com/Steamodded/smods/wiki/Calculate-Functions
your issue was, more specifically, that if context.cardarea == G.scored is meaningless
And it was doing that every time a context was called.
i might... copy this ngl
It shouldn’t ever have reached that line though if the copied code is correct
My Shark Army (Sharmy) approves
I was looking for this for past 2 hours, thank you
bump
You've got too many. Limit of 1 per entity
can i borrow one
okay so, i was looking at the contexts at the bottom of the page. how do you use these exactly?
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
skip_blind = true,
}```
say i want to use this. what do i follow up with? do i add anything else inside the brackets?
the brackets aren't actual code, it's showing what other context values will be set to if context.skip_blind is true. in that case you don't really get much of anything, you just get to know that you're currently skipping a blind
inside the brackets is just the additional information that exists in the context
yeha that
ah, so if i do an if context.skip_blind, that cardarea and skip_blind activate by default?
SMODS.Consumeable
that i already figured out
now I want to know how to set the edition
when?
apparently you use card:set_edition but it's not working for me
what exactly are you doing
when the context is called
turn your consumables into negatives
when acquired and not bought
all i'm missing rn is this
This still causes the other_card to be nil
no like the code
how do i make a deck that starts with a joker that has a custom edition?
Code?
also hi wow cute ralsei pfp
look at my mod’s code for naneinf deck
i figured it out :p
you need to pass a table and i wasn't doing that
i must not have that mod
like
polychrome jimbo for example
apply contains everything you need
The same one you gave me
Log?
now it is a change_base
other_card "Queen" does not seem to define for smods.change_base what value it should be changed to
anyone knows why my messages don't trigger but the event does?
No, did you save the file?
Yes, i have saved the file, I am telling you that assert(SMODS.change_base(context.other_card, "Queen")) is not a valid way to define card suit
Try Q
since i'm also trying to do something similar, what is this doing exactly? i'm reading it and seeing if i understand it
Yes, and I have fixed the code.
let me check then
that what @daring fern , it just, they updated the code in previous comment and edited it so i did not notice it
the idea is
if context.individual and context.cardarea == G.play and (context.other_card:get_id() == 13 or context.other_card:get_id() == 11) then assert(SMODS.change_base(context.other_card, nil, "Queen")) end
After playing a card that is a jack or kings into queens
before it is scored
if context.individual and context.cardarea == G.play then
if context.other_card:get_id() == 12 then
assert(SMODS.change_base(context.other_card, nil, "King"))
return {
message = "Card Modified!"
}
end
end
end
would this work?
Yes.
be grateful they didn’t start 🤔 reacting you
I am used to people posting new code instead of editing old comment of code, but yeah thats fair
what am i doing wrong here? probably a lot. but im trying to make it so that if the first hand scored coincides with a randomly selected hand (as per to-do list), the first scored card modifies the poker hand's base chips and mult based on its scoring values. the joker seems to activate but the hand's values don't actually change
calculate = function(self, card, context)
if context.scoring_name == G.GAME.current_round.pokervar_hand then
if context.individual and context.cardarea == G.play then
if (G.GAME.current_round.hands_played == 0) then
if context.other_card == context.scoring_hand[1] then
context.other_card.should_destroy = true
local chips = card_chips
local mult = card_mult
local x_mult = card_xmult or 0
local text = G.FUNCS.get_poker_hand_info(G.play.cards)
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.hands[text].chips = G.GAME.hands[text].chips + chips
G.GAME.hands[text].mult = G.GAME.hands[text].mult + mult
if x_mult > 0 then
G.GAME.hands[text].mult = G.GAME.hands[text].mult * x_mult
end
return true
end
}))
return {
message = "AUGMENT!"
}
end
end
end
end
jokerforge is limited
yeah, i figured
what do you mean?
i feel like it's still a great tool, specifically for me lol
uhhhhhh i think you aren't getting card_chips, card_mult, and card_xmult properly, so they're just becoming nil and therefore 0
Jokerforge is limited
bump
hi kimi or iris 2
Remove the second table from the return.
Also move the event out of the return.
Hi smt
bump
You would take ownership of The Hanged Man.
if i were to add a context.before, would this happen before the cards score?
To have it function differently when you have the joker?
No.
Yes.
so i remove everything from the return?
No, you move the event out of the return.
And you would remove the } below the r in return and you would remove the };
okay thank oyu!!
i think this is probably the case; what variable refers to the scoring attributes of a playing card? is it not card_chips, card_mult, card_xmult, card_xchips, etc?
i could just take the raw value of the score after the card is played but that won't properly multiply the base values when xMult is involved
I think I understand taking ownership, but still don't understand how to detect the cards between the selected ones
it is i think, but you can't just say "card_chips" or whatever. you have to get it from within context.other_card
gimme a second to find the exact syntax
thank you, and sorry for asking so many questions! :D
You would go through G.hand.highlighted find the positions of them, and see which cards are between.
context.other_card:get_chip_bonus(), context.other_card:get_chip_mult(), context.other_card:get_chip_x_mult(), context.other_card:get_chip_x_bonus()
you're a godsend
yes that's it
i cry everytime
it seems that get_chip_bonus() and get_chip_mult() exist, but not for the xmult and xchips. so I may need to make those myself
it's get_chip_x_mult() lmao
and it should be get_chip_x_bonus() for the xchips one
I'm still new to this, how do i get the positions from that?
for k, v in pairs(G.hand.highlighted) do
local my_pos
for i=1, #G.hand.cards do
if G.hand.cards[i] == v then
my_pos = i
end
end
end
is there a scaling method for messages?
this is what i've been up to (for the ppl that helped me (thanks guys))
I want to turn every consumable that is obtained through other than shopping to be turned negative. Right now, all consumables, regardless of origin, are converted. I would do something with buying_card, but it's called after card_added; I implemented a hack in the meantime.
There must be a way to do this in a more organized manner, but idk how to. Someone suggested doing a hook, but that's a little bit above what I can do (last time I tried to do something similar, I spent an hour to fruitless results). Any better ideas?
this works perfectly!! thank you so much!
one last thing, if you know; this works for the card itself and its enhancements but it isnt adding any bonuses from the card's edition. i tried to use context.other_card.edition:get_chip_bonus() etc. but that didn't work, likewise with using context.scoring_hand[1]:get_chip_bonus()
i copied the code to juice up the joker from invisible joker, so why is it visibly different from invisible joker's juice up animation?
Just add ((context.other_card.edition or {}).chips or 0) if it has an edition for all of the bonuses.
it might be getting applied multiple times
what's the size for mod icons in the mod menu
you have all genuinely been so incredibly helpful i can't thank you enough. i apologize for the very frequent questions but sincerely appreciate the assistance!!
that was in fact the case, fixed it now so thx
How possible is it for me to make contained hands count as played hands? It seems like the "played" hand is controlled by context.scoring_name, is there anything I can do with that?
I've already implemented contained hands adding score, that's just some manual addition
Well I do so looks like I'm leaving this out.
Definitely not worth rewriting a bunch of stuff for one joker
Game:start_run I'm pretty sure, it runs the load function in all the objects
Hello friends! I have a problem with one of my jokers
This is Ho-oh, and it's mechanic is that whenever three cards are discarded, it destroys them and replaces them with three randomly enhanced face cards.
But today while I was playing with it, I noticed that it only destroys the first card, not all three cards
is there any reason this doesn't work when loading a game but it works perfectly if you start a new run?
[patches.pattern]
target = 'functions/state_events.lua'
pattern = "delay(0.4); ease_ante(1); delay(0.4); check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})"
position = 'at'
match_indent = true
override = true
payload = '''
if not G.GAME.blind.small and not G.GAME.blind.big then
delay(0.4)
ease_ante(1)
delay(0.4)
check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})
end```
I've defined two new properties for blinds, small and big
so I can create custom small and big blinds
because after the first card is discarded, card.ability.extra.added gets set to false and therefore the check wont pass after the first card
can you fix this for me? i'd really appreciate it
just remove and card.ability.extra.added from the context.discard check
and just add another check for discarding exactly three cards instead
also use SMODS.add_card instead of that entire thing you have to add a face card
oh wait
no youre using SMODS.add_card() like create_card(), you can just do SMODS.add_card on its own and itll add the card to the area it should be in
also dont know if its intentional, but currently its making specifically a jack, queen and king
I knew it was doing that but I haven't bothered anyone to make the ranks random yet
also i'd imagine its easier to just convert the cards directly instead of adding and destroying but i would have to look up how to do that
yeah you're probably right
i'm trying to make a joker that copies the joker to its right but has a 1/4 chance to destroy it
my issue is that its never copying it
first issue is old probability system
well not an issue but you should switch to the new one
https://github.com/nh6574/VanillaRemade/blob/main/VanillaRemade.lua use vanillaremade as reference because it doesnt have shitty outdated stuff
yeah i heard that they changed it, i was waiting to finish all my planned jokers then change it
you shouldnt use context.post_trigger for blueprinting effects
it shouldnt need a context check at all
vanillaremade blueprint is just this
so just, directly after calculate
it is still in the calculate, just without any context check
aaaaaaaah, i'll try
also you should set the joker buffer back to 0 after the destroying event by the way
oh wait
nvm im blind lMAO
you shouldnt need any arguments for start_dissolve though i think
game crashed
uh probably the random closing curly bracket?
unless thats closing something i cant see
-50IQ, i closed the joker
When you go to the main_menu from a run, what is the function that stores the info from that run?
save_run?
It seems so yea
but if i remove it the game still crashes
you're ending the whole calculate function after the first blueprint_effect, adding the whole check_for_unlock function, and then continuing to write more code that i assume wants to be in the calculate function
no no i am
it just want to close it here
oh yeah why is check_for_unlock in the calculate
that should be its own thing
if you even want it
check_for_unlock isn't in the calculate
the calculate ends right before it
and then there's more calculate code outside of any function
oh yeah
the calc ends early
also please right click and do format document this indentation isnt great
ok hold on, im trying to format bc its not in my right click menu
if you right click anywhere on the document it should have a format document option
and if not you can just select everything and do format selection instead
hi all. back again because i break everything constantly lmao.
this works when the card has an edition, but when it doesnt, i get an error stating that im trying to index edition which is nil. so the "or 0" and "or 1" don't kick in and the game crashes when i attempt to score an uneditioned card with the joker
calculate = function(self, card, context)
if context.scoring_name == G.GAME.current_round.pokervar_hand then
if context.individual and context.cardarea == G.play then
if (G.GAME.current_round.hands_played == 0) then
if context.other_card == context.scoring_hand[1] then
context.other_card.should_destroy = true
local chips = context.other_card:get_chip_bonus()
local edition_chips = context.other_card.edition.chips or 0
local mult = context.other_card:get_chip_mult()
local edition_mult = context.other_card.edition.mult or 0
local x_mult = context.other_card:get_chip_x_mult() or 1
local edition_x_mult = context.other_card.edition.x_mult or 1
local x_chips = context.other_card:get_chip_x_bonus() or 1
local edition_x_chips = context.other_card.edition.x_chips or 1
local e_mult = context.other_card:get_chip_e_mult() or 1
local edition_e_mult = context.other_card.edition.e_mult or 1
local e_chips = context.other_card:get_chip_e_bonus() or 1
local edition_e_chips = context.other_card.edition.e_chips or 1
local text = G.FUNCS.get_poker_hand_info(G.play.cards)
...
formating did nothing, the code didn't change lmao
because context.other_card.edition doesnt exist if the card doesnt have an edition i think
code doesnt change but indentation should change
makes it better readable
so should i add like,
if context.other_card.edition =! nil then to all of the edition parts?
you can just say "if context.other_card.edition", nil is treated as false and nearly anything else as true
No, it should be ((context.other_card.edition or {}).chips or 0)
I can't see the diffrence, and i tried those two buttons
it refused, my IQ is lowering after each crash
you're always returning no matter what at the blueprint effect, so i think the game doesn't like that you have more code after it
but if i add an end it closes the calculate
blueprint doesn't wrk,,,
placeholder art but it finally works as intended !!!
I've got this to add all played poker hands to a table, so how can I cycle through and upgrade all poker hands not in the table?
if context.before and context.main_eval and not context.blueprint then
card.ability.extra.scored_hands[#card.ability.extra.scored_hands+1] = context.scoring_hand
end
Ngl placeholder goes hard
how can i tell how many cards are being destroyed in context.destroy_cards (or context.destroying_cards if that's the right context)?
destroy_card is to destroy, remove_playing_cards is when they're destroyed
#context.removed would be the number
Is there a way to make the enhancement appear after the cards are raised in a way that scores the enhancement?
left is scoring, right is unscoring
in that case can i also check context.scoring_hand to see whether or not it was a discard?
his name is jacques and he is a delightful little (big) rat
Oki, ty! (I'll try it and if it doesn't work I'll be back later)
note that having any card state change on an event, like enhancements or editions, will not apply it retroactively to the scoring
that being said what's your call to card:set_edition looking like
I did a fix already, but thanks
ah good
instead of doing v:set_edition() inside of the event, i just v:juice_up() and it worked out fine
apologies for the late reply, got caught up in something
how do i use the my_pos from here? this is what i made so far, but it doesn't work
for k, v in pairs(G.hand.highlighted) do
local my_pos
for i=1, #G.hand.cards do
if G.hand.cards[i] == v then
my_pos = i
end
end
end
for i=1, #G.hand.cards do
if G.hand.cards[i] <= my_pos then
G.hand.cards.to_be_removed_by = card
end
end
how do i get a poker hand's name from its key?
can someone explain to me what 'G.SHADERS['CRT']:send('noise_fac',0.001*G.SETTINGS.GRAPHICS.crt/100)' does exactly in game.lua
this dude is iterating through every card in the deck for count for some reason, which i dont want it to do
config = { extra = { count = 0 }},
...
--in the calculate function
if context.end_of_round and not context.repetition and context.individual then
card.ability.extra.count = card.ability.extra.count + 1
end
localize(key, 'poker_hands')
what is the goal
it's the crt shader i think
it applies the crt effect based on your settings
i want to check later if count == 'certain value'
i want it to happen after idk 3 rounds lets say
however since it iterates over all the 52 cards in the deck the goal is met instantly
this line specifically sends a variable called noise_fac to the CRT shader (you can find the shader from extracting the balatro exe file and going to resources/shaders/CRT.fs)
do if context.end_of_round and context.main_eval and not context.blueprint
gotcha
@chrome widget , hey . do you have any idea how can i replace / draw on top of the existing background shader ?
any idea how to fix it
local _hand, _tally = "Straight Flush", to_big(-1) -- ty vanillaremade for giving me all this code
for _, handname in ipairs(G.handlist) do
if SMODS.is_poker_hand_visible(_hand) and to_big(G.GAME.hands[handname].played) > to_big(_tally) then
_hand = handname
_tally = to_big(G.GAME.hands[handname].played)
end
end
``` why does this crash with custom poker hands (aikoshen)
Depends on what you need to do, though it's probably possible to patch the general drawing behavior in game.lua. for example I have a shader that I draw overtop the CRT shader for the entire screen. Depending on where you patch that should be easy enough?
try disabling talisman
I don't understand why this is crashing, by my understanding it should make a playing card with a random suit, rank and have the chance at a random enhancement
still crash
old version of steamodded
update to 0711a
is this a mod you made
sigh if i must
yup with joker forge
ask in the joker forge thread then in #1209506514763522108
ok ty
bump
what is the crash
this one was from a slightly older version that passed the localized name into SMODS.is_poker_hand_visible
they both crash though
why would is_poker_hand_visible not take the localized name who designed this
it just decided to randomly fix itself never mind
glad to hear
most balanced cryptid joker
also in your code you want to pass handname instead of _hand to is_poker_hand_visible
Updated and the error changed
you want only the key, so do pseudorandom_element(what you have).key for both rank and suit
hey quick question: how do i use pseudorandom_probability? I've used the exact same setup as all my other jokers but for some reason im either really lucky hitting literally a 1 in 625 or somethings wrong.
SMODS.pseudorandom_probability(card, 'j_mod_myjoker', card.ability.extra.chance_min, card.ability.extra.chance_max) (chance_min and max are defined and showing up in loc_vars)
Have you tried printing those values?
hello, anyone knows how to play music like when the custom joker is (on the jokers area) and enterin a round the music / theme plays and when the round ends it stops?
It works now, tysm!
Should I let the mult be a decimal or round it to be more vanilla?
if u want it to feel more vanilla then round it
i'd suggest rounding up
or down, do whatever
Rounding up is a good idea
is there a way to modify the cards in a booster pack after they're already generated? like, adding a specific seal to all the cards that didn't already have a seal, for instance
what's 'Tarot_Planet'?
-# can't belive i don't know this after 4 months-
it picks a tarot or planet
oh, that makes sense
i will add a note
would anyone happen to know if removing cards can work when a hand is played?
how do i fetch a joker name from a key?
gotcha
before it's scored?
you can destroy the card in context.press_play
do i keep type = "name_text" or do i have to change it
i actually didnt know this, this is a kinda cool effect
keep it
gotcha
so context.press_play might be interfering with next(context.poker_hands["Three of a Kind"])
when you play a three of a kind, with the first card (scoring or not) being a 7
gain $7 and destroy that card
oh, so you dont need the card to be destroyed before scoring then?
i suppose
use context.destroy_card and return { remove = true }
and?
earlier a few times and it did nothing as far as i remember
show me the code then
only worked with context.discard
fyi i did make a few changes before i did the context.destroy_card thing
idk if it made a difference
calculate = function(self, card, context)
local condition = false
if context.before and next(context.poker_hands["Three of a Kind"]) then
for i = 1, #G.play.cards do
if i == 1 and G.play.cards[i].base.id == 7 then
condition = true
end
end
if condition then
ease_dollars(7)
return {
message = localize("$").."7",
colour = G.C.MONEY,
remove = true
}
end
end
end
let me write how it would be for you
alr
calculate = function(self, card, context)
if context.destroy_card and next(context.poker_hands["Three of a Kind"])
and context.destroy_card == context.full_hand[1] and context.destroy_card:get_id() == 7 then
return {
dollars = 7,
remove = true
}
end
end,
should i paste that in and see what happens with it?
yes
Bump
i dont think it did anything
SMODS.Joker {
key = "GG_777",
atlas = "atlasholders",
pos = {x = 1, y = 0},
rarity = 2,
cost = 7,
loc_txt = {
name = "777",
text = {
"If the played hand is a {C:attention}Three Of A Kind{},",
"and the first card is a {C:attention}7{} {C:inactive}(Scored or not){},",
"destroy that card and gain {C:money}$7{}."
}
},
calculate = function(self, card, context)
if context.destroy_card and context.cardarea == G.play and next(context.poker_hands["Three of a Kind"])
and context.destroy_card == context.full_hand[1] and context.destroy_card:get_id() == 7 then
return {
dollars = 7,
remove = true
}
end
end,
--[[calculate = function(self, card, context)
if context.before and next(context.poker_hands["Three of a Kind"]) then
for i = 1, #G.play.cards do
if i == 1 and G.play.cards[i].base.id == 7 then
ease_dollars(7)
return {
message = localize("$").."7",
colour = G.C.MONEY,
remove = true
}
end
end
end
end]]
}
i commented out my old one and used your one instead
oh oops i see the problem haha
its alright
it works which is a plus
just curious if i can move it before scoring?
like when it happens
yeah but its a bit more complicated because you need to evaluate the poker hand manually, also it will change the poker hand so it might be a bit punishing (if a flush with a 3oak is played and the 7 is destroyed it wont count as a flush anymore)
I understand some parts of patching now, but how can I find the target and pattern I want to patch?
the target is the line(s) in the code you want to patch before/at/after and the pattern is what you want to add to/replace it for
Aahhhh, oki
Hello, I am trying to make it so that for each blind selected, this moss card creates another moss card.
bump
in calculate make it so that in context.setting_blind you use SMODS.add_card() to create a new card with the same enhancement
-# i am pretty sure this is correct, if someone smarter comes along then take their advice instead
is there a way to affect the joker's scaling
looking at the scalae code, brain hurt
hook to Game:update, check for value changes and multiply the difference
thats how i did it for stacked
it will only affect jokers right
mhm
:3
your mod blows btw
like, 99182 crashes specifically?
mhm
hi bepis
ic
just did 3 smods prs tho
dont worry
im used to hooking
i love hookers
im giving you the silent treatment nxkoo
bump
bump
D:
how do i get a random number, being 1 or 2
im trying to look at the info thing for math.random() but its confusing
pseudorandom(pseudoseed('farts'), 1, 2)
best seed
Hello guys, im really losing it with this, idk why is stack overflowing, and its not the getjokerid, its the "if G.jokers" line, can someone illuminate me please?
ty
Error screen if it helps
whats getJokerID??
to this
function getJokerID(card) --Stolen from Yahiamice Mod
if G.jokers then
local _selfid = 0
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then _selfid = i end
end
return _selfid
end
end
I'm very new at modding balatro, so im just making a bunch of random stuff to learn how does the enviroment work
Should i store it in locals then?
Its supposed to force trigger a joker from its sides
why do you need to store jokers then?
does force trigger need to do that
but now that you say it
that sounds weird
can you not just get the placement of the joker and toss that in there
-# for context, ive never checked how cryptid's force trigger works

itd make sense
Exactly, that's what i was about to say ahahaha
I have broken that thrice now lmfao
u hate me because im right!
I could save the placement instead of the card itself
According to cryptid, just card and context as args
pretty sure you could just replace card with the location
mhm
or use that as i mean
I dont want to touch the og cryptid code, so ill just store the number placement and call it with G.jokers.cards[id]
instead of saving it
does Cryptid.forcetrigger return a table?
if so, you want to use SMODS.merge_effects too
I think it does but its related to vanilla compatibility effects
what's merge effects?
local id = getJokerID(card)
if id then
local ret1 = G.jokers and G.jokers.cards[id+1] and Cryptid.forcetrigger(G.jokers.cards[id+1], context) or {}
local ret2 = G.jokers and G.jokers.cards[id-1] and Cryptid.forcetrigger(G.jokers.cards[id-1], context) or {}
return SMODS.merge_effects({ret1, ret2})
end
either that or
just Cryptid.force_trigger on the adjacent jokers without returning anything
idk
@manic rune this is just for you
good job nxkoo
ghh
if theres 2 or more return tables then u want to use SMODS.merge_effects to combine them
rq can u copy the whole code of the function over here
I think imma test it tomorrow, its quite late here, i'll do some tests with it tho
if i do G.money = G.money - 5
will it just do what i think
because i dont remember if thats how that works it probably is but i feel like i have to ask sry
ease_dollars(-5)
Not really since its not a retrigger
and its G.GAME.dollars for the value
-# changing it directly wont give you the animation
ty
Is there an example of a modded joker that upgrades multiple hands at once somewhere?
Think it like
a card that forces a perkeo at its side without fulfilling its context requirements
i can call ease_dollars() outside of a return riht
mhm
ok just making sure
Cryptid mod, theres planet cards that does that
shrug
how do i get a random poker hand