#mod_development
1 messages · Page 67 of 1
Yeah, you can use anything, was just an example. Can technically use anything
I know, I probably nitpick too much lol
Huh? Whats this for and how
In mod info*
There's version min and version max, so your mod only activates if true
can you do a non-inclusive max? like [41.78,42)?
Any screeenshot propf of concept
I'm more into the version control for say the mod itself.
(Not tied to the PZ version)
It's two parameters - so you set versionmin=41.56, versionmax=42
Idk if they allow for sub versions
Id have to check how it gets parsed
I just wouldn't want to have to put out tiny updates every time there is a new subversion to bump up the max, but also don't want people to think it will work on 42 since I'm sure that'll break everything, lol
Yeah, I only use min for that reason
I guess it's more responsible to version lock it - but honestly most mods will work forever
I'd like to see what the community could come up with to provide ideas on improved version control for mods and the workshop.
The workshop is a mess
It'd probably intersect topics around issues with mod content management in general.
The workshop tags were fixed which helped a lot for browsing
But the mod packs and server configs are choking up content lol
my biggest concerns is things like ItemTweaker, which doesn't really need to exist and makes loading super slow due to print spam. And stuff like that profession framework that has a dozen offshoots and nobody knows which one is the right one. We need some way to handle both of those situations
That'd require someone to spend time curating the workshop
My only current suggestion would be to allow for dependencies of mods or mods in server.ini to have mod_id:version;.. and the folder tree to have content/{version}/...
Not something that impacts anyone enough to do so imo
https://zomboid-javadoc.com/41.65/zombie/vehicles/BaseVehicle.html#setNeedPartsUpdate(boolean) what does this do? like can i force it to update or?
Javadoc Project Zomboid Modding API declaration: package: zombie.vehicles, class: BaseVehicle
or simply use mod data
Not atm, was just an idea- not something I have implemented yet.
In theory, you could use it for a lot tho. An idea I had is for crafting items with a lot of interchangeability, or for setting multiple effects simultaneously with varying degrees.
So, if you set the tags like
‘Tags = r.10, g.15, b.100’
You could have those values be the rgb color code associated with an output crafted item/ effect.
So, the function you put into the oncraft/oneat would take the array of tags, break them each down into the variable and number, and then your function would look for those to apply the effects.
For sure, but that requires you to set the mod data- this would be entirely contained in the item script files. It’s not anything crazy- but just an interesting concept
you can set moddata from the script 🤔
Theres a clone function on script manager i wonder if it works
Yes u can
Fair lol, but- what is the definition for that? I haven’t messed with mod data set by default, only modifying it on the fly
i wasnt asking was stating
Just make something = to something its auto moddata. I think everything on a script is moddata. Not sure tho.
But what brandon is saying goes beyond moddata
My bad
I need a value from GameTime. What is the earliest Event I can call it from without it being nil?
This is something that should run before the game begins
you don't need to do anything complicated like this
instead of putting these in tags, just go
effect = -10,```any invalid parameter is added as moddata to that item
neat
i remember someone having trouble with that not supporting a specific data type, i think it was booleans?
but other than that that's the easy way of doing that
since values equate to true just do = 1
yeah, they specifically wanted the moddata key to exist and be false, i don't remember exactly why
anyone have a link or just some insight into what skill's names i can use in a script? for example:
SkillRequired:Woodwork=1,
im trying to make a recipe need a minimum in aiming / cooking / etc
declaration: package: zombie.characters.skills, class: PerkFactory, class: Perks
they should use the names here
How can I access the enum MoodleType?
I need to go from the internal moodle name to the moodle
Hi, maybe this will be easy, but how can I specify if item could be added as a fuel (fire) and how to set its value?
MoodleType.MoodleName
o...kay...
I have the MoodleName stored in a variable
have you tried MoodleType[name]?
No, not yet....
Although I think my issue lies elsewhere actually
Because even if it doesn't grab the moodle correctly, it should print something...
camping_fuel.lua
There is a table of items and their efficiency in
Welp
That file 😂
oh, thanks
Well, I have indeed found my issue
somehow it's not loading the sandbox settings in correctly... I'll deal with that later
should those change to say FROZEN? at some point?
yeah
Good news, the mod itself works
But it isn't reading or writing the sandbox options correctly
they should be good then
and they aren't null
because then it would load the failsafe defaults
The error is in my function that converts the string into a proper config...
I...
I even made comments explaining this for myself
and only now do I see that I used the wrong index
N wait taht wasn't it, I'm not a full idiot
tonumber(string)
yes, my IDE suggested it
it finally works!
Now people can experience existential dread in zomboid when their characters are hungry
anyone know a mod that removes the chances to break when picking stuff up
What is happening here?
trying to get the tsarlib freezer to work.
and now that i have removed MY code. it's doing NOTHING.
it apparently needs to have it's own seat?
I thought of something regarding skillbooks - I'd only do it if I did not have to edit every single action - but it would be neat if having a skillbook in your secondary hand gave you a bonus to skills - but in exchange when you're performing a timed action you have to pause to read a bit from the book.
Kind of like double checking yourself
makes me think of a spellbook. Like you have to study it for an hour every morning to prepare
had the same idea initially, but rather than having to read it as a separate action there's a benefit to it
lol i fucked that ALL the way up

i.e.: you have to wait a bit longer to do XYZ you'd not normally be able to do
make books much faster to read but only a temporary xp boost... that might work
there is a mod that makes books consumed, but they give you xp straight up. Kinda liked that as an alternative, also saves you from constantly trying to filter out books you've already picked up
that's konijima's right?
there's a few like that
I don't recall
there's cdda reading, evelyn made one, i think konijima did write one too
yeah that always bugged me
I'd be ok with all of them vanishing or none of them, lol
instead of skillbooks sticking around and everything else disappearing
that's fair too
the next version of my mod makes them stay, but you can't reread them
skillbooks or regular?
regular, this is the default behaviour of skillbooks anyway
I didn't know you had a reading related mod
I like named Lit, chuck, because it gives me a reason to collect books. We've talked about this before.
named lit already has sandbox options to control rereadability 👉 👈
gotta get the whole set
it's actually my most popular mod - i've got a crazy big update coming (the changelog is literally a page long right now) so the current version isn't the absolute best
which?
I have a proclivity for random generation so the mod started as a 'I wonder if this would work', I think it's awesome people actually try to find whole sets lol
on the flip side I'll be real bummed if a book is missing because it didn't get scraped from whatever db you used, lol
I spent like 2 hours parsing GoodReads
top 100 per century, decade, then year
idk how they know what the top 100 books for the 4th century were
i think i wrote some stuff to make sure my mod was compatible with named lit, didn't realise it had that feature though
I added it after Udderly requested it lol
they didn't like the fact you could reread it up to 3 times
upto 3 times - each time expiring after 6 months
Which is your mod?
this version is probably compatible - i don't use named lit but i imagine i would've got complaints
the currently released version doesn't have any of the features that made me consider compatibility an issue
Ah nice
I think the other literacy mod had some issues for a bit - never got complaints for this one
the only compatibility issues i've had with it are with other mods overwriting things, as far as i know this one should play perfectly friendly with other mods
namedlit just adds onto the timed actions
it also strips off the vanilla stats for boredom/stress/etc
in my unreleased version read books are kept with a (Read) indicator, so i had to make sure it wouldn't overwrite your book names
i'll need to get around to adding some compatibility for your rereading system, probably just make it ignore my re-read blocking system when a sandbox option is enabled
local ISReadABook_perform = ISReadABook.perform
function ISReadABook:perform()
local bookNameLitInfo = self.item:getModData()["namedLit"]
if bookNameLitInfo and self.stats then
---@type IsoPlayer|IsoGameCharacter
local player = self.character
local bodyDamage = player:getBodyDamage()
local stats = player:getStats()
local title = bookNameLitInfo["title"]
local UnhappyChange, StressChange, BoredomChange = namedLit.readerMemory.statsImpact(self.item,title,player)
local totalTimesRead, timesStampsWhenRead = namedLit.readerMemory.getTotalTimesRead(self.item,title,player)
local canRead = SandboxVars.NamedLiterature.CanReadPassedMax or (timesStampsWhenRead < namedLit.readerMemory.getMaxTimesReadable())
if canRead then
if getDebug() then print("NamedLit: StressChange:"..StressChange.." UnhappyChange: "..UnhappyChange.." BoredomChange:"..BoredomChange) end
stats:setStress(math.max(0,stats:getStress()+StressChange)/100)
bodyDamage:setUnhappynessLevel(math.max(0,bodyDamage:getUnhappynessLevel()+UnhappyChange))
bodyDamage:setBoredomLevel(math.max(0,bodyDamage:getBoredomLevel()+BoredomChange))
end
namedLit.readerMemory.addReadTime(self.item,title,self.character)
end
ISReadABook_perform(self)
end
I also mimic the vanilla stuff for read update that locks the stats in place during reading
should be pretty compatible I imagine
yeah i'm pretty sure all i'll need to do is let people turn off the system that stops you from rereading books at all and then yours will kick in instead
lmk if there's anything I can change 👍
will do 👍
also I've added comics and untitled literature in the last update a few weeks ago
so stuff like newspapers can also be reread individually
where as named literature gets a shared history on title
I kind of wish there was a recently updated tab for workshop - although that'd be abused very quickly lol

oh 😮
I never noticed that - I assumed that was just for subscribed items
reorder the hotbar looks nice
I hope it works with swapit
how have you all learned to mod the game? just reverse-engineering other mods and building up your knowledge?
read the lua docs, then tinkered with other mods, ya
pretty much yeah
i started looking at other mods, now i usually just look at vanilla code
@willow estuary we hear you and we appreciate it
?
Blair is working on a variety of things – and is currently super proud of ‘LootLog’ which he wants advertised so modders are aware of it. This is a dev and modder tool that, once activated, logs every item that spawns around the player rather than wait for the player (or modder/dev) to discover it. Info logged includes a list of items; the room definition in question; the container type in question; and the X, Y and Z coordinates of the container in question.
This is intended as a tool for us and the modding community to evaluate the amounts of loot that spawn, and where it spawns. The blog writer is aware that it isn’t super sexy blog content – but Blair underlines that it is a ‘niche pleaser’ so if you are in that niche: consider yourself pleased.
from todays blog
Oh it came out - I tried checking earlier
no but blair wanted to be noticed
No, he wanted to please us 
anyone feel like terrorizing tsar lib for me?
also, cleaner debug tools are very welcomed
dev came back a few days and said to report bugs
new ‘filler’ book items with names dreamt up by dreamy Pat_Bren
😮
I wand tsar freezer stuff to work on a truck bed. anyone up for the challenge?
the danged thing can just be "on" always.
I've been redoing the F11 debug window, adding in better windowing, breakpoints, watching for changes, viewing globals, auto-reloading of marked files, and some other goodies.
Been spread a bit thin at work, but will most likely have time to button up the Inspect Item stuff along with this debug stuff over the holidays.
I also started toying around with a "plugin" to Mod Manager that checks for mods that overwrite files, and add a hook for future function analysis (eg. if a mod overwrites a class or function that's already defined).
😮 hot dang
idk if you ran into this issue but error print out is split erroneously - the header/footers get cut off
doesn't matter in the normal f11 as you can just hit next and keep printing them in a giant log
yeah, the error output needs some loving. I wanted to have a collapsible list of errors, to make it easier to see what actually happened. If possible, maybe save a snapshot of the stack at that error for debugging (might have this a toggle option, disabled by default).
Also want to improve the lua console, and add the console into the debug window - it'd be super nice to be able to run lua commands against the current stack (kind of like Python's debugger)
you can grab some coroutine stuff but honestly that's a bit above me
All I did for errorMagnifier was grab the errors, prevent duplicates, and cleaned up the header/footer
and gave it a nice UI with easy to use buttons lol
ok so I have this line
local bloodlustMeter = player:getModData().DynamicTraitsWorld.Bloodlust.BloodlustMeter;
in 2 functions that are run one after another, and nothing happens between that.
How come
print("Bloodlust Meter: "..bloodlustMeter);
prints 2 different things? 
In 1st function it prints one number
in 2nd it prints different dumber
did I fuck it up here, where I initialize my modData?
local function createModData(playerIndex, player)
player:getModData().DynamicTraitsWorld = player:getModData().DynamicTraitsWorld or {};
local modData = player:getModData().DynamicTraitsWorld
modData.VehiclePartRepairs = modData.VehiclePartRepairs or 0;
modData.Bloodlust = modData.Bloodlust or {};
modData.Bloodlust.BloodlustMeter = modData.Bloodlust.BloodlustMeter or 0;
modData.Bloodlust.BloodlustProgress = modData.Bloodlust.BloodlustProgress or 0;
end
Events.OnCreatePlayer.Add(createModData)
Where are the prints?
local function bloodlustMoodleUpdate(player)
if player == getPlayer() then
local moodle = MF.getMoodle("BloodlustMoodle");
moodle:setThresholds(0.1, 0.2, 0.35, 0.49, 0.5, 0.65, 0.8, 0.9)
local bloodlustMeter = player:getModData().DynamicTraitsWorld.Bloodlust.BloodlustMeter;
print("Bloodlust Meter in MoodleUpdate func: "..bloodlustMeter);
local var = bloodlustMeter / 36;
print("Var: "..var);
moodleValue = var;
moodle:setValue(moodleValue);
end
end
local function BloodlustKill(zombie)
local player = getPlayer();
if SBvars.Bloodlust == true and not player:HasTrait("bloodlust") then
local bloodlustMeter = player:getModData().DynamicTraitsWorld.Bloodlust.BloodlustMeter;
local distance = player:DistTo(zombie);
if distance <= 10 then
bloodlustMeter = bloodlustMeter + math.min(1 / distance, 1) * SBvars.BloodlustMeterFillMultiplier;
if bloodlustMeter >= 36 then
bloodlustMeter = 36;
end
print("Bloodlust Meter in BloodlustKill func: "..bloodlustMeter);
bloodlustMoodleUpdate(player);
end
end
end
you're changing it before printing
because you're doing a bunch of maths to the value in BloodlustKill
it only changes the entry in the table if you access it through the table, otherwise you're making a copy of the value and changing that
your maths changes the value that BloodlustKill prints, and then bloodlustMoodleUpdate grabs the original value from the moddata again
so if I wnat to update value in moddata I can't do local bloodlustMeter = player:getModData().DynamicTraitsWorld.Bloodlust.BloodlustMeter;
I need to do getModData fully?
doesn't lua works by reference?
only tables and functions work by reference
oh
local modData = player:getModData().DynamicTraitsWorld.Bloodlust
modData.BloodlustMeter = 5
```changes the original in the player's mod data, but
```lua
local modData = player:getModData().DynamicTraitsWorld.Bloodlust.BloodlustMeter
modData = 5
```does not
hm
I'll definitely fuck this up again
in some time

so this would be correct approach, right?
local function BloodlustKill(zombie)
local player = getPlayer();
if SBvars.Bloodlust == true and not player:HasTrait("bloodlust") then
local bloodlust = player:getModData().DynamicTraitsWorld.Bloodlust;
local distance = player:DistTo(zombie);
if distance <= 10 then
bloodlust.BloodlustMeter = bloodlust.BloodlustMeter + math.min(1 / distance, 1) * SBvars.BloodlustMeterFillMultiplier;
if bloodlust.BloodlustMeter >= 36 then
bloodlust.BloodlustMeter = 36;
end
print("Bloodlust Meter in BloodlustKill func: "..bloodlust.BloodlustMeter);
bloodlustMoodleUpdate(player);
end
end
end
looks good to me
what's the difference between prerender, render, and update on UI (ISPanel)? low ticks maybe?
if I had to guess prerender is before the actual render - and update is called after certain types of events?
I'm not sure what the benefit between prerender and render would be - but I've used prerender to render background elements as to not interfere with other UI stuff
sweeet, thx, so I'm right way
render/prerender and update happen on every "ui" tick (afaik). The render functions calls "prerender" before it calls the rest of "render".
Render will only run if the element is enabled, the element is visible, and the element is "really" visible (eg. not obstructed by the parent, like in a tab)
Update will run as long as the element is enabled, even if it is not visible.
YASSSS
how many ticks are in a second in game? Its different on the server vs client too right?
thats on the client for sure, I think its a lot less on the server
Been years since I looked & I can only remember Minecraft stuff.
The server doesn't need 60 since it only bounces client-authoritative zombies.
final float sqrt = Math.sqrt(2048.0f);
GL11.glScalef(-sqrt, sqrt, sqrt);
GL11.glMatrixMode(5888);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GL11.glTranslatef(n4, n5, n6);
GL11.glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
GL11.glRotated(Math.toDegrees((double)this.m_useAngle) + 45.0, 0.0, 1.0, 0.0);
GL11.glDepthRange(0.0, 1.0);
GL11.glDepthMask(this.bDepthMask);
}
So I just found this chunk in OpenGL "Charactermodelcamera.class"
Does anyone happen to know if this is a controller for the camera's rotation angle?
For what? 3D models?
For the game camera
The game camera statically points to the offset of the player in Iso coordinates..
I don't think it rotates in 3D space.
collision is handled partially server side, which is why I'm trying to figure out whats going on. Essentially I have the linear velocity of a vehicle and I think I need to divide it by ticks per second to get how far it moved since the last tick
hmmm.... Do you know a location of a possible controller .class file? I've been looking for a while and haven't found anything super close
This is the closest I've found but IDK just how related this is since there's like 50 different .class files of similar contents
(isocamera.class)
Not sure what you're trying to locate and modify.
Rotate the camera for what? The world?
I'm trying to add a rotation to the camera
I know that the SpriteRenderer does a batched render of OpenGL commands.
Maybe look into that and how that is set up with the camera?
I've yet to try to rotate the camera.
I'm working on adding a rotation/ Yaw adjustment before I continue making 3d models of all the objects and tiles
You wish to modify the game to render the game in 3D?
The game is technically already in 3d, There's just a good chunk of things that are in 2D that would need to be remade so they can be viewed differently
A lot of work to do for certain.. I had this view as well.
Yeah this game would benefit from being completely brought over to 3D.
I'm hoping to get something similar to Don't Starve
Not everything needs to be made 3D. Trees and foliage can just be cutouts to face the player
Fun. I'm working on a Java-mod that provides immersion modding utilities for themes like Don't Starve right now.
Like a GLSL uniform modifier API.
It's already in working order. =3
That would be super useful. I'm used to modding Unity so I'm in new territory RN
wasn't somebody already doing this? wonder how that's going
The 2nd picture is a GLSL live test of modifying the shader for the panic moodle.
The screen pulses and aberrates when max panic.
I wrote a sub-sound engine that sends live sound data as API that I connect to the GLSL API.
Sure.
🤔
Core mod?
Item with spritesheet that updates frames?
Pseudo vehicle with a dog model?
just a IsoPlayer with clothing lol
Nice. Now make AI for it hijacking the multiplayer protocol.
This was also a project I sort of tried back in the mid 2010's. 🙂
(MisterInsayne's model that I rigged in Blender)
But seriously, good freaking job @ruby urchin . Can't wait to see what you'd do in B42.
This is actually kinda cool
If you can get a fake player AI for dogs in B41, it'll catch on like fire.
This isn't as impressive, but I've managed to fix my highspeed collision detection
Nice.
I think thats the last case I have to handle, so over christmas holidays I should hopefully have time to button up my vehicle damage events mod. I want to add features like being able to tell which zombie is attacking your vehicle at any given moment, but I can add that stuff later
anyone know where itemcontainers are set?
anyone? the freezer version worked great. the fridge one not so much.
scarier than the zombies 
Holy SHIT this is incredible
I bet TIS is adding this if not they should
Now throw this on top of superb survivors and you have something.
Does anyone know how the game draws those green prompts near car doors that tell you which door you're about to enter?
Also, random different question... Is it possible to recompile Java classes and throw them in your mods folder beside media in the zombie folder where they belong and thus publish Zomboid mods via Steam that include Java code modding? If this is possible, would you be able to independently recompile the Java file somehow, or would it be necessary to recompile the full library of functions because of how Java works?
anyone got a idea what kind of gloves I can add
basically I wanted to add some new gloves to the game
and kinda ran out of ideas
Wolverine gauntlets
and so far I got:
Working gloves
Black Latex gloves used by the police in my country
and sniper gloves
idk more looking for a clothing
yes
How about a pair of gloves that just looks like you wear brass knuckles all day
idk seem like a better weapon idea
No punching yet afaik
But it would put some pressure on somebody to add it lol
To make the knuckles more valuable
And would be an essential component of brass knuckles once punching IS added
I think thats a bit over what I can
Mittens?
hoofs
Muppets
xD
the fallout terminal, WIP

Yo, I can't just put stuf like
local modData = getPlayer():getModData().DynamicTraitsWorld;
at the start of my lua file cuz it'll throw error on load since there's no player yet, right?
From testing confirmed I assumed correct

You can put local data on top and the add a table to it later
still having issues with this, any ideas?
why the hell would this throw error
-- this line is in function, player is getPlayer()
applyXPBoost(player, Perks.Electricity, 1);
--
local function applyXPBoost(player, perk, boostLevel)
local newBoost = player:getXp():getPerkBoost(perk) + boostLevel;
if newBoost > 3 then
player:getXp():setPerkBoost(perk, 3);
else
player:getXp():setPerkBoost(perk, newBoost);
end
end
it's literally same code I used in my other mod and there it works
function: traitsGainsBySkill -- file: DTWBySkills.lua line # 149 | MOD: Dynamic Traits World
Callframe at: se.krka.kahlua.integration.expose.MultiLuaJavaInvoker@51ae9641
function: onOptionMouseDown -- file: ISPlayerStatsUI.lua line # 635 | Vanilla
function: onMouseUp -- file: ISButton.lua line # 56 | Vanilla
oh wait im r-word
i put it under function where its called
it needs to be above

from messing with calories, maxweight is hardcoded

Is there something you're trying to do?
you can always change the display to your own number
I dont think weight has any bearing except for how quickly you burn calories
could make an extra variable called "ExtraWeight" that is maxweight + your additional.
I can't find any reference to createActivePart in Lua or Java, so it's kinda hard to give you any ideas without proper context
nah just general curiosity
Why does this reset the data when I call it OnCreatePlayer
player:getModData().KillCount = player:getModData().KillCount or {};
player:getModData().KillCount.WeaponCategory = player:getModData().WeaponCategory or {};
player:getModData().KillCount.WeaponCategory["Axe"] = player:getModData().KillCount.WeaponCategory["Axe"] or {count = 0, WeaponType = {}};
shouldn't it load Axe since its already there
it's ripped from the tsarlib. the freezer one works great (go download my icecream truck btw) the fridge one gives that error
how/when are you adding information to it?
Perhaps the issue is that it's not being added to correctly - I don't see an issue with this part
function CommonTemplates.createActivePart(part)
if not part:getLight() then
part:createSpotLight(1000, 1000, 0.001, 0, 100, 0)
end
end``` oh sumbitch. it;s just a LIGHT?
i couldn't find that dumb function lol i thought it was the item name that was the issue.
I'm not, other mod does. And in-game it displays proper counters and stuff
https://steamcommunity.com/sharedfiles/filedetails/?id=2553809727&searchtext=killcount
check screenshots
there's tab that gets updated
if weapon then
local weaponCategory = KillCountWeaponType.GetWeaponCategoryFromWeapon(weapon)
local weaponType = KillCountWeaponType.GetWeaponTypeFromWeapon(weapon)
if weaponType and weaponCategory then
if not wielderModData.KillCount.WeaponCategory then
wielderModData.KillCount.WeaponCategory = {}
end
if not wielderModData.KillCount.WeaponCategory[weaponCategory] then
wielderModData.KillCount.WeaponCategory[weaponCategory] = {count=0,WeaponType={}}
end
wielderModData.KillCount.WeaponCategory[weaponCategory].count = wielderModData.KillCount.WeaponCategory[weaponCategory].count + 1;
if not wielderModData.KillCount.WeaponCategory[weaponCategory].WeaponType[weaponType] then
wielderModData.KillCount.WeaponCategory[weaponCategory].WeaponType[weaponType] = 0
end
wielderModData.KillCount.WeaponCategory[weaponCategory].WeaponType[weaponType] = wielderModData.KillCount.WeaponCategory[weaponCategory].WeaponType[weaponType] + 1;
end
if KillCountWeaponType.Verbose and weaponType and weaponCategory then print ("KillCountWeaponType.addToKillCount "..tostring(weaponType or "nil").." "..tostring(wielderModData.KillCount.WeaponCategory[weaponCategory].WeaponType[weaponType] or "nil")..", "..tostring(weaponCategory or "nil").." "..tostring(wielderModData.KillCount.WeaponCategory[weaponCategory].count or "nil")) end
end
god this is disgusting to read
aka long lines, not the code itself

there' edited it a bit
ah im 
player:getModData().KillCount.WeaponCategory = player:getModData().WeaponCategory or {};```
okay so now all i gotta do is get my dumb garbage truck to sync and we are in bitness!
missed .KillCount in 2nd line
make sure you're using VSCode otherwise you're gonna have a rough time. Ctrl+Shift+F is your best friend
i am, but ctrl shift f is for notepad++ 😛 i'm not gonna have vs code search my entire mods folders.
doesn't have to search the whole mods folder, any dependencies you're using should be added to your workplace folder
notepad++ is an axe to VSCode's chainsaw
right click empty space in vs code folder view thingy -> add folder to workspace -> select mod folder you want to add
ez pz
you can also save the workspace config so that you don't have to redo that every time, along with a bunch of other workspace-specific settings n stuff
Yeah, I'd suggest making a few locals just for readability's sake lol
ye, had few but thought i fucked something up so rollbacked everything
lul
wasnt local fault
gonna remake it back to locals xd
Btw, if that kill counter is using drawText you could instead add a UI element (label even) and have the verbose stuff show on tooltip when you hover over it
does anyone know the name of the mod that allows you to open the sandbox menu during the game?
Change Sandbox Options
Eh, I'll leave it to that mod author
Already got stuff to work
And you know how it is, if it works - don't touch it
On one hand i want to move to Inteliji over weekend, on other hand i wanna finish my mod 
But then again there should be big mod update for Imperator Rome this weekend so idk when I'll ever do any of those things 
Is there an event for first time player is created? I need to update some moddata values if player starts with a trait, for example.
Crude way to do it would be creating bool in moddata and change it to true after it fires once on OnCreatePlayer
But I hoped there's more elegant solution
First time a player is created can be when your modData is initialized
Unless there's a scenario you have in mind? Like activating the mod I'm an ongoing save
stupid client commands.
sendClientCommand("GarbageTruck", "EmptyTrunk", {GTvehicle = vehicle});
should fire this right?
local Commands = {};
Commands.GarbageTruck = {};
Commands.GarbageTruck.EmptyTrunk = function(player, args)
print("it fired")
print(module)
local vehicle = args.GTvehicle
local TrashBox = vehicle:getPartById("TruckBed"):getItemContainer()
TrashBox:clear()
end
local onClientCommand = function(module, command, player, args)
if Commands[module] and Commands[module][command] then
Commands[module][command](player, args);
end
end
Events.OnClientCommand.Add(onClientCommand);
I initialize all my moddata OnCreatePlayer
So it fires every time player loads in
Afaik
if your mod is creating mod data anyway, just test for that
Wdym
if not player:getModData().KillCount then
-- trait stuff
end
-- make sure to do this before this part:
player:getModData().KillCount = player:getModData().KillCount or {}
Hm
I see
That wouldn't be pretty since i have separate Lua where I initialize all my moddata
Sadly
You can grab the first time it's initlized in onCreate
You aren't "initilizing" it everytime
I'll check that when back home, ty
That's what the 'or' is for
Yes, so you can just add another if at first to flag that it's the first time
Ye
Or change the current if
Smort smort
Out of curiosity, why do you need to know the first time?
I got a trait that you can earn/loose based on value on moddata that you increase by killing Z near you. And it decays over time. You earn it by reaching X on that value and you loose it by reaching X/2. So if someone would start with it, their X would be 0.
so just
if player:HasTrait('Trait') and not player:getModData().x then
player:getModData().x = 0
end
```?
sumbitch. it's not freezing again. ARGH

One-time use freezer 
it's caught the dumb.
Can I control the load order of files in my mod? I have HairAvatar.lua that depends on VisualAvatar.lua however the hair loads first. is there any problem using lua's require()? currently I'm just prefixing them with a/b but I was hoping for something better
you can just use require
Careful about renaming files if you've already uploaded them -- Steam doesn't remove files
ah okay, thanks!
that could be a problem, I've renamed and moved a lot of files to make it easier to maintain. so does steam just insert and replace?
Yeah pretty much. You'll need to place empty dummy files in place of the old stuff.
yeah that's what I was thinking, thanks!
Alternatively, you can release a whole new mod with a new ID, if you want to do a lot of file changing.
nah it's not that extensive I've basically just broke down a few larger files into smaller ones
it's pretty frustrating, one of my mods has entire structures of dummy files LOL
Can you target the media/lua folder with filewriting manually? Would it be possible to write Lua code to delete an old empty file?
i've come up with a couple ways to maybe get rid of them but i need to test them
that's one of them
I put a --TODO: Remove in a month -date
and when ever I notice the files again I'll do a sweep
A question more suited for someone else, but in theory this could work, if lua has access to the mod directory itself.
it does
A month seems a bit short to me. My setup on the desktop PC still has stuff from like June.
can you actually delete a file with the filewriter though?
i'm pretty sure all you can do is replace it with an empty file, which doesn't really help LOL
Perhaps not, but removing all contents in the file is just as well - it removes it from the mod itself.
It helps the moddev and keeps it clean for new installations 🙂
Now you just have one .lua file with a list of files to clean if they exist 😄
servers would get missing file errors though
Surely the server would run the same cleaner script, no?
but the idea here is to remove the files from the workshop upload and automatically empty old files if they exist, right?
Correct.
so:
if a player has an older version, their files don't exist on the server, and they won't be allowed to join
if the server has an older version, the client doesn't have files that exist on the server, and they won't be allowed to join
So you include a single lua script in the workshop upload, which is prefixed such that it runs before all your other scripts - and then deletes the things that has to be empty.
Ah, yeah, fair. I suppose in my head you always have the lua script checking disabled, because on my server that was the case, but that's... Not universally true.
i have a solution that i think would work a lot better, but i need to test it
Fingers crossed it works!
the basic concept is to move everything to a new mod folder that uses the same mod id, and include a blank mod.info in the old folder
since the old folder doesn't have a mod id it shouldn't get loaded ever and shouldn't cause any consistency errors
So essentially you'd end up with a version number on your directory, and ship some dummy-empty ones? Not a bad solution.
@finite radish can i bug ya?
Oh intriguing I've never tried
me and my friend are having difficulty loading maps onto our gportal is there anybody with experience in this
does anyone know of a way to keep a persistent variable that needs to be checked before global mod data loads? i thought about reading and writing a file but i only need a single bool... does anyone know a better way?
A bit scuffed, but you could make it a sandbox option as that should be available from the very start of the world.
actually this needs to run even before that, and it needs to be per-client
Thinking of handling withdrawing and depositing using a single slider
Not sure if I'm over thinking it
Total slider would be banked cash + wallet cash
default being inbetween (banked cash)
displays 0 / no changes
🤔
sqlite database
😎
think i'll just have to write a file - seems a little overcomplex but oh well
is I/O even exposed via Lua? I was under the assumption it wasn't, but I haven't checked
there's specific file writers and readers we can use
one for a mod's directory, one for the Zomboid/Lua/ folder, and... a writer for the sandbox folder, that doesn't have a matching reader, so we can't really use it for much
thanks my bad didnt see that channel
depends how much money you expect players to have really - a slider could be cumbersome with large amounts of money, but otherwise this sounds like a pretty clean way to go about it
yeah, I'm trying to debate on it
making an ATM UI would be neat and all, but it's not really intended for immersive gameplay lol
you sure? Adding ATM tiles that have to be powered to transfer money would be neat
project rp has an atm ui, sounds like it took them a while to get that working
nah was quite quick
really? i must've misremembered something
also what you talked about removing files wont work because of the checksum verification
it happens before anything is loaded at all
oh, it checksums the entire workshop item?
indeed it checksums all files
but surely it doesn't checksum workshop items that the server isn't using?
not that that really helps anything
what a pain...
best way to deal with it is really deleting all contents and leaving it there
could check if theres a way to tell it to unsub from mods and then resub
The way it was commissioned was to work alongside Shops and Traders as a 'faction banking' system so players could pool their money
Although I do agree having functional ATMs could be neat - idk if it would fit what they want
After I do my timed action on a building object my sprite goes invisible, anyone have an idea why that happens? The Object still exists, but the sprite is invisible.
that gets written to the log
are you changing the sprite with the timed action?
no, immediately after it's built it goes invisible.
the "ghost" is the correct sprite
and it flashes for a second and then evaporates
Hello, is there any mod existing wich i can repair my m16 without having another one? Cas it sucks when it is very high demaged and i cant use it
I think it has something to do with this portion of the Map Object, but when I set any part of these to line break it doesn't catch I'm not sure if it's not getting called correctly.
Check out Covins or Universal Gun repair
is it a custom sprite?
if not, there's a handful of vanilla sprites that are hardcoded to only exist in certain circumstances (trees being the first that come to mind, but there are others)
also, it looks like you're calling removeExistingLuaObject on the square itself which is probably not what you want to be doing, especially since within the same function you're operating on that object again
(when I say "that object" I mean the square, not the object that I assume you were trying to target)
I think this is for compatibility with the old way zomboid was doing it where they stored the object information on the square.
This sprite is the metal fire pit
there can only be one lua object per square
ah yeah I see, I just took a look at that function - it operates on the square, not removing the square itself
Yea, I know
I think those log lines are from this code.
isoObject:sendObjectChange('name')
isoObject:sendObjectChange('sprite')
isoObject:transmitModData()
end```
but I don't know what the 'sprite' is referencing
I don't need to change the sprite information, can I just take that out?
I actually don't need to change the name either, I just need the mod data to update
yeah you can just take it out
anyone knows wich lua file manages the inventory folders ?
i mean it's a whole system so several, but if you mean the UI in particular the most likely ones are ISInventoryPane and ISInventoryPage
Ty @finite radish
(also ISInventoryPaneContextMenu for right click actions, I believe)
chuck im gonna shoot you irl if you don't allow manual value entry. slider-only for complex numerical values is the work of satan
like have the slider too, cool, but i should also be able to manually change it

XD
Also, yeah probably need to add that
vanilla sliders have a click to slide increment as well as a shift click increment
in this case 0.01 and 0.5
true, which isn't as bad as "slider only" interfaces, but if I know for a fact that I want $350.00 even then I don't want to have to "feel around" on the slider for where 350 is, end up somewhere like $354.39, and then spam-click the arrows until I get the right value
fair
i honestly feel deep in my heart that any value that can't be represented without numbers shouldn't be a slider. hue, saturation, volume, etc... sure. but money? NAH MAN. NAHHHH

I'm gonna throw up man
phsyically nauseous looking at that
i can't even spell physically right
I thought it was kind of clever - especially the default being in the middle 😦
it's not so bad
I wonder if I can convert the display into an input that plays nice with the slider
just convert the entire game to be played with sliders. because why not. you've already committed the crimes, may as well go all the way
wanna eat an orange? gotta open the "Use Item" slider and slide it from 0.0000 to 1.0000
also, the only food item that spawns are sliders. as in, mini hamburgers
👍
we're gonna be rich
QTE sliders
like those games with button hold QTEs that reverse the events if you let go for some reason
you have to slide the slider at a certain speed for your attack to land
all the vehicle mechanics also run on sliders, so you need a slider for the gas, the brakes, and the steering. also one for horn activation and horn volume
(they can't be controlled with keyboard input either, so better be fast!)
also, having sliders for money creates an immersive experience as if shuffling your change around
🧠
i really don't miss that era of human life i'm gonna be honest
people only use cards now for a reason
i don't need to emulate the nightmare of awkwardly forking through a handful of dirty, ancient coins
i'm fully immersed without that
i just can't believe i'm in 1993 kentucky without awkwardly shuffling change

man i sure love being able to click a singular button to subtract a singular penny from my potentially 6+ digit money balance
i just wouldn't have six figures in my inventory
what kind of messed up economy is that
it's not much better even if you only had $20 in your inventory
there's still a hundred pennies in a dollar
at least the slider would be easier to get close to what you actually want, but still
pls no cancer ui
i'm still digging in but also trying to save some research time. am I able to add a custom item stat to any item? i'm working on diabetes dynamic trait mod where the goal is to add custom sugar stat values to most foods in game and utilize some checks to lipids and carbs to make some mix/max effect type of thing. noting up front that i am good with logic but literally newish to programming in general but not an idiot. i've been referencing many other instances of this type of usage across other mods to get an idea. but i haven't noticed an instance of someone adding custom stat values to items
you can - anyUnrecognisedParameter = value, in an item script will have every item of that type spawn with the mod data anyUnrecognisedParameter = value
i hope it goes well!

is it possible to debug server side lua?
Good afternoon.
fairly certain if you're in debug on a server, you get breakpoints for server executed code. it's been a while though and I could be misremembering tbh
pcall all the things.
debug in the client is clientside only, unfortunately
I mean if you want a UI yeah.
if you want breakpoints
I'm not able to figure out if my MO and Server system and Global Objects are even being called. There's no clear link between the Building Object and Client Side System/Object
You won't have the benefits of what the client-side gives however you can debug it just fine.
I'm still up against a wall with these sprites not showing up
and I don't understand why :/
fortune cookie says add more print
pretty much, ya
I managed to get my first working prototype last night of TS React & my mock HTML rendering engine for PZ UI.
/** @jsx PipeWrenchUI.createElement */
import * as Events from '@asledgehammer/pipewrench-events';
import { PipeWrenchUI, createUI } from '../../shared/pipewrench-ui/React';
Events.onMainMenuEnter.addListener(() => {
createUI(
<element
class="my-element"
style="top: 64px; left: 64px; width: 50%; height: 512px; background-color: #80ced6;"
></element>
);
});
-- DTWActionsOverride.lua
DTWActionsOverride = {};
function DTWActionsOverride.bodyworkEnthusiastCheck()
-- code
end
return DTWActionsOverride;
-- DTWBySkills.lua
local DTWActionsOverride = require "DTWActionsOverride";
local function abc()
-- code
DTWActionsOverride.bodyworkEnthusiastCheck();
end
java.lang.RuntimeException: attempted index: bodyworkEnthusiastCheck of non-table: null```
can sm1 help?
i did as someone showed in this channel
unless i missed something
is the directory correct? it should include all folders after server/client/shared
hey can we talk in dm i got an mod suggestion
Is the file for DTWActionsOverride called DTWActionsOverride? Is it in client, server, or shared?
e.g. shared/overrides/overrides.lua needs require 'overrides/overrides'
require points to a Lua file, not the name of the library.
It's in TimedActions.
Okay sure. I'll take a look in a couple minutes.
how does one include files other way around then? 
what do you mean?
like if i would want to include DTWByKills.lua in DTWActionsOverride.lua
Relative pathing?
require always searches from the start
and start is in?
so just require 'DTWByKills'
client, server, or shared.
all three are roots.
server-side doesn't load client however the client loads all three.
dont think that it'd matter for me but out of general curiosity does that mean that you can require lua from server folder?
only from files in the server folder, otherwise it hasn't been loaded yet
cheers
Actually there's technical ways you can however it wouldn't be wise if you're doing simple stuff.
Wouldn't make sense.
You might as well code modules in shared.
So I have this called on OnCreatePlayer
player:getModData().DynamicTraitsWorld = player:getModData().DynamicTraitsWorld or {};
local modData = player:getModData().DynamicTraitsWorld
modData.VehiclePartRepairs = modData.VehiclePartRepairs or 0;
why this throws nul error on repairs? I thought when I loaded player I either loaded existing modData or made the value 0?
local modData = player:getModData().DynamicTraitsWorld;
local repairs = modData.DynamicTraitsWorld.vehiclePartRepairs;
Hmm first I'd say you could clean this code up a fair bit. Cleaner code helps make your debugging much easier.
i mean i dont want to create local variable for thing that's called once
sure i can shorten player:getPerkLevel(Perks.MetalWelding) to local var called metalworking
but it's used once in whole function
Hmm ok. A suggestion.
Condition blocks that are this long smacks me in the head when reading. xD
check dm again
updated and yeeted all unneeded code
I don't think this works
modData.VehiclePartRepairs = modData.VehiclePartRepairs or 0;
Hey everyone I've just updated my mod after a while away and just wanted to say thank you to everyone in the channel for helping with all my questions!
I'm about to bullyping albion 
jkjk
can we talk in dm ideas of mods
looks fine to me, what isn't working?
throws nul at repairs
here
BRAH
small v
i hate my life
literally a typo mistake 
certified classic
still shouldn't throw an error unless you tried to do something with repairs, haha
it does cuz
local modData = player:getModData().DynamicTraitsWorld;
local repairs = modData.DynamicTraitsWorld.vehiclePartRepairs;
so
repairs = player:getModData().DynamicTraitsWorld.DynamicTraitsWorld.vehiclePartRepairs
i typed extra modID

ah, lol, ya that'll do it

ok i don't get, this exact code worked when i initially tested and now it doesn't and I really haven't changed anything.
local original_fix_perform = ISFixAction.perform;
function ISFixAction:perform()
local player = self.character;
local modData = player:getModData().DynamicTraitsWorld;
local vehiclePartCondition = 0;
if self.vehiclePart then
vehiclePartCondition = self.vehiclePart:getCondition();
end
original_fix_perform(self);
end
throws error inside if loop. I looked at game ISFixAction and it uses similar if, from my understanding it should update vehiclePartCondition with condition of the part that's being repaired in case its a vehicle part? And it literally worked before, the onlything that changed is that I made this lua required in other place, but I don't see how it would break it. Or can it?
For reference this is base game isfix
on other hand it does also use condition = self.item:getCondition()
but then why it worked before? i don't get it
java.lang.RuntimeException: __add not defined for operands in perform
I'm not even adding anything???
@finite radish
daymn
pretty happy with it
ye, looks sick
going to rework the split/withdraw in shops
Anyone knows how to make "isEquipped()" work with a if?
its a boolean it checks if the item is equipped but also for some weird reason interfaces has it too
if item:isEquipped() then
Are luas ran in alphabetical order? So if I have 2 luas that both have OnCreatePlayer event, they will go off in file alphabetical order?
that's right
its just for items
events fire in the order they were added
you can require the file you want to run first in the file you want to run later to force it to run first
ye just require
require "DTWModData" is enough right?
yeah
cheers
I was like "why does this moodle isnt showing up"
ah right
cuz it uses data thats initialized later

i made a habit of deleting all the old ones
I will
when im done with the mod
cuz i dont wanna do it in PZ
i'll jsut yeet folders from wherever saves are
cuz deleteing them 1by1 is pain
phew
part 1 of mod done
now part 2
part one was taking perks from non-maintained mod and rewriting them from the ground

Dynamic traits isn't maintained?
not that
Simple Traits or something
dont rememebr
last update like a year ago and code in some places was a mess
More Traits doing fine

140 sandbox options will haunt me forever

if I add recipes to playerRecipes and it's already there, is it fine or do i need to check if it's already known?
to player:getKnownRecipes() that is
I think you need to check first - atleast based on vanilla code they use isknown first

got a santa event while testing
._.
dudes unloading
guess that holiday date code works

weird, using the confirm button doesn't update the window :\
where can i find base game icons for traits?
ui/traits has like 5 pngs
I'm bout to get big mad, there are literally no trait icons in game folders
they're in texture packs
i forget what the tool to extract them is called, but they're all in profession framework anyway

Guess off I go downloading from wiki
Can't seem to overwrite base game traits
so im just disabling them and adding edited copy 
wait actually that'd be a bad idea to do that
cuz if other mods use base game traits for their stuff it'd fuck them up
Ok, new question
I can't seem to overwrite base game traits. I only need to change displayed name but if I do, description disappears and it refuses to even show perk gains when u hover over perk. For example,
I can overwrite the name, and i don't change anything else but it refuses to show original description
or ANY description, at that point
even if I make an entry in UI_EN
UI_trait_FirstAidDesc = "test",
ok nevermind i can load in my own desc
and technically as long as I don't change 1st param in traitfactory i can overwrite the traits with my own descriptions and expect it to work with mods that rely on using those perks

steam://openurl/https://steamcommunity.com/sharedfiles/filedetails/?id=2905858716
the container is done except for the ability to break into them .. will include on future update
Workshop ID: 2905858716
Mod ID: SafeCrackerMod
just sharing
thnx for all of those who supported =p
Nice work!
Can someone help me understand why the verbose call on my expanded table viewing function gets caught in an apparently infinite loop and triggers a stack overflow? I am just not seeing it.
BS.reveal = function(someTable, verbose, prefix)
if not (someTable and type(someTable) == "table") then return "" end
if not prefix then prefix = "" end
local result = ""
for key, value in pairs(someTable) do
result = result .. tostring(key) .. "\n"
if verbose then
local subresult = BS.reveal(value, verbose, prefix .. " ")
if subresult then result = result .. "\n" .. subresult end
end
end
if prefix == "" then
Clipboard.setClipboard(result)
print(result)
end
return result
end
ngl I think you could use a while loop here instead of recursion?
Are you trying to print a tables contents?
Yeah just print each table element of a given table the same way I print the first level of the table @sour island
Feel free to share a while loop solution... recursion feels like a natural way to solve this kind of problem, but I am clearly misunderstanding something crucial going on in this recursive loop
Currently just trying to get this right rather than start from scratch
function _internal.tableToString(object,nesting)
nesting = nesting or 0
local text = ""..string.rep(" ", nesting)
if type(object) == 'table' then
local s = "{\n"
for k,v in pairs(object) do
s = s..string.rep(" ", nesting+1).."\[\""..k.."\"\] = ".._internal.tableToString(v,nesting+1)..",\n"
end
text = s..string.rep(" ", nesting).."}"
else
if type(object) == "string" then text = "\""..tostring(object).."\""
else text = tostring(object)
end
end
return text
end
function _internal.stringToTable(inputstr)
local tblTbl = loadstring("return "..inputstr)()
return tblTbl
end
prints it in lua format
for reloading purposes
Not sure if you want to keep a specific format - but I've written something like this 3 times - so I know the pain
I fucking hate that pz devs made trait called "Angler" but gave it internal handler "Fishing"
makes my code ugly and inconsistent

Wait till you see the traits with typos

jokes aside, not changing names for aesthetics probably benefits not breaking something and going on an expedition
- all our mods still work months later cause the devs seem to take extra care not to shift too much around
I'm getting the same kind of errors...
yeah, making changes like that when you really don't need to is inadvisable
I copypasted what you sent, literally ONLY changed the name of the container object from _internal to an existing table in my mods (BS)
That's not possible unless something else is going on
breaking everything that uses a function is worse than a function having an annoying typo
function BS.tableToString(object,nesting)
nesting = nesting or 0
local text = ""..string.rep(" ", nesting)
if type(object) == 'table' then
local s = "{\n"
for k,v in pairs(object) do
s = s..string.rep(" ", nesting+1).."\[\""..k.."\"\] = "..BS.tableToString(v,nesting+1)..",\n"
end
text = s..string.rep(" ", nesting).."}"
else
if type(object) == "string" then text = "\""..tostring(object).."\""
else text = tostring(object)
end
end
return text
end
function BS.stringToTable(inputstr)
local tblTbl = loadstring("return "..inputstr)()
return tblTbl
end
what is the table you're tying to print?
Pasted this in terminal... called BS.tableToString(Jumper, 0) on the main table of my Jumper mod
My function can print the first level of Jumper just fine, but breaks the way my copypaste of your function breaks when I try to use it recursively
no need to have ,0
your table doesn't refer to itself, does it?
but what does Jumper look like?
A table of functions and tables, generally.
and some variables
Uhhh howso?
You mean do I somewhere say Jumper.whatAmIEvenDoing = Jumper?
If so, absolutely not.
Hmm I just don't see how but fair enough
under locals
anywhere where there is a circular reference of tables containing each other
is key = jumper?
Under locals? I don't understand
I wonder how I can change my code to identify recursive tables
yea i won't, just pains me greatly
in f11 where it says locals at the top - you can click for more info
it's not clear sometimes but it should have a break down
To my knowledge none of my tables do this but I see what you're saying and I will try to think of a way to circumvent circular references in my loop.
I mean I guess it's the likeliest explanation that something obscure like this is happening
If the code looks like it would work for non-circular tables.
I can modify my code to print out circular references
Where does it say "Locals"?
Yeah I was thinking I could add a table of found locations and skip processed tables in my loop.
Oh crap
would be beneficial to know where it's triggering
how would I make a test mod that I can just play around with? I tried copying (in workshop/content/108600) a pre-existing mod and changing the name & ID but it doesn't show up. Do I have to publish something as a workshop mod first?
function _internal.tableToString(object,nesting,tblLog)
nesting = nesting or 0
tblLog = tblLog or {}
local text = ""..string.rep(" ", nesting)
if type(object) == 'table' and not tblLog[object] then
tblLog[object] = true
local s = "{\n"
for k,v in pairs(object) do
s = s..string.rep(" ", nesting+1).."\[\""..k.."\"\] = ".._internal.tableToString(v,nesting+1,tblLog)..",\n"
end
text = s..string.rep(" ", nesting).."}"
else
if type(object) == "string" then text = "\""..tostring(object).."\""
else text = tostring(object)
end
end
return text
end
tested and works 👍
recursive tables will be printed as a string instead
I figured a part of your table might reference another part as well
@thick karma Here's my while loop solution
if not (someTable and type(someTable) == "table") then return "" end
local queue = {
{table = someTable, indent = ""}
}
local finished = {}
local result = ""
while #queue ~= 0 do
local t = table.remove(queue, 1)
local found = false
for t2 in pairs(finished) do
if t.table == t2 then
found == true
end
end
if not found then
table.insert(finished, t.table)
for k,v in pairs(t.table) do
result = result .. t.indent .. tostring(k) .. "\n"
if verbose and type(v) == "table" then
table.insert(queue, {table = v, indent = t.indent .. " "})
end
end
end
end
return result
end```
You don't need to publish it. Has to be in one of the local mod folders though - I'm not sure if workshop/content counts as one - but you can use the folders in user/name/Zomboid
I seeeee, that does make sense, nice
alright. Thank you!
np - the folders there are mods/ or Workshop/
they follow different folder structure - but there's a template mod in Workshop
I obviously haven't tested it in your use case but it should work, I didn't really get the purpose of the if prefix == "" check at the end though? so I it doesn't anything rn
Because in the recursive version I only want to copy final string to clipboard if it's the parent-level finished string.
There would be countless other substrings passing that point that would not be finalized and no point in sending to clipboard
ahh got it, you can get rid of that check then
Irrelevant to while solution.
Yours wouldn't need something like that.
Yeah
lmao in my quest to make this gd function work I've gone from throwing exceptions to outright crashing the game
Nice.
I'm good at this.
lmao @sour island gonna try what you sent soon
I tried this and crashed (or possibly got impatient and killed Zomboid but I'm pretty sure it was going to crash):
BS.reveal = function(someTable, verbose, prefix, found)
if not (someTable and type(someTable) == "table") then return "" end
found = found or {}
prefix = prefix or ""
found[someTable] = true
local result = ""
for key, value in pairs(someTable) do
result = result .. tostring(key) .. "\n"
if verbose and not found[value] then
local subresult = BS.reveal(value, verbose, prefix .. " ", found)
if subresult then result = result .. "\n" .. subresult end
end
end
if prefix == "" then
Clipboard.setClipboard(result)
print(result)
end
return result
end
if you have a recursive reference it's going to break - unless the code prevents it
I tried to by preventing the verbose descent when found[value] == true but no dice
you have to avoid passing sometable I imagine
the verbose thing is throwing me off a bit
verbose is a table right?
verbose is a boolean
Oh here if not (someTable and type(someTable) == "table") then return "" end
add the found[someTable] here
If it's not in verbose mode it doesn't recurse
Tried this:
BS.reveal = function(someTable, verbose, prefix, found)
if not (someTable and type(someTable) == "table") then return "" end
found = found or {}
if found[someTable] then return "" else found[someTable] = true end
prefix = prefix or ""
local result = ""
for key, value in pairs(someTable) do
result = result .. tostring(key) .. "\n"
if verbose then
local subresult = BS.reveal(value, verbose, prefix .. " ", found)
if subresult then result = result .. "\n" .. subresult end
end
end
if prefix == "" then
Clipboard.setClipboard(result)
print(result)
end
return result
end
Still crashed
Gah just realized I returned nil and need to return ""
But no exception, just crash?
I notice you do a max degree of nesting... is that required? Could you loop to the maximum possible depth? Or does that conversion lead to issues?
So I could just say nesting level 33094 and your function would be cool with that
for indentation purposes mostly
yes
TraitFactory.addTrait("Graceful", getText("UI_trait_graceful"), 4, getText("UI_trait_gracefuldesc"), false);
why is name from capital and in UI it's not

yes, rep = repeat
Works with pz ? Or just lua in general
Translate file
This is https://www.lua.org/cgi-bin/demo
yes i know how it works, im saying its inconsistent as fuck
some traits start from capital letter and inside UI string its also capital
some other way around
some both from capital
👌
if i make function that takes 5 arguments, can I call it like this to skip arg 3 and 4 for example, func(a, b, nil, nil, e)?
yes
are nil needed or can i just leve empty space and it passes nil by default?
not declaring arguments also = nil
yep
lol led to crash when I ran it on Jumper
it needs nil inbetween
wdym inbetween
Then the crash isn't related to recursive references
Intriguing
fun(arg1,,,arg4) = no go
yes
Yep
gotcha
will this work?
local function createTrait(name, cost, forcedName, forcedUI, isProfExclusive, isDisabled)
isProfExclusive = isProfExclusive or false;
isDisabled = isDisabled or false;
if forcedName or forcedUI then
name = forcedName or name;
local UI = forcedUI or name;```
so it uses forced name if its present
and if not, just name
what are you trying to avoid/do?
Im marking all traits that can be dynamically obtained with D
if submod is present
yes but your if chain troubles me
@sour island Okay when I added a depth feature and used it to limit my depth, it did not crash 2 levels deep
why
Idk, I'm just being nitpicky

I don't like seeing copy pasted code
as small as it is - it's nice to be able to change 1 line and have it change everything else
But hey now I have to account all the fucking inconsistencies in base game
mod
options
soundEnabled
animationEnabled
showGroupJumpOptions
neverForgetWhereYouComeFrom
showRecentlyVisitedLocations
groupJumpingHasPriority
onlyBringFactionMembers
singleMenuMode
names
soundEnabled
animationEnabled
showGroupJumpOptions
neverForgetWhereYouComeFrom
showRecentlyVisitedLocations
groupJumpingHasPriority
onlyBringFactionMembers
singleMenuMode
mod_id
mod_shortname
. . .
it's an issue of maintainability, i would recommend cleaning it up
Clearly I was not terminating the recursion somehow
Or at least... not for a long time
Idk
I'm open to advice on ways to do that
Could just be a really large table - what is Jumper?
the only difference is in one place you swap ui for name right?
A really large table lol
Post the code here a second
local function createTrait(name, cost, forcedName, forcedUI, isProfExclusive, isDisabled)
isProfExclusive = isProfExclusive or false;
isDisabled = isDisabled or false;
if forcedName or forcedUI then
name = forcedName or name;
local UI = forcedUI or name;
if getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") then
return TraitFactory.addTrait(name, getText("UI_trait_" .. name .. "Marked"), cost, getText("UI_trait_" .. UI .."Desc"), isProfExclusive, isDisabled);
else
return TraitFactory.addTrait(name, getText("UI_trait_" .. name), cost, getText("UI_trait_" .. UI .."Desc"), isProfExclusive, isDisabled);
end
else
if getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") then
return TraitFactory.addTrait(name, getText("UI_trait_" .. name .. "Marked"), cost, getText("UI_trait_" .. name .."Desc"), isProfExclusive, isDisabled);
else
return TraitFactory.addTrait(name, getText("UI_trait_" .. name), cost, getText("UI_trait_" .. name .."Desc"), isProfExclusive, isDisabled);
end
end
end```
yea, also use forcename instead of name if its present
cuz you see, for mod traits i can make stuff consistent but for base game i have to catch stuff like that so my name overwrite works with other mods
@sour island Increasing max depth to 10 led to lock up and crash
local function createTrait(name, cost, isProfExclusive, isDisabled)
isProfExclusive = isProfExclusive or false;
isDisabled = isDisabled or false;
local marked = (getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") and "Marked") or ""
local fetchedName = getTextOrNull("UI_trait_"..string.lower(name)..marked) or getTextOrNull("UI_trait_"..name:gsub("^%l", string.upper)..marked)
local fetchedDesc = getTextOrNull("UI_trait_"..string.lower(name).."Desc") or getTextOrNull("UI_trait_"..name:gsub("^%l", string.upper).."Desc")
return TraitFactory.addTrait(name, fetchedName, cost, fetchedDesc, isProfExclusive, isDisabled);
end```

not sure about the name handling
It may be shorter but it for sure aint more understandable
but this will grab something if its all lowercase or capitalized
but that's the thing
Some base game traits use capitalized in both name and UI
Some have just name capitalized
ok lemme try
local function createTrait(name, cost, forcedName, forcedUI, isProfExclusive, isDisabled)
isProfExclusive = isProfExclusive or false;
isDisabled = isDisabled or false;
local UI = forcedUI or name
name = forcedName or name
if getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") then
name = name .. 'Marked'
end
local desc = getTextOrNull("UI_trait_"..UI.."Desc") or getText("UI_trait_"..UI.."desc")
return TraitFactory.addTrait(name, getText("UI_trait_"..name), cost, desc, isProfExclusive, isDisabled);
end
TraitFactory.addTrait("Graceful", getText("UI_trait_graceful"), 4, getText("UI_trait_gracefuldesc"), false);
TraitFactory.addTrait("SpeedDemon", getText("UI_trait_SpeedDemon"), 1, getText("UI_trait_SpeedDemonDesc"), false);```
^ both base game perks
for example
albion way seem more readable 
it won't handle those annoying capitalisation variances unfortunately
updated mine
local marked = (getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") and "Marked")
returns "Marked" if the first thing is true
if it'll work I'll bully you for detailed explanation how it works
something like that might work
@sour island I am safely at depth 7 and seeing crap like this:
------------children
--------------3524
--------------3525
--------------3526
--------------3527
--------------3528
--------------3529
--------------3530
--------------3531
--------------3532
--------------3533
--------------3534
--------------3535
--------------3536
--------------3537
getTextOrNull returns null if the getText can't be processed - getText() returns the original text back to you
14 dashes = 7 layers deep into Jumper
same logic, if the first thing is false/nil it goes to the next after or
Jumper is that table of tiles right?
No a table of functions, variables, and tables. It's essentially a class
you can even use all caps as the argument for name
shouldn't matter

PS, 8 levels deep is where things broke for my function. Just crashed at 8 deep
Yeah may be
I can't test it as is, but I may have a typo
Oh well, that's life, I will just cap the depth at what appears to be safe.
you have
local function createTrait(name, cost, isProfExclusive, isDisabled)
isProfExclusive = isProfExclusive or false;
isDisabled = isDisabled or false;
local marked = (getActivatedMods():contains("DynamicTraitsWorldMarkDynamicTraits") and "Marked") or ""
local fetchedName = getTextOrNull("UI_trait_"..string.lower(name)..marked) or getTextOrNull("UI_trait_"..name:gsub("^%l", string.upper)..marked)
local fetchedDesc = getTextOrNull("UI_trait_"..string.lower(name).."Desc") or getTextOrNull("UI_trait_"..name:gsub("^%l", string.upper).."Desc")
return TraitFactory.addTrait(name, fetchedName, cost, fetchedDesc, isProfExclusive, isDisabled);
end
