#💻・modding-dev
1 messages · Page 688 of 1
above_stake is UI only, in vanilla it's for the vertical positioning next to the deck and with galdur it's used for the menu itself. applied_stakes is gameplay, it affects what other stakes actually have an effect in-game and galdur uses that info to build the stake stack
Alr
It's... a bit weirder than that! Though I do actually have some malverk compatibility (if the mod detects malverk installed, instead of loading the retextures like it normally would, it loads them as malverk texturepacks)
All of the retexturing for non-malverk works using take_ownership. This is a specific menu for changing what skin is being used for a card
The popup menu displays the different skins, which is where I'm encountering this issue
It works perfectly if it's only displaying the same kind (all animated or all static) but if it's trying to display both it encounters issues
so then what do I do with the actual timer logic thing that I moved back to calculate?
calculate = function(self, blind, context)
if G.SETTINGS.paused then
return 0
else
if blind.effect.extra.timer + (0.1 * (blind.effect.extra.timer_speed * math.min(G.SETTINGS.GAMESPEED, 4) / 4) / 3) >= blind.effect.extra.timer_end and not G.GAME.blind.disabled then
G.E_MANAGER:add_event(Event({
func = function()
local any_selected = nil
local _cards = {}
for _, playing_card in ipairs(G.hand.cards) do
_cards[#_cards + 1] = playing_card
end
for i = 1, 1 do
if G.hand.cards[i] then
local selected_card, card_index = pseudorandom_element(_cards, 'mannpower_haste2')
G.hand:add_to_highlighted(selected_card, true)
table.remove(_cards, card_index)
any_selected = true
play_sound('card1', 1)
end
end
if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) end
return true
end
}))
else
blind.effect.extra.timer = blind.effect.extra.timer +
0.1 * (blind.effect.extra.timer_speed * math.min(G.SETTINGS.GAMESPEED, 4) / 4) / 3
end
end
end
so after moving that to behind the SMODS.Blind, it crashes with this.
As far as I know, GAME is only active during an actual run and nil otherwise
I changed the applied stakes and above stakes yet nothing changed
Given a function that takes a seed for pseudorandomness, does the seed have to be a return value of pseudoseed() or can it just be a static value?
i.e. is providing the return value of pseudoseed() needed for proper pseudorandomness, or just redundant?
I was referencing this bit of code:
self.children.back = SMODS.create_sprite(self.T.x, self.T.y, self.T.w, self.T.h, atlas_key, self.params.bypass_back or (self.playing_card and G.GAME[self.back].pos or G.P_CENTERS['b_red'].pos))
self.children.back.states.hover = self.states.hover
self.children.back.states.click = self.states.click
self.children.back.states.drag = self.states.drag
self.children.back.states.collide.can = false
self.children.back:set_role({major = self, role_type = 'Glued', draw_major = self})
So then how tf do I do it
Oh, interesting! Maybe I need children.center:set_role?
self.children.center.states.hover = self.states.hover
self.children.center.states.click = self.states.click
self.children.center.states.drag = self.states.drag
self.children.center.states.collide.can = false
self.children.center:set_role({major = self, role_type = 'Glued', draw_major = self})
what does your hook look like now
Sick, I'm willing to bet role_type = 'Glued' is what I was missing
local original_update = Game.update
function Game.update(self, dt)
original_update(self, dt)
local blind = G.GAME.blind
if not G.SETTINGS.paused and blind and blind.config.blind.key == 'bl_modprefix_meow' then
blind.effect.extra.timer = blind.effect.extra.timer + dt
-- trigger after 10 seconds
if blind.effect.extra.timer >= 10 then
-- reset timer to 0
blind.effect.extra.timer = 0
-- do your effect that happens every 10 seconds here
print("meow")
end
end
end
SMODS.Blind {
key = 'meow',
loc_txt = {
name = "meow",
text = { "meow" }
},
config = {
extra = {
timer = 0
}
},
boss = { min = 1, max = 10 }
}
it's missing checking for whether the blind is disabled or defeated
but you get the idea
also no, G.GAME always exists, at least after mods are loaded
Damn, my bad
I must be thinking of something else
Question about main_start and the like, how would you add a new line to text? (I want the text on a joker to display vertically instead of in one long line)
return a table of row elements iirc
with new smods you can switch to using {element:#} though
in order to hijack another mod's booster (like with Omen Globe), do I have to have a higher priority than it?
why isnt blinds.lua loading and crashing the game. they are in the same folder
crashes when i hover over a custom blind, and it renders as just a thin line
What error is shown when it crahes?
Oops! 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: 0x08994338 {disable:function: 0x08994660, _saved_d_u:true, original_key:cane, mult:2, mod:table: 0x080f0f90, unlocked:true, registered:true, _discovered_unlocked_overwritten:true (more...)}
discovered = boolean: true
vars = nil
blind_text = table: 0x088ff1b0 {}
_dollars = number: 5
target = table: 0x089a3b40 {type:raw_descriptions, vars:table: 0x089359d8, key:bl_deluxe_cane, set:Blind}
(*temporary) = nil
(*temporary) = string: "bl_deluxe_cane"
(*temporary) = number: 1
(*temporary) = number: 22.0146
(*temporary) = table: 0x08753d18 {x:11.08567839196, w:1.3, y:0.8008374410286, h:1.3, scale:0.988, r:-0.019812468962916}
(*temporary) = number: 0.988
(*temporary) = table: 0x086e5e88 {x:-30, w:80, y:-11, h:33.5, scale:1, r:0}
(*temporary) = table: 0x08d54128 {y:1.665, x:11.086944444444}
(*temporary) = table: 0x08d54188 {y:5.05, x:8.5333333333333}
(*temporary) = table: 0x08d541b0 {}
(*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: 0x089369d8 {blind:table: 0x08994338, force_focus:true, card:table: 0x085235d0, center_key:c_base, center:table: 0x0880d228}
(6) Lua method 'update' at file 'engine/controller.lua:397'
Local variables:
self = table: 0x082ebfa8 {held_button_times:table: 0x0844bf10, focus_cursor_stack_level:1, snap_cursor_to:table: 0x08d54d90, interrupt:table: 0x08508478, GAMEPAD:table: 0x08413948 (more...)}
dt = number: 0.00699463
(7) Lua upvalue 'gameUpdateRef' at file 'game.lua:2769'
Local variables:
self = table: 0x081957c0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, F_ENGLISH_ONLY:false, sort_id:235, 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: 0x081957c0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, F_ENGLISH_ONLY:false, sort_id:235, F_DISCORD:true, STAGE:1, F_MOBILE_UI:false, F_NO_SAVING:false (more...)}
dt = number: 0.00699463
(9) Lua field 'update' at file 'main.lua:1024'
Local variables:
dt = number: 0.00699463
(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"])
any idea whats causing this
??
@idle plaza do you know what might be causing this
not sure why but it doesn't give ^2 mult per negative joker
It should be context.other_joker.edition and context.other_joker.edition.negative
does anyone know why my blind is crashing the game?
You still need to check if context.other_joker exists.
i still cant find a solution to this
for some reason the joker appears as a blank line too
Did you start counting the values from 0?
what values
x and y for the atlas position
yeah the first one is 0, 0
shoulds blinds.lua be in src or in the main mod folder?
src, but the atlas is in the main folder
weird it looks like even the correct positions still bug it out
it looks like half the blind icon
can the atlas be in the assets folder?
it looks like this
the physical png goes in assets/1x and assets/2x, what does the atlas' code is in the main.lua thing
34x34 right
that looks moreso misaligned?
hmm but the atlas file itself is alligned
ohh
theres no space between the blinds
okay yeah that would do it
anyone have a placeholder blinds spritesheet
i fixed the spacing still causign the nil crash
it looks like a localization issue
i created a consumable that gives 1.25 mult per joker owned (when the consumable is held), and the game crashes when i play a card
whats the code
i think in the togas pack mod theres a consumable that gives 3$ at round end, called glteapot. you could look at that for inspiration
You're not defining config
i'm not sure why the pluralization function from cryptid/spectrallib that i use does not function anymore on steamodded 1606b+. it's tested to work fine on 1503a and presumably below, but i can't get it to work on 1606b or 1620a. what's going on?
[manifest]
version = "1.0.0"
dump_lua = true
priority = -2
# right from cryptid
[[patches]]
[patches.pattern]
target = "functions/misc_functions.lua"
pattern = '''
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR')
'''
position = "at"
payload = '''
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or (Chimes.pluralize and Chimes.pluralize(subpart[1], args.vars)) or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR')
'''
match_indent = true
i don't really understand regex much so this is hard to debug for me
oh also by "doesn't work" i mean that pluralization just turns into nil
i'll give an example
c_chm_letter = {
name = "Letter",
text = {
"Remove the {C:dark_edition}Edition#<s>1#{} and {C:enhanced}Enhancement#<s>1#{}",
"from#< up to>1# {C:attention}#1#{} selected card#<s>1#,",
"then add#<, a>1# random {C:attention}seal#<s>1#{} to #<each,it>1#"
}
},
Is the patch actually succeeding in applying that change?
i mean, it previously worked in 1503a
i'll check if the line exists on 1606b
I had to change one of my patches for 1620a specifically.
Tried adding times = 1 to the patch specification?
hold on
even weirder, the line just doesn't exist at all (even without the error bit) on steamodded 1503a
which is odd because if i remove the patch then it also doesn't function
i think
hold on
nevermind steamodded just didn't load
(ignore that)
ok after looking through this for a moment, it seems as if the patch targets a line that doesn't exist, and only 2 lines without the or 'ERROR' bit attached exist
however, on 1503a, the pluralization breaks in the same way as seen above if the or 'ERROR' is removed, even though it doesn't seem to exist in lovely/dump/functions/misc_functions.lua... which makes no sense to me
wait interestingly one of them has this attached
ret_string = assembled_string or 'ERROR'
which would make it match
but the same exact bit exists in 1606b
argh this is such a stupid issue
oh my god i'm stupid i forgot the dump would have the end result and not the target
🤦
hopefully there's a solution to this because that area got moved around in 1606b and i'm not sure what to target now
is it possible to use SMODS.Back.initial_deck to create duplicates of cards?
i.e. a deck that starts with, say, 2 5s of spades
No, you would have to use apply for that.
could i get an example of how to use that to add cards to my deck? i'm currently using a really weird hook to remove all aces from my deck and then add duplicates of 5s, 4s, 3s, and 2s of every suit to my deck which is technically the effect but i'd like to know how to do it correctly
Add an event in the apply that calls SMODS.add_card for the wanted additional cards, with area set to G.deck.
don't forget to update starting deck size for Erosion-like effects
This might be a stupid and oddly specific question, but how do you mark cards your joker destroys as destroyed for glass joker canio etc. because my joker is destroying the card but not causing those cards to activate
how are you destroying the cards with your joker
if chosenCard.ability.name == 'Glass Card' then
chosenCard:shatter()
return true
else
chosenCard:start_dissolve(nil, not silent, 1, no_juice)
now that I think about it the no_juice is unnecessary but thats besides the point
yea, calling shatter or start_dissolve directly isn't gonna trigger destroy-card-related contexts
what's the full effect
I need context on that before deciding which way to destroy the card
At the start of the blind if selected the joker chooses a card at random, gains chips equal to twice the rank (50 instead if stone, gives 1 gold if gold, and glass plays the shatter sound effect)
and then destroys it
or, y'know, whatever else shatter() does
chooses a card in ur deck, mind ya
my description for the joker was better worded
calculate = function(self, card, context)
if context.setting_blind and not card.getting_sliced then
local selected_card = pseudorandom_element(G.playing_cards, pseudoseed("seed")
if selected_card then
-- do your joker scaling here, before destroying the card
SMODS.destroy_cards(selected_card)
end
end
end
oh so you use smods.destroy_cards
because it's not played cards that are destroyed, like Glass destroying itself by chance
yeah they arent being played
context.destroy_card doesn't make sense here, that's why we're using SMODS.destroy_cards instead
initial_deck = {exclude = true, Ranks = {'Ace'}},
apply = function(self, back)
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(SMODS.Suits) do
for kk, vv in pairs({'5', '4', '3', '2'}) do
SMODS.add_card({set = 'Base', rank = vv, suit = v.key, area = G.deck})
end
end
G.GAME.starting_deck_size = #G.playing_cards
return true
end
}))
end
yup that did it thanks
maybe ill add some other stuff if the destroyed cards have seals, but I gettin eepy
if it destroys a red seal it destroys again
🔪 better not make ur deck only red seals
ya yeet
it is a fun card its the complete opposite of my other one lol
uh, that doesn't make sense
joker retriggers are separate from playing card retriggers
hence the maybe, doesnt seem quite fitting
the free dollar is pushing it but, I think it should really only be 1 gag
cuz at that point might aswell change the description to triggers any card based effect on em
Maybe, its an uncommon right now tho but it is a more unreliable trading card
but trading card gives money this scales chips
this is my other card btw, im tempted to make it so if jobangles (the destroyer) doesnt select a negative card it rolls again
for jobingles I really wanted to add a hologram/certificate/etc. based legendary joker, cuz we dont have one that adds cards to deck
and also negative cards are silly
the game I pulled them from jobangles and jobingles arent counter synergistic though, you just expect them to be synergistic and they arent
negative playing cards are way too broken when talking about vanilla balancing
true
it is a really strong legendary
way too strong for base game
if I were to change it, I'd prob change the edition to something else
I added the fixed chance for the same reason
it was 100% at first
marble joker gives you an enhancement, certificat gives you a seal, jobingles gives you an edition
(and jokers with editions give x2)
but, eh
Could make it so you get a negative after a big blind
but if u pull a legendary card ante 7 and arent wanting to go to endless, it is no value unless u already got some
which I guess is fair there is that 2x king/queen for abandon deck u can just sell it but
the odds of not having a negative at ante 7 is like, y'know
but eh, this is modded 😛 who needs balance
depends on which way of balancing you want to do for a mod
on a scale of 1 to 10 (vanilla to Cryptid)
mine is 3+2i btw 
3 is the real part, which corresponds to the scale
2i is the imaginary part, which corresponds to unique mechanics my mod has
I dont mind havin a couple high roller legendaries, but atleast for commons/uncommons I wanna stay vanilla like
jobangles doesnt seem that bad, and if it feels too scaley ill tone it down
im less likely to tone down jobingles, cuz its a legendary (and also I like the concept of negative cards, as unbalanced as they may be)
I could see myself make jobingles only generate 1 negative card a selection
eh y'know
make that 9 an 8
(I dont know if that changes the number)
I'm gonna try to make jobingles as balanced as it can be considering the circumstance of free negative cards
thats probably my philosophy
replace it with editioned cards
guarantee first card added to be negative, exclude negative for subsequent ones
maybe
I'll think about it
but yeah, common/uncommons I wanna try to keep some sort of leash on it.
Legendaries, it depends
I wouldnt want them to be insta win buttons (to be fair, if u get jobingles ante 7, is 3 negative cards gonna win the run guarenteed? probably not lol)
6 might have tho
jobingles def scales tho, if u get him early not only can u build around him with death and stuff but also he'll generate more
but yeah maybe ill make it a random edition / only negative on the first go
Does feel like it compliments certificate adding seals, and marble adding enhancements
anyway, nighty
thanks for the help
❤️
True
I guess this legendary is kinda a fusion of those 2 uncommons if I went that path
Kinda anyway
Does the random stuff of cerificate, but doesnt add to hand but throws them in ur deck like marble
It would probably be more fun if its random
More I think bout it more your sellin me
How can i get the final chip count of a played hand?
like i wanna check if my hand scored greater than a specific variable
if context.after and SMODS.calculate_round_score() > number
ive got a fun bug where going back to menu resets a counter and causes very high value gain
It's been a while but I'm back with new motivation to mod! :D
How do I make Sprites/images be on screen and move them without breaking the game? I want to make a slot machine for one of my boss blinds and videos aren't that nice to look at imo. They break the game flow and such
can someone tell me how id fix this to prevent it still not consuming hand space after the enhancement is remvoed
it's not "+1 hand size", it's "takes 0 slots"
why would it reduce hand size on removal
replace calculate with these fields:
{
add_to_deck = function(self, card, from_debuff)
card.ability.extra_slots_used = -1
end,
remove_from_deck = function(self, card, from_debuff)
card.ability.extra_slots_used = 0
end,
}
I'm working with attributes and the new weight system, and wanting to increase the weight of objects with specific attributes if they have the given attribute. Checking objects from the pool means they're not cards, though, so I can't use Card:has_attribute. Is there another intended function to use?
Oh, I guess I can literally just check on the card 😅
By the way, to hijack another mod's booster (like with Omen Globe), does my mod have to have a higher priority than it?
???
use context.create_booster_card or context.modify_booster_card
No, you would just use context.create_booster_card
No, it should be card.ability.extra_slots_used = card.ability.extra_slots_used - 1 and card.ability.extra_slots_used = card.ability.extra_slots_used + 1
figures, no idea why I ditched that when editing the message
Thankssss
Least lucky based card in Balatro
you think wheel odds would be funny or 1/2
the tarot is basically broken with oops all 5s
but the mod allows twitch chat to mess with the game so I dunno if that would affect balacning
Idk
make it fixed
c_luminite doesn't seem to be a valid consumable key
it's missing your mod prefix
should be c_wheeloff_luminite
wait nvm
I used wheeloff for some reason
it should be your mod prefix, which is not shown in the crash log
nvm i think i fixed this one myself
fixed
thank you certificate for having the exact same code im looking for 🔥
Well, not the exact same. But almost
🔥
I didn't know G.pack_cards can exist without the cards field?
the legendary clown NERFED
hmm
Hey can someone help me load an editable config, it keeps crashing when I try to call SMODS.load_mod_config()
Is there a way, when making a mode, to disable certain base game jokers?
After an hour of me being stupid finally got it to work 🔥
@gilded blaze clown NERFED. And maybe more fun? 👀
The first selection is a negative card
all other selections are random but cant be negative
my long lost relative
exotic bingles, generates 1 of each
he only does base game editions I dont feel like bingling all the possible balloon animals
jobangles is complete now, got every case where a card could have modified chips
&& also funny gold clause
maybe ill make an achievement if you own both of them at once ~~idk how to do that 😭 ~~
Also, jobingles generates foil cards that jobangles can yeet for more chips
is this, synergy?
I might do a last card destroyed text on the description, so you dont have to search the deck to see what it yeeted
some qol
smods loads your config automatically
no need to call that function yourself
It doesn't show the config menu when I click on my mod tho
So I can edit it ingame
jobangles ate the 5th suit
making the collection card ace of spades like the rest sleep
make it a made up card suit awoken
you have to set up the UI separately
why doesntit work 😭
SMODS.Tag{
key = "geode_tag",
loc_vars = function (self, info_queue, tag)
info_queue[#info_queue+1] = G.P_CENTERS["p_wheeloffortune_mega_deposit_pack"]
end,
atlas = "wheeloffortune_Tags", pos = { x = 0, y = 0},
apply = function (self, tag, context)
if context.type == 'new_blind_choice' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep("+",G.C.WHEELOFFORTUNE_DEPOSIT_P,function ()
local key = 'p_wheeloffortune_mega_deposit_pack_'..(math.random(1,2))
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
return true
end
end
}```
you're just trying to make a booster pack, right?
where can I find what you see in the screenshot?
Im making so many jokers when blind is selected lol
maybe ill think about a skip joker, after im done makin the one im on
yep
if your booster pack does not have artwork variants, you should just use the key of it
alright, well vanilla remade already does most of the work for you
SMODS.Tag {
key = "standard",
min_ante = 2,
pos = { x = 1, y = 2 },
loc_vars = function(self, info_queue, tag)
info_queue[#info_queue + 1] = G.P_CENTERS.p_standard_mega_1
end,
apply = function(self, tag, context)
if context.type == 'new_blind_choice' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep('+', G.C.SECONDARY_SET.Spectral, function()
local booster = SMODS.create_card { key = 'p_standard_mega_1', area = G.play }
booster.T.x = G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2
booster.T.y = G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2
booster.T.w = G.CARD_W * 1.27
booster.T.h = G.CARD_H * 1.27
booster.cost = 0
booster.from_tag = true
G.FUNCS.use_card({ config = { ref_table = booster } })
booster:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
tag.triggered = true
return true
end
end
}
the math.random thing its for randomly selecting a variant
this one was a bit further down in the same page you were looking at, actually
https://github.com/Steamodded/smods/wiki/The-Mod-Object#additional-tabs
but ye, vanillaremade wiki is also quite helpful
is there anything like a "quick restart" that you can do for the game
is there a way to redeem a voucher while in blind select or after opening a booster pack? (so, context.type immediate)
alt+f5
does anyone know anything about custom shaders
SMODS.Tag{
key = "geode_tag",
loc_vars = function (self, info_queue, tag)
info_queue[#info_queue+1] = G.P_CENTERS["p_wheeloffortune_mega_deposit_pack"]
end,
atlas = "wheeloffortune_Tags", pos = { x = 0, y = 0},
apply = function (self, tag, context)
if context.type == 'new_blind_choice' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep("+",G.C.WHEELOFFORTUNE_DEPOSIT_P,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
return true
end
end
}```
?
local card should be using SMODS.create_card instead of just Card
no, that's on me, i should've been more clear
local card = SMODS.create_card { key = 'p_your_booster_key', area = G.play }
SMODS.Tag{
key = "geode_tag",
loc_vars = function (self, info_queue, tag)
info_queue[#info_queue+1] = G.P_CENTERS["p_wheeloffortune_mega_deposit_pack"]
end,
atlas = "wheeloffortune_Tags", pos = { x = 0, y = 0},
apply = function (self, tag, context)
if context.type == 'new_blind_choice' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep("+",G.C.WHEELOFFORTUNE_DEPOSIT_P,function ()
local card = SMODS.create_card{ key = 'p_wheeloffortune_mega_deposit_pack', area = G.play }
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
return true
end
end
}```
this better?
much better
it still doesnt work tho
im using debugplus
-i get the tag
- blind select
- deposit pack doesnt appear
Is it possible to have atlas changes be reflected without reloading - similar to changing config options without reloading? Changing the atlas will cause it to initialize properly next load, but if I try to use take_ownership to apply it after the game is already loaded up, I get an error:
Ctrl + m when using debugplus
Which is weird because that same atlas key is during initialization no problems, but if I use the mod prefix in front, it instead renders the default "not unlocked" sprite
That’s weird, idk what it could be then, cause everything else looks right
I mean for changing the skins on the player's end - they can select what skin they want a card to have if there's more than one
The menu I've set up is, surprisingly, working, it just doesn't take effect until a restart
the weird part is that wheel of fortune's mod id is wheeloffortune
…you mean just a deckskin?? Im confused
Nope! This is for jokers, I'll show you:
This is a submenu from clicking on a joker in a custom "additions" menu (it's reskins for vanilla jokers, so there's no additions menu in the config by default)
Clicking either of these means that is the skin that will be used for that joker next time the game restarts. I'm trying to figure out if I can get it to take effect without the restart
Ahhh i see
Sadly idk how to help you and im about to go to bed, but i hope someone else can give you the answer
No worries! Goodnight!
Yapping joker, instead of saying what he actually does says something at random when u select the blind
🔥
I should make blueprint compatible but only to say a message
but eh
is there a way to hide the mod name that appears under the rarity?
I'm making a mod with a polaroid camera joker that freezes values on other jokers, and so to do that i have to remake the jokers themselves so i can change them
whenever you take ownership, do it like this:
SMODS.Joker:take_ownership("ancient", {
-- ...all the ownership code...
}, true)
that true at the end hides the mod badge
Alright, thanku
Does there have to be something in the take ownership thingie for it to work? trying with an empty take ownership and a true at the end and it still shows up
It may need to be "j_ancient", not just "ancient"
no taking ownership specifically lets you leave out the prefix
you still need a mod prefix, but because you're taking ownership on specifically SMODS.Joker or SMODS.Consumable or whatever, it already knows what type of object you're working with
Ohhh, that makes sense
were you doing something different than taking ownership of ancient joker to modify it?
Yeah i just remade the entire thing myself cuz i didnt know about take ownership lmao
and then disabled the vanilla one from the joker pool
Oh, in that case there's probably a better option, but using the same take_ownership method, it would be like
-- ownership code
}, true)```
no that wouldn't work at all in this case, because the true only controls whether the taking ownership mod replaces the existing badge
Ohh
since the remade ancient copy originated from polaroid, it'll always have the polaroid mod badge
So if it did take something from the ancient joker, then it would hide it?
can someone PLEASE help with this ive been having the same issue
spent 1 hour making this card and 6 hours making the various lines if u buy jokers, sell jokers, and sell itself 🔥
probably a better mr.bones
but u are sacrificing a hand every turn to keep him around..
anyway, dev talk done 👀
i dont even know whats causing it anymor
it looks like it cant make the blind popup
ok i fixed it
now im getting this though
show line 22 in blinds.lua, as well as the surrounding context
calculate = function(self, blind, context)
if not blind.disabled then
if context.stay_flipped and context.to_area == G.hand and
context.other_card.ability.played_this_ante(true) then
return {
stay_flipped = true
}
end
end
end,
it should just be context.other_card.ability.played_this_ante, get rid of the (true)
How come I can't give color to the small and tiny blind the same way I can the boss blinds
okay then wtf was vremade's Omen Globe doing bc I have this
@red flower do you think vanillaremade should switch omen globe to use context.create_booster_card instead of taking ownership of arcana packs? it's a lot simpler
don't take ownership of anything, just give your voucher a calculate function like this
calculate = function(self, card, context)
if context.create_booster_card and context.booster.config.center.group_key == "k_cry_program_pack" and pseudorandom("developer_console") > 0.8 then
return { set = "Mannpower", key_append = "ar2" }
end
end
oh thank fuck that's way simpler
ya create_booster_card is a lifesaver
_ _
When I set the color the same was as with boss blinds it stays gray
non-boss custom blinds are really jank at the moment
lemme dig into morefluff to see how that does it for bigger blind real quick
Here is the code for them just in case there's something I also had to change but didn't know of
why exactly are the boss_colour lines commented out
Idk I didn't write the code I only changed the hexes
try uncommenting them?
By commented you mean the -- right?
ya
i'm looking at bigger blind and i don't really see any special patches or hooks related to setting the color
so boss_colour should just work for non-boss blinds i think (at least on the blind select screen)
nice lol
SMODS.Joker{
key = 'Shaco',
atlas = 'TrickyJoker',
pos = {
x = 0,
y = 0
},
rarity = 4,
cost = 20,
blueprint_compat = true,
calculate = function(self, card, context)
local jokerstable = {}
local jokerabilities = {}
for i = 1, #G.jokers.cards do
table.insert(jokerstable, G.jokers.cards[i])
end
for index, value in ipairs(jokerstable) do
table.insert(jokerabilities, SMODS.blueprint_effect(card, jokerstable, context))
end
return SMODS.merge_effects(jokerstable)
end,
}
Guys, it's crashing cause it says that it attempted to index config, which is a nil value
That's totally true, I didn't declare config. But that's on purpose, I don't need any config
Why can't I use an empty config (like
config = {
}
)?
ok so the crash isn't because your joker doesn't have a config, i's because you're merging jokerstable instead of jokerabilities in your return
but i don't think you need jokerstable in the first place. literally just do
table.insert(jokerabilities, SMODS.blueprint_effect(card, G.jokers.cards[i], context)) in the first for loop
oh yeah, my bad
also i just noticed that i'm passing the whole table to SMODS.blueprint_effect instead of an index of the table
yea, the second thing i suggested would fix that too
but why is it crashing on config instead tho?
msg = string: "[SMODS _ \"src/utils.lua\"]:2216: attempt to index field 'config' (a nil value)"
This was the crash
it's probably from the passing the whole table to blueprint_effect. it's expecting a single joker so it presumably checks that joker's config for something. a whole table of jokers does not have a config field
oh
yeah, that would explain it
makes sense
btw card is my current joker in this case, right?
cause i'm getting a crash on the insert function
oh wait it's backwards, my bad
should be SMODS.blueprint_effect(G.jokers.cards[i], card, context)
card in a joker's calculate function is always that joker that's calculating
i tried to avoid inserting the joker's own ability by doing this:
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if (G.jokers.cards[i] ~= card) then
table.insert(jokerabilities, SMODS.blueprint_effect(card, G.jokers.cards[i], context))
end
end
return SMODS.merge_effects(jokersabilities)
end,
wait wha
wait no some of the documentation is just bad?
idk
you were right the first time
what's the new crash
but in vanillaremade the blueprint implementation is the other way around
ohh right
blueprint_effect might not return anything at all
it should be this i think
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
declaring if as it is, is the same as if the variable isn't nil, right?
in this case
yep
if copy_effect
is the same as
if copy_effect ~= nil
well technically not quite, but for this purpose yea that's correct
ah
if the card being copied isn't blueprint-compatible
ah f
(to elaborate on this: if x then is more accurately the same as if x ~= nil and x ~= false then, but blueprint_effect won't ever return false)
and is such a weird operator imo
in lua, of course
i literally had to search it up
and took some time to understand it
alr so now it's not crashing, but it's not doing anything either
oh wait you probably have to unpack the table
so return SMODS.merge_effects(unpack(jokerabilities))
it takes the effect tables themselves as separate arguments
that should hopefully be it lol
okay
in the wiki it says:
SMODS.merge_effects(...) -> table
Takes any number of 2D arrays. Flattens given calculation returns into one, utilising extra tables.
This can be used to merge returns from SMODS.blueprint_effect
any... number?
yea it can take any amount of arguments, lua is cool like that
if you put ... as the arguments in the function definition, you can refer to {...} as a table of all the arguments
so it needs to be separate arguments, not one single table of all the effects
that's what the unpack function does
still nothing tho
maybe my table is empty rn?
can't i check my own code values somehow? a debugger of some kind?
if you have the DebugPlus mod installed, it'll put a console in-game, and you can just have print("something") in your code and it'll pop up in the console
put print(#jokerabilities) after the loop to see if it's actually getting blueprint effects
what's the # for?
#some_table is the number of elements in some_table
most readable function
it doesnt
it takes tables of effect tables
i get confused every time i use it and i wrote it lmao
no worries
alr that worked but
why am i seeing the table printing all the time
ik, i printed it on purpose but
shouldn't it only print once it needs to calculate?
or whenever you hover over a card that has a probability (like bloodstone)
and it's called a bunch of times during the main scoring loop
interesting
i'm now having a bit of an issue, which is totally expected.
if blueprint copies my joker, and my joker copies blueprint, and i have an extra joker, abilities of that extra joker are triggered 5 times instead of 3
that's expectable tho, i need to force it not to copy the abilities of blueprint only if blueprint is copying him
same for brainstorm
is there any way to make it so that the cards added to the deck can't be seen? it currently seems like they kinda flip on top of the deck
How would I go about making a joker thats unable to show up in the shop (I wanna make a joker that can only spawn from another one when conditions are met--kinda like gros michel/cavindish but you dont gotta find the cavindish equivilant in the shop)
is there a variable in SMODS.joker I can set?
in_pool = function()
return false
end
just do this and it won't appear in-shop
cool, thanks
how would i go about correctly making it such that if 4 aces are destroyed in one round, my deck will unlock? i thought my implementation used to work but i guess not now that i've tested it.
local original_card_remove = Card.remove
function Card:remove()
if self:get_id() == 14 then
if not G.GAME.bof_wooden_destroyed then
G.GAME.bof_wooden_destroyed = 0
end
G.GAME.bof_wooden_destroyed = G.GAME.bof_wooden_destroyed + 1
if G.GAME.bof_wooden_destroyed >= 4 then
for k, deck in pairs(G.P_CENTERS) do
if deck.key == "b_bof_l_wooden" and deck.check_for_unlock then
local unlocked = deck:check_for_unlock()
if unlocked then
G.GAME.bof_wooden_destroyed = 0
end
break
end
end
end
end
return original_card_remove(self)
end
...
local original_end_round = end_round
function end_round()
G.GAME.bof_wooden_destroyed = 0
return original_end_round()
end
in the deck:
check_for_unlock = function(self)
if G.GAME and G.GAME.bof_wooden_destroyed and G.GAME.bof_wooden_destroyed >= 4 then
return true
end
return false
end,
SMODS.Joker{
key = 'Shaco',
atlas = 'TrickyJoker',
pos = {
x = 0,
y = 0
},
rarity = 4,
cost = 20,
blueprint_compat = true,
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if (G.jokers.cards[i].label ~= Blueprint) and (G.jokers.cards[i].label ~= Brainstorm) and (G.jokers.cards[i].label ~= j_Planetarian_Shaco) then
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
end
end
return SMODS.merge_effects(jokerabilities)
end
}
Been smashing my head against this. Why is it still copying blueprint?
i'm not sure if i've seen "label" before
try making the string the key and then making it check for G.jokers.cards[i].key ~=
I've printed all G.jokers.cards[i].label values, and it gave me Blueprint, j_Planetarian_Shaco, and Jolly Joker, which were what I expected
oh nevermind then
still gonna try key
they're all nil
center_key is different tho
i get j_blueprint, j_Planetarian_Shaco
ok that's good
idk about jolly joker, didn't bother to check him
alr
nothing works now! great
oh, it's inside another table i think
it's copying, but it's the same thing
copying blueprint, even tho i specified it not to
SMODS.Joker{
key = 'Shaco',
atlas = 'TrickyJoker',
pos = {
x = 0,
y = 0
},
rarity = 4,
cost = 20,
blueprint_compat = true,
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if (G.jokers.cards[i].config.center_key ~= j_blueprint) and (G.jokers.cards[i].config.center_key ~= j_brainstorm) and (G.jokers.cards[i].config.center_key ~= j_Planetarian_Shaco) then
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
print("Copied effect of", G.jokers.cards[i].config.center_key)
end
end
end
return SMODS.merge_effects(jokerabilities)
end
}
INFO - [G] Copied effect of j_jolly
INFO - [G] Copied effect of j_jolly
INFO - [G] Copied effect of j_blueprint
INFO - [G] Copied effect of j_jolly
INFO - [G] Copied effect of j_jolly
INFO - [G] Copied effect of j_blueprint
This is what I get out of it, stupidly
aaaaaaaaaaaaaaaaaaaaaaaaaand
i'm comparing to a non existing string, yaaaay
"j_blueprint"
gosh
of course it would always return true since it's not nil
is there a way to make a custom joker debuff immune?
if context.debuff_card and context.debuff_card == card then
return {prevent_debuff = true}
end
thank ya
how do I check my own joker ability?
SMODS.Joker{
key = 'Shaco',
atlas = 'TrickyJoker',
pos = {
x = 0,
y = 0
},
rarity = 4,
cost = 20,
blueprint_compat = true,
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
end
return SMODS.merge_effects(jokerabilities)
end
}
I wanted to check if copy_effect was the same as my own joker, so it doesn't get added to the jokerabilities table
this prevents copying blueprint and brainstorm when they're copying my Shaco joker, and prevents my own joker from copying itself
{
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if G.jokers.cards[i].config.center_key ~= "j_modprefix_Shaco" then
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
end
end
return SMODS.merge_effects(jokerabilities)
end
}
this will only prevent my joker from copying itself
as i don't want to check the current joker, rather the ability
i tried to do it by indexing the current jokers and do it based on positions
however
this becomes unpractical if the user has multiple blueprints
there, changed to using joker key
still the same thing
if the center_key is blueprint it will copy the ability
and i don't want blueprint to not be copied, only i don't want it to be copied when it's copying my own joker. so if blueprint is copying one joker, i would trigger that ability 4 times instead of 3. the copied joker would be 1 time, blueprint would be 2, and my joker would be 3 and 4 since it's copying blueprint and that joker at the same time
for example
earlier i was determinating the position of shaco joker, and if it the blueprint position was that position - 1 it wouldn't insert into the table, but it was a mess
drives me nuts 
there must be a field from card or G.jokers.cards[i] which holds what a joker does, right?
then i could compare it if it's the same as copy_effect, so i don't insert that into the table
wait
you just gave me an idea then
i could create a temporary variable which holds the table of SMODS.blueprint_effect with Shaco, then compare it to copy_effect, as the tables would be identical
right?
identical here means 2 tables with the same key and value
the 2 tables themselves are not the same, only the same keys and values
Put blueprint_compat = false in the joker definition.
oh fuck
i thought of that
however i want blueprint and brainstorm to be able to copy my joker
just not the other way around, but only if they're copying my joker
basically i should only copy brainstorm and blueprint if they're copying another joker which isn't Shaco
(don't we have something to check what are brainstorm and blueprint copying???)
You would have to check manually.
that's not a problem
but where should i check?
If Blueprint is to the left of your joker and if your joker is in the first slot and the joker is Brainstorm
yes, but i would need to do this for every blueprint
manual check here means excluding the exact target joker of blueprint and brainstorm
if G.jokers.cards[i].config.center_key == "j_blueprint" and G.jokers.cards[i+1] and G.jokers.cards[i+1].config.center_key ~= "j_modprefix_Shaco" then
end
if G.jokers.cards[i].config.center_key == "j_brainstorm" and G.jokers.cards[1].config.center_key ~= "j_modprefix_Shaco" then
end
good idea
i'll try it
this is the only viable way tho
yeah, otherwise it becomes a mess
also it breaks if another mod takes ownership of blueprint/brainstorm by modifying the targets
yeah. i expect this
luckily, there doesn't seem to be any mod that does it
No, that wouldn't work for Blueprints copying a Blueprint that is copying your joker.
yeah
but
comparing an entire table isn't the same as comparing each one of its values?
oh
if context.blueprint_copiers_stack and context.blueprint_copiers_stack[#context.blueprint_copiers_stack] ~= card then
end
WHAT
where was this
from SMODS.blueprint_effect
wait hold on
I'm not sure if we're supposed to get the first or the last element of context.blueprint_copiers_stack
try both if you can
ah, okay
calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if context.blueprint_copiers_stack and context.blueprint_copiers_stack[#context.blueprint_copiers_stack] ~= card then
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
end
end
return SMODS.merge_effects(jokerabilities)
end
like that?
uh, use the first element instead
okay?
if context.blueprint_copiers_stack and context.blueprint_copiers_stack[1] ~= card then
end
honestly I'm getting spun around at this point

what if it's blueprint copying your joker copying blueprint copying your joker?
I think you need to check if your joker is anywhere in the stack?
my joker shouldn't be able to copy blueprint if it's copying my joker
that would be nice
function table.contains(table, element)
for k, v in pairs(table) do
if v == element then return true end
end
end
if context.blueprint_copiers_stack and not table.contains(context.blueprint_copiers_stack, card) then
end
i was about to write that but without a function
it's a helper function actually
Ortalab makes it a global, my mod appends it to tableLib instead
you might wanna use it elsewhere too, it's pretty common
probably
now something quite "funny" is happening
blueprint and brainstorm are copying the ability of my joker correctly
but my joker itself isn't doing anything???
ah crap
I forgor
Shaco is a blueprint-like joker
of course it must at least appear once in the stack
alrighty then
yeah but it's not like we're removing it from the stack or anything
if context.blueprint_copiers_stack then
for ii, vv in ipairs(context.blueprint_copiers_stack) do
if ii ~= 1 and vv ~= card then
--do stuff
end
end
end
how's that even possible
copying an ability that a joker doesn't even have
hold on while i test it
wait but does SMODS.blueprint_effect modify a table by itself, or does it only return a value?
it returns a new identical table
ah
basically the table it manages to grab as one of the return values of Card.calculate_joker
it triggered brainstorm 3 times and shaco and blueprint weren't even triggered
my jokers are ordered like this
how are you accessing context then
via calculate
what did you type in the console
eval calculate = function(self, card, context)
local jokerabilities = {}
for i = 1, #G.jokers.cards do
if context.blueprint_copiers_stack then
print(context.blueprint_copiers_stack)
for ii, vv in ipairs(context.blueprint_copiers_stack) do
print(vv)
print(ii)
if ii ~= 1 and vv ~= card then
local copy_effect = SMODS.blueprint_effect(card, G.jokers.cards[i], context)
if copy_effect then
table.insert(jokerabilities, copy_effect)
end
end
end
end
end
return SMODS.merge_effects(jokerabilities)
end
i'll do it from code even if it's laggy
smh
you're defining global calculate
it has nothing to do with context we're talking about
which is from SMODS.blueprint_effect
oh
doing it from code actually gave me the right context
also it wouldn't work because context.blueprint_copiers_stack seems to have the label of the joker it's copying
so if a blueprint is copying another blueprint which is copying my joker, the label would be "Blueprint" instead of "j_Planetarian_Shaco", making the table different
i'm thinking of adding a custom identification to my joker
so this way
if this argument gets passed into the table (assuming the entire table gets copied), i can identify it and thus not copying it
update: I fixed it
cool
the bane of my existance, using ' ' when I needed to use " "
wait..nevermind
dont think I fixed it lol
not really sure why it worked that time
wait
im stupid
I put the same joker with 2 identical pngs to debug, gave me the one I was testing on.
thats why it "worked"
lol
but I think I found the error cuz im a dumbass that forgot to give the joker pos variable
...nevermind
im not sure how that didn't break the joker before
but it did not fix my issue 🎊
now ima pass out
GAAAAAAAAAAAAAAAAAAAAAAAAAH
it's 6 AM
and i couldn't solve it
there must be a way of identifying my joker on the stack
i won't give up tho
i'll go to sleep but i'll keep on this tomorrow
iirc the context didn't exist at the time
can someone tell me why the "Nope!" text doesnt appear, i took it from vremade and it isnt working
yo i just tried this and it does absolutley nothing
What is that mean?!😢😢😢😢
So I was making a blind and im slightly confused, for some reason this effect is delayed to the start of the next played hand? I'm trying to make it update after the hand is played but its not working.. I also tried final_scoring_step but that did the same thing
you should use a blind_size return instead of changing blind size manually
what are you trying to do?
like whats the effect description
if context.after and G.GAME.chips+SMODS.calculate_round_score() < G.GAME.blind.chips then
return {blindsize = SMODS.calculate_round_score()/2}
end
correct me if I'm wrong, but I belive G.GAME.chips isn't the amount scored that hand
yeah it's SMODS.calculate_round_score()
I just tried that and it didnt do nuthin 
what's yer smods version
1.0.0~BETA-1503a-STEAMODDED
ill go update rq then 
Okay cool it works now thanks
I sometimes forget updating is a thing that I need to do
I'm struggling to understand shaders. Can someone help me understand it more?
is fileInfo.name just not a thing anymore
GLSL shader language is really difficult, theres some good books out there if interested
its like C but more specific and less documented
theres a website too
called the book of shaders (?) entirely free tutorial to GLSL, but be prepared to grit your teeth and get through it
can I see line 68 of your code
in that file
what it looks like is that you're trying to reference card when card does not currently exist at that point
yep
uh
gimmie a sec
--The Panopticon
SMODS.Blind {
key = "the_panopticon",
dollars = 7,
mult = 1.85,
pos = { x = 0, y = 3 },
boss = { min = 3 },
boss_colour = HEX("8c8a81"),
atlas = 'Blinds',
loc_txt = {
['name'] = 'The Panopticon',
['text'] = {
[1] = 'Scored face cards make you lose $2.',
},
},
calculate = function(self, blind, context)
if not blind.disabled then
if context.press_play then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.2,
func = function()
for i = 1, #G.play.cards do
if card:is_face(true) then
G.E_MANAGER:add_event(Event({
func = function()
G.play.cards[i]:juice_up()
return true
end,
}))
ease_dollars(-2)
delay(0.23)
end
return true
end
end
}))
end
end
end
}```
on line 24 you are referencing a non existent card
i would do it like this
for k,card in ipairs(G.play.cards) do
-- bla bla bla, replace i with k
end
i just used the tooth template from vanillareforged and added the if card:is_face(true) then
alright, but still. card is not defined as anything here
oh
you could say if G.play.cards[i]:is_face() then
also putting true in the is_face function is not needed
if its a face card then is_face() would read as
if true then
if not then it would read as
if false then
hopefully that helped
now theres another problem
it just removes 2$ if theres a face card in the hand rather than remove 2$ for every individual face
I'm going to try my best, thank you <_>
is it in the loop
calculate = function(self, blind, context)
if not blind.disabled then
if context.press_play then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.2,
func = function()
for i,card in ipairs(G.play.cards) do
if G.play.cards[i]:is_face() then
G.E_MANAGER:add_event(Event({
func = function()
G.play.cards[i]:juice_up()
return true
end,
}))
ease_dollars(-2)
delay(0.23)
end
return true
end
end
}))
end
end
end
}```
i think so
calculate = function(self, blind, context)
if not blind.disabled then
if context.individual and context.other_card:is_face() then
return {dollars = -2}
end
end
end
okay so i didn't
calculate = function(self, card, context)
if context.before then
for _, pcard in ipairs(context.scoring_hand) do
if pcard.get_id() >= 11 and pcard.get_id() <= 13 then
local newRank = pseudorandom(G.GAME.round_resets.ante,2,10)
local rankChange = (pcard.get_id - newRank) * -1
SMODS.modify_rank(pcard, rankChange)
end
end
end
end
pcard:get_id() instead of pcard.get_id()
ok cool thanks
and also that in the place where you calculate the rank change
ok
is there an easy way to move the location of a sticker or am i gonna have to figure out how drawsteps work
"but minty drawsteps are easy" that's just, like, your opinion man
what, you want your sticker to allow normal shader effects of the card on top of it rather than below?
i literally just want to move the image of the sticker up
so it sticks above the card
(it's kity ears)
idk anything about shader effects
look into how paperclips in paperback display i think? i'm pretty sure they move the location of the sticker so they can hang out of the regular bounds, and they're definitely just fancy stickers under the hood
probably by utilizing alignment_offset
it's a Moveable thing actually, the Sprite class is extended from Moveable after all
is there a context for after cards are scored but before jokers are? I cant really find any
@frosty dock in the blueprint copying stack, do we have some way of identifying the final joker it's copying if it's chained?
wdym?
let's say i have three blueprints copying a jolly joker
isn't there a way to know that they're all copying jolly joker
instead of two copying blueprint and one copying jolly joker
nope, sorry
ok, thank you
whenever a non-copying joker is being calculated, everything on the blueprint stack is directly or indirectly copying that joker
exactly, that's the point
don't we have a way of identifying what is indirectly copying?
since it's "chained"
yeah, the first entry is copying the second entry is copying the third entry etc. is copying the joker directly
the stack is the copy chain
yeah but it has quite a lot of info under that table
.label isn't useful here since it would return "Blueprint"
isn't it just an array of cards?
i would need to iterate through all cards, and get... what?
well what do you need out of the cards...?
the last copied joker
that's not on the stack, that's the card currently being calculated
I'm trying to use card:set_ability to transition a joker into another one of my jokers, but im getting "could not find center" error message and I can't for the life of me figure out why
the stack contains the copiers
oh so it isn't that useful here
did you forget your mod prefix?
huh
what is your goal exactly
sometimes its the stupid things
if you're doing a blueprint effect to copy a card, you already have that card. it's the first card you passed into the blueprint effect function lol
nvm i keep typing before my brain catches up
if you're trying to get to the end of the chain from the start of it, that's a different problem
I have a joker that copies abilities from all of my jokers
However, I want to not copy himself (which is easy), but i also not want to copy blueprints that are directly, or indirectly copying my joker in a chain
This joker is called Shaco
okay
yes
that's the idea
but why is it a problem
oh in that case it absolutely isn't
you just check if card is on the blueprint stack yet
yup that worked thank you, stupid me 👍
if it is, it is copying something that is directly or indirectly copying your joker
by blocking that effect, you're solving the problem at the end of the chain
ah alr
can i use
table.contains(context_blueprint_stack[#], card)
?
table.contains is a custom function but
alr
that fkn worked, ty
now i need to solve brainstorm
does it use the same stack?
nvm, it already works. hilarious
it's really strong. i always wanted a legendary like this
should it be able to copy a duplicate of it (like if I had two or more shaco jokers)?
maybe that's a bit op
bump
looks like malformed shader code
how do you change the cost of a jokers sell value?
sorry if dumb question 😭
could probably just look at how egg does it
how does one check if the blind defeated for calc_dollar_bonus is a boss?
if G.GAME.blind.boss
just remembered i fucking hate localisation 😭
i keep getting "ERROR" which makes me think i fucked up somewhere on the localisation fetching thing
ive got the localisation file right here
the prefix for this mod is hatchl
anywhere specific you're getting ERROR? stuff like custom rarities have extra places to localize for the badges
all of the additions ive added so far are getting errors
lemme specify in a sec
firstly, the enhancements
how would you get a list of all scored cards (as compared to all played cards with G.play.cards)
the enhancements return with "ERROR" which means the localisation is wrong
ill probably make a repo to show this off a little further
yea if i could see the code myself that'd help a lot
https://github.com/cosmeggo/hatchet-lite @frosty rampart
oh you've got to be fucking kidding me
it was a spelling error 😭
oh yea i just noticed it too
gotta be the american way to spell the localization folder
anyways it looks like theres no actual errors with my localisation, i just dont know american
sounds like i need to make an smods pr 
so i wasnt dumb all along
ok why are my jokers not localising????
everything else works but the jokers return with ERROR
oh i wrote jokers not joker
buh
what do i do abt the Xnil ?
no shot i didnt do a loc vars
im so stupid
anyways i think ive got it from here! thank you c:
nvm
how do i make a joker recognise when a poker hand is being levelled up and responding accurately
calculate = function(self, card, context)
if context.joker_main then
if G.GAME.level_up == true then
card.ability.extra.chips = card.ability.extra.chips - card.ability.extra.chips_sub
return {
message = localize { type = 'variable', key = 'a_chips_minus', vars = { card.ability.extra.chips_sub } },
colour = G.C.CHIPS
}
else
return {
chips = card.ability.extra.chips
}
end
end
end```
idk if G.GAME.level_up == true is an actual thing i lowk just made it up
ik this joker is missing a dissolve, ill be adding it later
apparently theres smth called upgrade_poker_hands
@frosty rampart im duuuumb idk what im doiiiing 🥺
the actual concept behind the joker works fine i just dont know what line of code is used for "if joker sees a poker hand upgrade, it loses 50 chips"
good news! new context from 1501a has you covered
woooo
wait is my mod on 1501a
lemme see
"Steamodded (>=1.0.0~BETA-1606b)"
thats over 1501a right
yeah i think so
yea if the number is bigger then it works
how do i change the shop rate of my custom center object, like how playing cards have G.GAME.playing_card_rate?
ok now ive broken something else else
calculate = function(self, card, context)
if context.poker_hand_changed == true then
card.ability.extra.chips = card.ability.extra.chips - card.ability.extra.chips_sub
return {
message = localize { type = 'variable', key = 'a_chips_minus', vars = { card.ability.extra.chips_sub } },
colour = G.C.CHIPS
}
end
if context.joker_main then
return {
chips = card.ability.extra.chips
}
end
if card.ability.extra.chips <= 0 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize('k_extinct_ex'),
colour = G.C.CHIPS
}
end
end```
if card.ability.extra.chips <= 0 then crashes the game oe
ok it looks like ive fixed it
i just had to steal the ice cream code and change a few things around
how do i increase the winning ante?
How do I make a card have a modded enhancement in SMODS.add_card
A specific not random one
"m_modprefix_enhancement", where "modprefix" is the prefix of the relevant mod and "enhancement" is the key of the enhancement
Is there a way to make joker display use SMODS.get_probability_vars() instead of (G.GAME and G.GAME.probabilities.normal or 1) for probability numerators? I'm hooking SMODS.get_probability_vars() for a special effect, but it's not reflected on the joker display.
i just put that under set?
so set = m_modprefix_enhancement?
SMODS.add_card({ set = 'Playing Card', enhancement = 'm_modprefix_key' }) iirc.
You should probably update jokerdisplay, I don't think it does that
also why are you hooking that function instead of using the contexts exactly
how do you make a stake after gold stake?
SMODS.Stake {
...
prefix_config = { applied_stakes = false, above_stake = false },
applied_stakes = { "stake_gold" },
above_stake = "stake_gold",
...
}
is there a way to check if you're currently playing in a blind in the calculate function of a joker?
ah, you ad above_stake
applied_stakes is what applies the effect, above_stake is what make it visually appear on top of/after gold stake in the UI
what's the actual, exact timing you want
I'm hooking it because I'm making all probabilities always occur, so I'm checking if a condition is met and setting the numerator to the denominator (i.e. 2 in 2 or 7 in 7), and I don't want something like an oops all 6's in a slot after it showing the doubled value because I think that 8 in 4 looks really messy
but yeah I do see now that updated joker display does use the SMODS function
also how do you make one below white stake?
just use context.set_probability, it overrides everything that context.mod_probability does
you have to take ownership of white stake and make it apply + be above your new stake
check if G.STATE == G.STATES.SELECTING_HAND, that's the state the game is in while idle in the middle of a round (and you can't sell a joker while cards are being drawn or played, so that's the only state during a round that the sell event could happen)
and that can just be put in the calculate function and its chill?
as long as you keep it within context.selling_self, yea
no problem
like this?
ah fuck my bad, it's fix_probability
The seal I'm testing has
calculate = function(self, card, context)
if context.main_scoring and context.cardarea == G.play then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'mult',
scalar_value = 'change',
message_colour = G.C.ATTENTION
})
return {
mult = card.ability.extra.mult
}
end
end,
which seems to be crashing this but I don't know why exactly?
Am I supposed to have the Seal use scale_card on self instead?
...if that's increasing perma-mult, you shouldn't be using scale_card, actually - that's for scaling Jokers and such. https://github.com/Steamodded/smods/wiki/Perma-bonuses
So I changed it to this (other_card was also crashing it) and I now have this crash
It should just be card
...and card.ability instead of self.config in loc_vars.
No, it should be card.ability.seal
...that too.
mfw joker bugged
if (context.debuff_card and context.debuff_card == card) or (context.joker_type_destroyed and context.card == card) and not context.blueprint_card then
card:set_ability("j_kdi_Kerry_rage")
end
my problem is, I only want card:set_ability to occur if it gets debuffed. The problem is context.debuff_card is called to determine if its getting debuffed
its proccing on asking the question not proccing off the answer
I guess I could have just done a conditional if it is debuff == true
you can probably just use update and check for card.debuff
there are too many ways of debuffing a card
also a debuffed card won't calculate
Yeah, thats why I was doing context.debuff_card to begin with
yeah but even if that was the context for when a card is debuffed it won't reach that because debuffed cards don't calculate
remove_from_deck might also work for what you want? it's called both on destruction and debuffing
x2.5 Mult 
Basically hes a weaker michel/caven (+15, x3 -> +10, x2.5) but has utility in not being debuffed, not needing to be bought, and also can proc destroy effects (like cere dagger)
and an easier/more reliable trigger then just rolling a 1/6
yeah remove_from_deck will work good enough for the transformation
you would still need joker_type_destroyed to prevent destruction
remove_from_deck is a function separate from calculate if that's not clear
Hes angy
Is it possible to give unlimited hand or discards
Or do you just set the number of hands to the max amount
progress
maybe it would be better to just "remove" the card, and then add enraged kerry. As opposed to using ability
kinda like how that looks more then just ability tbh
has a nice transition to it
btw it worked
🎊
even made sure to keep edition type consistant
I could also have the stickers be retained, but I kinda like it being cleansed in a gameplay sense
Meanwhile my progress looks like the vague idea of my Haste Blind kinda working maybe if I tweak it or something idk.
lol
When in doubt, you typo'd a variable
while making the editions carry over
I had an editionType variable, but I was putting editonType in SMODS.add_card
Not sure what mercenary I should do next
(making references to another game)
Maybe gold bot, gain gold when you skip a blind
gold bot gives 1d6 in goot, might be too much in this game tho
tho I mean there is that 25 gold one, in 3 blinds thats 8.3 gold assuming u skip small
want to make a blind skipping joker to make up for the fact I made 3 around selecting them
easy peasy
if you have oops all 6's you roll with advantage
🔥
The best part about petyr is I have to retroactively make sell quotes for him
he just doesnt stop yapping
add that as a fine print
because no one ever reads the fine print
(If you are lucky it rolls with advantage) 🔥
-# specify advantage too
You can always force it to a certain amount
For example, if the amount of available hands is 1, you change it to be 2
what does card.suit actually return if a card is wild?
I dont remember that being a thing
card.base.suit is the actual suit.
what are you trying to accomplish
i just mean whenever you check a card's suit, what do wild cards return
their suit
wild cards still have a suit
Wild cards just say yes when the card is asked about being a specific suit, regardless of its' actual suit.
how can i get if a card has the wildcard effect?
if SMODS.has_any_suit(card) then
unless you care about specifically the wild card enhancement, in which case check card.config.center_key == 'm_wild'
is there a way to get all "suits" on a card?
cause theres stuff like wild cards and smeared joker
Probably the same way you get editions from a card
no get_suits function exists as of yet, but you can do this
local suit_map = {}
for suit,_ in pairs(SMODS.Suits) do
if card:is_suit(suit) then
suit_map[suit] = true
end
end
though a function for this will at some point be added to smods
alright thank you
(I just forgot the difference between editions and enhancements)
-# probably alongside everything else that's waiting for quantum ranks
Can he use SMODS.smeared_check
?
why would you want to use that directly?
it's called in Card:is_suit when appropriate
Ah
No it's moreso trying to get forced timer discards to work
for compatibility with any effect like wild card or smeared joker
Also this is the seal that this code is for lol (don't feel like grabbing an in-game image of it because I'm not at my PC and I'd have to disable Cryptid bc it has a special texture with Cryptid that makes the counter say "CRYPTD")
(Dramatization)
And the version for if Cryptid is installed.
Because currently it also discards all selected cards and, more importantly, doesn't properly reset your selections, which means you wind up keeping your initial hand lol
Might try and use the "discarding selected cards" thing for Agility, but Haste probably should stay as just discarding non-selected cards.
Which would probably just require using a seperate table for Haste's selections than the highlighted cards (which is what The Hook uses) and changing for _, playing_card in ipairs(G.hand.cards) do into something like for _, playing_card in ipairs(G.hand.cards) and ~ipairs(G.hand.highlighted) do (or however that would actually look), but I don't know how that would affect the if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) thing from The Hook
TF2 x Balatro cross over should be a thing
why is heavy not a friends of jimbo skin
Truth nuke
how would I change the color associated with Diamonds? Like when Ancient Joker has selected Diamonds, the text is orange, and when it selects Spades the text is dark purple or black or something. Where do I change those colors? And the color of the rows in the menu you get when you hover over your deck mid-round?
You can look at Vanilla Remade. It shows how every joker etc. would be done in Steammodded
that's mildly unhelpful relating to changing the colors
Oh, my bad
the simplest way to do this is tying it to a SMODS.DeckSkin, in which case you just have to define colour on it
doing it outside of deck skins is thus problematic because it conflicts with the color changing when the deck skin does
is deck skin the High Contrast setting?
no, it's the friends of jimbo thing
can deck skins change the color of non-face cards??
you can change the color per palette (high/low contrast etc., also allows for other custom options) and change the sprites of all cards of the suit, not just faces
SMODS.add_card({ set = 'Joker', legendary = true })
Im trying to make a joker that creates a random legendary when sold but this didn't work for the joker spawning bit
it just spawned a random joker, not a legendary
huh, that seems like it should work
Do you maybe already have all legendary jokers? Because then it just gives jimbo x3
Or did it really just spawn a normal random joker (that's not jimbo)?
I have no idea 🤷♀️
I don't think it would be a Version issue, but.. What SMODS-Version are you using?
- Any other Mods active besides yours? ^^
1531
i do have some
ill try disabling them
Balatro is tweaking
In general not modwise
I gotta restart stuff
Alright x3
If there's still a problem, go install the newest SMODS release, maybe that also fixes it for ya' ^^
-# 1606 does mention "Consistency changes to SMODS.create_card by @Aurelius7309"
ok
1531 is bugged in a multitude of ways, including that it turns The Soul into judgement if you have object weights enabled
which is exactly the issue at hand^^
Ah well, that would do it 
Alrighty, this sounds REALLY easy, but alas I'm here now 
I have an open Question/Challenge for y'all:
Joker-Text:
X2 Chips for every 5 scoring cards
(Currently 0/5)
Base Code:```lua
if context.individual and context.cardarea == G.play then
card.ability.extra.count = card.ability.extra.count + 1
if card.ability.extra.count >= card.ability.extra.every then
card.ability.extra.count = 0;
return { xchips = card.ability.extra.xchips, colour = G.C.CHIPS }
end
end
I want this to be Blueprint compatible, but I only want the "card.ability.extra.count" to count up once per scoring card.
Reply Ping if you think you've got a working solution x3
-# The Main Goal is really just a Blueprint Compat.: "counting scoring cards and doing something every Xth scoring card"
context.blueprint is true if it's currently being calculated as a blueprint effect, and false if the joker itself is calculating
so incrementing the count (and only that line) should be wrapped in a check for if not context.blueprint then
what if the blueprints check before?
Exactly that
what i would do is like store the last scored card in a variable
and if the card is the same dont increment it
also you dont need a colour for the xchips return
wait no
what if you just count all the scoring cards in context.before
It has to work with an Setup like this and also work with Retriggers
retriggers?
bleh
actually this would break with retriggers too
-# I know, I'm just too used to adding it 
fair
are there other ways to apply stickers than card:add_sticker
card.ability.stickerkey = true right
that only sometimes works, because sometimes stickers do more than just setting that value to true (e.g. perishable sets a timer as well)
SMODS.Stickers.stickerkey:apply(card, true) should work too potentially
oooo let me try that
Also for for simplicity's sake, a full Joker-Example:
so it should be fine on other versions?
apply the xchips in joker main?
sweet it works perfectly now
That would not help for the main Goal of: "Do something every Xth scoring card"
uhhh maybe wrap the extra count inside a if not context.blueprint then like meta said?
If you follow the convo. a bit more; That wouldn't work for jokers that trigger before the "Counting Joker" x3
counting joker?
If you look at this: Blueprint wouldn't trigger the "X2 Chips", the "Counting Joker" or Main Joker WOULD give "X2 Chips", Brainstorm too.
Mind you, I have tried a LOT of different things, I'm giving this simple example so someone else has some thinking room x3
how would I make a joker only appear as eternal and negative
