#💻・modding-dev
1 messages · Page 639 of 1
yes like i said
you dont need to wait for loading though
afaik the metadata file values are all immediately set
i just wasn't sure about when the grads were initialized
yes but theres two senses of initialized isn't there
which are?
for some things no
well at least
the object that gets returned from any of the functions
is the same as what gets injected
okay so good news, it IS gradient-ing\
but it also seems like one of the colors its going to is invisible
or like 0 alpha
oh thats funny
yeah because
the second colour you put has an alpha of 01
and the first one has an alpha of 06
ngl just remove the alpha
its just gonna look weird
additional note: these are basically the same except that Game.update is called with self and dt, self being G while love.update is just called with dt
for your future reference
awesome it works! thank you so much!!
could anyone guide me on how to put rental jokers in a custom challenge i'm making? ctrl-f'ing it in this server doesnt help me much, other than the fact that "patching it in is easy"
how do you draw a seperate sprite underneath a joker card? i have a specific visual i want for my eldritch joker where it has sprawing veins reaching to the left when there's jokers left of it
the veins would probably just be a single sprite drawn below the eldritch joker, but preferably ABOVE other nearby jokers. is any of this possible?
do you know how to patch
stickers = {'rental'}
is that a new thing
i dont have it in my phone dump but it's like 4 smods versions old
do you actually check smods code on your phone
Oh. That's gore of my comfort Joker...
where would i put it
@narrow pendant are you the programmer for your mod? i wanna figure out how to do that soul drawsprite effect
I am, but i'm not an adept programmer
neither am i haha
the mod would probably be done if i was
this section here is all it needs for the base soul
Again, don't take my word with any weight
this is probably outdated as hell
seems like the only thing you'd prob wanna change is moving the loc_text variables to a proper localization file
everything else seems good, though!
no btw 😭 if you have any resources id be glad, i cant find anything about patching on the smod page (maybe im just dumb)
oh wait i think i figured it out, its a lovely thing right
yes
there's also my wiki
https://github.com/nh6574/VanillaRemade/wiki#whats-a-patch
it is possible but you will need to do a lot of shader drawing manually using SMODS.DrawSteps
or the draw function
dang, really?
i dont kknow how to do any of that lolll
is there anything abt that on the wiki?
not really other than the basic structure, I would look into card_draw.lua in the smods repo
thanks!! in the end i just figured it out by looking at another mod's code. unrelated, but would you by chance know if there's an easy way to make a food joker eternal?
card:add_sticker("eternal", true) should work i think
or SMODS.add_card { key = "j_key", force_stickers = { "eternal" } }
would this restrict the effect to the specific challenge im making? if yes, where would i need to put it?
you can add this in an event inside the apply function like this
but the problem is that it won't show up in the challenge description and you would need to patch the function that does that
ill try later, thank you so much
Is there a way to check if a calculate function affected any cards?
what is the goal?
Working on a consumable that is supposed to "revive" (gives +1 Hand) the player if they run out of hands and have yet to meet the chip requirement
Right now, I just have a G.GAME variable doing the check for me, but I wanted to see if it was possible to do something like how Mr. Bones saves the player
if you want to recreate the Mr Bones effect you can just replicate vanillaremade Mr Bones but in a mod calculate
but how is checking if something affected a card relevant to this exactly
I thought it would be if I wanted to make sure multiple consumables did not trigger, but I have a check for that already
😭 it's still sellable for some reason
where do you put SMODS.DrawStep in?
thanks
(not nested into anything)
dang it i was too late, i was gonna say thanks in response to this lmfao
but actually thank you
eternal incompatible jokers bypass the eternal effect, so you need to hook SMODS.is_eternal iirc
whats the cleanest way to undo a take ownership effect thats tied to a joker? my idea is to call two separate take ownership functions from add_to_deck and remove_from_deck, but i assume there's a better way to do it
dont take ownership during runtime
just take ownership once and check if you have the joker in the functions in it
ahh, yeah that makes way more sense, thanks
would it be possible to make a joker that has a different appearance every time it is seen? I want one of my jokers to have 1 of 7 possible appearances (all share the same effect)
I'm trying to play a video file but video:play() doesn't seem to work
how do i check for specific mods to make mod compat?
actually wait
i know the function i just dunno how i'd go about it
if next(SMODS.find_mod("mod_id")) then (do stuff) end
find_mod works pretty much the same as find_card
you can also set specific objects to have mod dependencies, which works the same and additionally adds the other mod badge to the card right below your own mod badge
thx
as for why, i wanted to make sure this joker gets added to the "cat" pool that Yahimod has, even tho that mod don't got any of it's own cross-mod compatability
i think there's an "add to pool" smods function
ah I see
I'm not actually sure there's any harm in just assigning a joker to a pool that doesn't exist though, so you technically shouldn't even need the check
No, just do pools = {['Cat'] = true}
When I play a video file with love.graphics.draw it works fine (unsure why it's purple tho) but on subsequent triggers is just doesn't display anymore and it just rendered as a transparent black square
function SMODS.Mods.FMod.play_video(name)
local path = SMODS.Mods.FMod.path.."assets/videos/" .. name .. ".ogv"
local file = NFS.read(path)
love.filesystem.write(name..".ogv", file)
fmod_video = love.graphics.newVideo(name..".ogv")
fmod_video:play()
end
loveUpdateHook = love.update
function love.update(dt)
loveUpdateHook(dt)
if fmod_video and not fmod_video:isPlaying() then
fmod_video:release()
fmod_video = nil
G.SETTINGS.SOUND.volume = G.fmod_game_volume
end
end
loveDrawHook = love.draw
function love.draw()
loveDrawHook()
if fmod_video then
local xScale = love.graphics.getWidth() / 1920
local yScale = love.graphics.getHeight() / 1080
--local xScale = love.graphics.getWidth() / fmod_video:getWidth()
--local yScale = love.graphics.getHeight() / fmod_video:getHeight()
love.graphics.draw(fmod_video, 0, 0, 0, xScale, yScale)
end
why is he there
This is the entire video playing code (That I stole from someone else's implementation in this chat)
This shouldn't cause any big issues though
I'm still wondering about this because I can't think of a way to do it myself
how do i draw extra sprites on top or behind of a joker card? i dont even know what to use or where to begin 😭
How do I make a deck start with a specific joker?
ive been trying to look through like, drawstep and stuff but i dont understand any of it
in set_sprites you can do card.children.center:set_sprite_pos({x=num, y= num}) to change the sprite
I know how to make a joker change sprite, I want a joker that can have 1 of 7 possible sprites when it spawns, I don't want it to change after it spawns
in config have jokers = { "j_modprefix_key" }
Thanks, I jkust typed in the key incorrectly 😭
Syntax is my #1 opp
in >>>>>>set_sprites<<<<<<< you can do card.children.center:set_sprite_pos({x=num, y= num}) to change the sprite
im not really sure how to do behind, i know it's possible but i would need to test it and i cant rn
for the front you can check The Soul on vanillaremade
but it basically boils down to the order of the draw_shader determines which sprite is in front
maybe i could test it out for you! where do i start?
gang am i seriously thinking about modifying the string metatable
no i would need to some searching i dont want to do unless i can check myself
unfortunate
@zealous glen might know
Now why is Canio's key mispelled

update on the woker
this is a lot of checks and the woker is unfortunately not woking
i mean working
key = "woker",
loc_txt = { name = 'The Woker',
text = { 'Retrigger all other',
'Polychrome Jokers'}
},
pos = { x = 3, y = 5 },
atlas = 'woker',
blueprint_compat = true,
rarity = 3,
cost = 9,
config = { extra = { retriggers = 1 }, },
calculate = function(self, card, context)
if context.retrigger_joker_check and not context.retrigger_joker and context.other_card ~= self
then
if context.other_joker
and context.other_joker.edition
and context.other_joker.edition.polychrome == true
and card ~= context.other_joker
then
return {
message = localize("k_again_ex"),
repetitions = to_number(
math.min(card.ability.extra.retriggers)
),
card = card,
}
else
return nil, true
end
end
end
}```
did you make sure to enable the joker retrigger optional feature
yea
from the vanillaremade wiki:
ohhhh missed that
im assuming that goes in metadata
no, just in your main lua file
ah alrighty
update i added in the retrigger_joker feature
woker is still not woking D:
from what i think i know
if context.retrigger_joker_check and not context.retrigger_joker and context.other_card ~= self
this part is the basic retrigger other jokers check
and this
and context.other_joker.edition
and context.other_joker.edition.polychrome == true
and card ~= context.other_joker```
is the check Stardust from Cryptid uses for checking if a joker is polychrome
not sure which one of the two is wrong
or if its somethin else
other_joker should be other_card always
also other_card ~= self is always true
i don't think not context.retrigger_joker is necessary either
alright i got it working!
adding those three things got it to do at least something (crash)
the problem was
math.min(card.ability.extra.retriggers)
),```
this shouldve just been
```repetitions = (card.ability.extra.retriggers),```
I couldn't get figure out how to get a joker to have a random sprite every time it loads, but apparently just putting a random number range in the atlas position works?!
it only does it every time the game loads but that's cool in its own right
never would have expected that to work like that
yeah you are creating the objects every time the game launches
it does make sense if you think about it but it's just something I didn't expect would work properly
I like this new effect more actually
less work mostly
How do you change the title sprite of the game?
Better question: can I remove the card from the title screen?
G.title_top.cards[1]:remove()
Does this line go anywhere in particular
Yes, in a Game:main_menu hook.
where was it that i can ask questions about modding balatro? here or in the chat room?
i currently need help modding balatro. game keeps crashing and i cannot pinpoint exactly where its breaking
line 12 doesnt need a }
probably means you placed one too many curly brackets
Anyone know an easy way to make a joker’s functionality only work once if there are multiple copies of it?
Not a blueprint/brainstorm situation I know how to deal with that, but specifically if there’s two or more of the same joker
This could also be something that requires more context potentially but I thought there might be something simple I just don’t know about
im not sure. i am spending more than 2 weeks on one joker
Average development time for +4 mult Jimbo
thats what it feels like
its my first time modding and everything is going awry
used Joker Forge but it only does so much
Definitely show us the file if you don't mind
it only had one joker. I started this like 3 weeks ago
forgot the comma after " pools = {["adofaicurses"] = true}"
forgot the ) after the joker definition (on the last line)
forgot the comma after you finish the loc_txt def
and probably more
Wrote my code smarter and the joker no longer cares about having duplicates
still having the same error
well yeah
probably
i don't actually know what line 12 is
your code is just riddled with problems lmao
loc_txt = {
also disregard the second thing i said
yes
text should be in {} and not ()
forgot a comma after "name = 'Core Curse'"
Have you taken a look at VanillaRemade by any chance?
Definitely do, it's Vanilla rebuilt from the ground up with the SMODS API to be an example for new modders to reference
i will tomorrow.
promise
but like
it was working earlier before i added the name and text lines to the code
it just crashed when trying to load the sprite
maybe i should leave the joker description-less
its giving me a ')' expected near ',' error
balatro modding sucks
im removing the line
it works fine without the line (?)
it just has no name and no description
that doesnt sound fine
it uh
it isnt doing anything
help
what did i do wrong? is the code skipping something?
so remove the entirety of line 26 or just context.joker_main?
wait its sometimes working
no the context.cardarea == G.jokers
you do have a 1 in 4 probability in there
ohhhh
wait apparently joker_main does have a cardarea argument? dont really need it here anyways though
uhhhh i might need some elaboration
on what part
cardarea arguments
the joker_main context DOES have cardarea in its context table
but unless a mod specifically patches it itll always be equal to G.jokers
so the check isnt needed
okay so then remove the check?
yes
other things to remove: the if true then and its corresponding end
and since the description doesnt mention probabilities remove the SMODS.pseudorandom_probability and its corresponding end so that it isnt a 1 in 4
i used Joker Forge. im not that experience with writing code. i'll copy the new script and put it in the old one
i also see that Joker Forge has a different way of setting up the description and name of jokers
disregard the description, didnt care to rewrite it
the [1] and [2] are not necessary
yeah theres literally no benefit to doing it this way
i doubt its easier to generate either honestly
maybe im wrong though
well it crashes when i did it the other way
my joker stopped working
how do i add sell value to a joker?
vanillaremade gift card should have the info you need
Every context should have a cardarea argument but it is almost entirely useless on most effects
Oh yeah wondering about some opinions on UX here:
When you open up a palette, the swatches on the right select palette colors and the controls below change the palette color
However, I've added the ability for any one card to override the primary palette color. Currently this is denoted by a purple background to show that a card is overriding the currently selected palette color. Right clicking a card toggles whether it uses the override, and left clicking selects whether you edit one card's override or the main color (which highlights it like a normal card)
Idk if this explanation makes any sense without being able to physically use the thing but control wise I'm not keen on the left clik right clock thing? Or how specifically it's denoting/switching between main and override colors
maybe it should be a checkbox
Is it possible to grab and store a specific consumable when it is created in an event
want to link a consumable to the joker that creates it and have the joker change/destroy the consumable
hey ive been trying to get this to work for like 2 hrs and i just cant figure it out
the "marked" text seems to always show up at the begining of scoring.
sorry the code is so messy its like 3am and my first time writing in lua and for balatro
key = "black_spot",
loc_txt = {
name = "Black Spot",
text = {
"After scoring,",
"{C:green}#1# out of #2#{} chance to",
"destroy all played cards",
"(Triggers the marked text",
"twice due to a bug)"
}
},
rarity = 3,
cost = 6,
atlas = "ModdedVanilla",
pos = {x = 0, y = 0},
loc_vars = function(self, info_queue, card)
local chance = 0.4 -- 40% chance
return { vars = { math.floor(chance * 10), 10 } }
end,
calculate = function(self, card, context)
if context.scoring_hand and context.cardarea == G.play then
if context._black_spot_done == nil then
local chance = 0.4
local roll = pseudorandom('black_spot')
context._black_spot_done = roll < chance
context._black_spot_message_shown = false
-- Save hand to be destroyed
if context._black_spot_done then
context._black_spot_hand = {}
for i, c in ipairs(context.scoring_hand) do
context._black_spot_hand[i] = c
end
end
end
if context._black_spot_done and not context._black_spot_message_shown then
card_eval_status_text(
card,
'extra',
nil,
nil,
nil,
{ message = "Marked", colour = {0,0,0,1} }
)
context._black_spot_message_shown = true
end
end
end,
on_score_end = function(self, context)
if context._black_spot_done and context._black_spot_hand then
SMODS.destroy_cards(context._black_spot_hand)
end
end
}```
You need a better context check, context.scoring_hand and context.cardarea == G.play exists in multiple calc calls, when do you want it to trigger?
If you want it to trigger like a normal Joker add context.joker_main
Is there any way to modify already scored chips?
For example make boss that "regenerates health"
Yes, ease_chips(number)
Not sure how frequently this is asked, i tried making my own gradient and use it in text, but its only showing 1 color instead of a gradient. I'm using SMODS and the vanilla attention_text:
G.C.cry2_rainbow = SMODS.Gradient {
key = 'cry2_rainbow',
colours = {
HEX('fe5f55'), -- red
HEX('fda200'), -- orange
HEX('f3b958'), -- gold
HEX('4BC292'), -- green
HEX('009dff'), -- blue
HEX('8867a5'), -- purple
},
cycle = 2,
interpolation = 'trig',
}
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.3,
func = function()
attention_text({
text = "Sorry, no rewards for U",
scale = 1,
hold = 3,
major = G.ROOM_ATTACH,
backdrop_colour = G.C.BLACK,
align = 'cm',
colour = G.C.cry2_rainbow
})
return true
end
}))
Is there another text function for gradients? I genuinely can't figure out this one
Oh wow thank you, I was sure there isn't a way
iirc attention text copies the color so gradients pause on whatever the color was at the time but i might be wrong
does someone know how to fix this issue? i am trying to make it so when a card with an edition is used the edition gets added to the level. but the issue i am walking into is that the text (like in the screenshot) sticks until it is updated again by something else
local use_consumeable_ref = Card.use_consumeable
function Card:use_consumeable(area, copier)
-- Check if this is a planet card with an edition
if self.ability and self.ability.set == "Planet" and self.edition then
local planet_card = self
-- Trigger edition effect with visual feedback (queued after the planet animation)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.8,
func = function()
-- Apply edition bonuses to the hand being leveled
local hand_key = planet_card.ability.consumeable and planet_card.ability.consumeable.hand_type
if hand_key and G.GAME.hands[hand_key] then
-- Base game editions
if planet_card.edition.foil then
-- Foil: +50 base chips to the hand (permanent, survives level-ups)
play_sound('chips1')
G.GAME.hands[hand_key].s_chips = G.GAME.hands[hand_key].s_chips + 50
-- Recalculate current chips based on new base
G.GAME.hands[hand_key].chips = G.GAME.hands[hand_key].s_chips +
(G.GAME.hands[hand_key].level - 1) * G.GAME.hands[hand_key].l_chips
update_hand_text({ sound = 'chips1', volume = 0.6, pitch = 0.9, delay = 0 }, {
chips = G.GAME.hands[hand_key].chips,
chip_addl = 50,
StatusText = true
})
-- Shake the hand display
if G.hand_text_area then
G.hand_text_area.handname.config.object:pulse(0.2)
if G.hand_text_area.hand_level then G.hand_text_area.hand_level:juice_up() end
end```
You can use the new SMODS.upgrade_poker_hands to do this
do you have documentation for this? cus i dont see it in the wiki
It’s in the latest release discussion
So there is none, i ended up making my own implementation, im sleepy, its not well implemented, but it works
Is there a way to access a card in played hand by index? Like say I'm playing a hand and want to check specifically the 3rd played card
context.full_hand[3]
Thank you very much.
How do people make those xmults for chips and money?
Return xchips = number and dollars = G.GAME.dollars*(number-1)
So it's a function built into the game? Figured it be something that would require a separate mod
its built in in smods
That's all I needed thx
Is there some kind of resource with vanilla booster pack weights
Or do I have to dig those out
vanillaremade
Oh
Wanted to come back and say thank you, quickest and most helpful response I've ever gotten here
what is the best way to implement custom cards?
wdym by custom card
specifically i'm recreating the honor tiles from mahjong
so they would have their own unique suit and rank which I have the documentation for
but for the card object itself not quite sure on how to do
there's a lot of resources of making jokers but not many for cards themselves
*playing cards
I don't think there's a way to do specific rank/suit combinations or playing cards with effects using smods api
it was planned at some point
you can add the rank and suit and then restrict them to a custom deck
I'll start with that
what's the goal with the tiles
I have the custom pokerhands for mahjong hands now, I just need to actually implement honor tiles for some of the other hands
and here's the absolutely cursed mahjong deck so far
Hi everyone! I need help with a mod, as I'm a complete newbie. I added three new Jokers to the game, added their textures to the atlas with the other Jokers, and everything worked fine on my PC. Afterwards, I decided to send the mod (copied the contents of the game folder from Steam and pasted it into another folder) as a zip archive. On a friend's computer, the Jokers had no textures. What could it be? Should I attach any more screenshots?
i did something similar with hanafudas but i just made them enhancements instead
a screenshot of the files you sent would be helpful
idk how I want to divide the ranks and suits rn
I could make each wind and dragon it's own rank and then they can cycle through each other in their categories with next which sounds fun
then just make all the honor tiles in the Honor suit
can I throw custom local variables in SMODS.Rank or will it crash the game?
I could just pick out all the individual cards in checking later but it would be convenient to go honor = true right below the face variable in the object
they will get saved to all cards with the same rank and not be kept on reload
but if its something you need to define once then yes you can add whatever
key = 'North',
card_key = 'N',
pos = {},
nominal = 10,
face_nominal = 0.1,
face = true,
honor = true,
shorthand = 'N',
next = {'East'}
}
SMODS.Rank {
key = 'East',
card_key = 'E',
pos = {},
nominal = 10,
face_nominal = 0.1,
face = true,
honor = true,
shorthand = 'E',
next = {'South'}
}
SMODS.Rank {
key = 'South',
card_key = 'S',
pos = {},
nominal = 10,
face_nominal = 0.1,
face = true,
honor = true,
shorthand = 'S',
next = {'West'}
}
SMODS.Rank {
key = 'West',
card_key = 'W',
pos = {},
nominal = 10,
face_nominal = 0.1,
face = true,
honor = true,
shorthand = 'W',
next = {'North'}
}```
i would recommend adding the modprefix to the key
ranks.lua rn
mods, break this guy's glass cards
now it's a matter of having at least blank image files so the game doesn't crash on loading
not sure how the images are referenced to the ranks/suits I have but I can send the crash log at least to debug
This atlas is designed for playing without pixel art anti-aliasing, which I warned a friend about, but it didn't help.
youre missing the x pos i think
yep the tables were just empty
oh, sorry no idea how modifying the exe works and its not recommended
How do you suggest I continue making mods without editing .exe? Are there any programs or something like that for easier game modification?
lmaoooooo
thanks!
SMODS.Back {
key = "mahjong_red",
pos = { x = 0, y = 0 },
config = { discards = 1, hand_size = 10, ante_scaling = 4},
loc_vars = function(self, info_queue, back)
return { vars = { self.config.discards, self.config.hand_size, self.config.ante_scaling} }
end,
apply = function(self, back)
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_play_limit(9)
SMODS.change_discard_limit(9)
return true
end
}))
local suits = {'S','C','D','H'}
local ranks = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'}
local winds = {'E','S','We','N'}
local dragons = {'R','G','Wh'}
for i=1,3 do
for _, suit in ipairs(suits) do
for _, rank in ipairs(ranks) do
G.E_MANAGER:add_event(Event({
func = function()
local card = SMODS.add_card({set = 'Base', area = G.deck, suit = suit, rank = rank})
return true
end
}))
end
end
end
for j=1,4 do
for _, wind in ipairs(winds) do
G.E_MANAGER:add_event(Event({
func = function()
local card = SMODS.add_card({set = 'Base', area = G.deck, suit = 'Winds', rank = wind})
return true
end
}))
end
for _, dragon in ipairs(dragons) do
G.E_MANAGER:add_event(Event({
func = function()
local card = SMODS.add_card({set = 'Base', area = G.deck, suit = 'Dragons', rank = dragon})
return true
end
}))
end
end
end
}```
in theory it should be pulling just from the table in the local variables but it seems to check every rank and suit when constructing the deck
that seems like it would break every normal deck in the game though
or use in_pool to not add them
no?
in you deck i mean
hold on let me check something
yep those suits are part of the base set not just this back
need to exclude the new suits and ranks from the default pool
that would make them show up in boosters on that deck too
if that's what you want then yes
you wouldn't happen to know which variable that is by name right
checking through vanillaremade rn for anything close
key = 'North',
card_key = 'N',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'N',
next = {'East'},
in_pool = function(self, args)
return G.GAME.selected_back == 'bm_mahjong_red'
end
}```
something like this?
deck.effect.center.key crashes the game
unless I don't need the deck reference 1 second
G.GAME.selected_back.effect.center.key
and do I need my mod prefix for the back key
if i have an object that extends SMODS.Voucher, how would i go about allowing it to use the Card.redeem() function? trying to use it gives me a crash that the object doesnt have the function, but i cant seem to find a place in the code where vouchers are given this function
is this to say it doesnt get used while under smods...?
it does
i have already lovely patched it to look for my object type too
what's the error specifically? redeem is nil?
yeah
can i see the whole log and the code
oh, you are calling the redeem function without it having one
smods checks if the voucher has one
also i think that's not how select_card should be used
makes sense, but i still dont know how i would give it the redeem function
i tried adding redeem = Card.redeem into the object definition but it didnt help
still crashes
hmm
ok i see the problem
card is the booster
for some reason
just tried pack and got no crash
ahhhh
got it, thanks N'
thank you for the help N, i really appreciate it!
Hello, im trying to make a joker that gives chips for every different enhancement and edition in your deck,
I tried this...
local diff_editions = 0
local list_different_editions = {}
local diff_enhancements = 0
local list_different_enhancements = {}
local is_unique = true
if G.playing_cards then
for _, playing_card in ipairs(G.playing_cards) do
is_unique = true
for _, i in ipairs(list_different_enhancements) do
if i == SMODS.get_enhancements(playing_card, false)[1] then
is_unique = false
end
end
if is_unique then
diff_enhancements = diff_enhancements + 1
list_different_enhancements[diff_enhancements] = SMODS.get_enhancements(playing_card, false)[1]
end
is_unique = true
for _, i in ipairs(list_different_editions) do
if i == playing_card:get_edition() then
is_unique = false
end
end
if is_unique then
diff_editions = diff_editions + 1
list_different_editions[diff_editions] = playing_card:get_edition()
end
end
end
But it gives out 1560 chips, as if all cards had a different enhancement and a different edition.
Does anyone know why?
thank you N!!
get_enhancements returns a table of { m_prefix_key = true, m_prefix_key2 = true, etc... } iirc
game crashes when selecting cards from the new suits or ranks
probably has to do with interacting with the default straights in a bad way
How'd you define your rank
SMODS.Rank {
key = 'North',
card_key = 'N',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'N',
next = {'East'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Rank {
key = 'East',
card_key = 'E',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'E',
next = {'South'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Rank {
key = 'South',
card_key = 'S',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'S',
next = {'West'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Rank {
key = 'West',
card_key = 'We',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'We',
next = {'North'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
-- Dragons
SMODS.Rank {
key = 'Red',
card_key = 'R',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'R',
next = {'Green'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Rank {
key = 'Green',
card_key = 'G',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'G',
next = {'White'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Rank {
key = 'White',
card_key = 'Wh',
pos = {x = 0, y = 0},
nominal = 10,
bm_honor = true,
shorthand = 'Wh',
next = {'Red'},
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}```
inside the next table of each one you need to add your mod prefix before the rank key
should next be bm_next?
so modprefix_Red
lmao almost the same time
there's also a game crash on the main menu when it tries to render one of the new cards I think
what's your suits in pool function look like
key = 'Winds',
card_key = 'Wi',
pos = {x = 0, y = 0},
ui_pos = {x=0,y=0},
keep_base_colors = true,
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}
SMODS.Suit {
key = 'Dragons',
card_key = 'D',
pos = {x = 0, y = 0},
ui_pos = {x=0,y=0},
keep_base_colors = true,
in_pool = function(self, args)
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
}```
you need to check that G.GAME.selected_back exists first i guess
ur welcome
:D
can in_pool control the splash animation
it seems the args passed were, initial_deck = false and rank = 6
but i guess you can just check if there's no deck selected like it happened here
well this is weird
calling self.ability works without issue but then if you ask for self.ability.set it suddenly crashes and says ability is nil?
ok!
But then, why do I have the same issue with Editions?
A silly question but
Did anybody ever list vanilla jokers that use ability.extra for their xmult values
Haha
Hahahahaha
not that i know of but you can probably Ctrl+f the jokers table in card.lua
How do I overlap sounds?
I have
if context.press_play then play_sound(sound) delay(0.25) play_sound(sound) delay(0.25)
and it only plays sound 1 time
try putting the play_sounds in events
Guess I'll have to learn how to use events after all
get_edition is ironically not used to get an edition
use card.edition instead
ok
perfect
hm...
still gives +1560 mult (it's 15 per different edition and enhancement)...
where? I just want it to trigger at the begining of scorring
Maybe its a problem when detecting if the enhancement is unique?
what would the naming conventions for the correct 1x/2x texture files of my new cards be (assuming i'll just make a unique texture for each "correct" wind/dragon for now)
there aren't any afaik
you can name stuff whatever you like as long as 1x and 2x have the same name
same as the joker tutorial, seems easy enough
What if you add context.before?
It really feels like is_unique is never set to false
is_unique = true
for _, i in ipairs(list_different_editions) do
if i == playing_card.edition then
is_unique = false
end
end
if is_unique then
diff_editions = diff_editions + 1
list_different_editions[diff_editions] = playing_card.edition
end
.edition is also a table so it'll always be unique
playing_card.edition and i == playing_card.edition.key or something
let me try this
ok, edition seems to work!
I'll try to implement enhancements differently...
if you want to ignore quantum enhancements you can just check card.config.center.key
👍
where?
Along your scoring hand and g play check
now it doenst seem to be triggering at all
i feel like this code got overcomplex
Show your new code?
key = "black_spot",
loc_txt = {
name = "Black Spot",
text = {
"After scoring,",
"{C:green}#1# out of #2#{} chance to",
"destroy all played cards",
"(Triggers the marked text",
"twice due to a bug)"
}
},
rarity = 3,
cost = 6,
atlas = "ModdedVanilla",
pos = {x = 0, y = 0},
loc_vars = function(self, info_queue, card)
local chance = 0.4 -- 40% chance
return { vars = { math.floor(chance * 10), 10 } }
end,
calculate = function(self, card, context)
if context.scoring_hand and context.cardarea == G.play and context.before then
if context._black_spot_done == nil then
local chance = 0.4
local roll = pseudorandom('black_spot')
context._black_spot_done = roll < chance
context._black_spot_message_shown = false
-- Save hand to be destroyed
if context._black_spot_done then
context._black_spot_hand = {}
for i, c in ipairs(context.scoring_hand) do
context._black_spot_hand[i] = c
end
end
end
if context._black_spot_done and not context._black_spot_message_shown then
card_eval_status_text(
card,
'extra',
nil,
nil,
nil,
{ message = "Marked", colour = {0,0,0,1} }
)
context._black_spot_message_shown = true
end
end
end,
on_score_end = function(self, context)
if context._black_spot_done and context._black_spot_hand then
SMODS.destroy_cards(context._black_spot_hand)
end
end
}```
im gonna try this
if context._black_spot_done and context._black_spot_hand then
card_eval_status_text(
card,
'extra',
nil,
nil,
nil,
{ message = "Marked", colour = {0,0,0,1} }
)
SMODS.destroy_cards(context._black_spot_hand)
end
end
}```
Whats on_score_end? Are you using an API or its something you made?
It (almost) works like a charm! thanks N and srockw!
I feel like there's a simpler way to achieve what you want but I dont have my pc to help
Sorry
i do as well
im gonna revert to an earlier working version and mess around a but
ok heres the earliest working version i still have
key = "black_spot",
loc_txt = {
name = "Black Spot",
text = {
"After scoring,",
"{C:green}#1# out of #2#{} chance to",
"destroy all played cards",
"(Triggers the marked text",
"twice due to a bug)"
}
},
rarity = 3,
cost = 6,
atlas = "ModdedVanilla",
pos = {x = 0, y = 0},
loc_vars = function(self, info_queue, card)
return { vars = { 4, 10 } }
end,
-- this is really messy due to my attempts to fix the marked text showing up twice
calculate = function(self, card, context)
if context.scoring_hand and context.cardarea == G.play then
if context._black_spot_done == nil then
local chance = 0.4
local roll = pseudorandom('black_spot')
context._black_spot_done = roll < chance
context._black_spot_message_shown = false
-- Save hand to be destroyed
if context._black_spot_done then
context._black_spot_hand = {}
for i, c in ipairs(context.scoring_hand) do
context._black_spot_hand[i] = c
end
end
end
if context._black_spot_done and not context._black_spot_message_shown then
card_eval_status_text(
card,
'extra',
nil,
nil,
nil,
{ message = "Marked", colour = {0,0,0,1} }
)
context._black_spot_message_shown = true
end
end
end,
on_score_end = function(self, context)
if context._black_spot_done and context._black_spot_hand then
SMODS.destroy_cards(context._black_spot_hand)
end
end
}
ok i got rid of it and it works like this but still shows the message twice
if context.scoring_hand and context.cardarea == G.play then
if context._black_spot_done == nil then
local chance = 1
local roll = pseudorandom('black_spot')
context._black_spot_done = roll < chance
context._black_spot_message_shown = false
-- Save hand to be destroyed
if context._black_spot_done then
context._black_spot_hand = {}
for i, c in ipairs(context.scoring_hand) do
context._black_spot_hand[i] = c
end
end
end
if context._black_spot_done and not context._black_spot_message_shown and context._black_spot_hand then
card_eval_status_text(
card,
'extra',
nil,
nil,
nil,
{ message = "Marked", colour = {0,0,0,1} }
)
SMODS.destroy_cards(context._black_spot_hand)
context._black_spot_message_shown = true
end
end
end,```
i only want it to display the marked text the first time
My playing card isn't using the specified texture, do I need to affect the atlas elsewhere?
atlas = "bm_red",
key = 'Red',
card_key = 'R',
pos = {x = 0, y = 0},
nominal = 25,
bm_honor = true,
shorthand = 'R',
in_pool = function(self, args)
if G.GAME.selected_back then
return G.GAME.selected_back.effect.center.key == 'b_bm_mahjong_red'
end
end
}
SMODS.Atlas({
key = "bm_red",
path = "bm_red.png",
px = 71,
py = 95
})```
ok ive tried adding context.before context.after context.joker_main and not context,joker_main and still no dice. not context.joker_main worked but the marked message still showd twice
context.before and context.after do not work at all
not context.before works but triggers twice
not context.after doesnt work
Is there a guide for writing your mod description using a localization file?
not context.final_scoring_step works but still 2 messages
context.final_scoring_step doesnt work
what's the goal with the effect
i think you're overcomplicating it
let me write it
if context.after and SMODS.pseudorandom_probability(card, 2, 5, "seed") then
local cards = context.scoring_hand SMODS.destroy_cards(cards)
return {
message = "Marked!"
colour = {0,0,0,1}
}
end
something like that
hmm this might cause a problem let me fix it
sorry if the formatting is bad im on phone
where do i put this? what does this replace in my current code
which is here
all of it inside calculate
my calculate looks like this and it currently isnt working
if context.scoring_hand and context.cardarea == G.play then
if context._black_spot_done == nil then
local chance = 1
local roll = pseudorandom('black_spot')
context._black_spot_done = roll < chance
context._black_spot_message_shown = false
-- Save hand to be destroyed
if context._black_spot_done then
context._black_spot_hand = {}
for i, c in ipairs(context.scoring_hand) do
context._black_spot_hand[i] = c
end
end
end
--thanks N' and SDM_0 on discord for helping with this
if context.after and SMODS.pseudorandom_probability(card, 2, 5, "seed") then
local cards = context.scoring_hand SMODS.destroy_cards(cards)
return {
message = "Marked!",
colour = {0,0,0,1}
}
end
end
end,```
remove everything except my code
it crashed
upon scoring
key = "black_spot",
loc_txt = {
name = "Black Spot",
text = {
"After scoring,",
"{C:green}#1# out of #2#{} chance to",
"destroy all played cards",
"(Triggers the marked text",
"twice due to a bug)"
}
},
rarity = 3,
cost = 6,
atlas = "ModdedVanilla",
pos = { x = 0, y = 0 },
-- green text values
loc_vars = function(self, info_queue, card)
return { vars = { 4, 10 } }
end,
calculate = function(self, card, context)
-- thanks N' and SDM_0 on discord for helping with this
if context.after and SMODS.pseudorandom_probability(card, 2, 5, "seed") then
local cards = context.scoring_hand SMODS.destroy_cards(cards)
return {
message = "Marked!",
colour = {0, 0, 0, 1}
}
end
end
}```
Anyone know how to perform an action if a card is being destroyed? Context is a seal that triggers if the card is being destroyed
I was looking at context.destroy_card but I’m not sure that’s quite right
sorry it was SMODS.pseudorandom_probability(card, "seed", 2, 5)
is it a fixed 2 in 5 chance?
yes
nice
i was gonna say its a good idea to have the probability as a loc_var
a belated thank you very much
would it still work with oops all sixes like how it is right now? i think it should. or do i need to add it as a loc_var
you also need to do things if you want to remove the default white background so it looks like normal descriptions
the effect will work but the description will not update properly
Also look in: Cavendish
https://github.com/nh6574/VanillaRemade/blob/d4fa384914116d9e570ce7d5da9d070642c33308/src/jokers.lua#L1614
ah. ok how do i do that then
see either of the links
how do i display the text
never mind
wait no im wrong
how do i display the text of the updated probabilites
Check the loc_vars func of this
progress
I think the tiles being beige solves the issue of not having corner symbols
anyone know of any mods that add ui elements to rounds (not card areas)? i wanna look for reference
i add buttons
in joyousspring
will take a look, thank you
tiles done
is there a context for WHEN you get a specific joker
kinda like increasing the initial chip value for ice cream
card_added
wait but that doesnt actually have text
im confused
do i just do text as normal?
nvm figured it out
Can I use a custom color in a card description by putting the hex value
Like {C:000080} or something like that?
no
check vanilalremade wiki for adding custom colors
Gotcha
yes yes you do
If I put the loc_colour thing in one file will it be accessible in other files?
yes it needs to be the file that loads first
of all of them, not necessarily the overall first
as of right now I cannot track multiple flags of parts at once, and crashes on scoring_hand's evaulation
if not (#parts.bm_mahjong > 0) then return {} end
return { hand }
end,
modify_display_text = function(self, cards, scoring_hand)
local tanyao = true -- no honors or teminals
local honroutou = true -- all honors or terminals
local chinroutou = true -- all terminals
local triple_chi = false
local pure_double_chi = false
local twice_pure_double_chi = false
for j = 1, #scoring_hand do
local rank = SMODS.Ranks[scoring_hand[j].base.value]
local honor = rank.bm_honor
if rank.key == "Ace" or rank.key == "King" then
tanyao = false
elseif (#scoring_hand.bm_pure_double_chi > 0) then
pure_double_chi = true
elseif (#scoring_hand.bm_pure_double_chi > 1) then
twice_pure_double_chi = true
elseif (#scoring_hand.bm_triple_chi > 0) then
triple_chi = true
elseif honor then
chinroutou = false
tanyao = false
else
honroutou = false
chinroutou = false
end
end```
this is in an smods.pokerhand
I could also try and move some of the local variables outside of modify_display_text so I can grab condition while still in evaluate() but idk where to put them
wait i'm dumb I can just call self.var
i wouldn't recommend that
you shouldn't modify prototypes at runtime
if you need globals make a table for your mod and save them there
how would i make a joker that adds a red seal to a random played card? i looked at certificate and dont understand what its doing
wait i found it
hhhhhhhh
hmm i have seen this before but i dont remember what the fix is
try adding min = 1 to the boss table
same(?) thing
did you start a new run
key = "Boykisser",
rarity = 2,
cost = 5,
atlas = "ModdedVanilla",
pos = { x = 0, y = 1 },
soul_pos = { x = 4, y = 1 },
loc_txt = {
name = "Boykisser",
text = {
"After scoring,",
"{C:red}#1# out of #2#{} chance to",
"Kiss a random played card"
}
},
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 3, 10, 'red_seal')
return {
vars = { numerator, denominator }
}
end,
calculate = function(self, card, context)
if context.after and SMODS.pseudorandom_probability(card, "red_seal", 3, 10) then
local played_cards = context.scoring_hand or {}
if #played_cards > 0 then
local target_card = played_cards[math.random(1, #played_cards)]
card:set_seal("Red", false, true)
return {
message = "Kissed!",
colour = {1, 0, 0, 1}
}
end
end
end
}```
just did, it shows up normally
try removing the false, true
also don't use math.random
pseudorandom_element(played_cards, "seed") will work
if context.after and SMODS.pseudorandom_probability(card, "red_seal", 3, 10) then
local played_cards = context.scoring_hand or {}
if #played_cards > 0 then
local target_card = played_cards[pseudorandom_probability(1, #played_cards)]
card:set_seal("Red")
return {
message = "Kissed!",
colour = {1, 0, 0, 1}
}
end
end
end```
like that?
now it just didnt apply at all
i think it was applying to the joker because i did card instead of targetcard
oh wait im dumb
yeah lol
what are the color/font style editing options in the localization text?
it would be nice if I could add something extra to some of these poker hand titles
poker_hands = {
["bm_Mahjong"] = "Mahjong",
["bm_Tanyao"] = "Tanyao",
["bm_Honroutou"] = "Honroutou",
["bm_Chinroutou"] = "Chinroutou",
["bm_Seven Pairs"] = "Seven Pairs",
["bm_Pure Double Chi"] = "Pure Double Chi",
["bm_Twice_Pure_Double_Chi"] = "Twice Pure Double Chi",
},```
{C:attention} i assume
the solution I went went is really ugly but it does work
just defining local functions inside of modify display text
since I have the array of cards I can retrieve any conditions that check for those, no need to circle back to parts
it will make this file horrifically large by the end though
SMODS.Seal {
name = "Kiss",
key = 'Kiss',
atlas = "KissedStamp",
pos = { x = 0, y = 0 },
config = { extra = { retriggers = 1 } },
badge_colour = G.C.RED,
loc_txt = {
label = 'Kiss',
name = "Kiss",
text = {
"Retrigger this card 1 time",
"(Litterally just red seal)"
}
},
calculate = function(self, card, context)
if context.repetition then
return {
repetitions = card.ability.seal.extra.retriggers,
}
end
end,
loc_vars = function(self, info_queue, card)
return { vars = { self.config.extra.retriggers } }
end
}
-- Red Seal Joker
SMODS.Joker{
key = "Boykisser",
rarity = 4,
cost = 5,
atlas = "ModdedVanilla",
pos = { x = 0, y = 1 },
soul_pos = { x = 4, y = 1 },
loc_txt = {
name = "Boykisser",
text = {
"After scoring,",
"{C:green}#1# out of #2#{} chance to",
"Kiss a random played card"
}
},
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 3, 10, 'red_seal')
return {
vars = { numerator, denominator }
}
end,
calculate = function(self, card, context)
if context.after and SMODS.pseudorandom_probability(card, "red_seal", 3, 10) then
local played_cards = context.scoring_hand or {}
if #played_cards > 0 then
local target_card = pseudorandom_element(played_cards, "seed")
target_card:set_seal("Kiss",false,true)
return {
message = "Kissed!",
colour = {1, 0, 0, 1}
}
end
end
end
}```
im unsure why its crashing. it was working before with the red seal
modprefix_Kiss
target_card:set_seal("Typ0_Kiss",false,true)
like that?
yes
try starting a new run
sorry another issue
SMODS.Joker{
key = "Boykisser",
rarity = 4,
cost = 5,
atlas = "ModdedVanilla",
pos = { x = 0, y = 1 },
soul_pos = { x = 4, y = 1 },
loc_txt = {
name = "Boykisser",
text = {
"After scoring,",
"Kiss a random {C:attention}King{}",
"or {C:attention}Jack{}"
}
},
calculate = function(self, card, context)
local played_cards = context.scoring_hand or {}
if #played_cards > 0 then
local target_card = pseudorandom_element(played_cards, "seed")
if context.target_card:get_id() == 11 or context.target_card:get_id() == 13 then
target_card:set_seal("Typ0_Kiss",false,true)
return {
message = "Kissed!",
colour = {1, 0, 0, 1}
}
end
end
end
}```
context.target_card doesn't exist, but target_card does.
if self.can_use == true always returns false (no parallel found) even when the card is usable
How do I get this to stop buffing the suits when a Joker is sold, card destroyed, etc?
if card:can_use_consumeable()
so this is how i learn that variables don't apply text styling
You can do something like this
"...become {C:attention}#1#{C:inactive}#2#..." and depending on what you got you make #1# or #2# equal to your value or ' '
Or maybe use V: but i dont know properly how to set it up
how would i force a crash
uh, error("message")?
oh bet
doesn't work
You need to use eval to run code in the DebugPlus console.
Well. I guess that's what it does.
think one of you can help me with this?
it is working then
sorry but how would i check what joker is to the left of me? would it just be something like
if other_joker.id == "joker" then
ive found other joker in a few places as both context.other_joker and just other joker
but im not sure on what the diffrence is and what they are actually doing
and i cant find any docs for other_joker but i can for context.other_joker and context.other_joker doesnt seem like what i need
did you check blueprint's code
yeah
SMODS.pseudorandom_probability(card, 'bruh', card.ability.extra.chance, 10) for the calculation
local numerator, denominator = SMODS.get_probability_vars(card, card.ability.extra.chance, 10, 'bryh') for the loc vars
i dont understand what its doing
it loops through all jokers to find the index for blueprint and the addresses index+1
in your case it would be index-1
the key is in G.jokers.cards[index-1].config.center.key
what's chance
weird
i thought im doing it wrong
that looks correct to me
but i never tried 0 so there might be some safeguard
there shouldn't be
smods issue then
smods sucks
😭
so local other_joker = G.jokers.cards[-1]
and then something like
other_joker = "joker" then
no
i dont know how to explain it better than that
what would it be
^
im not coding it for you
yeah i dont understand what that is
or where that goes
i dont want you to code it for me
sorryu
is there any way to retrigger consumables? (in steammodded)
i see all this stuff for retriggering jokers but i dont see much for what I wanna do
which is planet cards
i dont think so, i think mods have their own implementation of that
aw
Yes, hook Card:use_consumeable
is there like any ways to recreate Cookie's Clicker function from Cryptid
trying to find how they do it, cant find them
Hook Controller:L_cursor_press
oh i thought this was controller thing
How do I get a pack to stop generating the same Joker if I have one of it already?
Code?
Make a SMODS.ObjectType of those jokers, then return {set = 'objecttypekey'}
Lemme make those changes
So remove all in that create_card except return {set = 'objecttypekey}?
[EXTREMELY LOUD INCORRECT BUZZER]
It's set not key
Thank you for catching that. I'm stupid sometimes.
TAKE 2
Ok, so we're not getting a crash.
The bad news is: It's only spawning Jimbos.
The thing is, the Joker keys are correct, the ObjectType key matches.
So why is it not getting the correct ones?
You seem to be missing your mod prefix on the joker keys.
Let me do that rq
Aaaand more Jimbos.
@daring fern Please tell me how the game is refusing to see these Jokers. Make this make sense.
in the create_card i think you need to add your prefix to the set
No, SMODS.ObjectTypes don't have mod prefixes.
how do you create a joker from a specific mod
is this for modmod
just add them all to a pool
yeah
how
idk
local jokers = {}
for k, v in pairs(get_current_pool('Joker')) do
if G.P_CENTERS[v] then
if G.P_CENTERS[v].set == 'Joker' and G.P_CENTERS[v].original_mod and G.P_CENTERS[v].original_mod.id == 'modid' then
table.insert(jokers, G.P_CENTERS[v].key)
end
end
end
local key = pseudorandom_element(jokers, 'seed')
SMODS.add_card({key = key})
thanks
oh nvm
how would i block negative?
no_neg = true iirc
it's funny how these problems have shockingly simple solutions
You just have to know they exist is all lol
I wanna add some sprites through function love.graphics.newImage(), but it tracks the base game directory. The SMODS Atlas somehow uses self.full_path = (self.mod and self.mod.path or SMODS.path), how do I get that mod path, supposedly it will be the path to my mod
SMODS.Mods["modiid"].path?
it gives me the \folder/another_folder with no file found treatment :/ probably have to edit some of the forward/back slashes
Nope, doesn't work even with all '/' or all '\', otherwise the crash report prints out the path entirely as it should, odd
that's funny, i have no idea if i missed something
It's no_negative
i see
Ok. Guys trying to figure the code to a way too complicated Joker, that I am trying to make.
It should trigger when you play no clubs and all clubs in hands, permanently get 15 chips
not that simple
the entire text changes depending on if a card is:
- selected
- not selected
- and selected, but it does not have a parallel counterpart
What if you make multiple loc entries and change the key in loc_vars?
local function apply_autograph_deck(self)
G.E_MANAGER:add_event(Event({
trigger = "before",
delay = 0,
func = function()
local ranks = { "Ace", "King", "Queen", "Jack" }
local suits = { "Spades", "Hearts", "Clubs", "Diamonds" }
-- Fully clear deck the SAFE way
for i = #G.playing_cards, 1, -1 do
local card = G.playing_cards[i]
card:remove()
end
G.playing_cards = G.playing_cards -- keep reference
G.deck.cards = G.deck.cards -- keep reference
G.deck.config.card_limit = 0
-- Create exactly 48 cards
for _, suit in ipairs(suits) do
for _, rank in ipairs(ranks) do
for i = 1, 3 do
local card = create_card(
"Base",
G.deck,
nil, nil, nil, nil,
nil,
"autograph_deck"
)
SMODS.change_base(card, suit, rank)
card:add_to_deck()
G.deck:emplace(card)
table.insert(G.playing_cards, card)
G.deck.config.card_limit = G.deck.config.card_limit + 1
end
end
end
return true
end
}))
end
return DeckHelper.basic({
key = "autograph",
name = "Autograph Deck",
order = 15,
atlas = deck_atlas_key,
pos = DeckHelper.get_pos("autograph") or { x = 0, y = 0 },
description = {
'Starting deck consists of',
'{C:attention}three{} Aces, Kings, Queens,',
'and Jacks {C:attention}per suit{}'
},
apply = function(self)
apply_autograph_deck(self) -- it has this annoying thing where it triggers after the ui shows the default 52
end
})
Ok, so this probably a silly thing for the more experienced. I have this deck, it works, but...
It has this quirk where the deck shows the original 52 for a moment before changing
meaning this executes after the original deck is created and rendered in the UI, i was wondering if there's a way to override the deck before that ever happens
Any suggestions?
Patch Game:start_run
I don't quite understand, you mean run a context with calculate checking for when the game runs?
why is my config not showing up in my mod's menu? it is in the root directory of the mod yet it doesnt seem to be doing anything
Giving it a read rn
You mean the config tab?
I need help with coding a Joker that: trigger when you play no clubs and all clubs held in hands, permanently gain 15 chips
Is there a way to detect a joker preventing death
if context.post_trigger and context.other_ret.jokers and context.other_ret.jokers.saved
Thank you
So I gave a read but I still dont fully grasp it
In an apply or a calculate function you can pretty much alter the deck object, add cards, do stuff like that, in the very code i shared i pretty much did just that. And just so in case I understood, patches ONLY make sense if the action to be altered is before AND during an ongoing event? And I ask before because I thought that deck building would count as something before the game starts, which is why one puts it on the apply (start of the game) and specifies to trigger before so it happens before the game actually starts. But then, building a deck would mean is its own event and using a patch is meant to override that ongoing event? I just want to make sure I understand correctly
patches ONLY make sense if the action to be altered is before AND during an ongoing event
no it makes sense if you want to modify base game code that's hard to reach, events being an example
okay i have a config tab now but it immediately crashes when i open it despite the fact the all the ui elements have a colour defined
node is too nested
i think
or the opposite
That is what I fail to understand, the "hard to reach" part
Why would it be hard to reach?
if you have a function from the base game and you need to do something in the middle of that function it is kinda annoying to do without patches
I... still dont get it. Why would it be annoying? Because UI would execute after the change like what is happening to me with the snippet i shared?
Is it more of a timing problem?
idk i havent read your problem i was just clarifying what a patch is
ok now i have, the problem is that there's no timing in apply for you to delete the cards before you can open the UI afaik
honestly, there should be an easy way to stop the initial cards in a deck
what you can also do is hook SMODS.add_to_deck and block all ranks and suits from spawning on the initial deck
So far, what I understood is
- patches are used only to override base game or existing mod events before these are executed
- apply function execute the moment the game start
- Attempting to create an event in the apply function would put it in a later position in the event queue after the base game event
- Because We cannot access the card game data unless we send it unto said event and it would be unreasonable to use manual timing (youd be fighting the engine at that point), patches are instead used
I haven't thought about hooking it at that before 🤔
sorry wrong function
SMODS.add_to_pool
so basically
if i have the non-variable messages like
"Select a card to view it's Parallel"
"No Parallel found"
and then have "Card will become" as the variable text
then have {C:attention}#2#{} where #2# is either the name of the Joker or blank for the other text
Ah, I tried that one before, but wasn't sucesful, tho its likely in part of how i was hooking it. I'll give it a try and share what i got for the benefit of everyone
like this
`
oops
local smods_add_to_pool_ref = SMODS.add_to_pool
function SMODS.add_to_pool(prototype_obj, args)
if args and args.initial_deck and G.GAME.selected_back.effect.center.key == "b_modprefix_key" then
return false
end
return smods_add_to_pool_ref(prototype_obj, args)
end
it literally only just started doing this when i separated the two
don't set card to a different card
here
ye that did the trick
one more thing
how do i obtain an entire joker's information if i just have the key
G.P_CENTERS[key]
gotcha
Lovely
Is there a context for joker being destroyed like context.selling_self?
context.joker_type_destroyed
Ty
if you need to do something on any type of removal just use remove_from_deck() tho
making a blind that removes enhancements and has the boss blind remove some chips from your total score for every enhancement it removes, but i'm having issue with the round score being updated
the score visibly subtracts, but effectly does not
You're missing the bit that updates the text but I forgot what its called
Vanillaremade wiki prob has a section on that
when does this code trigger
what with the key is wrong? my mod's prefix is rb
you're giving 0 context here lol, what's this a key for and what are you using it for?
context.before
a tag that creates a pack
image one is the pack and image two is the tag
sorry for the little amout of context lol
this is overriden by the score after the hand calculates im pretty sure, im not sure how to do that effect properly
it should be p_rb_
try modifying the chips outside the event
I have, and it does work, but then the chip juice up doesn't happen at the same time
update G.GAME.chips_text in the event instead
i think
I'll have to give that a try
awesome! i haven't had to use prefixes often so this is really helpful
Is it possible to detect detecting joker being destroyed? (For example joker that creates a tarot card when destroyed)
I have tried context.joker_type_destroyed and context.card == card but it seems that joker gets destroyed before creating
that should work
how are you doing it
if context.joker_type_destroyed and context.card == card then SMODS.add_card({key = 'j_joker'})
With dagger
It works when I remove context.card == card and destroy other joker
let me try, i was testing with madness
Madness didn't work too
it looks like a problem with the rest of your code
that part should be working
make sure your smods is updated too
Maybe that's the problem because I don't know what can interfere with it, its the only context there
Show your full calc function
So trying to play around with the concept of even and odd calculations and struggling a bit, could get some help codding wise
what do you need help with
If I have a Joker that check that have even number of Jokers, and then turns the most left one negative how would I code that
which part of that are you having trouble with
do you know how to turn a joker negative
also when does it do the effect, continuously?
The issue having trouble is computation of when, how do code "must be even/odd number to turn Joker into X edition"
Because I am planning few others too
when do you want it to happen tho?
when you get the joker? all the time? when the blind is selected?
does it remove negative when the condition is not met anymore?
what
I want to happend the end of the blind, yes the Joker would keep the negative status
ok, then you would do it in context.end_of_round and check #G.jokers.cards % 2 == 0 to see if it's even
for the joker to the left you can check brainstorm and for how to set an edition: https://github.com/nh6574/VanillaRemade/wiki#edition
are you fr
Oh I didn't think about the brainstorm thing wow
Good idea
Thank you
And need help with one more N and that it
Sorry keep doing that it culture thing
I need help with coding a Joker that: trigger when you play no clubs and all clubs held in hands, permanently gain 15 chips
Would I use Hiker for the chip gain, that fine but how do the Club or any other suit part
loop through context.scoring_hand and check that there are no clubs with :is_suit
No I didn't, man really got think outside the box. Thanks guys
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
return {
xmult = card.ability.extra.xmult
}
end
if context.destroying_card then
if pseudorandom('shaped_glass_break') < 0.25 then
return true
end
end
end
this is a joker, but how can i make the card shatter instead of dissolve?
Hook SMODS.shatters function.
Looking for help to make a very big balatro mod. I have many ideas that supersede any actual skill, so I'm looking for where to start. I have.. very little experience coding, to say the least, but i want to learn and YT tutorials on Balatro modding are few and far between. Any pointers?
SMODS.Joker{ --Chip Chad
key = "chipchad",
config = {
extra = {
xChips = 1.5,
xchips0 = 1.5,
repetitions = 1
}
},
loc_txt = {
['name'] = 'Chip Chad',
['text'] = {
[1] = 'First played {C:orange}face{} card',
[2] = 'gives {X:blue,C:white}X0.1{} Chips when scored.',
[3] = '{C:inactive}(Currently{} {X:blue,C:white}X#1.5#{} {C:inactive}Chips){}'
},
['unlock'] = {
[1] = ''
}
},
pos = {
x = 0,
y = 0
},
display_size = {
w = 71 * 1,
h = 95 * 1
},
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
atlas = 'CustomJokers',
pools = { ["ttv_memejokers"] = true },
loc_vars = function(self, info_queue, card)
return {vars = {card.ability.extra.xChips}}
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
if (function()
for i = 1, #context.scoring_hand do
local scoring_card = context.scoring_hand[i]
if scoring_card:is_face() then
return scoring_card == context.other_card
end
end
return false
end)() then
return {
x_chips = 1.5
}
elseif (SMODS.get_enhancements(context.other_card)["m_bonus"] == true and context.other_card:is_face()) then
for i = 1, 1 do
card.ability.extra.xChips = (card.ability.extra.xChips) + 0.1
end
end
end
end
}```
trying to add a +0.1 xChip mult when a face card is scored with bonus enhancement working similar like photo
the x1.5 chips works but I can't get the +0.1 to work
is this description better than what was previously
Would there be any way to check how many Jacks there are in the full deck without just adding to a variable every time one is added?
check how cloud 9 does it in VanillaRemade
G.playing_cards is a table containing all the cards in your deck
Okay, thank you
how do i get the current sleeve being used in the case that cardsleeves is active?
G.GAME.selected_sleeve
awesome thx
- Write down all ideas just to not forget them
- Start by learning Lua programming language first
ok, so it's my first time making a mod and i just wanna make a really simple texture mod compatable with malverk (its what i use for texture packs). what should my first step be when creating this
Atlas handles textures so probably look into that
If you're just replacing textures just open the sprite sheets in a photo editor
ok, will do
I would look into another malverk mod, just search malverk in #1209506514763522108
i might have to make a readme
I made a localization file for my mod for a cleaner and easier way to change text, the first 4 jokers I did worked fine, but all the rest show blank text boxes and no names in-game.
here's one of the ones that worked:
j_mysingingjokers_ambigram = {
name = "Ambigram",
text = {
"Each scored {C:attention}#1# {}gives {X:red,C:white}X2{} Mult,",
"rank switches to {C:attention}#2# {}next round"
},
},
here's one of the ones that didn't:
j_mysingingjokers_collectionbook = {
name = "Collection Book",
text = {
"{C:blue}+10{} Chips for every unique",
"{C:tarot}Tarot{} card used this run",
"{C:inactive}(Currently{} {C:blue}+#1# {}{C:inactive}Chips){}"
},
},
is it even a code issue?
doesn't look like the issue is there
make sure those tables are not nested and there isn't anything in loc_vars that might break it
and that the keys are correct too
keys are definitely correct
and all the formatting in the localization file is consistant
I'll check the other thing you said
it all seems like it should work
I can't find anything that would affect it
the weirdest thing is that it's specifically the first 4 I did that work
all the ones after that don't work
and I didn't change how I did it between them
ah I found the issue
one of the brackets was slightly misplaced
wait it still doesn't work?
I have no idea then
just a second slightly misplaced bracket
and it actually works now for real
maybe try calling it something other than just "blinds"? that's my first/only guess tbh
didnt change anything
how are you testing the blind, are you discovering it with debugplus
yes
god damnit
i think if you close the collection it works
yeah it works now
oh yea it won't load the proper atlas if you discover it that way lmao
No, it would be madman_c.key
Also it's c_modprefix_key
the problem is still that you're adding the card to itself in the info_queue so that check is still wrong
idk why it's wrong, I would recommend printing out madman_c
Trust me, my ideas are written down 😅 I have over 120 Joker ideas plus tarots/spectrals/seals etc. But i shall look into Lua thank you 👍
I think thats a copy of the fool but for spectral
madman_c should be aura
since madman_c is just the last spectral according to this and in my test its aura
the crash happened pretty soon after i used the madman to dupe aura
the best advice i can give is look at what other mods that do similar ideas do
and if its something in vanilla
thanks! 🫡
does anyone know what exactly G.P_CARDS is used for?
it's a table of every possible rank + suit combination
card:set_base() takes an entry from G.P_CARDS as an argument, which determines what rank and suit the card is set to
i see
wait, so could i then use set_base to, for example, tranform a card into an Ace of the same suit?
yea
although you really shouldn't, because SMODS.change_base exists and abstracts that process away
ah
wish i had found that sooner then .w.
very helpful documentation page, lists a bunch of utility functions that smods implements (including change_base, add_card, smart_level_up_hand, etc)
https://github.com/Steamodded/smods/wiki/Utility
how can i get the selected poker hand when i'm selecting cards in a booster pack? context.other_drawn is a table of cards, but i can't figure out how to get what poker hand they can form
is there a way for a joker to lower a blind requirement, i had a look but couldnt find the actual way to do it but ik its possible
i think i just saw a how to in the vanillaremade wiki lemme check
G.GAME.blind.chips = math.floor(somevalue)
G.GAME.blind.chip_text = number_format(G.GAME.blind.chips)
G.GAME.blind:wiggle()
is the some value the percentage it changes by
no, just a number
G.FUNCS.get_poker_hand_info
ok i think i got it
seems to be working! is there also a way i can get a table of cards that actually make up the poker hand?
i see that the function returns scoring_hand, but that doesn't seem to be it, unless i'm trying to highlight the cards from it wrong
How do I call function defined in main body?
I have main_suit = function() .. return true end
and then local_vars calling main_suit.
It crashes saying attempt to call global 'main_suit' (a nil value)
Like
SMODS.Consumable{ main_suit = function() .. end local_vars = function() .. end }
self.main_suit()
Thanks!
Yes, it is scoring_hand
local pokerhand, _, _, handcards = G.FUNCS.get_poker_hand_info(context.other_drawn)
for _, _card in ipairs(handcards) do G.hand:add_to_highlighted(_card, true) end
It's not doing the highlighting tho, is this code wrong?
okay it actually does highlight them, it just unhighlights them instantly further in the code instead of waiting for the other stuff to complete
How to implement clicking between frames
if i add a bunch of jokers to my own pool how can i reduce the shop spawn rate of those jokers through the pool?
how can I texture pack a mod "from the outside"?
I want to change Multiplayer's blind images
what function should i patch in order to have a certain joker always be picked by a random selection (e.g. Madness, Crimson Heart, Wheel of Fortune)
you'll probably need to patch each item individually to have them select the joker. maybe you could patch pseudorandom_element() to detect if it's picking jokers and then always pick your joker, but i dunno
you could probably just hook pseudorandom_element for this and check if the elements in the table are also tables and then check if their area == G.jokers
feels like delving in the mod's code is a bit immoral
its open source and its just replacing an image file
but you can just make a texture pack with #1300851004186820690 for it too ig
how can i check if a card is a consumable? checking individually for tarot/planet/spectral feels hacky
card.ability.consumeable
it'll be true or false?
i see
(so therefore it'll act like true on consumables, and act like false on non-consumables)
how do i make a timer
cant believe theres isnt actually a clean way to trigger a level up all hands animation like black hole
you can make your own by copying it into a function, that's the magic of programming
I believe there is now via new SMODS, see SMODS.upgrade_poker_hands https://github.com/Steamodded/smods/discussions/1131
it levels up all the hands but it painstakingly goes through and does the level up animation for each one individually
Oh ouch
i dont think it's necessary for that to be an api thing
probably not but it just caught me off guard
Black Hole level up all hand is kinda scuffed tbh
i dont think there's a single ui/animation thing that isn't
Lmao
balatro ui truly is scuffed
how can i check which boss blind i am facing and do something when it's triggered?
if G.GAME.blind.key == "arm" and G.GAME.blind.triggered then doesn't seem to do the thing
any particular reason this doesnt work? im trying to get this joker to only show up in shops, buffoon packs, and rare tags
for the first:
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-get-the-set-pool-or-key-of-a-specific-cardobject
for the second question that's correct but the triggers are inconsistent and some are bugged, see matador
for the arm it would be bl_arm
ah thank you :)
where else does it appear
also this will crash because sometimes args is nil
consumeables
like judgement?
it shouldnt but it is doing that
oh is this why not args is needed?
well in this case it would be args and ...
not args is in the case where you want it to appear if args is nil
ah i see
hmm no idea why judgement doesn't work tho i have tested that before and it worked for me
so it would be return args and pull == "sho" and pull == "buf" and pull == "rta" ?
return args and (pull == "sho" or pull == "buf" or pull == "rta")
ahhhh
thaaaat makes a lot more sense thank you
nop
i'm testing this with wraith, it's spawning on wraith still
do i have to refer to them inversely? like putting in which cases it shouldnt spawn instead?
that shouldn't make a difference
have you tried setting it to false to see if it works at all
good call because it doesnt work when i set it to false either
OH
im so dumb
i only put in_pool
i need to add [joker_name].in_pool
uh... should we... not be?
i have seen people do that but it makes me doubt you're adding stuff to the joker correctly at all lol
should be like this
https://github.com/nh6574/VanillaRemade/blob/2c62cb545526bfcca0f2792a55ce82fde6fe748a/src/jokers.lua#L807
well i haven't seen how you do it
what we're doing rn is having each joker be their own .lua
and then the config, functions, and .Joker are all separated in there
i wouldn't recommend that, some things are taken care of during initialization
doesn't matter for in_pool in particular but it's not a good idea
Is there a way to make a larger than normal blind reward not look awkward? I want one of my boss blinds to have a $20 reward (in exchange for -$10 per hand) but it makes the blind really wide and bad looking. I think I've seen numbers been used before to represent rewards?
basically this question because I can't find an answer to it
god what may missing here
-- Png.Joker
SMODS.Joker {
key = "png_joker",
blueprint_compat = false,
rarity = 1,
cost = 4
pos = { x = 0, y - 0 },
config = { extra = { h_size = 2 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.h_size } }
end,
add_to_deck = function(self, card, from_debuff)
G.hand:change_size(card.ability.extra.h_size)
end,
remove_from_deck = function(self, card, from_debuff)
G.hand:change_size(-card.ability.extra.h_size)
end
}
this going to drive me to drinking it keeps saying crash
if someone could explain to me what missing thank you
Maybe cuss I haven't slept in 24hours but just can't see what missing
i have currently been going through it adding a new consumable type
key = 'clo_Blueprint',
default = 'clo_closet',
collection_rows = { 4, 5 },
primary_colour = '00598b',
secondary_colour = 'ffffff'
}
SMODS.Atlas({
key = "closet",
path = 'blueprints.png',
px = 72,
py = 72,
})
SMODS.Consumable {
key = "closet",
set = 'clo_Blueprint',
atlas = 'closet', pos = { x = 0, y = 0 },
display_size = { w = 72, h = 72},
pixel_size = { w = 72, h = 72 },
loc_txt = {
name = 'Closet',
text = {'Grants two',
'random Consumables'}
}
}```
it says attempt to compare number with nil but im not sure where in here I'm doing that D:
hey , i want to make a joker that free shop reroll and a joker that make all the card feel like wild card ( has propertises of wild card but look likes normal cards)
how can i do that
Primary and secondary colours needs to be HEX('00598b')
that does not seem to be the issue
(i fixed that and got the same error)
oop wait nvm i got it
good news! it exists
bad news
also setting the display and pixel size didnt work
my poor closet has been stretched :(
In your loc_txt you need to add collection = 'Closet cards' or whatever you want
Also not sure why you're using display/pixel size when its the same values as your atlas dimensions
yes
