#💻・modding-dev
1 messages · Page 676 of 1
it's a flag in the metadata, it's in the docs iirc
HOOOLY SHIT
all that effort for it to actually be one line of code
thank you N
you are a lifesaver
that's how it is sometimes
had i looked at the docs like a little closer i probably wouldve seen that
you are lucky because i decided to not use discord this week and i only checked the channel randomly while checking a notif
for the mod manager should i get exe or msi for windows?
since when was there a mod manager
#⚙・modding-support but either
mb, is there a difference?
i didnt even know about this mod manager but i'd assume the exe isn't an inst- yeah what he said
i just happened to click on his profile
WHY does this have rich presence
trying to make a joker scale of of its own chips, and the game crashes. any idea how to fix this?
which line is 296
oh
its an issue with dividing a variable these i think
card hasnt been defined yet
so just ability.extra.chips then?
just chips i think
no, you need to hardcode it or make chips a separate variable
you can't use the chips value because it's defined at the same time
so where should it go then?
before smods.joker do
local chips = number
and then use that for chips and chips gain
also chip_message is not necessary there
will that still scale exponentially tho? the general idea is that it scales off of its previous value
ah
no
you need to do that in calculate, the config gets computed once when the game boots
Hey guys, super super question.
Do you know if max_ante = is a thing for tags?
no
ok i think i got it
damn
return (G.GAME.round_resets.ante >= 2 and G.GAME.round_resets.ante <= 3)
end,```
Does this serve for that purpose?
that would work, yes
omg, thanks. ❤️
is it possible to cycle through every card you have (including jokers and consumables) or should i just do it manually (like hand, fyull deck, consumables, and jokers)
Cycle as in viewing them like the deck selector or the collection in vanilla?
Hold on, I should probably not answer with a question without reading the prior context, haha.
Sorry.
Cycle as in ipairs
No the context hasn't been said lol
I'm trying to remove every instance of a certain edition that you have
Oh, I see. Not so sure I've seen that one.
I'll just do it manually
unrelated, is there a function that like. draws the next card
because I have a thing that destroys a card and I feel like it should draw another card in its place
since it's not being done during scoring or anything
draw_card
oh ok lmao
can i do a check to see if the game is currently scoring? is that a variable?
so, I see how to change the color, but what about the highlight? like yk how xmult the red is highlight
wrap it in another UI node
amd then give that node color
when the soul tries to spawn a legendary joker, does it check in_pool?
so like if in_pool returns false, it can't spawn that joker
Yes, it does.
one small issue
do i need all these values
cuz i'm not sure what to set card to because tehres no way self.foobar_reference is a thing
ohwa it im wrong
it can br any card in deck
yeah thats what i thought
if u want the top do G.deck.cards[1]
G.deck.cards is the shuffled deck
kk
also bump
i want to make the ability not usable during scoring
as to not break stuff
Sigh.
Let Me Guess It Doesn't Work Like This
should I use events maybe?
i'm also not sure what percent does
its sound related iirc
try G.deck.cards[#G.deck.cards]
tats usually an issue with improper card destruction i believe
I wasnt destroying cards though
idk
No it's fine I fixed it
balloon :0
also
couldn't find anything in the docs after some skimmin
if next(G.play.cards)?
For some reason, after updating SMODS to 1.0.0-beta-1503a, I noticed that anytime I used SMODS.add_card to create a playing card, or whenever my custom booster created cards, they wouldn't show any suit/rank data on them. Is it possible to fix this within my mod, or do I need to backport to an older SMODS version?
does anyone remember how string substitution works
i forgot
nvm, figured out a better, if not more janky way to do what i wanna do
known smods issue in 1503a
does pseudorandom_element work on keyed tables and if so, is it possible to get the chosen key from the result?
Yes, it's the second output.
how would you capture that?
local result, key = pseudorandom_element(table)
```?
Yes, but you could also do select(2, pseudorandom_element(table)) if you don't need the first output.
what's the simplest and most efficient way to pull two unique nvm thought of a better solutionpseudorandom_elements from one table
~~```lua
local result, key = pseudorandom_element(table)
is leaving both result and key nil despite a populated table~~
nope, nvm, i'm dumb. forgot about card configs
does notable.remove(t, 1) work on keyed tables?
Hey. How do I refer to the total number of cards in deck?
#G.deck.cards does current cards in deck, not what I'm looking for.
I found it. It's #G.playing_cards.
Discord's search can be a godsend sometimes.
is xchips and exponent built into SMODS? if so, or if not how to I implement it.?
Xchips is, exponents are not
You can implement them by hooking SMODS.calculate_individual_effect, see how other mods add calculations that way
iirc rank and suit currently need to be the card_keys and supplying keys doesn't work
and not supplying both results in no front, both of these should be changed
Okay, thank you. But where would I put this?
I'm quite terrible at lua coding, and have been reusing vanilla code with modifications.
You could also just do return {mult_mod = (-mult)+mult^number, message = '^'..number..' '..localize('k_mult')}
Thank you, so just at the top of the Joker's code or the Jokers code?
It would go where you want to give the exponential mult.
k, thanks
I'm trying to remake the boss tag so that it disables the boss instead of rerolling it, and it's not working, and I'm pretty sure it's the context.type stuff but idk
the way it works is that the tag just stays there until you enter a boss and then it activates and disables it, like selling a Luchador
if context.type == 'round_start_bonus' and G.GAME.blind.boss and not G.GAME.blind.disabled then
tag:yep('+', G.C.GREEN, function()
return true
end)
G.GAME.blind:disable()
tag.triggered = true
return true
end
TYTYTY
one more thing, I'm modifying the voicher tag to make it free and I can't for the life of me figure out how to do it
I tried like 8 different things and nothing works and idk what properties vouchers have
You should be using take_ownership, also you would have to hook Card:set_cost
sorry it's not taking ownership, I'm planning to do something else
also how do I even hook card:set_cost like what does that mean
I feel bad for asking but I'm new to this
YOU ARE AMAZING
how would i supress all normal game inputs?
Why
doing a custom minigame thing that uses base love2d stuff and it breaks if you pause and exit the run while it's active
I think you set game state to something that's not selecting stuff?
Oh, maybe G.CONTROLLER.locks.use = true?
ty
Shit gtg back to work
im not sure if there's a state that stops pausing
i feel like what you should be doing in that case is to make it not break in that circumstance rather than just prevent the player from pausing and exiting the run
i mean sure ig they can just alt f4 if they need to, but
but a hacky way of forcing this could be to do something like
if G.SETTINGS.paused then
G.FUNDS.exit_overlay_menu()
end
alternatively you can hook G.FUNCS.options and G.FUNCS.go_to_menu and just have them return early when your minigame is active, which is probably better
thoughts on this? legendary? or give it a big drawback and make it custom rarity?
This is fine as rare i think
Since you need a ton of hands to get a lot of the really good jokers
Yeah, rare
How do I apply mult/chips from context.before?
don't, use context.initial_scoring_step
Thanks
😈
calculate = function(self, card, context)
if G.STATE == G.HAND_PLAYED then
return { mult = -1 }
end
end
so -1 mult for every context?
pretty much - a silly little idea that i had
why does this happen
SMODS.Consumable {
key = 'igoera',
set = 'scarlet',
atlas = 'deconsume',
pos = { x = 1, y = 1 },
loc_txt = {
name = 'Igoera',
text = { '3 selected cards are', 'upgraded to {C:attention}Premium{}' }
},
cost = 3,
config = {},
loc_vars = function(self, info, card)
return { vars = { card.ability.extra } }
end,
use = function(self, card, area, copier)
end
}
SMODS.Atlas({
key = "modicon",
path = "icon.png",
px = 32,
py = 32
})
SMODS.Atlas({
key = "dejoker",
path = "dejokers.png",
px = 71,
py = 95
})
SMODS.Atlas({
key = "deconsume",
path = "consumables.png",
px = 71,
py = 95
})
SMODS.current_mod.menu_cards = function()
return { -- This takes any SMODS.create_card parameters
key = "c_deja_vu",
remove_original = false -- This removes the vanilla Ace
}
end
local may = {}
may.items = {
'jokers.lua', 'pokerhands.lua', 'scarlet.lua', 'code.lua'
}
may.lib = {
'recharge.lua'
}
for k, v in ipairs(may.items) do
assert(SMODS.load_file("items/"..v))()
end
for k, v in ipairs(may.lib) do
assert(SMODS.load_file("lib/"..v))()
end
This is just a guess but it looks like what'd happen if you forgot to scale the image file in your assets/2x folder by 2x.
i did
same bug
scale it by 4x instead just to see what happens (this is never actually correct, I'm doing science)
sprite didnt change
what is your pixel art smoothing setting?
off = uses your 1x asset
on = uses your 2x asset
then the file hasn't been scaled
how this happened, i can't imagine, but that's what this result means
the sprites are correct, but i want to fix it in the code
there's no error in the code
did you make the image bigger, or the canvas?
odd
your code and images are both correct
i guess balatro arbitrarily doesn't work for you for no reason
literally 1984
what precisely did you do when you tried scaling the 2x image by 4x for science?
quadrupled 1x's image size and replaced the 2x image with it
(this should not fix the problem, but it should at least make it a different problem)
then committed it with vscode
try doubling the 2x image directly
nothing changed
okay. at this point i suspect the game isn't looking at the 2x image you think it is for the 2x sprite. test 2 of this hypothesis, scribble randomly over the 2x image
nothing changed
okay, so that image is straight up not the 2x sprite sheet
i dunno why i nilchecked center.
what does your asset folder look like?
like actually, is there anything that could warrant nilchecking for center in locvars
when i look at it in vscode it isnt updated correctly, but in file explorer its correct
is your vscode environment actually operating on the same folder as the one balatro loads from?
the appdata mods folder
yeah that'd do it. editing the wrong file entirely
hey everyone, I was wondering if anyone knows in which context glass cards get destroyed
i've heard that there's a function that should be used instead of math.random, what function is it?
something something pseudorandom?
i need this for the title screen, so it needs to be unseeded
(i assume pseudorandom needs a seed, but i might be wrong)
do you need the context to do a similar effect or do you need the context to detect them getting destroyed?
well the joker idea that I have is one that enhances scored cards to glass cards only for as long as they are in the played hand, e.g. after scoring they are unenhanced, but currently, when using the context where I unenhance them (final scoring step) right now is seemingly causing glass cards to never shatter
do it in after
it happens during context.destroy_card which is just before after iirc
right that worked. thank you!
you dont have to give a seed i think
if you pick something from a table i believe its pseudorandom_element
as in to hook or for an individual card
to hook
idk i wanted to hook that earlier but found an alternative
its probably next to the one to start a game
im pretty sure using pseudorandom with a seed outside a game just runs math.random with no seed
but you can also use math.random directly in that scenario
i've tried that, but it's giving me the same number repeatedly
do i need to plug in the current time?
alright gotcha, thanks ^^
heyyyyy quick little question, how would I have a joker where hearts & clubs are the same suit
-# who doesn't love a weird mixed up half smeared joker
Hook SMODS.smeared_check.
local oldsmodssmearedcheck = SMODS.smeared_check
function SMODS.smeared_check(card, suit)
if not next(SMODS.find_card('j_modprefix_key')) then
return oldsmodssmearedcheck(card, suit)
end
if ((card.base.suit == 'Hearts' or card.base.suit == 'Clubs') and (suit == 'Hearts' or suit == 'Clubs')) then
return true
end
return oldsmodssmearedcheck(card, suit)
end
All of the code I have works, but how do I update the blind chips visually after changing the ante scaling? I'm assuming you use some sort of HUD_Blind thing but idk
since this is a tag it's outside of a blind, I want to update the chips on all the blinds visually before I enter one (after I enter and leave a blind it works fine)
why that way around and not
local oldsmodssmearedcheck = SMODS.smeared_check
function SMODS.smeared_check(card, suit)
if
next(SMODS.find_card('j_modprefix_key'))
and ((card.base.suit == 'Hearts' or card.base.suit == 'Clubs')
and (suit == 'Hearts' or suit == 'Clubs'))
then
return true
end
return oldsmodssmearedcheck(card, suit)
end
honestly imo smeared should just be made into a calculate call with its own context
Is there a way to iterate over the entire localization file using current_mod.process_loc_text?
Most examples assign to specific strings individually
so I've got an idea & am having an immense struggle bus trying to get it to happen, I'm trying to make a joker that makes played debuffed cards give 100 chips & 2.5 xmult, I've gone back to a clean slate now & can't think atm where to start
you can cheat around it by making the joker score those cards in another context that's not individual
the animations will happen at a different time tho
I'm creating a new polychrome tag that gives polychrome to the next joker you buy instead of just adding it to one in the shop, but I don't really know what the context.type is for this scenario. There might be something else wrong too
i dont think there's a context for that
i would use your mod's global calculate with context.buying_card and call tag:yep from there
how would i make a joker that copies the ability of a random joker you have every round?
you would need to set a flag on that joker (joker.ability.modprefix_flag = true or something) and then copy blueprint's code but instead of checking for position you check for that flag
you would also need to decide what you do if the joker is not there anymore
i guess i could have it check on round start
if card.area and card.area == G.jokers then
local other_joker
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then other_joker = G.jokers.cards[i + 1] end
end
local compatible = other_joker and other_joker ~= card and other_joker.config.center.blueprint_compat
main_end = {
{
n = G.UIT.C,
config = { align = "bm", minh = 0.4 },
nodes = {
{
n = G.UIT.C,
config = { ref_table = card, align = "m", colour = compatible and mix_colours(G.C.GREEN, G.C.JOKER_GREY, 0.8) or mix_colours(G.C.RED, G.C.JOKER_GREY, 0.8), r = 0.05, padding = 0.06 },
nodes = {
{ n = G.UIT.T, config = { text = ' ' .. localize('k_' .. (compatible and 'compatible' or 'incompatible')) .. ' ', colour = G.C.UI.TEXT_LIGHT, scale = 0.32 * 0.8 } },
}
}
}
}
}
return { main_end = main_end }
end
end,
calculate = function(self, card, context)
local other_joker = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then other_joker = G.jokers.cards[i + 1] end
end
local ret = SMODS.blueprint_effect(card, other_joker, context)
if ret then
ret.colour = G.C.BLUE
end
return ret
end
}``` which part of blueprint denotes the position?
it loops until it finds blueprint in G.jokers.cards[i] and then it gets i+1 which is the card to the right
ah ok
fuck fuck what did I do, I was already treading weird waters with reversing boss blinds, then suddenly I've been getting this error, tried a simple step back to something I knew ran fine, but that ain't the fix & I'm worried I've just screwed everything
TY FOR THIS IDEA, might just make a transcendent joker (Acheron) that reverses boss blinds 10x in a row
do you mean replacing the apply function with a calculate function? I thought that didn't work for tags, is a global calculate function different
ok am I doing this right or is this the wrong way to implement global calculate (I'm making the tag give polychrome to the next joker you buy)
ok it broke bc I didn't even say what the tag was lol oops
Yes, you need to iterate over G.GAME.tags and check if v.key == 'modprefix_key'
sorry for sounding stupid but what do you mean by iterating over G.GAME.tags
oh I get it
thank you lol
it's still not working and I'm really sorry for the constant asking for help but I don't know what to do
global calculate is something I've never done before
Replace the "vremade" in the check with your mod prefix
vremade is what I'm using to learn lol
I've programmed in other languages but this is my first time with anything lua
Also, it should be v not tag
Is it possible to add a badge from another mod for crossmod content
Like for the partner badge can you set it to display that badge when it'd otherwise be inaccessible without partner
How do I add dynamic line to description? (like ankh adding "removes negative from the copy" when you have a negative joker) I've tried to copy Ankh's loc_vars from vanillaremade but it doesn't work
You can return key in loc_vars to a different localization entry that contains the extra line.
Thanks
Is it possible to make all jokers from my mod 2x more common in the shop for a deck? If so, how would I do this, and if not, what are some things I could do to achieve a similar effect?
local oldgetcurrentpool = get_current_pool
function get_current_pool(_type, _rarity, _legendary, _append)
local g, _pool_key = oldgetcurrentpool(_type, _rarity, _legendary, _append)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.effect.center.key == 'b_modprefix_key' then
for k, v in pairs(copy_table(g)) do
if v ~= 'UNAVAILABLE' and G.P_CENTERS[v] and 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(g, v)
end
end
end
return g, _pool_key
end
```?
if you're just adding something, you can also use main_end
you can put dependencies on an object to both only exist if the other mod is loaded, and add its badge
making a tag that creates 2 other random tags, I can't figure out what I've done wrong
How would you create a joker where a property of it must be above a threshold (e.g. only Jokers that cost more than 7 or have "immutable" as true)
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].cost > 7 or G.P_CENTERS[v].immutable) then
table.insert(jokers, G.P_CENTERS[v].key)
end
end
end
local key = pseudorandom_element(jokers, 'seed')
if key then
SMODS.add_card({key = key})
end
makes sense
G.tags isn't what you want here. add_tag { key = psuedorandom_element(G.P_TAGS, 'tag_vremade_random).key }
TYTY
Tried it and it crashes when trying to create a Joker that is already present (I think at least)
oh wait nah I found the solution
yeah nah I didn't
one final thing with this, when the tag is triggered the two tags it produces don't, even if they're supposed to trigger immediately like a garbage tag or something
lmk when you figure it out
hi im trying to create a joker that gains mult only when selling jokers (and not other cards) and i tried doing this code but testing it also gains value when selling other cards, any ideas?
my bet is that context.cardarea returns card area of THIS joker, not the one that is being sold
and is there a way to return the area of the other jokers?
im kinda new to modding and i still dont know a lot of things sry
if context.selling_card and context.card.ability.set == 'Joker'
that worked!! thank you so much
why are my jokers ignoring the "one card of each max" rule
Did you spawn that joker with DebugPlus?
ye
That's the answer, they still can appear if spawned with debugplus
So in normal run this won't happen
ok
what mult on a boss blind should i put for a garunteed the soul (inspired by panopticon)
is it same as add_tag(Tag(key))?
yes
yo anyone here know how to make a texture pack for just one card?
ive made the texture pack, but its only for one card so i just want it to only be that one card (standard joker)
ahh okay
so whenever you're making a custom context, how can i modify a variable declared in the context?
like i have a damaging context but i have something that scales down your damage and it seems to modify stuff locally, but it doesnt actually change the context value
and im not really sure how effect tables work or how to implement them properly
do you want to modify a context.something or do you mean a return in that context?
Would it be possible to like. Exit a blind without cashing out, and mark it as skipped?
Also, how do you influence hands per round, permanently and temporarily
I figured out how to do it temporarily, but not permanently
And same with permanent hand size
tysm
and bunp
is it possible to make a gradient with another gradient as a constitutent colour or do you have to do merging stuff
you can definitely do that, and I don't think it's easily replicable by doing something else, either. Might look weird though as you'd have moving interpolation endpoints
i agree. what if i wanted to extract the constitutent colour table of a gradient to be part of a new gradient table
there's utils for merging tables
i know - my hang up is how i would get the tables of the gradient in the first place. can i just do .colours?
I made a tag that creates 2 other random tags, but when it's triggered the two tags it produces don't trigger immediately, even if they're supposed to like a garbage tag or something
...do non-gradient colours have colour tables too? how do i distinguish between them
a colour isn't any type of complex object, it's just a table of 4 numbers
a gradient is an extension on this which still has indices 1-4 akin to being a colour, but have additional fields that define their behaviour as gradients
the colours table on a gradient is, in turn, a table of an arbitrary amount of colours
i see
i must turbojank my implementation then
G.STATE = G.STATES.BLIND_SELECT
G.STATE_COMPLETE = false
G.GAME.blind:defeat()
ease_chips(0)
G.FUNCS.draw_from_hand_to_discard()
G.E_MANAGER:add_event(Event({
func = function()
G.E_MANAGER:add_event(Event({
func = function()
G.E_MANAGER:add_event(Event({
func = function()
G.FUNCS.skip_blind(G.blind_select_opts[G.GAME.blind_on_deck:lower()]:get_UIE_by_ID('tag_'..G.GAME.blind_on_deck).children[2])
G.GAME.tags[#G.GAME.tags]:remove()
return true
end
}))
return true
end
}))
return true
end
}))
bump
help
it really specifically does not like trying to draw the new badge with the gradient
ohhhhhhhhhhh
figured it out nope, nvm. i'm just gonna implement this a different way
ok so the lesson here is to just not try and create gradients during runtime
don't do that
I have a problem with my consumable set. My set has two rarities, which I use to make some cards more rare than others. However, these consumables can be added and removed from the pool at any time, meaning if all consumables from rarity 1 are unavailable, then the shop will spawn jimbos in their place, instead of defaulting to rarity 2, which is what would be left. I understand that this is to keep rarer cards from becoming too common, however this is not how I want the set to work. can I disable this?
disable_if_empty https://github.com/Steamodded/smods/wiki/SMODS.Rarity
Does anyone have tips on where I should start with coding in Lua? This is my first time going into coding fully, I'm not completely clueless but it sure feels like I am at times lol, looking at some of this stuff is overwhelming so I just need a specific place to start at
Like any recommended tutorials/guides
For Lua as a whole no, but for Balatro modding there's a pretty decent guide here #1349064230825103441
I've also been working slowly on a video guide for balatro modding so hopefully that becomes of use when its finished too
Thanks cause I really couldn't find many helpful things, I found how to get the source code for balatro but not really what to do with it
happy to help
Is it possible to change the weights of booster packs mid-game? I've attempted to change the weight of a booster pack of mine using the un-commented code shown (which equates to ~20,000 for testing purposes), and nothing changes. However, when I manually set it as shown to 9,999 it shows up effectively 100% of the time, which makes me think that it doesn't update the weights automatically
where on the smods docs is talisman compat/power mult located? i saw it once and im having trouble finding it right now
emult is a smods feature now
fr? where is it documented?
as for talisman, just use Amulet instead, as it does not require specific compat usage
Looks like it isn't for somereason, but I believe you can just use emult as a return key for power mult
you WHAT
where is the talisman compat located anyway? more people use talisman anyway
i dont think it is, it just shows error and no changes on a joker
values on a table when you define an object is only computed when the game loads
boosters have a get_weight function for this
🫡
it's not in the docs let me add it real quick
i may have just missed it
nah it just isnt there
oh fire
no?
I am stupid
I could've sworn it was added at some point lmfao
are you thinking about this maybe? https://github.com/nh6574/VanillaRemade/wiki#how-do-i-add-exponential-multchips
i should replace talisman with amulet there
is this what a joker that score exponential mult should look like?
just emult
emult_mod will not have a message
youre missing quotes here btw
yes
it still works so uhh, aint broke dont fix?
i can assure you that wont work
so it either didnt save or its doing another strange lua behavior that will break the description
lol
windows 11 - now with added vibe coding!
(and 6 quintillion bugs)
also whats the standard color for expontential mult in most mods?
keep it red or was it purple?
Purple
just X:purple works, or do i need to define it
Just checked and it's actually X:dark_edition
yeah its dark edition
after How do I cash out immediately? you should add How do I crash out immediately? and the answer is lua G.FUNCS.quit()
-# also "optional opt-in" is redundant
key = 'GreenSquare',
loc_txt = {
name = 'Green Square',
text = {
"{X:purple,C:white} ^#1# {} Mult, Increases by {X:purple,C:white} ^#2# {}",
" Mult after boss blind"
}
},
config = { extra = { emult = 1.2, emult_mod = 0.4 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.emult } }
end,
rarity = 4,
atlas = 'Modtest',
pos = { x = 2, y = 0 },
cost = 20,
calculate = function(self, card, context)
if context.joker_main then
return {
emult = card.ability.extra.emult,
}
end
if not context.blueprint and context.end_of_round and G.GAME.blind.boss and context.main_eval then
card.ability.extra.emult = card.ability.extra.emult + card.ability.extra.emult_mod
return {
message = '{X:purple,C:white} Upgrade!{}',
}
end
end
}```
this is my joker, any idea why the #2# part shows up as nil? i thought it was there in the config.extra, and it correctly scales after beating the boss
You only passed one variable in the loc_vars function's return. That's what feeds the descriptions, not the extras table.
bump
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = '''create_option_cycle({options = loc_options, w = 5.5, cycle_shoulders = true, curr_suit = _suit, opt_callback = 'change_collab', current_option = current_option, colour = G.C.RED, focus_args = {snap_to = true, nav = 'wide'}}),'''
position = "at"
payload = '''
create_option_cycle({options = loc_options, w = 5.5, cycle_shoulders = true, curr_suit = _suit, opt_callback = 'change_collab', current_option = current_option, colour = G.C.SECONDARY_SET.UIDefault or G.C.RED, focus_args = {snap_to = true, nav = 'wide'}}),
'''
times = 1
match_indent = false```
...right. i need to patch that 
it works! 
...does anyone know where the collection's tag and blinds cyclers are created?
search for collection_option_cycle_colour
how should i go about making a joker that scales its mult off of jokers of a certain type, do i add jokers to a pool and then do it there? what if i wanted to add vanilla jokers?
yeah i would do that, you can add vanilla jokers when you create the pool
the default is whatever joker (or card) it should give when you have all of them without showman
Where in G (i.e., eval G.<???>) is the information for Challenge Decks stored?
What'd you use to search for that, is that through GitHub?
(Also, it is working; eval G.CHALLENGES[1] returns The Omelette's information.)
vscode
i just have the smods and lovely folders in my workspace
I only have Notepad++, but I coded a simple Python program to search through all files in a directory for a given phrase. It goes a little something like this:
What directory would you like to search in?: <directory/goes/here>
What string are you searching for?: <string_goes_here>
----------
Found in file://C:/Users/path/to/file/that/string/is/found/in.txt
----------
I didn't know where ever to start looking, though, and thought someone in this channel might know.
Roxy kinda finished I just need to make a signature
you should get vscode if you have notepad++ lol
am i doing this right? i made a pool but the game crashes when obtaining the joker, with the log message in the txt file
G.jokers.cards.KryptonGreen is not a thing
you need to iterate through G.jokers.cards and check each one for the pool
how would i do that?
how to iterate or how to check the pool?
obv thru a loop, but what to check
(joker.config.center.pools or {}).KryptonGreen
How do make this not overwrite the cards already banned in the challenge?
include the cards that were already banned
is there a way to import them? or do I have to manually re-ban everything?
probably manually
although a way to add banned cards to existing challenges might be interesting
you would need to access SMODS.Challenges.key.restrictions and merge the lists
ill give that a try later
does anyone have a good way of changing which ranks jokers target? at least when it comes to jokers that hardcode targetted ranks
(which i assume is 90% of modded jokers that target ranks)
how do i offset a message's position?
the best thing i can think of is maybe patching before caclulate contexts to temporarily set playing cards with the changed ranks to have the joker's requested rank? i dont know how that'd work in practice but
dang, that's what im doing rn, and it works but i cant help but feel it's super scuffed
that's the closest thing i could think of without editing other joker's contexts which is very scuffed
are you actually changing the rank
you could hook card:get_id() if you aren't already
This sounds like quantum ranks bs 😭
Looked at vanilla + smods code: no current straightforward way, you'll have to patch card_eval_status_text in common_events.lua and do something with the offset values in the attention_text usage
if I were to steal the code from Oops would running that code affect the probabilities forever
or would it affect it just for the round (this is what I want)
Forever
👍
...oh no
im reading through friend group stuff since friend of mine helped with this problem and i realized that my dumbass didn't pick up on what is essentially my friend's suggestion to hook card:get_id()
also realizing im not using get_id() enough
Is there an easy way to only affect it for the round?
This code-snippet is in my utility/functions.lua file, to confirm if these functions can be called immediately after they're defined. Why aren't they?
LAPSEMS.recursive_list_maker = function(list_to_use, end_of_list)
--[[
k_lapsems_list_and = "#1# and #2#",
k_lapsems_list_or = "#1# or #2#",
k_lapsems_list_recursive = "#1#, #2#",
--]]
if not LAPSEMS.contains({'and', 'or'}, end_of_list) then
end_of_list = 'and' -- defaults to "and"
end
if #list_to_use == 1 then
return list_to_use[1]
elseif #list_to_use == 2 then
return localize{
type = 'variable',
key = 'k_lapsems_list_' .. end_of_list,
vars = {
list_to_use[1],
list_to_use[2]
}
}
else
return localize{
type = 'variable',
key = 'k_lapsems_list_recursive',
vars = {
table.remove(list_to_use, 1),
LAPSEMS.recursive_list_maker(list_to_use, end_of_list)
}
}
end
end
print('test: ' .. LAPSEMS.recursive_list_maker({1, 2, 3, 4}, 'or'))
-- Should print "1, 2, 3 or 4"
Oh actually I can't even steal from this code
Is this a consumable?
No it's a custom thing
I have a button that does an effect
You can only use it once a round
Except for this effect which is infinite but you pay money to use it
I’d set some sort of global variable, funnel it into mod_probability thru mod calculate, and then reset the var at the end of the round also with mod calculate
I could also just make a copy of Oops that gets deleted at the end of the round except that's stupid
Do Jokers that aren't in G.jokers still trigger I have a stupid fucking idea
Nevermind actually I'm not going to do that
wait nvm i remember why, it's because the behavior i need does indeed require something akin to quantum ranks
Any takers?
Seems like a localization issue?
im so sorry LMAO
those last two messages (now deleted) were meant for another server LFMAO i wasnt watching where i was typing
is this a bad idea
Like I'm not sure what you're looking for when you're saying "can be called immediately after they're defined"; the functions should be useable after that Lua definition
But an "ERROR" output implies that an error with keys has occurred in localize, whose values are outputs for LAPSEMS.recursive_list_maker

It's no localization error, I can input that function statement and it works with no hassle.
I'm making a Challenge Deck that has only a limited selection of Boss Blinds, and I want the custom-rule localization text to read "All Boss Blinds are #1#", with that variable being a string of all the permitted Boss Blinds.
is it possible to make a timer countdown on a joker description countdown while hovering over it? it stays at one value until i hover off and on it again
oh ok
No that's almost definitely a localization error. Nothing else would just let you print "ERROR' like that.
I don't know for sure, but if you're only seeing this error in this specific context, it's possible that the mods' lua files are loaded before localization files. Try running this print statement with a version of the function that outputs raw strings, without localize() calls.
How do I get the localization files to load first?
Oh wait, I see the issue now
SMODS is loading the main file, which loads ??? which loads utility/functions.lua, which runs the print function - all of which occurs before localization is loaded
Print function occurs before localization Ioading - so localize is called before localization is loaded - which causes ERROR because localize is trying to refer off of an empty localization table at that point in time
So how do I load the localization files before anything else?
Afaik you kinda can't, or at least you'd need patching of major SMODS loading processes (not fun)
You were just trying to test the function to begin with, right? You're likely off just calling the function later instead.
I wanted to see where the error originated. And at what point is this "later"?
I mean like, at any point after that game has actually loaded everything? Really I just don't understand why your immediate first response is to consider changing around the order of how a bunch of files get loaded.
How do I find that point, after all else has been loaded?
You can hook a function like Game:main_menu(change_context) and test your function there. There are probably other hookable functions that would work too, but pretty definitively, the title screen only shows up after everything else gets loaded.
how do I do take_leadership for joker descriptions? I'm trying to override matador
SMODS.Joker:take_ownership('matador',
{
--Your code goes here!
},
true
)
I would have the take ownership on a different file and keep the new description on the localization file.
It helps a lot to keep things organized.
good idea
Remove the vremade_
I was overriding all the tags with new ones (most of which work fine), but the speed tag gave me this error when I tried to view its description text
sorry for the massive dump of information
Try adding name = 'Skip Tag (Mod Name)'
to the take_ownership function?
like with the other variables?
oh you mean replacing i
gotcha
nope that failed
:(
I can also send the additional context if that helps
Yes.
oh ok
is the brace below Tag in your localization a bug? I don 'think there should be one there
it worked :D tyty
No, that's just the localization entry above it.
oh, I see. Thanks.
I made a new tag that creates 2 other random tags, but when it's triggered the two tags it produces don't trigger immediately, even if they're supposed to like a garbage tag or something
I believe that is a bug of the base game. Seen it quite a bit in mods.
I don't know if there is a solution.
dang
You need to call the trigger
wotdefok am i doing wrong its like right back to balanced gamemode when i try to set it to elation: unleashed then exit the config menu and enter it back
local mod = SMODS.current_mod
mod.config = mod.config or {gamemode = "Balanced"}
SMODS.load_mod_config(mod)
mod.config_tab = function()
return {
n = G.UIT.ROOT,
config = { align = "cm", padding = 0.05, colour = G.C.BLACK, r = 0.1 },
nodes = {
create_option_cycle({
label = "Gamemode",
options = {
"Balanced",
"Elation: Unleashed"
},
ref_table = mod.config,
ref_value = "gamemode",
w = 4
})
}
}
end
Are there any way to mod Balatro on phone (Android)?
rule 4
its against that platform's tos
is there a wiki page for the smods operator api?
Thanks, i could not find it for the life of me
aw fuck is there a new way of loading files in smods now
my old system is no longer functional
oh wait
is this channel no longer for programming help?
it's been ages since I've been here
What is your old system
this basically
I’m not aware of a reason this wouldn’t work anymore
Oh yeah that’ll do it
how do you check for each unique card modification(enhancement, edition, seal) in deck?
Doesnt ascensio have something like this you could look at
Exotic drivers license iirc
what's number.exp
how do i change the buy price of a card but like not in config
no that's the sell price
no i know
i wanna change it's buy price
like egg but for buy price
i suppose
well you can change its cost in its ability table iirc
yeah but is that table editable at runtime
there is also G.GAME.inflation but thts for all items in shop
idk
Revo, what’s number.exp
like a joker that, for example, start off costing $20 but gets $2 cheaper each time you see it and don't buy it
that kinda functionality
idk
should be possible
im generalising what im trying to do in case i can use it for something else later
but now i sound like im being cagey about it
you could save the new cost to a variable and set it as that when it appears
im still perfecting Imposterous the buy price and it being always uncommon gives it away
so can you just chage self.cost or is that a read only value at that point
it might not even be in an ability table i was guessing
yeah change taht 💔
running card:set_cost() would reset it though
i think?
no nvm
it would afaik
how often is it ran
cuz for my purpose i think it's fine since i need it only to display in shop to disguise it
well if you buy that one voucher it will update
How would I create a cardarea that doesn't draw the rectangle or the X/Y, but still renders the cards in it? I tried some stuff but everything I tested that hides the rectangle also hides the cards 🤔
i think im okay with that, it's an uncommon situation that they appear together and when they do the player gets an extra clue to tip them toward realising something is wrong
no_card_count and bg_colour = G.C.CLEAR
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-make-a-new-card-area
very intentional game design
great thx
issues lie within the commentslua SMODS.upgrade_poker_hands{ from = card, parameters = { "chips", "mult"}, level_up = false, hands = "",-- most played poker hand func = function (base, hand, param) return base -- ^^ cm end }
there's a snippet in vanillaremade wiki for most player poker hand
obelisk?
no, the wiki
this wiki
not that question
that's just the default in case it doesn't find anything but in most cases it doesn't matter
Is there a way to get Text with Color out of the v_dictionary? (Or are the any Alternative ways)
Example Entry that I want to reference;```
[...]
v_dictionary = {
SEMBY_next_test = "Next in {C:attention}#1#{}"
},
[...]
I have a Text-Box/Joker and want to be able to Switch a Single Line in it with multiple other Lines that have Different Colors and Values
no.
Unless you parse a line manually w/ SMODS.localize_box(loc_parse_string(..))
Well, I'm gonna take a look at that then 
how do you tetrate in lua?
talisman and amulet have functions for it
otherwise you get to manually recreate it via a function yourself
so you can just write return base ^^ cm?
no
function
idk what its called but there is a function for it
oh its a method
BigNum:arrow(arrows, operand)
so i return Bignum?
what
well you need to convert the base to bignum to use arrows
i assume thats what you mean
i'm just trying to return a value bigger than the original
so
i'm guessing i put 2 in arrows
yeah
and base in operand
this is equivalent to base^^amount if written out as an actual math expression
ok so operand is cm
yea
math.exp returns e^x
ascensio uses Number.exp for Drivers License Exotic
oh i assume the amulet one is a regular exponent
this is what it looks like in ascensio```lua
function Number.exp(a, b)
return Number.toBig(a):pow(b)
end
though you shouldnt need that here since this doesnt scale multiplicatively like drivers license exotic
Boss Blind Jokers
Defeating a Boss Blind adds its Legendary Joker to the shop for $30. This card does not take up a shop slot. These cards can also be obtained via soul cards.
Trapper (The Hook)
After each hand, discard 2 random cards from your hand.
Discarded cards gain a random Edition and Steel.
Cattleman (The Ox)
When you play your most played hand, lose 10% of your money and gain that amount as +Mult.
10% chance this card gains XMult equal to 25% of that amount.
Tenant (The House)
Your first hand each blind is drawn face down.
Each flipped scoring card gains +Chips equal to its rank and +1 Mult when scored permanently.
Warden (The Wall)
Blind requirement is reduced by 8% of its base value per hand played.
Blind requirement cannot go below 56% of its original value.
Stagecoach (The Wheel)
1 in 8 cards are drawn face down.
If a flipped card is played and does not score, it becomes Negative and gains +4 Mult when scored permanently.
Strongman (The Arm)
When you play a hand:
If it is your most played hand, nothing happens.
Otherwise, reduce its level by 1 and increase your most played hand level by 1.
Knight (The Club)
All Clubs are debuffed.
If your first hand contains only debuffed cards, held cards gain chips equal to that hand’s total Chips permanently.
Mermaid (The Fish)
After each hand, draw cards face down.
If all cards played are face down:
Level up that hand twice
This card gains X1.15 Chips permanently.
Seer (The Psychic)
Hands must contain exactly 5 cards.
Unscored cards grant +Mult equal to their rank and trigger their Seals and Enhancements.
Mercenary (The Goad)
All Spades are debuffed.
When another card or Joker would be debuffed, destroy a Spade in hand to prevent it.
Sailor (The Water)
Start each blind with 0 discards.
For each discard removed this way, gain:
+0.75 XMult
+1 Hand Size (this blind only)
Assassin (The Window)
All Diamonds are debuffed.
If a debuffed card is played and does not score, transform it into a random scoring card with a random Seal or Edition.
Aristocrat (The Manacle)
-1 Hand Size.
If you beat a blind without discarding, gain +1 permanent discard.
Supervisor (The Eye)
You cannot play the same hand type twice per blind.
At end of blind, all hands played this blind gain +1 level per hand played.
Vocalist (The Mouth)
You may only play one hand type per blind.
If you do not discard this blind, when blind ends:
Level up your most played hand
Gain $1 per level of that hand
Gardener (The Plant)
Face cards are debuffed.
All numbered cards count as the same rank (Ace)
Alchemist (The Serpent)
After each play or discard, draw 5 cards.
Architect (The Pillar)
Cards played earlier this ante are debuffed.
When you play a debuffed card, create a copy with a random Enhancement or Edition.
Doctor (The Needle)
You may only play 1 hand.
All remaining hands become discards.
No discard limit.
Gain +1 Hand Size per removed hand.
Intellectual (The Head)
All Hearts are debuffed.
When discarding a debuffed card, adjacent non-Edition cards have a 50% chance to gain Negative or become debuffed this blind.
Dentist (The Tooth)
Lose $1 per hand played.
After defeating a Boss Blind, gain triple the money lost this ante.
Pyromaniac (The Flint)
Base Chips and Mult are halved.
All +Chips, +Mult, and XMult effects are doubled.
Revolutionary (The Mark)
All but 1 card are drawn face down.
Each scoring card grants:
+2 XMult
+5 Mult
X2 Chips
Dagonet (Amber Acorn)
All jokers are shuffled face down each blind. Each joker's positive values are doubled and all negative effects are removed.
Folly (Verdant Leaf)
All cards are debuffed until selling 2 jokers this ante.
After selling 2 Jokers this ante:
Replace them with Negative copies of random Jokers you own
Jasper (Violet Vessel)
Reduce Blind requirements by 8% per Joker owned (max 96%).
Cicero (Crimson Heart)
Each hand, a random Joker is disabled.
If this disables Cicero:
At end of blind, increase all Joker values by 50% each time this happens.
Clopin (Cerulean Bell)
1 card is always selected.
If you discard a non–High Card hand, destroy those cards.
If played, the selected card gains:
+2 Mult per card destroyed
+0.2 XMult per card destroyed
bruv
I apologize for the wall, I know you two were talking
I've been writing this in here for awhile, I am genuinely sorry
exotic drivers license uses this x_mult = Number.exp(card.ability.extra.base, cnt)
Generally just want people's thoughts on the jokers I made here
yeah because the xmult stacks multiplicatively
probably better put it in #⚙・modding-general then
since this channel is for dev help
Ouh, my apologies then, I'll go do that
so the thing drivers license uses in ascensio is mod_count, and it's set to 0, so i'll just set that to 1
--thanks ascensio
local function count_mod()
local mod_count = 0
if G and G.deck and G.deck.cards then
for _, card in ipairs(G.deck.cards) do
-- edition
if card.edition then
mod_count = mod_count + 1
end
-- seal
if card.seal then
mod_count = mod_count + 1
end
-- enhancement
if next(SMODS.get_enhancements(card)) then
mod_count = mod_count + 1
end
end
end
return mod_count
end```
so then cnt + 1?
i would assume so
i should probably add an "if not 0.33" somewhere
well you can just check count > 0 instead then
though count shouldnt ever be less than 0 anyway
or check if total > 1 i guess
mod_count > 1?
.
i think count_mod() > 0 is valid?
count_mod isnt a function
but yeah
assuming you use whatever your own variable name is
did you scroll u-
oh
well
better to store the count from count_mod once
and then use it in the check and level up
so you dont count them once every time
also drivers license uses local cnt = count_mod(), so maybe cnt > 0?
thats tghis
i pray this workslua calculate = function (self, card, context) local cnt = count_mod() if context.before and (cnt > 0) and not context.blueprint then local _handname, _played = 'High Card', -1 for hand_key, hand in pairs(G.GAME.hands) do if hand.played > _played then _played = hand.played _handname = hand_key end end local most_played = _handname local cm = ((card.ability.extra.cm * cnt) + 1) return { message = localize("k_upgrade_ex"), colour = G.C.DARK_EDITION, func = function() SMODS.upgrade_poker_hands{ from = card, parameters = { "chips", "mult"}, level_up = false, hands = most_played, func = function (base, hand, param) return to_big(base):arrow(2, cm) end } end } end if context.end_of_round and context.main_eval or context.forcetrigger then SMODS.add_card({ key = "c_familiar", area = G.consumeables }) end end,
i would assume it does
you probably want to set a custom StatusText parameter so it doesnt say just the addition for the animation
StatusText = "^^"..cm
in func or upgrade_poker_hands
in upgrade_poker_hands
With caps?
yes
function count_mod()
seen = {}
for _, c in ipairs(G.playing_cards) do
local ed = c.edition and c.edition.key
local seal = c:get_seal()
local enh = SMODS.get_enhancements(c)
if ed then seen[ed] = true end
if seal then seen[seal] = true end
for _, key in ipairs(enh) do seen[key] = true end
end
return #seen
end
it should be smth like this
for unique modifiers
in full deck
so i got rid of the cnt > 0 and it works, but literally no change in poker hand whatsoever
#seen won't exactly yield what you want by doing that.
Either add
local mods = 0
for _, mod in pairs(seen) do
if mod then mods = mods + 1 end
end
return mods
or do table.insert instead of setting values in seen directly.
i'm guessing i replace return #seen with this?
Pretty much.
I forgot
it does not check for enhancements
local enh = SMODS.get_enhancements(c)
--or
local enh = next(SMODS.get_enhancements(c))
It should not be next
try for key in pairs instead of for _, key in ipairs
I forget how exactly the get_enhancements return is structured
i also wanna change the leveling color of the status text
also this only affects chips, idk why mult doesn't upgrade too
ok enhancement checking works
idk about the upgrade problems
It should work just fine
And i dont think custom colours can be set for the statustext since its part of a vanilla function
ok nvm i was just blind
god i love this placeholder
ok now i need to set up the spectral spawning.
how's this?lua if context.end_of_round and context.main_eval or context.forcetrigger then local itemtray = { "c_familiar", "c_grim", "c_incantation" } SMODS.add_card({ key = itemtray[math.random(#itemtray)], area = G.consumeables }) end end,
math.random 🥀
hey, 900n1 used it
his name forgotten months after the coveted 900n1's Gamblepack was unveiled 🥀
ok but like outside of particles there's like few reasons to use math.random
Okay but you should still use pseudorandom functions for gameplay related things yeah
i'll change it
unless you explicitly want to allow savescumming
well im trying to modify a context.something, but it doesnt change anything
look at SMODS.update_context_flags
local itemtray = {
"c_familiar",
"c_grim",
"c_incantation"
}
local g = pseudorandom_element(itemtray, "busterb_hedera")
SMODS.add_card({key = g, area = G.consumeables, edition = "e_negative", key_append = "minos"})
end```
oh wait i forgot to change the append
does this work?
what would i return as a flag?
that function doesnt return
i see
i know this is a dumb question, but what would you put in as the flag for this function to work? in the game dumps, im seeing that theres a loop that iterates through a separate smods function but im not really doing that
guys im so stupid idk how to fix this
-- Plea Deal
SMODS.Joker({
key = "pleadeal",
config = { extra = { card.ability.extra.d_size } },
loc_txt = {
["name"] = "Plea Deal",
["text"] = {
{
"{C:red}Discards{} are added to {C:attention}hand size{}",
}
},
},
pos = { x = 4, y = 7 },
cost = 9,
rarity = 3,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
add_to_deck = function(self, card, from_debuff)
G.hand:change_size(card.ability.extra.d_size)
end,
remove_from_deck = function(self, card, from_debuff)
G.hand:change_size(-card.ability.extra.d_size)
end
})```
WHAT DOES THIS MEAAAAAN 
change card to self and see if it works
...no
what is the big idea with the config here
shouldnt you be having d_size = some number
idk i just got this from drunkard's code
-- Drunkard
SMODS.Joker {
key = "drunkard",
blueprint_compat = false,
rarity = 1,
cost = 4,
pos = { x = 1, y = 1 },
config = { extra = { d_size = 1 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.d_size } }
end,
add_to_deck = function(self, card, from_debuff)
G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.d_size
ease_discard(card.ability.extra.d_size)
end,
remove_from_deck = function(self, card, from_debuff)
G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.d_size
ease_discard(-card.ability.extra.d_size)
end
}
config = { extra = { d_size = 1 } }
It says it there
o
wait so how do i tie the hand size to discards? wont it just give me +1 hand size instead
maybe when you select a blind it gives +discards hand size and when you discard it gives -1 and at end of round it also just subtracts discards from hand size
true
that was the intent at least
sorry, i didnt mean to call the function
you need to hook it
Is it cool if we discuss it in dms?
no
how to hook a function in general or how to do it with this specific one?
Generally, im kind of a noob when it comes to modding lmao sorry
the function itself is easy, you just update the context.something with whatever you return (flags)
so would i call this in the context.X function or whenever the SMODS.calculate_context function is called?
i have another funny error
-- Tarot Ritual
SMODS.Joker({
key = "ritual",
config = { extra = { discards = 5, tarot = 1 } },
loc_txt = {
["name"] = "Tarot Ritual",
["text"] = {
{
"Create a {C:dark_edition}Negative{} {C:tarot}Tarot{} card",
"if {C:attention}5{} cards are discarded",
"at the same time"
}
},
},
pos = { x = 6, y = 7 },
cost = 9,
rarity = 3,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.discards, card.ability.extra.tarot } }
end,
calculate = function(self, card, context)
if context.first_hand_drawn then
local eval = function() return G.GAME.current_round.discards_used == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
if context.discard and not context.blueprint and
G.GAME.current_round.discards_used <= 0 and #context.full_hand == 5 then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Tarot',
edition = 'e_negative'
}
G.GAME.consumeable_buffer = 0
return true
end
}))
}
end
end
})
So, this code mostly works - there's just one small snag
It creates five Negative tarots rather than one
idk how to fix this
like what are we even doing here 😭
did you discard five cards?
if so, it probably created one per card. context.discard occurs for each individual card discarded
yeah i discarded five cards
oops
how do i make it so it creates 1 tarot if 5 cards are discarded (similar to faceless joker)
i remember seeing a simiilar thing happen a short while ago, lemme see if i can find the solve
unless N beats me to it
context.pre_discard and #context.full_hand == 5?
gotcha
depends on where the animation should be played
if context.other_card == context.full_hand[5] then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Tarot',
edition = 'e_negative'
}
G.GAME.consumeable_buffer = 0
return true
end
}))
}
end
end
end
so i do this?
oops i got an error
if context.first_hand_drawn then
local eval = function() return G.GAME.current_round.discards_used == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
if context.discard and not context.blueprint and G.GAME.current_round.discards_used <= 0 and #context.full_hand == 5 then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Tarot',
edition = 'e_negative'
}
G.GAME.consumeable_buffer = 0
return true
end
}))
}
end
end
``` current state of the code before adding the snippet
i was gonna say, can you even return an event like that inside the joker return table
i dont know
you shouldnt but it should still work
nvm i think i fixed it
nvm
now when i discard, it does nothing
-- Tarot Ritual
SMODS.Joker({
key = "ritual",
config = { extra = { discards = 5, tarot = 1 } },
loc_txt = {
["name"] = "Tarot Ritual",
["text"] = {
{
"Create a {C:dark_edition}Negative{} {C:tarot}Tarot{} card",
"if {C:attention}5{} cards are discarded",
"at the same time"
}
},
},
pos = { x = 6, y = 7 },
cost = 9,
rarity = 3,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.discards, card.ability.extra.tarot } }
end,
calculate = function(self, card, context)
if context.first_hand_drawn then
local eval = function() return G.GAME.current_round.discards_used == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
end
if context.discard and not context.blueprint and context.pre_discard and #context.full_hand == 5 then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Tarot',
edition = 'e_negative'
}
G.GAME.consumeable_buffer = 0
return true
end
}))
}
end
end
})```
current state of the code ^
context.pre_discard runs when you discard not but for each card
just use that
without any other of the checks (keep and not context.blueprint tho)
yes, pre_discard and discard are separate contexts
oops i didnt read the joker description
do you want it to be for the first discard only?
no
then remove and G.GAME.current_round.discards_used <= 0
oke
would i remove if context.first_hand_drawn then local eval = function() return G.GAME.current_round.discards_used == 0 and not G.RESET_JIGGLES end juice_card_until(card, eval, true) end too
yes
oke
random question, how do i change the cat to an icon of my own? i know ruby did something like that for her mod
ruby did that as a personal edit to her smods copy
not part of entropy
and that was just a copy of the loading bar with different text, image and colour below it
[manifest]
version = "1.0.0"
dump_lua = true
priority = 1
[[patches]]
[patches.pattern]
target = '=[SMODS HotPotato "Perkeocoin/ads.lua"]'
pattern = '''tutorial = ad.config.tutorial,'''
position = "after"
match_indent = true
payload = '''
velocity = ad.config.velocity,
'''```
im trying to patch into hotpotato but no patch folder is being created in lovely and nothing is happening in game (i tried print as well)
any ideas why?
real talk, we should be able to add to an image and colour pool to cycle the cat and loading bar through while loading so people at least have something to look at if it's taking a while to load 
oop
trying to make a challenge and its not working
-- Magic Ritual
SMODS.Challenge {
key = 'magicritual',
jokers = {
{ id = 'j_hatch_ritual', eternal = true, edition = 'negative' },
{ id = 'j_merry_andy', eternal = true, edition = 'negative' },
},
loc_txt = {
['name'] = 'Magic Ritual',
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
modifiers = {
{ id = 'hand_size', value = 9 },
custom = {
{ id = 'no_shop_tarots' },
},
restrictions = {
banned_cards = {
{ id = 'p_arcana_normal_1', ids = { -- Boosters
'p_arcana_normal_1', 'p_arcana_normal_2',
'p_arcana_normal_3', 'p_arcana_normal_4',
'p_arcana_jumbo_1', 'p_arcana_jumbo_2',
'p_arcana_mega_1', 'p_arcana_mega_2', }
},
{ id = 'j_8_ball' }, -- Jokers
{ id = 'j_superposition' },
{ id = 'j_vagabond' },
{ id = 'j_hallucination' },
{ id = 'j_cartomancer' },
{ id = 'v_tarot_merchant' }, -- Vouchers
{ id = 'v_tarot_tycoon' },
},
banned_tags = {
{ id = 'tag_charm' },
},
},
}
}
for starters, ritual isnt eternal (it should be)
second, the hand size isn't 8, it's still 7 for some reason
thirdly, it still has tarots in store
yea if you want to ban all tarot cards you have to. ban each tarot card
check paperback, it has a few challenges based on the minor arcana that ban regular tarots
you can still manually create them yes, it's just getting them randomly that'll be stopped
i think there's also something else you should do to stop excess jimbos from popping up, but it's been a while since i made those challenges
maybe ill just keep the hand size as is
ok yea you have to hook game.start_run, check if self.GAME.modifiers.no_shop_tarots is true, and then set the tarot_rate
yea the minor arcana suits
paperback has challenges based on each suit
if challenge = "magic trial" then self.game.tarot_rate = 0 ?????
so you see where your challenge definition has custom = { { id = "no_shop_tarots" } }? that means that, while the challenge is active, G.GAME.modifiers.no_shop_tarots is true. in the Game.start_run function, self is G, so you'd check if self.GAME.modifiers.no_shop_tarots is true, and if it is, then you set the tarot_rate
why no apply function
idk lmao
ok scrap everything i just said, add an apply function to your challenge, and just set G.GAME.tarot_rate = 0 in that apply function
how would i write an apply function
any idea why my text wont appear?
generate_gameplay_ui = function(self)
local ret = {}
local SCALE = 1
for rowi, row in ipairs(self.ability.grid) do
table.insert(ret, {n=G.UIT.R, nodes={}})
for coli, cell in ipairs(row) do
local color = {G.C.GREY, G.C.BLUE}
color = color[(rowi + coli) % 2 + 1]
table.insert(ret[#ret].nodes, {n=G.UIT.C, config = {align="cm",padding=0.1,outline=1,outline_colour=darken(color, 0.1), minw=1,minh=1,maxw=1,maxh=1,colour=color}, nodes={
--{G.UIT.T, config={scale=1,text="testing",colour=G.C.RED}}
{G.UIT.T, config={scale=0.2,text=cell.mine and "!" or (cell.number == 0 and "" or cell.number), colour=G.C.RED}}
}})
end
end
return ret
end
the text is generated in the UI table
SMODS.Challenge {
...
restrictions = {
...
},
apply = function(self)
G.GAME.tarot_rate = 0
end
}
ohhh
WHY ARE YOU NOT ETENRALLLLLL
i wish i could help 😭
ui stuff is beyond me
also tarots still show up
-- Magic Ritual
SMODS.Challenge {
key = 'magicritual',
jokers = {
{ id = 'j_hatch_ritual', eternal = true, edition = 'negative' },
{ id = 'j_merry_andy', eternal = true, edition = 'negative' },
},
loc_txt = {
['name'] = 'Magic Ritual',
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
restrictions = {
banned_cards = {
{ id = 'p_arcana_normal_1', ids = { -- Boosters
'p_arcana_normal_1', 'p_arcana_normal_2',
'p_arcana_normal_3', 'p_arcana_normal_4',
'p_arcana_jumbo_1', 'p_arcana_jumbo_2',
'p_arcana_mega_1', 'p_arcana_mega_2', }
},
{ id = 'j_8_ball' }, -- Jokers
{ id = 'j_superposition' },
{ id = 'j_vagabond' },
{ id = 'j_hallucination' },
{ id = 'j_cartomancer' },
{ id = 'v_tarot_merchant' }, -- Vouchers
{ id = 'v_tarot_tycoon' },
},
banned_tags = {
{ id = 'tag_charm' },
},
apply = function(self)
G.GAME.tarot_rate = 0
end
},
}
``` the code at current
i manually made tarot ritual infinite
on a standard run, it's finite for some reason
vro forgor n =
nvm aiko figured it out
bruh
idk then
manual time
why is apply inside restrictions
idk 😭
take it out
oke
hmm yes
minesweeper
oh turns out it isnt eternal compatible for whatever reason
fixed
huh, new bug discovered
a LOT of jokers in 1.6.0 were not eternal compat
anyways tarots still show up even when the rate is outside
can i see the current code
i just got back hold on
oh my god
-- Magic Ritual
SMODS.Challenge {
key = 'magicritual',
jokers = {
{ id = 'j_hatch_ritual', eternal = true, edition = 'negative' },
{ id = 'j_merry_andy', eternal = true, edition = 'negative' },
},
loc_txt = {
['name'] = 'Magic Ritual',
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
restrictions = {
banned_cards = {
{ id = 'p_arcana_normal_1', ids = { -- Boosters
'p_arcana_normal_1', 'p_arcana_normal_2',
'p_arcana_normal_3', 'p_arcana_normal_4',
'p_arcana_jumbo_1', 'p_arcana_jumbo_2',
'p_arcana_mega_1', 'p_arcana_mega_2', }
},
{ id = 'c_fool' }, -- tarots (dear god i had to do this manually fuck that)
{ id = 'c_magician' },
{ id = 'c_high_priestess' },
{ id = 'c_empress' },
{ id = 'c_emperor' },
{ id = 'c_heirophant' }, -- (sic)
{ id = 'c_lovers' },
{ id = 'c_chariot' },
{ id = 'c_justice' },
{ id = 'c_hermit' },
{ id = 'c_wheel_of_fortune' },
{ id = 'c_strength' },
{ id = 'c_hanged_man' },
{ id = 'c_death' },
{ id = 'c_temperance' },
{ id = 'c_devil' },
{ id = 'c_tower' },
{ id = 'c_star' },
{ id = 'c_moon' },
{ id = 'c_sun' },
{ id = 'c_judgement' },
{ id = 'c_world' },
{ id = 'j_8_ball' }, -- Jokers
{ id = 'j_superposition' },
{ id = 'j_vagabond' },
{ id = 'j_hallucination' },
{ id = 'j_cartomancer' },
{ id = 'v_tarot_merchant' }, -- Vouchers
{ id = 'v_tarot_tycoon' },
},
banned_tags = {
{ id = 'tag_charm' },
},
},
}```
i tried putting the apply function outside and it still didnt work
so then i try this
it still doesnt work
curiously strength is the only tarot to show up
WHATS GOING ON 😭
everytime i refresh i still get strength
what even is this error
this happens when i buy strength too
i might just delete this challenge
STRENGHT IS ALSO THE ONLY TAROT THAT SPAWNS
😭 IM CACKLING
yes strength is the default for the type
same thing would happen if you ban every joker or planet but for their defaults
oops
Couldn't you just hook save_ad?
like this?
save_ad = function (ad)
return{
key = ad.config.key,
id = ad.config.id,
offset = ad.alignment.offset,
position = {x = ad.T.x, y = ad.T.y},
scale = ad.config.scale,
tutorial = ad.config.tutorial,
velocity = ad.config.velocity,
}
end```
No, like this:
local oldsavead = save_ad
function save_ad(ad)
local g = oldsavead(ad)
g.velocity = ad.config.velocity
return g
end
i see
if you dont mind me asking how would i do the same for this
[[patches]]
[patches.pattern]
target = '=[SMODS HotPotato "Perkeocoin/ads.lua"]'
pattern = '''for key, ad in pairs(G.GAME.hotpot_ads) do'''
position = "after"
match_indent = true
payload = '''
ad.T.x = ad.T.x + ad.config.velocity.x
ad.T.y = ad.T.y + ad.config.velocity.y
if ad.T.x > screen_border[3]-ad.T.w then
ad.config.velocity.x = -ad.config.velocity.x
elseif ad.T.x < screen_border[1] then
ad.config.velocity.x = -ad.config.velocity.x
end
if ad.T.y > screen_border[4]-ad.T.h then
ad.config.velocity.y = -ad.config.velocity.y
elseif ad.T.y < screen_border[2] then
ad.config.velocity.y = -ad.config.velocity.y
end
'''```
(i know the code could be better ill get to that once i get it to patch in)
You can't, you would have to patch for that.
do you have any idea why it would not be working in that case?
what is the file called that this is in
ads_replace.toml
and what is the folder its in called
i patched something else from another mod and it worked fine its just hot potato thats the issue
lovely
oh okay
im just confused because i seem to be doing everything for hot potato right
check the log if theres anything about not finding a patch pattern
What happens when you print debug.getinfo(create_ads)?
do i put that into lua or the payload
No, you would just print that somewhere you can see, such as eval in the DebugPlus console.
yeah i don't know what that means sorry, im relatively new to this
Install https://discord.com/channels/1116389027176787968/1228149931257237664 and type eval debug.getinfo(create_ads) in the console.
it froze wtf
nvm
(i'm also overwriting the create_ads function but i probably shouldnt be i'd assume)
if you override the create_ads function that removes the patch pretty much doesnt it
since it wont use the patched function anymore
Do the same thing with a function that's in that file and you didn't override or hook it.
well you see i tested everything in the original file and it worked completely fine
if context.discard and context.other_card == G.discard.cards[1] how do I check for the first discarded card
either i messed up in in translating it to my mod or the patches just dont work 😢
so..... how do i use context variable??
if context.discard and context.other_card == context.full_hand[1]
oh neat
mainly to know if a played card has a certain type like hearts
if context.individual and context.cardarea == G.play and context.other_card:is_suit('Hearts')
oh thanks
alright so now i need to understand the basics of the SNOWBALLER CARD
so like how do i add the score part
also what is card_eval_status_text
and how do i use it
the example you might be looking at seems old
this is greedy joker's code as an example of what you want to do:
https://github.com/nh6574/VanillaRemade/blob/1abd606dc26c46f0c7b281995f40fb25b1d54b4f/src/jokers.lua#L47
I just recieved this error out of nowhere, I would add more clarification but sadly I don't know what I changed to cause this to happen. Does anybody know what kinds of bugs would cause this to pop up?
👍
also why are you playing with vanillaremade on 😭
ahhh
and I wanted to make a mod that just rebalances the game
then this is the correct channel
so might as well just use a mod that recreates it 1-to-1 and tweak
this looks like a deck creator issue
the mod doesnt work anymore
use debugplus to test
huh that's weird
This error occurred while I was playing on a version of the Green deck I modified with take_ownership and it crashed after I finished the Big Blind just before the money calculations
lemme turn off deck creator and see if it still crashes
it hasnt been updated in a long time so it has random crashes
ok that makes sense
kinda unfortunate, it's a dope mod
ok yeah it didn't crash that time
thx
sorry for asking again but what did you mean by this exactly?
I'll just remake all the custom decks manually instead of using the mod then
eval debug.getinfo(hp_isDesktopPlatform)
Add that extra / to your patch.
thank you. i'm just gonna sit and think about that for a sec
🤔 i'm thinking about a deck effect that guarantees new cards on shop reroll (i.e. if you were in the shop and you see the base joker for sale, when you reroll, there will under no circumstances be a base joker in the rerolled jokers)
my thoughts of how to accomplish this are to hook Card:in_pool and have that check against a variable i set up in G.GAME and populate via context.reroll_shop in current_mod.calculate, but i'm not sure what timing of anything would facilitate my effect. does current_mod.calculate come before Card:in_pool?