#💻・modding-dev
1 messages · Page 648 of 1
Hi all, I am new to the scene, but am looking to try and make a bot as a ML project, has anyone made a mod to trigger actions programmatically, strip the visuals, a state recorder/replayer, a list of function triggers, or a mod that connects to web that I would be able to hook into, or reference?
or has anyone just made a bot already?
the crash was toga all along
i have seen many people come here to say they're going to do that but none did lol
what did i miss? stickers arent displaying descriptions and stuff
i'm fucking stupid
badge says error though
badge is localized elsewhere
labels?
yep
misc -> labels -> modprefix_stickerkey = "something"
card:add_sticker("modprefix_stickerkey", true)
yes, that is on the console
running eval [lua code] in debugplus will run the lua code
and in particular, eval dp.hovered:add_sticker("modprefix_stickerkey", true) will add the sticker to the card that you're currently hovering over with your mouse
how do i open the dev console on debug plus again
i got a new error now
the revised code
my sleep was really inconsistent today so theres probably something im missing
Ok i finnaly tested it, it actually fixes my problem. the problem was in incorrect key
message should not be a table
when did they change that?
recently
i see
(also you should probably just use message = localize("k_plus_tarot"))
i dont bother with localization in my mod so i think it better to keep things consistent
i want a joker to act like a glass card (1 to 1 chance of breaking when triggered) what context do i need to add
doesnt need to be any context in specific
i'm using the sticker in both jokers and playing cards
so far it breaks playing cards fine
will it destroy the joker if it doesnt score or trigger?
it will
that sucks
whats the actual effect meant to be
if the joker triggers / card scores, break
so it should break on every trigger?
it should break and die yes (so it should trigger once)
then do a little ```lua
if context.post_trigger and context.other_card == card then
card.getting_sliced = true
SMODS.destroy_cards(card)
end
shouldnt need a card type check since this context only runs on non-playing card triggers anyway but might be good to do for future proofing
i mean if it detects a playing card first, its going to return (and exit the calculate function)
also true
forgot to upload thing to git hub pretty sure it is the same but an error appears
you misspelled odds as oddds
yup
-_-
happens to everyone at least once
how would i go about having a consumable cause an effect at the start of the next X rounds? i have one that increases your hand size then slowly decreases it back down by -1 every round until its back to normal
two options
- don't destroy the consumable until it's done, and just have it do things in its calculate function
- set some value in G.GAME when you use the consumable, and track it/do things in your mod's global calculate function
two options, either have the consumable hang around and give it a calculate function, or have it set a flag that is handled by your mod object calc function
lol
ill probably have it hang around since i imagine it would be easier to deal with having multiple active that way
now the question is if i let the player get the consumable slot back immediately or if they gotta wait for it to wear out
probably the former seeing as it can stick around for as much as 8 rounds at max level
it didnt break
wait
it didnt save
do you have the post_trigger optional feature enabled
where
it crashed
SMODS.current_mod.optional_features = { ... }
and then put post_trigger = true in there
in main.lua?
whats the log
i misspelled smth lol
oh ok
it broke yay
epic
return { vars = { card.ability.extra.chips } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
for _, scored_card in ipairs(context.scoring_hand) do
if scored_card.vampired == nil then
card.ability.extra.chips = card.ability.extra.chips + 20
return {
message = "Upgrade!",
colour = G.C.BLUE
}
end
end
end
if context.joker_main then
return {
chips = card.ability.extra.chips
}
end
end
}```
MODIFIED CODE
im looking at the vampired documentation on vanillawiki rn
uh now the sound plays when i play a card
-- See note about SMODS Scaling Manipulation on the wiki
Found this is green joker on vanilla remade, anyone know what its talking about? I just dont know what it could be referring to that would need further explanation
not important particularly just have no idea what its for
have you seen the note about SMODS Scaling Manipulation on the wiki
no lol idk where it is exactly
on the wiki
i wrote so you could ctrl+f SMODS Scaling Manipulation
that like, tells u "hey ur card's enhancement was removed!"
context.setting_ability can help
oh thats good my bad
it gets called when a card has its ability set
so for playing cards it would be getting or removing enhancements
how would i reproduce this effect then
ok i think at this point im dumb but idk what page im ctl-f ing
the wiki
oh the faq
that makes sense, didnt know what page to be on
the faq page is awesome its just the rest of it that can be hard to search thorugh
would i do smth like context.setting_ability = SMODS.vampire = true or smth
ty, sorry for bothering you
Okay weird Pokermon skins toggle + Malverk texture crash fix time
this time it only happened when I enabled/disabled the texture
OH yeah i found why
so @wintry solar do alt textures register atlases also?
and if so - what are the odds that these two having the same key is the culprit
it would for atlas registry wouldn't it
I think this is a combination of both mods having broken code 🤣
how can i use juice_card_until to make a card juice up perpetually until it's destroyed?
not entirely sure how the function arguments work
thought juice_card_until(card,function() return false end, true) might work but apparently not
okay so Malverk is crashing for me regardless of the stake sprite toggle
and the texture
yup looks good!
no crash on my end
I'll PR the prefix config thing for the atlas anyway
yeah, I think that will crash without Malverk if you toggle it
and I think Malverk would actually prevent that crash because of when it initialises the default values
Why do my debuffed cards still score?
(Example code)
calculate = function(self, blind, context)
if not blind.disabled then
if context.after and context.main_eval then
if #context.scoring_hand == 1 then
context.card:set_debuff(true)
G.GAME.blind:wiggle()
context.after is after main scoring, isn't it?
wouldn't you want context.before if you didn't want it to score?
I need another help. I tried to change my function that was changing every joker in the shop on baron. I tried to firstly create a card, check if thats a common then change it onto baron.
local original_create_card = create_card
function create_card(card_type, area, legendary, rarity, skip_materialize, soulable, forced_key, ...)
local card=original_create_card(card_type,area,legendary,rarity,skip_materialize,soulable,forced_key,...)
rar=card.config.center.rarity
if rar==1 then
print("Change every common with baron")
return original_create_card(card_type,area,legendary,rarity,skip_materialize,soulable,'j_baron',...)
end
return card
end
But because i created the common joker first, after i create a baron, the common one becomes just a dragable copy. How can i fix this?
how do i prevent a card from being sold if a condition is met?
you should instead run code before the original function since currently you are just creating an additional card
here that would be if key_append == "sho" and card_type == "Joker" then forced_key = "j_baron" end
I'll be honest, I forgot about context.before
there are also the shop contexts that mean you odn't need to do this hook at all
right
ye context.create_shop_card is your best friend
whoever is doing that
(I don't know how I of all people managed to forget about that one considering I built a whole ass reroll simulator and had to account for it)
Ok, thanks everyone for help il try to figure something out
bump?
either hook SMODS.is_eternal or use context.check_eternal, whichever makes more sense
in the context check, you can check context.trigger.from_sell to only catch the sell button; in the function, the trigger argument behaves the same and you can check trigger.from_sell. returning true in the hook, or { no_destroy = true }, should make the sell button greyed out like an eternal card's is
odd, i tried that and it didnt work
if context.check_eternal and card == context.other_card then
if card.ability.extra.activated then
return {no_destroy = true}
end
end
splendid
maybe the hook will have better luck? idk
Are there any special requirements for the atlas of a back?
No
Ok thanks
If anyone would mind taking a look at this, been a minute since I've made a joker, just trying to figure out why I'm not getting any of the extra retriggers to activate despite my deck being 100% KoHs. Any help would be greatly appreciated!
because the bonus reps are never computed in the actual effect in calculate
you need to copy the loc_vars stuff again in calculate
ah
thank you ðŸ˜
I'm getting two retriggers after moving it to the calculate, but it should be four now, maybe I made some logic error and I forgot how math works?
i wanna make an enhancement that bloats the hand, basically u can't select it, play it, discard it or sell it, unless u r in a custom blind
does G.playing_cards count the full deck or just remaining cards *in the deck?
full deck
okay odd
remaining deck is G.deck.cards
if its 1 the first condition will always be true
you need to do == 1 first then .66 then .33
🤦 I gotta brush up on my *logic thank you king
can u even sell a playing card
Yes, if you run G.FUNCS.sell_card({config = {ref_table = card}})
would it make u able to show the sell button
No, you would have to add that yourself.
I'm having trouble figuring out how to replace the main theme with a variation in a different soundfont; I'm looking at the Steamodded wiki but I'm not sure how to get create_replace_sound(self,replace) to work in practice
how do i make the blind size mod or just the text update happen upon trigger, it does it immediately
Put it in a func in the return and in an event.
do you mean i put it in the return function or not idfk man i feel so dumb ðŸ˜
hi
how do i make a joker retrigger a card multiple times and change the message each time
Yes, put that in the return
return {repetitions = 1, message = 'message', extra = {repetitions = 1, message = 'message'}}
Yes:
local effects = {}
for i=1, number do
table.insert(effects, {repetitions = 1, message = 'message'})
end
return SMODS.merge_effects(effects)
oh wait what does merge effects do
It takes a table of effects, and turns it into a single effect using extra
heyo so i need a bit of help
^ this is the joker im trying to fix
basically when oops6 is used, the DISPLAYED number is above the denominator
but inside the loop the INTERNAL odds eventually hits 0 which terminates the loop since zeroed odds do nothing
if context.repetition then
-- this SHOULDNT be null but just incase
card.ability.extra.chain = card.ability.extra.chain or card.ability.extra.initial_down
local odds = card.ability.extra.initial - card.ability.extra.chain
-- [...]
while SMODS.pseudorandom_probability(card, "nflame_dicechain", odds, card.ability.extra.initial) do
if activations > 100 then break end
odds = odds - 1
card.ability.extra.chain = card.ability.extra.chain + 1```
is there any ways to prevent the early termination at 0? obviously if i just start the odds at the get_probability_vars then it would effectively double the odds from the displayed numbers
actually nvm im going to keep it
in context.remove_playing_cards, if I checked context.removed would those cards also still be in G.playing_cards?
And in context.playing_card_added is context.cards in G.playing_cards already?
Yes, because the card is usually destroyed in an event, and yes, because the card is usually not created in an event.
Okay, cool
man we really should have valkriya's cookies here
that would be really fun
(get a cookie for getting someone to thank you, pointless but fun leaderboards for being helpful)
Does context.setting_ability trigger when using stuff like Death?
Yes, because Death uses copy_card which uses Card:set_ability which triggers context.setting_ability
gotcha
thanks!!
Is there already a table I can access that has all the consumeable names in it or do I gotta make one
G.P_CENTER_POOLS.Consumeables
Does there exist an update boolean like card.added_to_deck and card.removed for setting_ability or otherwise changing enhancement to a card?
I think the game has an unlock check when that happens
Iirc it's called inside Card:set_ability
oh, yeah modify_deck
How would I make use of that inside an update function though? Is there some boolean flag set in check_for_unlock that I can check for or something?
I mean I suppose I could patch something, but I feel like it's bad practice to just make a new global variable
@normal crest I suppose I will just put a patch in card.lua at the point where it makes that check. Although, since this is something that could be updated more than once, what would be the best way to mark it as false so it can be checked again?
uhhh
It seems all I had to do was hook SMODS.calculate_retriggers and add 1+#retriggers retriggers.
you use card.ability.extra.Xmult in the code when you put xmult in the config
ahhhh
you also dont have a Xmult_gain1 in the config
i am stupid and i apologize,
So does anyone know why this isn't giving money? I copied the code from Rocket and modified it a little.
the code for Rocket's money uses calc_dollar_bonus, not calculate
so you should either return { dollars = amount } or move the code that gives the money to calc_dollar_bonus
So like this?
Oh, because we're still returning something, so it won't infinitely loop.
got it
also idk if G.GAME.blind.chips gets adjusted before calc_dollar_bonus runs, so that might be something youll need to work around
Nah, it's working as intended.
awesome
this code in card.lua doesn't seem to be running, when opening a Standard pack:
elseif self.ability.name:find('Standard') then
card = create_card((pseudorandom(pseudoseed('stdset'..G.GAME.round_resets.ante)) > 0.6) and "Enhanced" or "Base", G.pack_cards, nil, nil, nil, true, nil, 'sta')
local edition_rate = 2
local edition = poll_edition('standard_edition'..G.GAME.round_resets.ante, edition_rate, true)
card:set_edition(edition)
card:set_seal(SMODS.poll_seal({mod = 10, guaranteed = next(SMODS.find_card("j_phanta_stampedjoker")) and true or nil}), true, true) print("kjdfngdf")```
is the code for this elsewhere?
isnt SMODS override all booster packs?
:set_ability(center)
G.jokers:set_ability(center)?
working on a command that'll pick a joker at random and swap it with a michel or Cavendish
G.jokers.cards[1]:set_ability(G.P_CENTERS.j_rocket)
replace j_rocket with j_(jokername)
It only replaces the first slot i'm assuming it's related to [1]
that's the slot number
?
hmmm
I guess I could make it select a random number between 1 - 6 unless there's a real way to randomly select
oh
I didn't realize the defuse button i made is on every joker lol
Yes, pseudorandom_element
right now I need to figure out why the defuse button is on every joker
I thought I put it only on the bomb joker
Code?
key = 'defuse_button',
order = -30, -- before the Card is drawn
func = function(card, layer)
if card.children.ttv_bomb_button then
card.children.ttv_bomb_button:draw()
end
end
}
}
local function defuse_button(card)
return UIBox {
definition = {
n = G.UIT.ROOT,
config = {
colour = G.C.CLEAR
},
nodes = {
{
n = G.UIT.C,
config = {
align = 'cm',
padding = 0.15,
r = 0.08,
hover = true,
shadow = true,
colour = G.C.MULT, -- color of the button background
button = 'ttv_defuse_button_click', -- function in G.FUNCS that will run when this button is clicked
func = 'ttv_defuse_button_func', -- function in G.FUNCS that will run every frame this button exists (optional)
ref_table = card,
},
nodes = {
{
n = G.UIT.R,
nodes = {
{
n = G.UIT.T,
config = {
text = "Defuse",
colour = G.C.UI.TEXT_LIGHT, -- color of the button text
scale = 0.4,
}
},
{
n = G.UIT.B,
config = {
w = 0.1,
h = 0.8
}
}
}
}
}
}
}
},
config = {
align = 'cr', -- position relative to the card, meaning "center left". Follow the SMODS UI guide for more alignment options
major = card,
parent = card,
offset = { x = -0.2, y = 0 } -- depends on the alignment you want, without an offset the button will look as if floating next to the card, instead of behind it
}
}
end
-- Will be called whenever the button is clicked
G.FUNCS.ttv_defuse_button_click = function(e)
local card = e.config.ref_table -- access the card this button was on
play_sound("ttv_bomb_explosion", 1.0, 0.7)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.5,
func = function()
if G.STAGE == G.STAGES.RUN then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
end
end
}))
-- Show a message on the card, as an example
SMODS.calculate_effect({ message = "Hi!" }, card)
end
-- Will run every frame while the button exists
G.FUNCS.ttv_defuse_button_func = function(e)
local card = e.config.ref_table -- access the card this button was on (unused here, but you can access it)
-- In vanilla, this is generally used to define when the button can be used, for example:
local can_use = true -- can be any condition you want
-- Removes the button when the card can't be used, otherwise makes it use the previously defined button click
e.config.button = can_use and 'ttv_defuse_button_click' or nil
-- Changes the color of the button depending on whether it can be used or not
e.config.colour = can_use and G.C.MULT or G.C.UI.BACKGROUND_INACTIVE
end
SMODS.draw_ignore_keys.ttv_bomb_button = true
local highlight_ref = Card.highlight
function Card.highlight(self, is_highlighted)
if is_highlighted and self.ability.set == "Joker" and self.area == G.jokers then
self.children.ttv_bomb_button = defuse_button(self)
elseif self.children.ttv_bomb_button then
self.children.ttv_bomb_button:remove()
self.children.ttv_bomb_button = nil
end
return highlight_ref(self, is_highlighted)
end```
just slightly modified from the vanillia wiki
doesn't really do anything other than end the game
You need to check if self.config.center.key == 'j_modprefix_key' in the Card.highlight hook.
well it removes the defuse button but now when the bomb spawns it's missing
function Card.highlight(self, is_highlighted)
if is_highlighted and self.config.center.key == 'j_ttv_bomb' and self.area == G.jokers then
self.children.ttv_bomb_button = defuse_button(self)
elseif self.children.ttv_bomb_button then
self.children.ttv_bomb_button:remove()
self.children.ttv_bomb_button = nil
end```
unless i'm doing this wrong
nvm
I forgot to remove the --- on the file that loads custom buttons

now it works
I keep getting this crash error but I higkey have no clue why its doing that since it's almost complete copy+pasted code from another joker I have which works normally
I don't think DARK_EDITION is an actual colur could be wrong
try setting it to G.C.WHITE see if that works
I just took it from the smods wiki
I'll try that
this gives the same error
it is a color
the problem is that the message is a table
it should be a string and the color should be a different attribute
idk works for me
mult_mod is not really recommended, try mult and use mult_message = { message = "text", colour = G.C.DARK_EDITION }
What is the global for the hand size
like is there a G.GAME.hand_size or something like this
G.hand.config.card_limit
oh ok nice
G.hand:change_size(G.hand.config.card_limit) that will double the hand size right
Yes.
this doesnt create a perishable joker, why
card.ability.extra.original_size = G.hand.config.card_limit
G.hand:change_size(G.hand.config.card_limit)
end
if not context.blueprint and card.ability.extra.original_size <= G.hand.config.card_limit and context.ending_booster then
G.hand:change_size(-G.hand.config.card_limit)
end````
Why does the end size always become 0 when returning to the blind
need a ui wizard to help with creating an option cycle
all other things work well though
i creates a rare joker
you're reducing the hand size by the hand size, thus it goes to 0 every time
you should be reducing it by the difference between the original handsize and the current handsize (also, won't this logic not work properly if you use ectoplasm or other handsize reductions mid booster?)
you can put
local _card =
before smods.add_card
then make changes to _card (add the sticker manually)
force_stickers = true
add card can probably do it on its own but idk i dont use it
Oooo yeah I understand why
I just add this as an extra parameter? Ok, I'll test it later
does anyone knows how to change the base suit rate in in the shop?
like making it so that you only have heart suit but unlock others through vouchers?
Yes, take ownership of the suits and add an in_pool function.
take ownership?
thanks!
Why is "round_resets" always nil? I tried everything, unless if I'm missing something obvious...
SMODS.Blind {
name = "b_metro",
key = "b_metro",
loc_txt = {
name = "The Metro",
text = {
"Debuff #1# random",
"cards for every Blind",
"skipped this run"
}
},
unlocked = true,
discovered = true,
pos = {y = 20},
atlas = "Blinds",
dollars = 5,
mult = 2,
boss = {min = 1},
boss_colour = HEX("000000"),
loc_vars = function(self, info_queue, card)
return {vars = (G.GAME.current_round.round_resets.blind_ante or 0)} -- Here
end,
set_blind = function(self)
G.E_MANAGER:add_event(Event{func = function()
local targets = {}
for k, v in ipairs(G.deck.cards) do
table.insert(targets, v)
end
for i = 1, (G.GAME.round_resets.blind_ante * (G.GAME.skips or 0)) do
local target, key = pseudorandom_element(targets, pseudoseed("metro"))
target:set_debuff(true)
table.remove(targets, key)
end
return true
end})
end,
}
Remove the current_round
oh
thank you :3
I "fixed" it, but #1# still just says "nil" ingame
SMODS.Blind {
name = "b_metro",
key = "b_metro",
loc_txt = {
name = "The Metro",
text = {
"Debuff #1# random",
"cards for every Blind",
"skipped this run"
}
},
...
loc_vars = function(self, info_queue, card)
return {vars = tostring(G.GAME.round_resets.blind_ante or "0")}
end,
vars = { ... }
oh i thought i put the curly brackets in
thank you
‎
is there a vanilla pool for food jokers
no
alright
consensus is just to make a food pool with the same key as the cryptid one
its this one except cryptid uses ride the bus as default for some reason https://github.com/nh6574/VanillaRemade/wiki#how-do-i-create-a-poolset
mm, bus
(card.config.center.pools or {}).Food
theyre in G.P_CENTER_POOLS.Food too
oh thats simple
i should check if the pool exists before i make it and not make it if cryptid is there right
no it will just fail without errors
?
like, you can make it and even if it exists it will just throw a warning before the game loads but it wont do anything bad
oh i see
i think i'll still not make it if cryptid is present
that sounds like not a good idea
how can i make this not count debuffed aces?
not SMODS.drawn_cards[i].debuff (also context.hand_drawn == SMODS.drawn_cards and it's probably better than using an internal value that might change)
thanks
Is there a way to conditionally take_ownership of an enhancement? Context is I’m trying to make a voucher that when redeemed modifies the behavior of an enhancement
My initial approach was to take ownership of the enhancement and then check for voucher redemption to modify the calculate function, but that doesn’t help with changing the text descriptions on the enhancement and such
You can return key in loc_vars to change the description.
can i directly patch an audio file?
because using SMODS.Sound for certain stuff does not work
how do i add a separate text box for a card?
Returning a new key or the original key of the enhancement?
What is the goal?
No, the key of a localization entry.
trying to replace the ambientfire sound
and the organ for the high scoring hand
using SMODS.Sound does not seem to work
You can't patch an audio file, you would have to patch where it plays the sound.
like this
does anyone know what the multiplayer nemesis blind uses instead of G.GAME.blind.chips to see the chips your opponent has?
never played mp so i might be wrong but this?
i dont see it..
the "tooltips" this part refers to
i see, but looking at the flame handler file, it seems complicated, how would i do it per se?
how do you get the current cost of a card
card.cost
How do you make it do that you get a joker when you select a certain deck?
config = {jokers = {'j_modprefix_key'}}
thanks
SMODS.Joker{
key = "windmill",
config = {
extra = { chips = 0 }},
loc_txt = {
['name'] = 'Windmill',
['text'] = {
[1] = 'This Joker gains {C:blue}+20{} Chips when a',
[2] = '{c:attention}card Enhancement{} is removed',
[3] = '{C:inactive}(Currently {C:blue}+#1#{C:inactive} Chips)',
[4] = 'CURRENTLY BROKEN!'
},
},
pos = { x = 0, y = 5 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.chips } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
for _, scored_card in ipairs(context.scoring_hand) do
if context.setting_ability == true then
card.ability.extra.chips = card.ability.extra.chips + 20
return {
message = "Upgrade!",
colour = G.C.BLUE
}
end
end
end
if context.joker_main then
return {
chips = card.ability.extra.chips
}
end
end
}```
how do i fix this joker?
im aware i havent defined the ability but like
idk what smods function is used to declare a card enhancement removal
if context.setting_ability and G.P_CENTERS[context.old].set == 'Enhanced' and G.P_CENTERS[context.new].set ~= 'Enhanced' then
card.ability.extra.chips = card.ability.extra.chips + 20
return {message = localize('k_upgrade_ex'), colour = G.C.BLUE}
end
You know, while developing API or QoL-only mods has own benefits (like no need to draw or come up with new content ideas), it has own drawbacks.
And the biggest 2 of them are: balatro players can't read, and balatro players are lazy.
This makes my life so so much more difficult. Starting from people have no idea how to install mod properly, ending basically too lazy to update mod to get new and better features.
If you will work with smth similar, take this into account. Its much bigger problem that you think
Code?
SMODS.Joker{
key = "windmill",
config = {
extra = { chips = 0 }},
loc_txt = {
['name'] = 'Windmill',
['text'] = {
[1] = 'This Joker gains {C:blue}+20{} Chips when',
[2] = '{C:attention}card Enhancement{} is removed',
[3] = '{C:inactive}(Currently {C:blue}+#1#{C:inactive} Chips)',
},
},
pos = { x = 0, y = 5 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.chips } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and not context.blueprint then
for _, scored_card in ipairs(context.scoring_hand) do
if context.setting_ability and G.P_CENTERS[context.old].set == 'Enhanced' and G.P_CENTERS[context.new].set ~= 'Enhanced' then
card.ability.extra.chips = card.ability.extra.chips + 20
return {message = localize('k_upgrade_ex'), colour = G.C.BLUE}
end
end -- credit to Somethingcom515 for the enhanced ability thing
end
if context.joker_main then
return {
chips = card.ability.extra.chips
}
end
end
}```
Replace everything in calculate with the code I gave you except the context.joker_main check.
whenever im here nowadays its either
- tries coding something with zero equivalent in the vanillaremade wiki
- a simple mistake
and i love it /positive
oke
does not crash but does not replace rank
it works! thank you
if v:get_id() ~= 2 then
SMODS.change_base(v, nil, '2')
end
b is the prefix for backs, not j
so it shouldbe b_sj_2_deck
j is for jokers
thank you flash card /lh
LOL
where do I find the code for Merry Andy's effect?
for editing or reference purposes?
I want to create my own custom joker with a similar effect pertaining to discards
I wanted to see how Merry Andy's code works to see how I could go about making my own
use vanillaremade for reference, it remakes vanilla content in a manner similar to how modded content should be made
https://github.com/nh6574/VanillaRemade/blob/main/src/jokers.lua#L3821 this should take you right to merry andy
thank u
yeah that works heres the code if anyone else uses G.GAME.blind.chips for anything
function Game:update(dt)
upd(self, dt)
-- Only run during a game run
if G.STAGE ~= G.STAGES.RUN then return end
if G.GAME and G.GAME.blind
and G.GAME.blind.config.blind.key == 'bl_mp_nemesis' then
G.GAME.blind.chips = to_big(
MP.INSANE_INT.to_string(MP.GAME.enemy.score)
)
end
end
i think im dumb ðŸ˜
SMODS.Joker{
key = "limepie",
config = {
extra = { dollars = 8, discard_sub = 1 }},
loc_txt = {
['name'] = 'Lime Pie',
['text'] = {
[1] = 'Earn {C:money}$8{} at end of round',
[2] = 'Payout reduced by {C:money}-$1{}',
[3] = 'per discard'
},
},
pos = { x = 2, y = 5 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.dollars, card.ability.extra.discard_sub } }
end,
calculate = function(self, card, context)
if context.discard and not context.blueprint and context.other_card == context.full_hand[#context.full_hand] then
local prev_gold = card.ability.extra.dollars
card.ability.extra.dollars = math.max(0, card.ability.extra.dollars - card.ability.extra.discard_sub)
if card.ability.extra.dollars ~= prev_gold then
return {
message = localize { type = 'variable', key = 'a_dollars_minus', vars = { card.ability.extra.discard_sub } },
colour = G.C.YELLOW
}
end
end
if context.end_of_round and context.game_over == false and context.main_eval and not context.blueprint then
if card.ability.extra.dollars - card.ability.extra.discard_sub <= 0 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize('k_eaten_ex'),
colour = G.C.RED
}
end
end
calc_dollar_bonus = function(self, card)
return card.ability.extra.dollars
end
end
}```
it returns with "ERROR" likely because of an undefined key
which liek
i dont know how to define it so like
also it doesnt gimme the monies
what do I do?
hmmm
lemme check my code
is this in a localisation file (en-us.lua)
i believe you'd need to add a descriptions bit, maybe?
descriptions = {
Back = {
b_vremade_abandoned = {
name = "Abandoned Deck",
text = {
"Start run with",
"no {C:attention}Face Cards",
"in your deck",
},
taken from en-us.lua
yes
hm
Don't think so
all good
idk im pretty new
i only started coding proper like, december
before that i used to use jokerforge for everything
lol I started like 2- 3 weeks ago
I feel like I am doing horribly
Anyone know if theres a way to change the pitch of a sounds if its played within a calculate function? Would I need to make an event?
play_sound('modprefix_key', number) or pitch = 1 if it's in a return.
oh, that works in a calculate funtion? for some reason I thought it didnt
my fault lol
i'm not quite sure how SMODS.mod.process_loc_text works, can someone please explain?
what are you trying to achieve
i want to add a localization string
you should use a localization file to do that
i mean specifically i have this line
info_queue[#info_queue+1] = G.P_CENTERS.m_coin
how do i define a p_center
the game should automatically define it
I just released v0.9.0, please be aware of the breaking changes: https://github.com/ethangreen-dev/lovely-injector/releases/tag/v0.9.0
but if this is a custom enhancement, it needs to be m_modprefix_coin where "modprefix" is your mod's prefix
this is not a drill
have you looked at the release notes willy ðŸ˜
yes
phew
did you forget about https://canary.discord.com/channels/1116389027176787968/1214591552903716954
this is not a custom enhancement
what is it then
i'm just trying to add a tooltip
to be clear, this is a completely custom tooltip that isn't supposed to be the description for any card modifier/joker/etc in the game?
yes
put it in descriptions -> Other -> m_coin in your localization file, format it the same (containing a name string and a table of text), and then do this:
info_queue[#info_queue + 1] = { set = "Other", key = "m_coin" }
what did I do wrong
[SMODS FOXALATRO "FOXALATRO.lua"]:92: attempt to index field "consumables" (a nil value)
if #G.consumables.cards + G.GAME.consumable_buffer < G.consumables.config.card_limit then
consumeables notice the e
no that's a typo on my end, in the code it's written correctly
wait
am I stupid
I misunderstood sorry
sobbing
did you also know that hierophant's internal ID is c_heirophant
what is the fools key for it to be called in add_card ?
is it just the_fool or something else
c_fool
thanks
all consumables start with c_
hey guys
what would your reccomendation for a modding tutorial be
or should I just learn Love 2d in general
is there an equivalent for for i, removed_card in ipairs(context.removed) do but for joker cards instead of playing cards?
Looking for some help with a joker, trying to destroy a random card for every G.GAME.probablities.normal if you play 5 scoring cards, but I can't wrap my head around how to make the random selection not have a chance of selecting the same card twice, let alone function. I've tried looking at the code for immolate but I can't piece it together, any help would be very appriciated!
(here is what I have so far, I'm aware it wouldnt be functional lol)
like for joker card owned? or for jokers destroyed?
jokers destroyed
context.joker_type_destroyed but it doesn't work the same way, it's called once per card
so if multiple jokers get destroyed at once (ex. Ankh) it would trigger once for each destroyed joker?
with context.joker_type_destroyed
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-start-making-balatro-mods
there are resources at the end of this question too
yes
Okay, think I'm getting closer, getting an error on line 159, but I think its starting to make a bit more sense, still not sure if this would even function as intended though ðŸ˜
oops I didnt put the line numbers
oh sweet, that makes more sense ty
okay I can boot in now but it doesnt seem to be destroying cards, am I using "SMODS.destroy_cards" correctly?
actually it's not triggering anything at all, probably something is wrong in the conditions to make it return
okay yeah that was it, its crashing now but atleast something is happening lmfao
had a thought, and was wondering if this would be possible or not with Balatro's engine
would it be possible to make a deck where the top card of the deck is face up? as in, it'll show you the next card you'll draw in your deck?
I'm sure it's possible through lovely patches but am curious if SMODS has anything built in for cases like that
it doesn't
i dont think it would be hard to do tho
iirc you would need to render the other layers of the card
I think there's a check for it being in the deck but I cant remember where that is
there should be a helper in the game for it
New to modding but using the mod manager and grabbing this regirock (Makes all cards act as stone cards) turns all cards white. Who do I need to reach out to? wanna make sure this is on someones radar if they arent aware.
I know misprint has functionality for getting the rank and suit of the next card in your deck, so I'm sure I can piggyback off something in the base game
the top card is in G.deck.cards[#G.deck.cards]
I'm not sure if the alignment in the deck area is from top to bottom or not
please split your patches bro
or at least organize them really well in the file
the pokermon github
also this kind of question is for #⚙・modding-support
thanks
yeah my longest one is 113 because i have multiple
maybe split it just for organization
What do I do?
your localization is not the issue im pretty sure
oh wait
you opened two tables in the text and only closed one
thanks a lot dude
the code for the back if you are wondering
it should be text = {"string1", "string2", etc...} not text = {{"string", "string", ...}}
that may not fix it but it is an issue
ok
I forgor
am I allowed to put an arbitrary function in my joker (to avoid code duplication)?
Or should I put it somewhere else
yeah you can
fuck yeah
the entire thing is copied over so you can just , do that
I think I'm grossly misunderstanding how to use SMODS.destroy_cards ðŸ˜
worked
how is it nil
is it possible to have a function on a joker that detects when playing cards are triggered by any means
*retriggered
😠I have no idea
uhhhh I don't think so lmfao
oh one issue with your code
1.0.0~BETA-0506a-STEAMODDED
LMFAO
i was JOKING
BAHAHA
It doesn't display the deck correctly...
https://github.com/Steamodded/smods/releases/tag/1.0.0-beta-1224a go here and update
TWEAKING
Okay I'll update that thank you
ðŸ˜
you never set the atlas in the back definition
add atlas = "2_deck", somewhere
ok
like, +1 mult any time a card is retriggered for example
I found context.repetition in the wiki but I'm not sure it works perfectly for this since it seems to randomly add values when nothing happens
im not sure myself, but check https://github.com/Steamodded/smods/wiki/Calculate-Functions
there is every calculate context in there so if there is a way you'll find it there
its still crashing but now I dont even get an error message dawg what did I do ðŸ˜
I'll try to double check
context.repetition is for adding retriggers, not for checking them btw
do you have a 2x version of your png
yes
this?
ah
you set pos to x=1,y=3
but your atlas is only one sprite
anything past that is just treated as empty space - it doesn't loop over
so put it to 0,0?
yes
yep
in loc vars return put a localize { name = "whatever", etc }
also hiii heloo haiii :3
meow
i actually have no clue if theres no error message or anything
OKAY SO ITS KINDA WORKING, only issue is its destroying cards left in my hand, not the scoring ones, I'm assuming I need to change "G.hand.cards" to something to refer to specifially the scoring cards?
oh yes
I just had to move where my smods.destroy_cards was
g.hand is your hand, G.play is the cardarea youre looking for
also
you should probably movew the smods.destroy cards outside of the return but still inside of the if-statement
okay I'll try that too, thank you!
its not technically an issue but basically youre returning xmult = [number], message = [string], 1 = nil, remove = [boolean]
which is a little strange
Would this be how you call it?
update_hands = function(card)
if G.playing_cards then
local steel_tally = 0
for _, playing_card in ipairs(G.playing_cards) do
if SMODS.has_enhancement(playing_card, 'm_steel') then steel_tally = steel_tally + 1 end
end
local new_handsize = math.min(math.floor(steel_tally / card.ability.extra.divisor))
local change = new_handsize - card.ability.extra.hand_size
if change ~= 0 then
G.consumeables:change_size(change)
card.ability.extra.hand_size = new_handsize
end
end
end,
calculate = function(self, card, context)
if context.remove_playing_cards or context.playing_card_added or context.setting_ability then
card.ability.update_hands(card)
end
end,```?
well, it'd be . since i'm not asking for self
right
probably should just because its standard with every other function but thats up to you
:P
either way it would be self rather than card.ability in which you find the function
yaha! it works!
how does one make a subcategory of hand type (like how royal flush is a subcategory of straight flush, though its still a straight flush)
how would I make a joker that makes all cards considered the first played card?
I might know how
for my patches (my mod is basically just patches), do I:
3
4
2
split it
i don't think that's feasible
the way content generally checks for "first played card" is just to check if the card is the first element in G.play.cards, which is like. a regular array. you could probably do some shenanigans with moving cards into the first slot when it's their time to score, but that might have visual effects + it won't work with anything that affects the first played card outside of context.individual
even if it was feasible to do what you set out to do, that would not be remotely close to it
Your best bet is to override everything that triggers on first scoring card but that would suck ass
yeah
wh
how would you check if you played a hand with context
I saw something about accessing the discard pile in the smod wiki but I'm not sure how to make use of it, how would i for example access the last card in the discard pile?
something to do with context.cardarea == G.discard
when adding rarities to the atlas how do i actually add them to the rarity pool
i thought adding new ones would make it default to 5 since 4 is legendary
doing rarity = "whatever" doesn't work
how do I debuff a random joker?
i give up, is there a way to change the rarity string/color through loc_vars so i can just set the rarity to 4 and display it like it's a new one?
something like
can i see the joker
it should be modprefix_key
G.discard.cards[#G.discard.cards]
how do I make variables in joker text update in menus? more specifically where do I put the condition to update those variables to be updated in the menu?
in the joker object or the rarity?
In your case, you'd need to set it in the Joker description to be +#1# Chips to point to a variable.
it's pointing to it, it just does not update in the menu
left is in use, right is in collection/shop
like how people spy the top of the deck with misprint
Post the code?
SMODS.Joker {
key = "Dusty Cabinet",
loc_txt = {
['name'] = 'Dusty Cabinet',
['text'] = {
[1] = '{X:chips,C:white} +1 {} Chip for every person playing',
[2] = '{X:default,C:edition}#1#{} on {C:dark_edition}Steam',
[3] = '{C:inactive}(resets every blind)',
[4] = '{C:inactive}Currently {C:blue}+#2#{C:inactive} Chips'
},
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
cost = 4,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
config = {
extra = {
name = "",
activegame_players
}
},
loc_vars = function(self, info_queue, center)
return {
vars = {center.ability.extra.name, center.ability.extra.activegame_players}
}
end,
calculate = function(self, card, context)
recheckSteam()
card.ability.extra.activegame_players = activegame_players
card.ability.extra.name = activegame_name
if context.joker_main then
return {
color = G.C.BLUE,
message = "+" .. card.ability.extra.activegame_players,
chip_mod = card.ability.extra.activegame_players
}
end
if context.end_of_round and context.game_over == false and context.main_eval and not context.blueprint then
recheckSteam("please")
return {
message = localize('k_reset')
}
end
end
}```
recheckSteam() calls steam api code for a random game name/active player count, similar to the yahimod twitch logic
joker, its missing the prefix
Maybe give activegame_players a number value in the extras?
what prefix, where do i set that
that helps but I think I need to call recheckSteam at an earlier time
values are just the default of my local variable bc it doesn't run that until calculate()
let me check how vanillaremake misprint works
j_MODPREFIX_JOKERKEY
it should be in your mod's json
its for a rarity
Then it'd be MODPREFIX_RARITYKEY?
yeah
is it possible to make a mod that allows me to run tarot loops as fast as possible? I already have the script for loop automation, but even with animation skip I still have to wait a half second after emperor to use the next tarot
works but the badge color and the rarity name don't show up
vanilla remade doesn't have much info on adding new rarities
that last screenshot doesnt make sense
where is that
did you read the documentation
hi!
so im having an issue with a custom context not working
SMODS.current_mod.calculate = function(self, context)
-- [...]
if context.nflame_post_shuffle then print("otherside") end
end
local cas = CardArea.shuffle
function CardArea:shuffle(_seed)
local retr = cas(self, _seed)
print("from hook")
local sortab_raw = {}
local sortab = {}
SMODS.calculate_context({ nflame_post_shuffle = true, cardarea = self, seed = _seed }, sortab_raw)``` these two prints work just fine and fire properly
so its not an issue with setting up the context
but in my boss calculate function lua calculate = function(self, context) if context.seed then print(context.seed) end if context.nflame_post_shuffle then print(context.seed)
it doesnt hit either trigger
does it work if you print without any context check
hm ill try that
pr'd a fix
Alright, why isn't it working?
(fyi, it's supposed to buff the second most common suit ignoring ties)
Why is it showing x1 for both Chips and Mult in the game, but xnil for Money?
card.ability.extra
wait, in the loc_vars?
Nevermind, fixed. Thanks
‎
if i'm using a localization file, when creating a joker/deck/etc should there be something else in place of the loc_txt field?
no
SMODS.debuff_card(joker, true, "unique source string")
how would I set a specific card's repetitions?
trying to do a "mime" effect for specific cards in hand
I have the card object from its index in the hand if that helps
I'd assume just returning a repetitions value would affect all cards
Some guy asked me to make a joker that restores the last destroyed glass card at the start of a blind, any way I could do this?
if context.other_card == card
Yes, every time a glass card is destroyed you would save it in a global variable using Card:save, then you would load it using Card:load
could I exchange other_card for G.hand.cards[x]?
No, it would replace card
How do global variables work? I mean, how can I configure one to only work in a single game?
trying to retrigger cards adjacent to a specific card in hand
not sure how I'd do that
G.GAME.variable = value
Oooooh
Its that simple? Ok
i wonder why this is erroring
trying to check whether a file is a directory/folder
well
i know why it is erroring but im clueless as to how i would be able to check a file's info
oh
oops
i forgot to add an slash
can i change the sound of a message return without changing the message? returning sound doesn't work
i believe the scoring sounds are hardcoded?
ouch
mult_message = {message = 'message', sound = 'modprefix_key', colour = G.C.colour}
you can use localize to create the mult message and set that tho
i dont remember the key for it :(
so you still have to redefine the message
bummer
if i wanted to run a function each time jokers are rearranged (via dragging or jokers being added/destroyed), how would i go about this? is there a function i should hook into, is there a relevant context for this, or?
can i use context.other_card to check a card against copy_card?
as in if i used copy_card earlier to copy a playing card and then used context.other_card to try and see if its the same card as before
does that work or do i need to use a different function/context
No, because two cards cannot be the same.
No, that still wouldn't work, because that just checks the rank.
oh, okay
you want to see if it's the same card as you copied? you can add a flag to the card
how would i do that
copied_card.modprefix_flagname = true if you only need it for a calculation cycle or copied_card.ability.modprefix_flagname = true if you need it to be saved
(you need to set it to nil after using it)
thank you
`calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
local check_copy = copy_card(context.other_card, nil, nil, G.playing_card)
check_copy.states.visible = nil
if check_copy.FOXA_flagname == true then
return {
xmult = card.ability.extra.x_mult
}
end
check_copy.FOXA_flagname = true
end
end`
not sure what i've done wrong here, my intention was to have an effect where if a card is retriggered it grants x mult (check if the card that just scored is flagged, meaning it was scored before, as its supposed to flag a card after scoriing it the first time)
yeah you're setting the flag on the copy
theres no reason to copy the card at all
also you need to reset the flag after a hand is played
what
copy_card creates a new card thats a copy of a given card, so you shouldnt need to use that at all? just set the flag on context.other_card
Hello, it's been a bit. I'm still struggling to get this to work.
I want the edition to have a fixed 1 in 4 to not trigger. The problem right now is that it is triggering non-stop and I don't know how to change that.
I’m still having a bit of an issue trying to make an enhancement work differently (and have different text) once a voucher is redeemed. The main thing is the text, I was told to return a key to a localization entry in loc_cars but I’m a little lost
Trying to take ownership of an enhancement and then check for voucher redemption to then alter its behavior
That itself seems to be fine, but swapping out the text of the card seems tricky
Code?
Yes, because eval_card runs every time a context is called.
trying to make a joker that makes numbered cards also be treated as double their number. what did i do for this to happen
Also you should be using SMODS.pseudorandom_probability
This looks better
You're returning 14 every time but also that is not how you do quantum ranks.
Not even trying to do the voucher logic rn, just trying to test if I can get the localization entry to pop up for the card's text at all since until now I've just done loc_txt for stuff
yeah thanks jokerforge
Put key = 'm_jonkler_stone_upgrade' in the return of loc_vars
Tried this and self.key instead of key, first one didn't work and the second one crashed
hm wait
I see my problem
Okay fixed that, is there a way for me to implement the voucher logic specific part? I want the key to stay the same unless the voucher is redeemed I suppose?
Or maybe I can conditionally take ownership of the enhancement once the voucher is redeemed. Not sure what would work as the best method
No, you shouldn't take ownership after the game has loaded
Good to know
My initial thought is some method of checking for voucher redemption and then setting the key as a result of that, but I don't think that would work since that kind of logic might need to happen after the text stuff is already finished
aren't vouchers also evaluated during scoring
just have the voucher itself give xchips for stones held in hand
So within the voucher itself do calculate and context stuff
local key
if G.GAME.used_vouchers['v_modprefix_key'] then
key = 'm_jonkler_stone_upgrade'
end
return {key = key}
how do you get the level of the played poker hand?
G.GAME.hands[context.scoring_name].level
neato thanks!!
was more so confused on how to get the played poker hand i forgot context.scoring_name is a thing
Forgot I could perform logic within loc_vars like that very handy, thank you
to elaborate, it crashes when i try and do "scored_card"
How can I make a consumable stick around until a function that it called is finished running? It disappears immediately and when the booster pack closes the game freezes
im trying to have it so it converts all played cards into hearts
hm
idk ðŸ˜
me too bestie
keep_on_use = function() return true end
im trying to have it so it converts all played cards into hearts
when a hearts card is scored
And how do I make it not trigger non-stop?
It's context.full_hand not G.scored_cards
You check for a specific context.
And I'm not using that because it's a fixed 1 in 4. I don't want it to be affected by probability changing stuff
No, set the sixth input to true
how can i get all held cards with a specific edition (just like SMODS.find_card)
how it is rn
local cards = {}
for k, v in pairs(G.hand.cards) do
if v.edition and v.edition.modprefix_key then
table.insert(cards, v)
end
end
Remove the .key
bump
It works now, thank you :3
What is the condition that make a consumable usable in a pack
like G.GAME.pack.in_pack idk
this isn't what i mean, i mean how do i prolong the "usage" of a consumable until a function is done doing its thing
i don't want the player to keep it, i just need it not to disappear for a bit of time
i.e. so the booster pack doesn't immediately close
G.STATE == G.STATES.SMODS_BOOSTER_OPENED or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK i think
Yes, you would make it disappear after the function runs.
has anyone else experienced context.post_trigger issues like this?
basically, I have a joker that gains chips when another joker triggers. but for some reason, if I have Oops all 6s, this joker gains chips basically any time I hover over an item in the shop
I could technically just exclude any joker named Oops all 6s, but it'd be nice to know the actual source of the problem so I could fix that instead
Real quick, what is the name of the variable that is all the mult in the scoring?
What is your SMODS version?
1317a
i have a joker that makes it so when you play a flush, it converts all played cards into random suits
although it worked, it was a little janky
so i decided to add a flip animation
now it isnt working
this was originally generated using jokerforge
Is it only when you hover over cards with probabilities?
im gonna go to the bathroom rn, but ill need some clarification as to what it is i may need to do
no, did you remove the text to add the image?
what text
the description you want to add, check if your code removes it
seems like it, yeah
it should be there by default
hold
BadDirector.description_loc_vars = function()
return {
text_colour = G.C.WHITE,
background_colour = G.C.CLEAR,
scale = 1
}
end
SMODS.current_mod.custom_ui = function(nodes)
local logo = {
n = G.UIT.R,
config = {
align = 'cm',
colour = { 0, 0, 0, 0 },
r = 0.3,
padding = 0.25
},
nodes = {
{
n = G.UIT.R,
config = { align = 'cm' },
nodes = {
{
n = G.UIT.O,
config = {
object = SMODS.create_sprite(
5, 0,
8, 4,
'bd_modlogo',
{ x = 0, y = 0 }
)
}
}
}
}
}
}
table.insert(nodes, 2, logo)
return nodes
end
the text thing is there
Thank youuu
do i remove the loc vars thing?
w-why is the button gone
EXACTLY WHAT IM THINKING
ðŸ˜
it happens after i added Mod
it shows but no text?
ok can i see the loc
sure
i think thats the problem
wait, what category should Mod be
that part is fine because it wouldnt break it otherwise
oh brh
return {
descriptions = {
Mod = {
baddirector = {
"{s:1.2}Test{}"
}
},
ah yeah thats the problem
I'm not following
By "function" I mean the consumable calls a function outside of itself when it's used, and then immediately dips
This causes issues because the function operates on cards in hand, and if the consumable is in a booster pack, the pack closes before the function is done and it softlocks the game
So I need the consumable not to dip before the function is done doing the thing
thats why it breaks the button too
fair
Hi, I trying to figure out if I got this code correctly placed
text = {
'Every played odd card {C:attention}odd{}",
"{C:inactive,s:0.8}(Excludes face cards){}" 'permanently gains',
'{C:red}+2{} Mult when scored'
}```
where is it placed..?
and not SMODS.is_getter_context(context.other_context)
It place in Localization
May I ask, what part need to format better
between 2 string in middle line place comma and it should work
Also adding "+2" in localization is working but not correct way to do it, use loc_vars
thanks, that worked!
it works, tyy!
i just gotta position the logo correctly
no matter what i do, it always stretches
wrap it in container then
what container
it is row tho
You actually already did this I see
yeah
Then just adjust sizes for sprite you create
w = 8 and h = 4 is probably not correct ratio for your sprite
oh yeah, speaking of
whats the first and second parameter
x, y
ohhh
when its placed inside G.UIT.O has no effect
noted
hi
ok this isn't what's supposed to happen at all, what went wrong
If I have a .jokerforge file, can I convert it to lua somehow so I can code in effects that joker forge doesn't support?
Im not great at lua yet so I was tryna get as much mileage out of jokerforge as I could
14 is the id of the Ace rank.
ah
that's not supposed to happen at all
what are ids of the numbered ranks, if not just the numbers themselves
It is just the numbers.
when making effects that destroy cards is it supposed to play the destroy sound automatically or do we need to add it in?
it does play a sound im pretty sure
you can export the mod from jokerforge and just look inside its code, though that's highly not recommended because jokerforge code is not meant to be readable or efficient
I did look inside, can I write into it like a standard lua file? Is there documentation on it?
i mean export it like a finished mod
ok so its not doing that for us
then inside the .zip with the mod there will be .lua files and other stuff
It does play the sound unless you use Card:remove.
that you could look at
Yea, I got it exported and such, my issue is that I wanted to add joker effects -- like a midas mask that adds mult cards under certain circumstances -- but I don't know how to code said file, like if I can write in it
would I break the whole thing
.lua files are just text, you can write in them
so why is this not playing the sound then?
local config = card.ability.extra
if context.after and G.GAME.current_round.hands_played == 0 and #context.full_hand == 1 then
local played_card = context.full_hand[1]
if played_card.base.value == config.triggering_rank then
SMODS.destroy_cards(context.full_hand)
J_O_Y.create_tag {
predicate = function(tag_key)
return tag_key == "tag_" .. config.tag
end
}
return { message = localize "j_o_y_fart" }
end
end
end```
but again, jokerforge code is convoluted and you'll be better off starting from scratch yourself
aight so I can write in it as if its a lua file?
cool
Ill try and redo things, thanks!
ok so i fixed the return issue, but i want them to also be treated as their original rank, without having the opposite relationship. any help?
bump
bump again
local suits, suits2 = {}, {}
for k, v in pairs(G.playing_cards) do
suits[v.base.suit] = (suits[v.base.suit] or 0) + 1
end
for k, v in pairs(suits) do
table.insert(suits2, {suit = k, count = v})
end
table.sort(suits2, function(a,b) return a.count < b.count end)
card.ability.extra.target_suit = suits2[#suits2-1]
Are their resources for balatro keywords? Like is_face i see in the midas mask remake, is there like is_enchanted or is_multcard
No, those would be next(SMODS.get_enhancements(card)) and SMODS.has_enhancement(card, 'm_mult')
Thanks!
Is there anywhere I can look for these keys rather than ask about them all here
jokerforge actually lol
theres a page on the left with all the keys
thats hilarious, thank you
yeah its nice, ive never used jf but i use that page
for the functions theres none however, you would need to look at the code
yea I got a remake of midas mask up atm
its a weird joker effect but having this as a semi reference helps a lot
wait you made this midas mask, lmao, thanks for the framework
:3
loc_vars = function(self, info_queue, card)
info_queue[#1116390750314307698_queue + 1] = G.P_CENTERS.m_gold
can I ask what this does? It runs on midas before the function does
the loc_vars function handles passing variables to localization (e.g. a scaling joker displaying its current value) and adding tooltips next to descriptions (e.g. the description for Gold Cards appearing next to the description for Midas Mask)
cool, thanks!
bump
You should be using context.destroy_card
how is that used to destroy a card? wouldnt that only check if a card is destroyed?
as per the documentation, no
https://github.com/Steamodded/smods/wiki/Calculate-Functions
how do I check the position of the card
I wanted to enchant a random card in the hand if that helps the answer
local pos
for i,v in ipairs(G.hand.cards) do
if v == card then pos = i break end
end
the vanilla remade wiki has a lot of answers, and the vanilla remade repo itself is a great learning tool for examples
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-get-a-random-numberelement
and if pos is nil after that it means the card isn't in G.hand
so it stopped working,
if you already have the chosen card then this doesnt do anything....
so, hold on
or at least theres no reason to do the loop
what exactly is the intended behavior here
you want to destroy a card after a hand is played, right?
Code?
incorrect, it gets the card's position in the hand
local config = card.ability.extra
if context.after and context.destroy_card and context.cardarea == G.play and G.GAME.current_round.hands_played == 0 and #context.full_hand == 1 then
if context.destroying_card.base.value == config.triggering_rank then
J_O_Y.create_tag {
predicate = function(tag_key)
return tag_key == "tag_" .. config.tag
end
}
return {
message = localize "j_o_y_fart",
remove = true
}
end
end
end```
i want it to work like how sixth sense does
well okay but you dont need that to enhance a random card
context.after and context.destroy_card don't happen at the same time, so this if condition is always false
when does destroy card happen?
on its own
it's its own thing
they seem to be going at this in a way that does, somehow
why does this for loop keep resulting in slot being 2 (slots_to_retrigger is populated with several values)
it works!
like its exclusively just 2
You can only return once.
... i don't know why it's 2, but it's returning early
ah
