#💻・modding-dev
1 messages · Page 687 of 1
essentially i'm trying to not load some crossmod content if a certain option in the other mod is selected
yeah same thing, config is not indexed at this point
what of that is line 93
Tried this and ended up with
can someone explain why this only works if i put a number in and refuses to work with a variable
Depends on the variable
if target_joker then
BAGGUTRO.modify_joker_values(target_joker, {['*'] = card.ability.extra.value}, {x_mult = 1, x_chips = 1, h_size = 0, extra_value = true, cry_prob = true, d_size = 0, card_limit = true, extra_slots_used = true})
end
card.ability.extra.value
And which variable do u want to use for that?
config = {
extra = {
value = 1.2
}
loc_vars = function(self, info_queue, card)
local val = (card.ability.extra and card.ability.extra.value) or self.config.extra.value
return {vars = {val}}
end,
value
thats the name of the variable
Why not just
local val = card.ability.extra.value
Did you start a new run?
ah that fixed it, for some reaosn it just stopped working completely until starting a new run
How would I make the value given by a consumable increase after scoring over the blind threshold?
Because I tried
config = { extra = { money = 5, money_gain = 3 } },
loc_vars = function(self, info_queue, card)
if SMODS.last_hand_oneshot and test ~= true then
card.ability.extra.money = card.ability.extra.money + card.ability.extra.money_gain
end
return { vars = { card.ability.extra.money, card.ability.extra.money_gain } }
end,
use = function(self, card, area, copier)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
card:juice_up(0.3, 0.5)
ease_dollars(card.ability.extra.money, true)
return true
end
}))
delay(0.6)
end,
but that increases the value whenever I hover over it (if the last hand oneshot the blind) and for some reason doesn't let me actually use the consumable
How do I access the primary_color and secondary_color of a consumable type?
SMODS.ConsumableTypes['key'].primary_colour and SMODS.ConsumableTypes['key'].secondary_colour
do I keep the []?
Yes.
Also for some reason my booster packs refuse to localize at all whatsoever, despite me having both packs' keys (mannpowerpack_1 > p_mannpower_mannpowerpack_1 and mannpowerpack_2 > p_mannpower_mannpowerpack_2) defined in en-us.lua's descriptions, and the group key in its dictionary, with k_mannpower_pack = "Mannpower Pack"
create_card = function(self, card, i)
return {
set = "Joker",
rarity = "Legendary",
edition = "e_baggutro_faded",
stickers = {"perishable" , "rental"},
area = G.pack_cards,
skip_materialize = true,
soulable = true,
key_append = "baggutro_faded_legends_pack"
}
end,
why does this not apply the stickersx i want?
You need force_stickers = true
This has no reason to not be working
put them under Other not Booster
i have a joker that makes it so that celestial packs have a chance to have tarot cards in them
now, obviously, tarot cards often need a hand in the booster pack to actually do stuff with, so i made it so that draw_hand = true in my hook
...but now hands are always drawn regardless of the ownership of the joker. how can i make it so that draw_hand equals false unless my joker is owned (in which case it'd be true)?
because this didn't work
draw_hand = next(SMODS.find_card("j_bof_j_eureka")) and true or false,
i assume this function in booster packs isn't always updated but i'm not quite sure how to get around that
What function are you hooking?
SMODS.Booster:take_ownership_by_kind("Celestial", {
er wait maybe i misunderstood that question since i think draw_hand is the function
or i'm overthinking it
update_pack = function(self, dt)
local state_wasnt_complete = not G.STATE_COMPLETE
SMODS.Booster.update_pack(self, dt)
if next(SMODS.find_card('j_modprefix_key')) and state_wasnt_complete then
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
G.FUNCS.draw_from_deck_to_hand()
return true
end
}))
return true
end
}))
end
end
where do i check to see if my joker is owned?
or wait is this supposed to be in the hook or the joker itself
oh i just saw the edit
it works perfectly now!! thank you so much
question: why are there two events inside of each other?
just curious
Because that's how it works in the SMODS.Booster.update_pack function.
cool
Is there any sort of template for Joker mods or at least a rundown of the functions?
okay trying to hybridize green joker and greedy joker isn't going as well as i'd hoped
at least as far as deciphering it goes
one calculate/loc_vars overrides the other, you need to merge these into one function
i know that, i just have them back to back to try and cross reference and combine them
what i'm trying to accomplish is that if a scored card is not exclusively Diamond suit (this includes wild Diamonds) it loses 1 mult
but if it is exclusively Diamond suit, it gains 1 mult
You mean you want to check for cards that only count as Diamonds and not any other suit?
Basically yes
if context.individual and context.cardarea == G.play then
local passed = context.other_card:is_suit(card.ability.extra.suit)
for k, v in pairs(SMODS.Suits) do
if context.other_card:is_suit(v.key) and v.key ~= card.ability.extra.suit then
passed = false
end
end
if card.ability.extra.mult >= card.ability.extra.false_sub and not passed then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'mult',
scalar_value = 'false_sub',
operation = '-',
no_message = true
})
return {message = localize({type = 'variable', key = 'a_mult_minus', vars = {card.ability.extra.false_sub}}), colour = G.C.RED, message_card = card}
elseif passed then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'mult',
scalar_value = 'true_add',
no_message = true
})
return {message = localize({type = 'variable', key = 'a_mult', vars = {card.ability.extra.true_add}}), message_card = card}
end
end
if context.joker_main then
return {mult = card.ability.extra.mult}
end
Oh uh
Thank you, didn't expect this
Ooh cat
i wanna make it so if the player has smeared joker and changes the atlas of the deckskin
how do i do that
how do i change a texture of something in runtime
Malverk actually allows such things
but you need to modify it to fit your needs
is there a different way
cause i see a lot of mods that has cards that change texture like blueprint for example
the blueprint mod uses shader, which is way too advanced
there's only Malverk for runtime changes
then how do i do it
again, you need to modify it to fit your needs
it's simply a texture pack manager with its own API
ok but how do i do it
how does malverk change textures?
it creates default atlas data based on what's already in the game, makes space for storing external texture packs and redirects several method calls to seamlessly switch between them
because it switches textures in runtime
it's mainly designed to switch textures at runtime, but through a config page
to do that automatically for your Smeared Joker case, you have to tweak the code a bit and squeeze your logic inside
how does take_ownership() work
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
if SMODS.get_enhancements(context.other_card)["m_steel"] == true then
return {
repetitions = card.ability.extra.retrig,
message = localize('k_again_ex')
}
end
end
if context.repetition and not context.cardarea == G.hand and context.end_of_round and (next(context.card_effects[1]) or #context.card_effects > 1) then
if SMODS.get_enhancements(context.other_card)["m_steel"] == true then
return {
repetitions = card.ability.extra.retrig,
message = localize('k_again_ex')
}
end
end
end
can someone explain why this doesnt work?
steel cards don't trigger at end of round
also it's recommended to use SMODS.has_enhancement(context.other_card, "m_steel")
not context.cardarea == G.hand also doesnt work
not is like one of the first things that happens in order of operations
plus the cardarea will pretty much always be G.hand at end of round
not (context.cardarea == G.hand) ? 
Kid named ~=
so, the reason most multi-effect consumables were worked is because they were being deselected
but now, i run into another problem
since it is probably needed
mythril.lua is here
remaining 29 lines
end
for i = 1, #G.hand.highlighted do
local percent = 0.85 + (i - 0.999) / (#G.hand.highlighted - 0.998) * 0.3
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.15,
func = function()
G.hand.highlighted[i]:flip()
play_sound('tarot2', percent, 0.6)
G.hand.highlighted[i]:juice_up(0.3, 0.3)
return true
end
}))
end
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.2,
func = function()
G.hand:unhighlight_all()
return true
end
}))
delay(0.5)
end
end,
can_use = function(self, card)
return (to_big(#G.hand.highlighted) <= to_big(3))
end
}
missing an end
where
55
tysm
so 55 would be end and 56 would be for i = 1, #G.hand.highlighted do
??? what the fuck
oh right. maybe its syntax
no its not
okay
what happens when i use mythril is as follows
- all of the cards selected flip over
- the queen unflips
- cards flip again
- game crashes
idk why its doing that
bumping this
i am about to lose it
...assuming context.other_card, should be checking if that's defined. 😅
Something like if context.other_card and context.other_card.farts and such.
Guys. How do I change the shop size for a deck? I'm trying this but it doesn't work.
change_shop_size(2)
end,```
im using context.scoring_hand[1]:get_id() in a mod im making and am wondering what the id's are for the non numbered cards and or where to find them
you've gotta put it in an event i think, the deck apply probably runs before the shop is properly set up
jack/queen/king/ace are 11/12/13/14
for modded ranks, you can get the ID via SMODS.Ranks.modprefix_rankkey.id, to ensure that you always get the correct ID regardless of which order mods load in
Thank you : D
Just tried it and it doesn't work. ðŸ˜
I've seen the code I sent work for negative shop slots, so it's odd
odd
how do i drawstep BELOW the card or
z order overall for that matter
order can go below 0, and in fact the "center" (the card itself) is at order = -10
i'd recommend staying above -50, as that's when the card's tilt variables get updated, so if you go below that then the tilt will be 1 frame behind the rest of the card
oh thanks!!
Aight, I found what was wrong, I think.
I had 2 instances of "apply". My bad.
so sorry i just got around to testing this buuut uh
where am i supposed to put this
this is how i have it
but it wasnt working
waitholdon
nevermind!!! i fixed it myself so sorry to bother you
im having an issue where when i remove this enhancement it still doesnt take up any space
Enhancements don't have on_apply or on_remove
how do you change the weight of a modded rarity
SMODS.Rarity {
key = "lunar",
pools = {
["Joker"] = true
},
default_weight = 0.05,
badge_colour = HEX('0a2533'),
loc_txt = {
name = "Lunar"
},
get_weight = function(self, weight, object_type)
return weight
end,
}
heres what i have with my rarity
that's not what i mean; i'd like a deck to change the weight of a rarity
oh no clue
Modify G.GAME.modprefix_keylowercase_mod
(for vanilla rarities that's G.GAME.common_mod etc)
how would i go around making a seal that treats the hand played (with the seal) as first hand played, cus idk what im doing wrong but it just doesnt really work
for context
if context.press_play then
local passed = false
for k, v in pairs(G.hand.highlighted) do
if v == card then
passed = true
end
end
if passed then
G.GAME.modprefix_old_hands_played = G.GAME.current_round.hands_played
G.GAME.current_round.hands_played = 0
end
end
if context.after and G.GAME.modprefix_old_hands_played then
G.GAME.current_round.hands_played = G.GAME.modprefix_old_hands_played
G.GAME.modprefix_old_hands_played = nil
end
Loose , somewhere.
So how do those pop-ups of side-info work? Like, if you have a joker that works with steel cards, how does it display the pop-up to explain steel cards
so where exactly am I going wrong with this one?
(I wanted to build it off of Midas Mask instead but the way it's structured made me unsure how to redirect it to unscored cards)
context.cardarea == "unscored"
like this?
(i already fixed the ccontext typo)
No, you would iterate over context.full_hand and check if not SMODS.in_scoring(scored_card, context.scoring_hand)
I'm not sure I understand what line that goes on
wait shoot i should include the line numbers
why cant i continue my run?
How do I get the base chips and Mult of a straight?
_
sorry I'm genuinely not sure where you're telling me to add this
G.GAME.hands["Straight"].chips
And mult
?
What is the goal?
Played face cards become Steel cards when unscored
Replace context.cardarea == "unscored" with context.full_hand and replace scored_card:is_face() with scored_card:is_face() and not SMODS.in_scoring(scored_card, context.scoring_hand)
Are you sure this checks for if the card is not scoring? The way it's written sounds like if it is
not SMODS.in_scoring
where the hell is it talking about
[lovely SMODS.preflight.loader "src/preflight/loader.lua"]:775: [SMODS lusciousjoker "attempt.lua"]:28: '}' expected (to close '{' at line 18) near 'pos'```
I can't find a single spot where a } is missing
you're probably missing a comma
I tried adding a comma and it just said there was an unexpected symbol
show lines 18-29
yeah there's clearly a missing comma on line 27
this is the error i get instead
what's on line 66
just a }

I need some context, don't you think
a few surrounding lines
Also you should really install a lua extension
okay there we go
there's a missing end above line 66
okay now that the lua extension kicked off it's saying there's 17 problems in the file
but i think most of them are just complaining about things like "SMODS" and "localize"
ew
-Diamond
i thought just mimicking green joker would've made it plug and play
what do i need to fix to get it to display correctly
Code?
"{C:mult}+#1#{} Mult per {C:diamonds}Diamond{} suit scored",
"{C:mult}-#2#{} Mult per any other suit scored",
"{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
}```
you need to set loc_vars accordingly
There we go
Now I just need to get it to point to the actual graphic
... ignore the + i already know why that's there
what should i fix on my mild salsa card so heart cards gain +1 mult when scored and increase each time its played something is causing the heart cards to not get it and just says error instead of the +1 mult when trigger
key = 'mildsalsa',
loc_txt = {
name = 'Mild Salsa',
text = {
'Every played {C:hearts}#2#{} cards',
'permanently gains',
'{C:mult}+#1#{} Mult when scored',
},
},
atlas = 'Jokers',
rarity = 2,
cost = 5,
unlocked = true,
discovered = true,
blueprint_compat = true,
perishable_compat = false,
pos = {x = 0, y = 0},
config = {extra = {mult = 1, suit = 'Hearts'}},
loc_vars = function(self, info_queue, card)
return {vars = {card.ability.extra.mult, localize(card.ability.extra.suit, 'suits_singular')}}
end,
calculate = function(self, card, context)
if context.individual and context .cardarea == G.play
and context.other_card:is_suit(card.ability.extra.suit) then
context.other_card.perma_mult = (context.other_card.ability.perma_mult or 0) +
card.ability.extra.mult
return {
message = localize('k_upgraded_ex'),
colour = G.C.RED
}
end
end,
}```
its k_upgrade_ex instead of k_upgraded_ex
yeah I'm not sure how to get this to point to my actual joker sprites
You would make an atlas and put atlas = 'atlaskey' in your joker.
but it says now +1 extra mult at my 5 of hearts i test the joker atm
is there a possibility for patches to work on one device but not another
one of them uses bmm the other doesn't
most cases like this was fixed
somehow my patch that added main end to decks isn't working for @surreal talon
im gonna a switch it to the new custom ui in loc vars later, but im confused as to why its breaking
okay I can now confirm this unfortunately does nothing
Can anyone tell me what the failure point is on this?
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.true_add, localize(card.ability.extra.suit, 'suits_singular'), card.ability.extra.false_sub, card.ability.extra.mult } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
local passed = context.other_card:is_suit(card.ability.extra.suit)
for k, v in pairs(SMODS.Suits) do
if context.other_card:is_suit(v.key) and v ~= card.ability.extra.suit then
passed = false
end
end
if card.ability.extra.mult >= card.ability.extra.false_sub and not passed then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'mult',
scalar_value = 'false_sub',
operation = '-',
no_message = true
})
return {message = localize({type = 'variable', key = 'a_mult_minus', vars = {card.ability.extra.false_sub}}), colour = G.C.RED, message_card = card}
elseif passed then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'mult',
scalar_value = 'true_add',
no_message = true
})
return {message = localize({type = 'variable', key = 'a_mult', vars = {card.ability.extra.true_add}}), message_card = card}
end
end
if context.joker_main then
return {mult = card.ability.extra.mult}
end
end
}```
Yes, I edited the message to fix it.
Thank you!
Would it be possible to change two ranks to act as both ranks at once via hooks, in a similar manner to pareidolia, which makes ranks simultaneously count as faces? So like, I have an ace and a 8, both ranks can trigger both scholar and 8 ball
I've been trying to put it in code but its kind of wack, cause even with a hook, you kinda gotta send a final rank to finish the checks
Could prolly do a lovely patch huh
Gotta look into that
let me introduce you to https://github.com/Steamodded/smods/pull/838
+Title
I gave implementing quantum ranks a try and am quite happy with the result.
Currently this supports all hand detection stuff (X same and Straight), I don't know how inefficient it ge...
why do you suddenly use context.other_card when you correctly used card before?
i dunno
i'm still figuring it out 💔
but thanks for informing me
now theres something else going on
line 82 is lua if not card:is_face(true) and SMODS.pseudorandom_probability(self, "wheeloffortune_sailboat_blind",self.config.numer, self.config.denum) then
give the full calculate function please
calculate = function (self, blind, context)
if context.hand_drawn and not blind.disabled then
for i, card in ipairs(context.hand_drawn) do
if not card:is_face(true) and SMODS.pseudorandom_probability(self, "wheeloffortune_sailboat_blind",self.config.numer, self.config.denum) then
context.card:set_debuff(true)
end
end
end
end
}```
literally card. not context.card, not self.config.card, not context.other_card. why are you still doing something else
context.card:set_debuff(true)
oh
thank you
you did it right in the line above that. make mistakes but be consistent. if you're using different stuff next to each other, some part of it will always be wrong
how do you check if ante is -8?
G.GAME.round_resets.ante == -8
if {[-8] = true}[G.GAME.round_resets.ante] then end
trying to do this one thing i'm working on rn
spawn condition for thomas
requirements: Ante is -8, boss is cerulean bell, sell cryptid during boss blind
when selling cryptid, the blind size would increase by x100M
and then you have to beat the bell.
i already got the take_ownership thing
i see...
how about the club then
you probably want to change the ante>0 check to an ante~=0 check with a patch
oh that also works
for the bell?
yea i'm switching to the club
fuck
please go learn lua this is like the 20th syntax error I've seen you send
--Spawn Condition for Thomas
SMODS.Blind:take_ownership('bl_club', {
set_blind = function (self)
if {[-8] = true}[G.GAME.round_resets.ante] then
G.GAME.blind.effect.ante = true
print("club")
else
G.GAME.blind.effect.ante = false
print("noclub")
end
end,
calculate = function (self, blind, context)
if context.selling_card and context.card.config.center.key == "c_cryptid" then
G.GAME.blind.effect.soldcryptid = true
print("ready")
end
end,
defeat = function (self)
if G.GAME.blind.effect.ante and G.GAME.blind.effect.soldcryptid and not next(SMODS.find_card('j_busterb_thomas')) then
SMODS.add_card{ key = "j_busterb_thomas", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("superwinner")
end
end
})
man
whats the issue
IM TRYING
currently it's the set_blind part
iirc {}[] is innalid syntax
no its valid
{}[] looks like 4th dimension Markdown Link syntax
why not G.GAME.round_resets.ante == -8?
i'm just following what aure said
I always had do to ({})[]
that. was surely a joke right
can I have some of what they where on
hi can u start reading ur errors especially if its for syntax issues
hold on
🤷
because it does nothing
actually
yeah its invali
({[print]=function()return {[math]=print} end})[print]()[math]("hi")
works on my machine
you added ()
yeah
you need parentheses
thats why it did
god this is so cursed
what that works???
no reason it wouldnt
your never indexing the array though?
local table = {}
table[table] = table
the array starts at one
i saw minty type i was preparing for metatables
ifnyou call am array it does array[1]()?
oh wait i got the cats confused
its lily that's metatable obsessed
man fuck this
im gonna say it works though to spread misinformation
yeah I'm the cat that likes silly recursion
are you using vscode
do you have a lsp
yep
my brain on syntax errors
to which question
both
true...
how do you have a lua lsp and still have syntax errors
the lsp should tell you when theres a syntax error
typing too fast
1000 mod files
fuck you mean this shit ain't work
set_blind = function (self)
if G.GAME.round_resets.ante == -8 then
G.GAME.blind.effect.ante = true
print("club")
else
G.GAME.blind.effect.ante = false
print("noclub")
end
end,```
what is the intended trigger condition
nothing is print?
does it print the wrong thing, or does it not print a thing at all?
did you load the file?
then set_blind isn't being called
yes
then that function isn't running
are you taking ownership correctly
when are you expecting that function to run?
are you sure the club is the boss blind
SMODS.Blind:take_ownership('bl_club', {
set_blind = function (self)
if G.GAME.round_resets.ante == -8 then
G.GAME.blind.effect.antething = true
print("club")
else
G.GAME.blind.effect.antething = false
print("noclub")
end
end,
calculate = function (self, blind, context)
if context.selling_card and context.card.config.center.key == "c_cryptid" then
G.GAME.blind.effect.soldcryptid = true
print("ready")
end
end,
defeat = function (self)
if G.GAME.blind.effect.ante and G.GAME.blind.effect.soldcryptid and not next(SMODS.find_card('j_busterb_thomas')) then
SMODS.add_card{ key = "j_busterb_thomas", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("superwinner")
end
end
})
SMODS.Blind:take_ownership('club'?
print("a thing")
SMODS.Blind:take_ownership('club', ...
is this in a separate file and is that file asserted or something
hey
this time i have something thats NOT A SYNTAX ERROR (or atleast, i believe)
i want so you can use ts when you have 3 or less cards selected
but for some reason you cant use it, no matter how much cards you select
why do you use to_big
can_use = function(self, card)
if not (G.hand and #G.hand.highlighted > 0 and #G.hand.highlighted <= card.ability.max_highlighted) then
return false
end
for i = 1, #G.hand.highlighted do
return true
end
return false
end
Remnant of jf code
yeah i'm kinda stumped on how to go about the rest of the function
especially the randomization element
you can't do context.joker_main in "final discard"
that doesn't make sense
I didn't mean to imply any of the other code actually worked
i've just been making ransom notes out of other jokers and hoping for the best
context.pre_discard will work instead.
anyway
calculate = function(self, card, context)
if context.pre_discard and G.GAME.current_round.discards_left <= 0 not context.hook then
local selected = pseudorandom_element(G.hand.highlighted, pseudoseed("katyas_haunt"))
selected:set_edition("e_negative", true)
return nil, true -- allows joker retriggers if you wish
end
end
thank you
and not context.hook, oop.
is the pseudoseed meant to match the joker's key or no
It can be whatever you want. The point of it is just to be distinct.
Had to bump up the discard check to 1 rather than 0 but it works otherwise
has wrapping straights been coded yet id rather not reinvent the wheel on it
surely someone's done it
hook SMODS.wrap_around_straight
it returns false by default since no vanilla joker does it
oh cool so if that returns true straight wrapping is enabled?
yep
why the fuck is it not working..
is there a way to "juice up" the selected card? it does the sound effect but the cards are off screen before you can really register what happens
have you tried not using to_big
no
and this
How do I add custom localize lines
like "Steel!" or "Negative!"
...why do you have the entire consumable definition again in an event in the use function?
OH
wrong copy paste
mb
this is what i was meaning to put
40 lines are missing
}))
end
for i = 1, #G.hand.highlighted do
local percent = 0.85 + (i - 0.999) / (#G.hand.highlighted - 0.998) * 0.3
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.15,
func = function()
G.hand.highlighted[i]:flip()
play_sound('tarot2', percent, 0.6)
G.hand.highlighted[i]:juice_up(0.3, 0.3)
return true
end
}))
end
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.2,
func = function()
G.hand:unhighlight_all()
return true
end
}))
delay(0.5)
end
can_use = function(self, card)
if not (G.hand and #G.hand.highlighted > 0 and #G.hand.highlighted <= card.ability.max_highlighted) then
return false
end
for i = 1, #G.hand.highlighted do
return true
end
return false
end
end
end
}```
You should review/fix your indenting. Secretly, your can_use function is inside the if statement in your use function. Notice the two ends at the bottom of the file.
For reference, this is how your file looks with corrected indenting and nothing else changed.
No it's still wrong.
note that the indenting itself isn't the issue
Close but it should look like
No, but fixing it makes the issue more obvious.
true
if this is wrong feel free to throw tomatoes at me
not sure at a glance but why are we creating cards manually
That's just how the code was from the vanillaremade arcana pack iirc
The indenting was still a little wonky, use this corrected file.
And for the deck itself I think I had to just mug Cryptid's The Decision blind for some loose code, since the Anaglyph Deck just makes a tag.
why
because you compared number with nil
What does your code look like now?
You have one for i = 1, #G.hand.highlighted do that's inside another for i = 1, #G.hand.highlighted do. This causes issues because they're both trying to track their progress using the i variable, making them conflict with each other.
To fix this, use any other letter for the for i = 1, #G.hand.highlighted do on line 56.
Also you can probably remove some of your events in general. Your file calls G.hand.highlighted[i]:flip() on 4 separate occasions, that probably isn't necessary.
ts doesnt work ðŸ˜
What's the error?
And also I don't know how else I'd even do it.
Is there a history of certain actions in the game?
Like, used consumeable cards?
I feel like that'd be a great inclusion to SMODS if there isn't, because that would make effects like "last spectral card used" or "+mult for each The Fool you've used this run" or any other thing targeting custom cards a lot easier to do without having to hook anything yourself
you don't have to hook anything yourself
just use the mod calculate and context.using_consumeable to track it
man i really thought i was gonna be able to do this one myself
What's your code?
You want context.discard instead as that's an individual card context, instead of context.pre_discard which is only checked once. It also doesn't use context.hook at all so you can remove that check.
Use https://github.com/Steamodded/smods/wiki/Calculate-Functions as a reference for what contexts exist and when to use them.
well it fixed that issue
but it's giving them chips instead of dollars and the "upgrade" popup is appearing on the joker instead of the card
That's because perma_bonus is only for chips. Replace that with perma_p_dollars to make the bonus dollars instead.
In your return table, add the line message_card = context.other_card so the individual card gets the message instead.
like this? or am I misunderstanding
return {
message = localize('k_upgrade_ex'),
colour = G.C.MONEY,
message_card = context.other_card
}
thanks
Ok so I have this credit card modification and I was wondering how could I update G.GAME.bankrupt_at value update when card.ability.taw_data.bankrupt change ?
Where do I put the dictionary section in my localization files? Because when I left it out of the descriptions = {}, it didn't actually load them or anything, and when I put it in there, it showed this error and then my entire PC hit me with the wii crash sound
is this effect possible yet
if not i can just comment out this joker for now
yes
also this isnt yugioh you dont have to specify face-down
no the point is that when you draw them again, they come to the hand face down
oh
that's a little complicated but still possible
Me vs. The evil localization files that crash my whole PC
dictionary should be inside of misc
which is outside of descriptions
this crash seems unrelated though unless im mistaken
i mean it was literally mid-launch when it happened lol
isn't that part just the whole "stay flipped" check?
I'm more confused about the part of getting them to the deck
SMODS.Consumable {
key = 'precision',
set = 'Mannpower',
atlas = 'mannpowercards',
pos = {
x = 2,
y = 1
},
select_card = 'consumeables',
config = { extra = { money = 5, money_gain = 3 } },
loc_vars = function(self, info_queue, card)
-- supposed to increase the money one time when a hand scores more than the blind requirements, but currently increases it each time you hover over it, as long as the last hand was a oneshot.
if SMODS.last_hand_oneshot then
card.ability.extra.money = card.ability.extra.money + card.ability.extra.money_gain
end
return { vars = { card.ability.extra.money, card.ability.extra.money_gain } }
end,
use = function(self, card, area, copier)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
card:juice_up(0.3, 0.5)
ease_dollars(card.ability.extra.money, true)
return true
end
}))
delay(0.6)
end,
can_use = function(self, card)
return true
end
}
Also there's this thing I'm having trouble with
uhhh there's a couple mods that do this, degeneracy has a whole deck about this mechanic
how do i get the total number of Chips a card will give when scored?
[including base and bonus chips but not Joker triggers]
card:get_chip_bonus()
thanks ^^
It's get_chip_bonus not get_chips_bonus
That only considers base Chips, including perma-bonuses.
function get_chips_from_edition(card)
if not card.edition then return 0 end
local ret = card:calculate_edition({main_scoring = true, cardarea = G.play})
if not ret then return 0 end
if ret.chips then return ret.chips end
if ret.chip_mod then return ret.chip_mod end
return 0
end
something like this gets most edition chips
that has the issue of calculating the edition tho, if an edition has some event in it (or literally anything that's not supposed to happen outside of its intended calculation) that can cause problems
there's no perfect way to do it regardless
I'm not sure what I'm misunderstanding
context.remove_playing_cards is called whenever playing cards are destroyed.
i don't think you can do this effect with a simple calculate function?
or at least not with a new context
At least, not for just scoring cards with one context.
Assuming the "face down" will also imply drawing said cards to remain face down.
if context.stay_flipped and context.other_card then
-- Are we drawing from played area?
if context.from_area == G.play then
-- Mark the card.
context.other_card.patti = true
return { modify = { to_area = G.deck } }
-- Are we drawing from the deck? Check if we got the mark.
elseif context.from_area == G.deck and context.other_card.patti then
-- If so, remove the mark and ask to remain flipped.
context.other_card.patti = nil
return { stay_flipped = true }
end
end
Something like so?
i'd probably put the marker in card.ability, but yea that looks right
Good but there should probably be a check to un-flip them at the end of a round
The point of it is meant to be more evident in very thin decks
is it possible to flip and shuffle cards of the hand you played like amber acorn does with jokers?
The default is to draw face up from deck to hand.
return { stay_flipped = true } maintains the face down, however, if anything does return { prevent_stay_flipped = true }, that takes priority.
I see
... Maybe I could also make this joker treat face-down cards as steel? So it's not like, bad to leave them face down
sticker compat are true by default, right ?
Does anyone know a mod that lets you chose the next jokers to appear on the shop
GRAAAHH WHY ARE MY MODS BLIND ANIMS NOT PLAYING
Nvm I found one
Actually what is the context for identifying if a card is flipped
if card.facing == 'back'
fack
can we see the line 
wdym extra is a nil value, tf is this crash
how do i add a custom tooltip to info_queue from the localization files without adding something to p_centers
Did you start a new run?
table.insert(info_queue, {key = 'localizationkey', set = 'localizationset'})
okay yeah that was the issue my b
ok for some reason it's not working
{key = 'bex_tooltip_food_joker', set = 'bex_tooltips'}
the name gets added to the tooltip but not the description
ohfair
then you can do info_queue[#info_queue + 1] = {set = 'Other', key = "food_joker"}
or table.insert whichever you prefer, doesnt matter
hm.
???
yeah idek
happened when I hovered over it
hold on lemme do it again do u want the stacktrace
actually i can also looka t the staackrace
just show the code for now
replace the second one by info_queue[#info_queue + 1] = G.P_CENTERS.c_bex_transcend
how do you increase a blind's score requirement using the blind itself?
return {blindsize = number} in the calculate function.
i'm guessing this is addition normally but does it also multiply
Yes, it would be xblindsize
neat
whats the best way to go about learning lua? i used to know a bit of C# but ive forgotten it
?
apply = function (self,tag,context)
local result = nil
if context.type == "new_blind_choice" then
local lock = tag.ID
result = SMODS.pseudorandom_probability(self,"t_void_Bloody Tag",1,tag.config.chance)
if result then
G.CONTROLLER.locks[lock] = true
local key = "p_void_Bloody Pack"
tag:yep("+", G.C.SECONDARY_SET.Spectral,function()
local card = Card(
G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2,
G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2,
G.CARD_W * 1.27,
G.CARD_H * 1.27,
G.P_CARDS.empty,
G.P_CENTERS[key],
{ bypass_discovery_center = true, bypass_discovery_ui = true }
)
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({ config = { ref_table = card } })
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
tag.triggered = true
else
tag:yep("Failed",G.C.RED,function ()
tag.triggered=true
return true
end)
end
end
end,
why does this open multiple booster packs at once instead of waiting for the booster pack to be finished
what is this indenting 
i know this doesnt exactly answer your question but it will still be useful when starting out
this has the basics on how to make mods https://discord.com/channels/1116389027176787968/1486847115127947374 the smods wiki and vanilla remade are useful tools to make mods
https://github.com/Steamodded/smods/wiki/
https://github.com/nh6574/VanillaRemade/
ok its more so the syntax i need to learn
attempting to make a spawn condition where if you have 100 gold seal/golden cards, a joker spawns```lua
SMODS.current_mod.calculate = function (self, context)
local hundred = 0
for k, v in pairs(G.deck) do
if SMODS.has_enhancement(context.other_card, 'm_gold') or
context.other_card:get_seal() == 'Gold' then
hundred = hundred + 1
end
end
if hundred == 100 then
SMODS.add_card{ key = "j_busterb_samson", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("winner")
end
end
replace context.other_card with v
It should be G.deck.cards not G.deck, also you need a context check.
currently```lua
SMODS.current_mod.calculate = function (self, context)
local hundred = 0
for k, v in pairs(G.deck.cards) do
if SMODS.has_enhancement(v, 'm_gold') or
v:get_seal() == 'Gold' then
hundred = hundred + 1
end
end
if hundred == 100 and not next(SMODS.find_card("j_busterb_samson")) then
SMODS.add_card{ key = "j_busterb_samson", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("winner")
end
end
idk where to go with this.
That should at the very least spawn it if you have the 100, but it's only gonna trigger when calculate is called
also you should pick a context for when this should happen like somethingcom said
And it's only ever gonna trigger if you have exactly 100
additionally, do you... want it to keep spawning them? or not spawn if you already have one
because it can just end up spamming them depending on how you set up your condition
oh wait nvm, you have a not next(SMODS.find_card()) 
i expected it to wrap the whole process as there's kinda no point iterating through the entire deck over and over if you're not going to enter the condition regardless
-- Spawn Condition for Samson
SMODS.current_mod.calculate = function (self, context)
local hundred = 0
for k, v in pairs(G.deck.cards) do
if SMODS.has_enhancement(v, 'm_gold') or
v:get_seal() == 'Gold' then
hundred = hundred + 1
end
end
if context.setting_blind and hundred >= 100 and not next(SMODS.find_card("j_busterb_samson")) then
SMODS.add_card{ key = "j_busterb_samson", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("winner")
end
end
idk
I don't know if it's storing local values that makes this a problem
no, you can 100% store local values in current_mod.calculate
You should probably do the check under the context.setting_blind check.
i think if there's any problem, it's going to be performance, because... do you know how many times calculate is called? and for how many contexts? and each time, you're going to be iterating through the deck.
whenever you hit play, it's gonna do press_play, before, individual, initial_scoring_step, joker_main, final_scoring_step, after and that's only the ones i can think of off the top of my head
now imagine doing like 10 iterations of a deck that's gonna be at least 50 cards, that's then not going to do anything because even if you meet the condition for hundred, the context check won't be met
it is, it's just
-- Spawn Condition for Samson
SMODS.current_mod.calculate = function (self, context)
if context.setting_blind and not next(SMODS.find_card("j_busterb_samson")) then
local hundred = 0
for k, v in pairs(G.deck.cards) do
if SMODS.has_enhancement(v, 'm_gold') or
v:get_seal() == 'Gold' then
hundred = hundred + 1
end
end
if hundred >= 100 then
SMODS.add_card{ key = "j_busterb_samson", edition = 'e_negative', stickers = {'eternal'}, force_stickers = true }
print("winner")
end
end
end

yes yes
no prints
fuck...
@shrewd cobalt dawg it doesn't work man
-# yea i decided to keep you because you have been one of the most respectable people i've ever met
Try changing it to G.playing_cards instead of G.deck.cards
no result
Given
SMODS.add_card {
set = "Base",
enhancement = "m_stone",
area = etc.
}
Will the card have a random suit/rank?
i think so
Yes.
If a card has an enhancement is it possible to make adjacent cards not able to be debuffed
Trying to see if this will make the enhancement desirable
if context.debuff_card then
local my_pos = 0
for k, v in pairs(card.area.cards) do
if v == card then
my_pos = k
end
end
if context.debuff_card == card.area.cards[my_pos-1] or context.debuff_card == card.area.cards[my_pos+1] then
return {prevent_debuff = true}
end
end
this also requires recalculating debuffs on rearrange if you want it to be visually accurate
When moving the card around will it remove the debuff from the cards adjacent to the new postion and reinstate the debuffs from ones they were adjacent to previously
Yes
Forgot to mention that the card itself can't be debuffed, and does it recalculate debuffs on rearrangement
Also will recalculating debuffs on rearrangement be taxing on the game
Actually wait it could just be recalculated only when the redacted card changes positions
idk, try it
it's probably fine unless you're actually doing it every frame
Is it possible for an enhancement to not have the base card included in its look
Do I just not include the enhancement on top of a base card in the atlas
enhancement sprite replaces the base center sprite
So I don't include it on top of a blank card in the atlas
If you want it to be drawn on top of the rank and suit you would have to use SMODS.DrawStep
I want the enhancement to look as if it fully replaced the base card
Let me show an example
Ignore my selection at the top-left
Yes, all enhancements fully replace the base card sprite.
it already does
i'm honestly at a loss myself
not sure why it wouldn't work
debating with an idea here of a tarot card
for the twitch mod
it's originally was gonna be 50/50 crash the game or get all legendary jokers
but thought about making it more skewed to crashing
50/50 with 1 oops makes it always give legenaries but I think that could be good balanced againts commands that destroy your jokers
but can't decide which seems like a better option
If it just crashes the game could you just re open the game and use it again until you get all the legendaries?
once a seed is created doesn't it always crash once the tarot is created?
I don't think u can change the odds after it's created
unless u get oops
is it possible to make a joker that turns all boss blinds (not counting final bosses maybe) into one specific one
technically. you could fake it by copying like. All the ui code for it
://CRASH in Cryptid saves the game before proceeding to crash
when loaded again, the consumable is already used up
I dont think thats true
Well it does save when its used
But reloading doesnt have it already used up iirc
friend of mine managed to force a boss blind to appear in a specific ante on a specific deck I could peak see how it's done probably use something similar on a joker
try looking at how G.GAME.perscribed_bosses works in common_events.lua
noted
G.GAME.perscribed_bosses = G.GAME.perscribed_bosses or {
}
if G.GAME.perscribed_bosses and G.GAME.perscribed_bosses[G.GAME.round_resets.ante] then
local ret_boss = G.GAME.perscribed_bosses[G.GAME.round_resets.ante]
G.GAME.perscribed_bosses[G.GAME.round_resets.ante] = nil
G.GAME.bosses_used[ret_boss] = G.GAME.bosses_used[ret_boss] + 1
return ret_boss
end
if G.FORCE_BOSS then return G.FORCE_BOSS end```
this is porbably the functions ur wanting
jsut need to modify it
hook get_new_boss to always return a specific key
Unless the showdown check would succeed
anyone know how to make the player discard their entire hand?
oh, i did this a while ago
you have to cycle through and select every card and use the discard function
no?
use draw_from_hand_to_discard and provide all the cards in hand
sniff
what
someone else told me that was bad practice
okay maybe i misremembered as well
I dont knw
Might be because discard related contexts are calculated in discard_cards_from_highlighted? Not sure if thats true though
Oh nvm that is pretty bad
try temporarily increasing G.hand.config.highlight_limit or whatever it is
and also yeah this
And then just select and discard the cards like the hook does
this is what i did
G.E_MANAGER:add_event(Event({
func = function()
local old_limit = G.hand.config.highlighted_limit
G.hand.config.highlighted_limit= 9999
local any_selected = nil
for _, card in ipairs(G.hand.cards) do
G.hand:add_to_highlighted(card, true)
any_selected = true
play_sound('card1', 1)
end
if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) end
G.hand.config.highlighted_limit= old_limit
-- G.E_MANAGER:add_event(Event({
-- -- no_delete = true,
-- -- trigger = 'after',
-- -- blocking = false,blockable = false,
-- -- delay = 2.5,
-- -- timer = 'TOTAL',
-- func = function()
-- G.CONTROLLER.locks.skip_blind = nil
-- return true
-- end
-- }))
return true
end
}))
yoink
ignore the commented shit that was a futile attempt at something that i didnt end up fixing
Yk you can make multi-line comments by using --[[ ]] right
That comments everything in the brackets
[[this is a string btw, it accepts literal newline characters as opposed to \n]]
(also cuz i just highlight everything and hit ctrl+/)
ok so this doesn't work for my situation
aw shit
print[[hi]]
the situation is i have a joker that causes you to discard your whole hand on discard which ends up causing this to happen
Oh
this is the calc func
calculate = function(self, card, context)
if context.discard then
G.E_MANAGER:add_event(Event({
func = function()
local old_limit = G.hand.config.highlighted_limit
G.hand.config.highlighted_limit= 9999
local any_selected = nil
for _, card in ipairs(G.hand.cards) do
G.hand:add_to_highlighted(card, true)
any_selected = true
play_sound('card1', 1)
end
if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) end
G.hand.config.highlighted_limit= old_limit
return true
end
}))
end
end
sniff
if #G.hand.cards == 0 then
SMODS.draw_cards(G.hand.config.card_limit)
end
idk
no you draw the cards back after a bit i think it just spams the event queue because each card discarded retriggers the discard hand event
ill try adding a helper var
how do you destroy the whole deck minus the aces
this is what i have currently```lua
if context.using_consumeable and context.consumeable.config.center.key == "c_judgement" then
for k, v in ipairs(G.deck.cards) do
local card_id = v:get_id()
if card_id ~= 14 then
end
end```
check the contexts for the destroy context and return true for every card that isnt an ace
wait what the fuck
what is this. supposed to do
is it like a joker
when you use judgment, destroy all cards that aren't aces?
if you use a judgement, it destroys all cards except for aces
huh. alright
it's a special interaction thing
^^
oh
wait
no
SMODS.destroy_cards(v)
i tihink
i might be stupid
local get_new_boss_ref = get_new_boss
function get_new_boss()
return next(SMODS.find_card("j_bex_j_pareidolia_ex")) and not G.GAME.blind.config.blind.boss.showdown and "bl_serpent" or get_new_boss_ref()
end
calling that on every card is inefficient
just put all the non-aces into an array and feed that in
something something add cards to an arra- yeah
G.GAME.blind is just the current blind object
put all cards to be destroyed in a local table, then call it with said table as the argument instead
Oh
You need to copy the check for a showdown blind from the original function
got the joker working with a helper var but now you have to select, deselect, and reselect your hands for it to properly register your hand
config = {
helper = {
discarded = false
},
},
calculate = function(self, card, context)
if context.discard and not card.ability.helper.discarded then
card.ability.helper.discarded = true
G.E_MANAGER:add_event(Event({
func = function()
local old_limit = G.hand.config.highlighted_limit
G.hand.config.highlighted_limit= 9999
local any_selected = nil
for _, card in ipairs(G.hand.cards) do
G.hand:add_to_highlighted(card, true)
any_selected = true
end
if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) end
G.hand.config.highlighted_limit= old_limit
return true
end
}))
end
if context.hand_drawn then
card.ability.helper.discarded = false
end
end
i think just resetting highlighted cards should fix
((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) should work right? just checks the ante
wait i should just: try
yeah this fixed it
yeah it works
how do you directly manipulate the ante?
like how instead of using ease_dollars to change the money, you use G.GAME.dollars to do that.
ease_ante modifies G.GAME.round_resets.ante G.GAME.round_resets.ante_disp, see the function in the dump for more info.
function SMODS.current_mod.calculate(self, context)
if context.joker_type_destroyed then
if context.card.config.center.bex_exfood and #G.consumeables.cards < G.consumeables.config.card_limit then
SMODS.add_card { 'c_bex_transcend' }
end
end
end
kay what the hell is happening
SMODS.add_card { key = "c_bex_transcend" }
Bump
drawstep
whats that
hmm
you can find all the default drawsteps here for code reference
oh hm
that's what the drawstep will do
i see i see
this is what i have for rarity so far
this is slightly outdated code i think
make a drawstep that checks if the card has the given rarity and then draw the edition shader stuff
oh wait hold on
i think im going about this all wrong
so the idea is that evolved is just a regular ass rarity
and that every single divine joker is supposed to spawn with the "divine" edition
so all i need to do is find a way to like, have each divine joker appear in the divine edition
that should only be a few lines of code perhaps
i redid all of the divine joker code a while back with some help, so that's probably why its missing rn
i just apply context.card:set_edition("e_hatch_divine", true) i think
or just card
lemme test that out
sort of works - it accidentally set the divine shader to the consumable instead
that should be fixed with the local evolution varaible i made
yep it works LOL
man i am a genius
im looking for help from anyone available right now
if anyone's open, i'd appeciate if someone could make shaders for 6 editions i want to add (because frankly im too terrified of F# to try it myself)
please dm me and i can give you any extra info you need
(found someone now, yall can ignore this (thank you Meta :3) )
i'm trying to debuff all face cards in the deck / added to the deck while you own this Joker, but selling it didn't remove the debuffs. why not?
It should be v:is_face(true)
The suit under the 2s aren't supposed to be visible, how can this be fixed
I want the bars to cover the 2s like how the jumbled suits cover them in wild cards
Wild Cards do not cover the suits, #💻・modding-dev message
Oh
claims that juice up is a nil value?
im copying this after a tutorial btw
i dont use juice up either
Replace the SMODS.calculate_effect with a return and put it after the SMODS.scale_card
how come this is a causing an issue?
also i copy and pasted the code from the tutorial, and it hs it with smods calculate before scale card (and it works fine)
oh i forgot to do message_colour
i did just put message
Because you're not inputting the card correctly but you should still be using a return
This stake is supposed to have the aged sticker show up on cards but it isn't despite aged being enabled
Do you check for those variables in the SMODS.Stickers should_apply?
What is Card:get_nominal supposed to be for?
gets the number of chips that the card's base rank gives
(i.e. ignores bonus enhancement and any permabonus chips)
i see
No, it's used for sorting.
The base chips would be card.base.nominal
ah
How does updating the smods in your mod work
Like
Does the coder need to have an updated smods to implement the new stuff
Is everything technically up to date if there's nothing modern smods releases don't conflict with
Yes.
Alright
Is it that if the one coding has the updated smods they can implement all the new stuff
_ _
Yes, but you would also have to update it in your dependencies.
I mean yes
Can G.ASSET_ATLAS load atlases declared as animation_atlases?
e.g.
} SMODS.Atlas { key = "j_arrowhead_anim", path = "UNBELIEVABLE.png", atlas_table = 'ANIMATION_ATLAS', frames = 67, fps = 8, px = 71, py = 95, }
Trying to load this results in a crash using G.ASSET_ATLAS["modprefix_j_arrowhead_anim"]
(with the modprefix set to what it needs to be, of course)
G.ANIMATION_ATLAS
Thankfully I managed to figure that out just a second ago, but now I'm getting a similar crash stating that attempting to index field 'atlas' (a nil value)
Is {C:blind} the new color for blind size
If so it isn't showing the color, it's black by default
it's on, uh
card.children.center.atlas = G.ANIMATION_ATLAS["modprefix_j_arrowhead_anim"], effectively
Are you trying to swap atlases?
Yeah
iirc you should do
card.children.center:remove()
card.children.center = SMODS.create_sprite(card.T.x, card.T.y, card.T.w, card.T.h, atlas, pos)
where atlas is either a string atlas key or table of the G.ANIMATION_ATLAS["modprefix_j_arrowhead_anim"] directly and pos contains the { x = 0, y = 0 }, although x will automatically update, so it is y that you need to ensure what row of the atlas is chosen for the animation.
Sick
The next couple of lines were doing the set_sprite_pos, so that's easy
does context.remove_playing_cards also occur when jokers or consumables are destroyed? like any card object?
context.joker_type_destroyed for anything destroyed that's not a playing card.
so if context.remove_playing_cards or context.joker_type_destroyed then covers all kinds of card destruction?
Yes.
context.remove_playing_cards + context.removed (ordered table of playing cards to destroy) & context.joker_type_destroyed + context.card respectively.
and the correct way to get the total amount of destroyed cards, #(context.removed or {}) + #(context.card or {})
_ _
Correct for context.removed, but context.card is an individual card that's being destroyed.
oh, right. so in that casee context.card and 1 or 0
I just need to know the {C:color} for the new blind size color is all
...I don't think that has been set, unfortunately.
G.C.BLIND_SIZE = HEX('ad5353')
That's a red color
C:blind points to G.C.DYN_UI.DARK
is c:blind for something else then
G.ARGS.LOC_COLOURS['blind'] == G.C.DYN_UI.DARK is true.
So that dark color is supposed to be the new blind color?
I suppose?
Will something happen if I put c:blind_size?
the blind color matches with the color that the currently active blind sets
the shop sets it to red i think
Ohh
but it'll match the color of the current blind during a round
Let me test that rq
iirc you just get G.C.UI.TEXT_DARK if an invalid one is specified.
i don't think that exists
What does small blind set it to
Ok it's not changing color at all I think I'm missing something
Basically, anything in G.ARGS.LOC_COLOURS is what you can use for text styling.
Turns out it is changing color, but it's barely noticable
I suppose it matches the color of the boss blind symbol?
Nope it's just generally super dark
Where do I find this
With DebugPlus, execute eval G.ARGS.LOC_COLOURS in-game.
C:blind is for Blind size. You can also scroll through the Lovely console to see what keys you can use for colorizing the text.
So these dark ahh colors are the intended result?
C:blind is for effects pertaining to the Blind size (perma-bonuses, effects from Jokers and/or playing cards) - if you want the actual BLIND_SIZE reddish color, that's not exactly accessible without defining the key in G.ARGS.LOC_COLOURS.
All I was told is that there's a new color partaining to blind size, which my -blind size effects are a part of
Well it was worded as -score requirement but you know
C:blind is it.
...or you can define your own color in G.ARGS.LOC_COLOURS and use that.
G.ARGS.LOC_COLOURS['scorereqred'] = HEX('aaaaaa'), where you swap aaaaaa for the HEX value you want to use, then C:scorereqred. Should probably add your mod prefix to the key.
I will likely define colors for my mod's bzr boss blinds
So the C:scorereqred will add 1 color to the loc_colours?
To the G.ARGS.LOC_COLOURS, yes.
Do I have to do it while facing the specific blind to assign the color to that blind?
...you can hook loc_colour function to add your color to the G.ARGS.LOC_COLOURS table or at any point during loading, but, otherwise, you can define it at any point in time.

Though, as there's a fallback, could also just make G.ARGS.LOC_COLOURS empty so that all color-based text styling uses same colors. 😂
You could also just use V:1 and do return {vars = {colours = colour}}
I don't know what that one does
V:1 will use color defined from return { vars = { colours = { ... } }.
return { vars = { colours = { HEX('FF0000') } } would lead to your own red color for V:1.
https://github.com/Steamodded/smods/wiki/SMODS.Blind
https://github.com/nh6574/VanillaRemade/blob/main/src/blinds.lua
im new at programming do i just need the blind image to add it to the game (and the programming of course), or do i need a whole animation? also is there a video tutorial. can i use spritesheets as well
the smods page is sort of confusing
You can have it just be a simple atlas w/o animation.
also how do i make the descriptions?
i already have the art
do i just create a blind folder or do i do anything in main.lua
You define the atlas that uses your art from 1x and 2x folders of assets of your mod through SMODS.Atlas, then use the key of the defined atlas for SMODS.Blind.
sorry and how do i make descriptions? also do you have an example atlas for blinds
Descriptions can be done by defining loc_txt, but are preferred to be made through localization files.
got it
can there only be1x files
and no 2x
1x and 2x are needed.
what if i dont have a 2x file though, could i keep it the same as 1x?
2x are just basically 1x scaled up 200% without any smoothing (i.e. nearest neighbor) when increased.
or could i just scale it up with out ruining the file
Can scale it up and save in 2x.
ok. sorry for all the questions. should i just plop these blind spreadsheets into the assets folder?
Into both 1x and 2x of that, yes.
A pair of https://github.com/TheOneGoofAli/TOGAPackBalatro/blob/main/assets/1x/togazefunny.png and https://github.com/TheOneGoofAli/TOGAPackBalatro/blob/main/assets/2x/togazefunny.png as example.
got it. also how do i add multiple assets. right now i just have a joker template spritesheet
ok so i can create multiple atlas functions, one for joker atlas and one for blinds?
https://github.com/TheOneGoofAli/TOGAPackBalatro/blob/main/assets.lua You can have a whole bunch of atlases for various needs.
cool
do i need to fileload blinds in main.lua or can i just make a blinds.lua?
Can do either - if you want to load other scripts from main file, do assert(SMODS.load_file("filename.lua"))().
do i just paste that at the end of main.lua then?
would you also recommend different files for each blind or just one big blinds.lua
You can have your main script load whatever and however... and same applies for organization of your items - if you want one big file for just Blinds, sure.
where can i find a list of all the contexts in smods
https://github.com/Steamodded/smods/wiki/Calculate-Functions has most useful ones.
and one more question sorry i cant find any info on this: how can i find if a card has been played this ante
if card.ability.played_this_ante, where card is the given playing card - usually referenced as context.other_card (context.other_card.ability.played_this_ante) or context.debuff_card (context.debuff_card.ability.played_this_ante).
so like this
also this doesnt seem to be loading blinds.lua correctly
if context.other_card.ability.played_this_ante then
Did you create the blinds.lua file next to your main script?
sorry, put it in src
crashes when i go to the collection page thoughOops! The game crashed:
functions/UI_definitions.lua:4415: attempt to index a nil value
Additional Context:
Balatro Version: 1.0.1o-FULL
Modded Version: 1.0.0~BETA-1620a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.9.0
Platform: Windows
Steamodded Mods:
1: DeluxeBlinds by MrSpaceFish [ID: DeluxeBlinds, Version: 0.0.1]
2: DebugPlus by WilsontheWolf [ID: DebugPlus, Version: 1.5.3~dev, Uses Lovely]
Lovely Mods:
Stack Traceback
(3) LÖVE metamethod at file 'boot.lua:352'
Local variables:
errhand = Lua function '(LÖVE Function)' (defined at line 616 of chunk [lovely debugplus.console "debugplus/console.lua"])
handler = Lua function '(LÖVE Function)' (defined at line 616 of chunk [lovely debugplus.console "debugplus/console.lua"])
(4) Lua global 'create_UIBox_blind_popup' at file 'functions/UI_definitions.lua:4415'
Local variables:
blind = table: 0x220d4870 {disable:function: 0x220d4cf0, _saved_d_u:true, original_key:cane, mult:2, dollars:5, registered:true, _discovered_unlocked_overwritten:true, order:33 (more...)}
discovered = boolean: false
vars = nil
blind_text = table: 0x220600b8 {}
_dollars = number: 5
target = table: 0x21eb6130 {type:raw_descriptions, vars:table: 0x22074e50, key:bl_deluxe_cane, set:Blind}
(*temporary) = nil
(*temporary) = string: "bl_deluxe_cane"
(*temporary) = number: 1
(*temporary) = number: 17.5238
(*temporary) = table: 0x21ad0218 {x:11.08567839196, w:1.3, y:0.76315399653988, h:1.3, scale:0.988, r:0.016726950123151}
(*temporary) = number: 0.988
(*temporary) = table: 0x21ba9158 {x:-30, w:80, y:-11, h:33.5, scale:1, r:0}
(*temporary) = table: 0x220f8780 {y:2.0591666666667, x:11.899166666667}
(*temporary) = table: 0x21ebdba8 {y:5.05, x:8.5333333333333}
(*temporary) = table: 0x21e920c0 {}
(*temporary) = number: 0
(*temporary) = boolean: true
(*temporary) = number: 22.5
(*temporary) = number: 33.5
(*temporary) = Lua function '?' (defined at line 130 of chunk [SMODS _ "src/ui.lua"])
(*temporary) = boolean: true
(*temporary) = boolean: true
(*temporary) = string: "attempt to index a nil value"
(5) Lua method 'hover' at Steamodded file 'src/overrides.lua:360'
Local variables:
(*temporary) = table: 0x2211cb30 {blind:table: 0x220d4870, force_focus:true, card:table: 0x21b0bd20, center_key:c_base, center:table: 0x21fc1090}
(6) Lua method 'update' at file 'engine/controller.lua:397'
Local variables:
self = table: 0x21c44070 {held_button_times:table: 0x21a2cbc0, focus_cursor_stack_level:1, snap_cursor_to:table: 0x222fcc78, interrupt:table: 0x21a2cc10, GAMEPAD:table: 0x21a655b0 (more...)}
dt = number: 0.0068243
(7) Lua upvalue 'gameUpdateRef' at file 'game.lua:2769'
Local variables:
self = table: 0x218cf2b0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, F_ENGLISH_ONLY:false, sort_id:33, F_DISCORD:true, STAGE:1, F_MOBILE_UI:false, F_NO_SAVING:false (more...)}
dt = number: 0
(8) Lua method 'update' at Steamodded file 'src/ui.lua:456'
Local variables:
self = table: 0x218cf2b0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, F_ENGLISH_ONLY:false, sort_id:33, F_DISCORD:true, STAGE:1, F_MOBILE_UI:false, F_NO_SAVING:false (more...)}
dt = number: 0.0068243
(9) Lua field 'update' at file 'main.lua:1024'
Local variables:
dt = number: 0.0068243
(10) Lua function '?' at file 'main.lua:962' (best guess)
(11) global C function 'xpcall'
(12) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
func = Lua function '?' (defined at line 933 of chunk main.lua)
inerror = boolean: true
deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
'
Did you make the description for it?
no sorry i didnt know i had to
didn twork
bleh, brain fried atm, can't really help much past this point - do check your atlas definition, its' key used in the atlas in SMODS.Blind, etc... otherwise, wait for someone else to assist. 💀
Had an idea for a Joker but it might be too complicated for my first time using lua -_-
Picks a random common joker in the collection and has that effect. Changes at the end of every round.
There are issues that might arise with some jokers, especially scaling, but writing the code for it is a struggle. Not sure when or how to trigger things :P
Am I in the wrong channel? I thought this was for development help.
oh nvm i didn't click the thing
how would i make a card created from add_card a negative card?
i cant find it in the documentation
edition = 'e_negative'
is there not a way to directly make the card spawn as a negative card?
put set edition in an event
edition = "e_negative"
in the arguments
that totally is in the docs...
i dont know where it is in the docs
i'm assuming that joker copies created via invisible/ankh call add_to_deck, right?
yes
is it possible to make consumables that only work when they are in consumable slots?
evaluate "work"
did you mean "only usable while in consumable slot"
Like it stays in there and gets used passively
Like the tapes from cardsauce or zodiac cards from some other mod
well the fact that those consumables already exist means that the answer is yes
and yea you can just give consumables a calculate function, works exactly the same as jokers
here's an example with upgraded planet cards from my mod
how would i check for the number of king cards in the deck again?
i know i've seen a similar example somewhere but i cant find it-
local kings = 0
for _, v in ipairs(G.playing_cards) do
if v:get_id() == 13 then
kings = kings + 1
end
end
thanks!
I’ll check back in a second
Hey. How do I set Pack appearance rate to 0 in a Deck?
Kind of like G.GAME.tarot_rate = 0, but for Arcana Packs.
you can use the new object weights system in the decks calculate function
uuu, what's that new function? Don't know about it.
Okay. I found the object_weights thingy, but I don't get how to use it.
can someone elaborate on why this doesnt modify certain jokers (odd todd, golden joker ect)
the function is too big to send but that works fine so idk why this doesnt
there's nothing in the joker that does this effect
the problem's in whatever that function you're talking about is
BAGGUTRO = BAGGUTRO or {}
function BAGGUTRO.perform_operations(val1, op, val2)
if type(val2) == "number" then
if op == "=" then return val2 end
if op == "+" then return val1 + val2 end
if op == "-" then return val1 - val2 end
if op == "*" then return val1 * val2 end
if op == "/" then return val1 / val2 end
if op == "%" then return val1 % val2 end
if op == "^" then return val1 ^ val2 end
elseif type(val1) == "number" and type(val2) == "table" then
local final = val1
for _, v in ipairs(val2) do
final = BAGGUTRO.perform_operations(final, op, v)
end
return final
end
end
part 1
function BAGGUTRO.modify_joker_values(card, modifytbl, exclusions, ignoreimmutable, nodeckeffects)
if not card or not modifytbl then return nil end
if card.config.center.immutable and not ignoreimmutable then return nil end
local cardwasindeck = card.added_to_deck
if not nodeckeffects and cardwasindeck then card:remove_from_deck(true) end
exclusions = exclusions or {}
local ops = {"=", "+", "-", "*", "/", "%", "^"}
local function modify_value(ref_table, ref_value, isdirectlyinability)
if type(ref_table[ref_value]) == 'table' and (ignoreimmutable or ref_value ~= "immutable") then
for k, v in pairs(ref_table[ref_value]) do
modify_value(ref_table[ref_value], k, false)
end
elseif type(ref_table[ref_value]) == 'number' and ((not (exclusions[ref_value] == true or exclusions[ref_value] == ref_table[ref_value])) or not isdirectlyinability) then
for i, v in ipairs(ops) do
if modifytbl[v] then
ref_table[ref_value] = BAGGUTRO.perform_operations(ref_table[ref_value], v, modifytbl[v])
end
end
end
end
for k, v in pairs(card.ability) do
modify_value(card.ability, k, true)
end
if not nodeckeffects and cardwasindeck then card:add_to_deck(true) end
end
the otehr half
i have otherh things and it works perfectly on those
i'd just throw prints everywhere and see which part doesnt work
might just change it to something else that i have working
How are you using the function?
SMODS.Shader({ key = 'laminated', path = 'laminated.fs' })
SMODS.Edition {
key = 'laminated',
shader = 'laminated',
in_shop = true,
weight = 3,
extra_cost = 6,
apply_to_float = false,
badge_colour = HEX('867a90'),
sound = { sound = "baggutro_Laminated1", per = 1.2, vol = 0.4 },
disable_shadow = false,
disable_base_shader = false,
loc_txt = {
name = 'Laminated',
label = 'Laminated',
text = {
[1] = '{C:attention}All{} values increasd',
[2] = 'by {C:attention}50%{}',
[3] = '{C:inactive}[where possible]{}'
}
},
unlocked = true,
discovered = true,
no_collection = false,
get_weight = function(self)
return G.GAME.edition_rate * self.weight
end,
on_apply = function (card)
BAGGUTRO.modify_joker_values(card, {['*'] = 1.5}, {x_mult = 1, x_chips = 1, h_size = 0, extra_value = true, cry_prob = true, d_size = 0, card_limit = true, extra_slots_used = true})
end,
on_remove = function (card)
BAGGUTRO.modify_joker_values(card, {['/'] = 1.5}, {x_mult = 1, x_chips = 1, h_size = 0, extra_value = true, cry_prob = true, d_size = 0, card_limit = true, extra_slots_used = true})
end
}
this is one i have that works, for edditions
and this is a sjoker that uyses it
at a glance i dont see a reason for it to not work
it works but only with certain jokers
anyway i changed it to use the binder code but only apply once and its a bandaid fix but it works i thiknk
i mean again, just throw prints everywhere on that function and use it on odd todd, you'll see where it fails
yeah fair enough i could do that
So then would that look like this?
Why is it that the stakes are stacked out of order on the galdur stake selection
It's supposed to stack the reverse way vanilla does, starting with the rightmost one (black stake) on the bottom
Also blue stake (2nd to left) is completely omitted from the stake stack for some reason
Selecting black stake and teal stake stack it fine, however:
When selecting pink, olive, blue, and tanzanite stakes the stack is out of order
When selecting white stake the stack includes orange stake for some reason
When selecting orange stake white stake isn't there for some reason
the definitions for which stakes apply other stakes are probably just fucked?
stake code
Alright
this in particular
I'm encountering an interesting issue with SMODS.create_sprite
It makes the sprite correctly, but it appears offscreen, and only flies up to where it's supposed to be when the card is grabbed (as if to drag it) and remains wherever it's left, floating, instead of attached to the card's center
applied_stakes = {"stake_bzr_black","stake_bzr_teal"},
Does it have to start with the previous stake then work its way down to black stake
no
this is evaluated recursively to include all stakes applied by applied stakes, so you usually don't need to specify multiple stakes here
ah
is there any reason you're creating just the sprite, not a whole card object?
no, the hook part doesn't go in any of the blind functions
So remove stake_bzr_black
you'd put it before the SMODS.Blind call for example
but it can be anywhere as long as it loads
I create the card as a copy of an existing one, then am removing the center and creating a new one because I need to change the atlas type (asset_atlas to animation_atlas, or the reverse)
and the if to check if your blind is active would go inside the hook
