#mod_development
1 messages ยท Page 259 of 1
I wonder
if all else fails, put a luarc in the lua dir and set like
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"diagnostics": {
"enable": false
}
}
or even then, in your main luarc you might be able to edit workspace.ignoreDir and add the ABSOLUTE path to your pz lua folder like C:/Program Files (x86)/Steam/steamapps/common/ProjectZomboid/media/lua/
tried this too
because tehre's no way in vscode to disable an extension for a workspace folder specifically, only per-workspace
jesus idk then

"Lua.workspace.ignoreDir": [
"lua",
".vscode"
],
"Lua.diagnostics.ignoredFiles": "Disable",
```works on my end
Am I doing something wrong?
its whatever
fuck it
I'll just have it in separate window
ah wait, apologies, it's a seperate folder "opened" into the workspace instead of added, didn't read fully...
in that case, it should work with a seperate .vscode folder and settings.json in said lua folder with "Lua.diagnostics.enable": false
Sorry ๐
(at least that, too, works on my end)
I'm just cursed, it's fine
did you give it time to refresh diagnostics? (It does it automatically upon saving said file on my end, did take a few seconds)
Yes, I reloaded the IDE
It doesnt show problems initially but as soon as I open any of my luas it fetches problems from whole workspace
Including things it's supposed to ignore
Aka folder excluded in like 5 places and set to not run diagnostics inside

It's whatever
I got another question tho, In IntelliJ setting up params for function works fine but in VSCode it complains about it 
Umbrella on both sides
Do you use a different lua extension? ๐ค Those "complaints" look strange to me ๐
was umbrella definitely enabled for this workspace? you need to enable it in each one if you aren't aware
SumnekoLua on both
without umbrella enabled, my "complaints" look like this:
And yes umbrella is on, just re-enabled it to make sure
got the same without umbrella
- same warn on top

I see stuff like LuaHelper andSpell on your bottom right.
Could those complaints be from that helper thing?
Oh ffs why is that enabled
Your usual stupid 
wait because of that it was probably fucking up my problems

Guess your issues are solved. For now 
Only costed me half of my sanity and unnessesary bothering of good ppl in here 
Eh, it happens. ๐ซ Don't worry too much!
will add folder back to workspace and see if i can make it ignored
Guess I'm VSCode PZ user now
Been using it for Escape for Tarkov mods before 
@ancient grail was able to figure how to make it check only clothes that CAN have blood
---Function responsible for checking % of bloodied clothes
---@param player IsoPlayer
---@return number -- percentage of bloodied clothes (0-1)
local function bloodiedClothesLevel(player)
local wornItems = player:getWornItems();
local totalBloodLevelPercentage = 0;
local amountOfWornItems = 0;
if wornItems ~= nil and wornItems:size() > 1 then
for i = 0, wornItems:size() - 1, 1 do
local item = wornItems:getItemByIndex(i);
if instanceof(item, "Clothing") then
---@cast item Clothing
if item:getBloodClothingType() ~= nil then
local bloodLevel = item:getBloodLevel() or 0;
amountOfWornItems = amountOfWornItems + 1;
totalBloodLevelPercentage = totalBloodLevelPercentage + bloodLevel;
if detailedDebug() then print("Clothing: "..item:getClothingItemName().. " | blood level: "..bloodLevel) end;
end
end
end
local avg = totalBloodLevelPercentage / 100 / amountOfWornItems;
if detailedDebug() then print("avg: "..avg) end;
return avg;
end
return 0;
end
Confirmed that it skips belt and underwear and stuff cuz item:getBloodClothingType() returns array of locations where blood is
nice work bro
can* have blood
LOG : General , 1725117764524> nil
LOG : General , 1725117764524> nil
LOG : General , 1725117764524> [ShirtLongSleeves]
LOG : General , 1725117764525> Clothing: Tshirt_WhiteLongSleeveTINT | blood level: 4.313725471496582
LOG : General , 1725117764525> nil
LOG : General , 1725117764525> [Shoes, LowerLegs]
LOG : General , 1725117764526> Clothing: Socks_Long | blood level: 0
LOG : General , 1725117764526> [Trousers]
LOG : General , 1725117764526> Clothing: Trousers_DefaultTEXTURE_TINT | blood level: 4.86274528503418
LOG : General , 1725117764526> [Shoes]
LOG : General , 1725117764527> Clothing: Shoes_TrainerTINT | blood level: 3.1372551918029785
LOG : General , 1725117764527> avg: 0.03078431487083435```
this was print where I was printing return of `item:getBloodClothingType()` first

meanwhile im figuring out how to improve my tank zed mod
cuz i dont want them to bite players
so i set noTeeth
but that makes me not damage players
so i made my own damage functions
but im worried it might not be balanced
right so why did you need the blood anyways
for dynamic trait
easier to earn/harder to lose if bloodied
if bloodlustModData.BloodlustMeter >= 18 then -- gain if above 50%
local bloodLustProgressIncrease = bloodlustModData.BloodlustMeter * 0.1 * (1 + bloodiedClothesLevel(player)) * ((SBvars.AffinitySystem and modData.StartingTraits.Bloodlust) and SBvars.AffinitySystemGainMultiplier or 1);
bloodlustModData.BloodlustProgress = math.min(SBvars.BloodlustProgress * 2, bloodlustModData.BloodlustProgress + bloodLustProgressIncrease);
if debug() then print("ETW Logger | bloodlustTimeETW(): BloodlustMeter is above 50%, BloodlustProgress =".. bloodlustModData.BloodlustProgress) end
else -- lose if below 50%
local bloodLustProgressDecrease = bloodlustModData.BloodlustMeter * 0.1 * (1 - bloodiedClothesLevel(player)) / ((SBvars.AffinitySystem and modData.StartingTraits.Bloodlust) and SBvars.AffinitySystemLoseDivider or 1);
bloodlustModData.BloodlustProgress = math.max(0, bloodlustModData.BloodlustProgress - (3.6 - bloodLustProgressDecrease));
if debug() then print("ETW Logger | bloodlustTimeETW(): BloodlustMeter is below 50%, BloodlustProgress =".. bloodlustModData.BloodlustProgress) end
end```
oh so being bloody is a booster
nice

ive recently added a new ways to use boolean for player datas
i add temporary trait
its cuz im not familiar with moodles just yet
Moodle framework is goated
@bronze yoke @grizzled fulcrum Please explain, am I misunderstanding something or is the helicopter sound also coded so much that it is impossible to know whether it is currently playing?
the trait idea is good cuz they can see it
but moodles should be better
ye you cant fetch whats playing
you have to check if its playing
i used a table to check of zeds are playing sounds listed on a table
then stop it
thats what i did inorder to replace em
can you pls explain in more detail?
check out goose zed mod
took me a bit of digging on figuring how moodles framework work but they are pretty cool.
https://github.com/MusicManiac/EvolvingTraitsWorld/blob/main/Contents/mods/Evolving Traits World/media/lua/client/ETWMoodles.lua
- there's tutorial on workshop but I remember having to DM the guy with few questions

do you mean this function?
don't use ipairs btw, unrelated tip not related to your issue
for i, v in ipairs(tbl) do
end
-- is equivalent to
for i = 1, #tbl do
v = tbl[i]
end
it is faster to do the bottom one than the top one
wait nvm that's not even your code ๐ญ๐ญ๐ญ
The goose zed mod code you screenshotted is using zombie's sound emitter to check if the emitter is playing the sound
Since I don't think there is a global sound emitter object for stuff like helicopter sound, you should just be able to call it the way the vanilla games does
which you do that but it is retuning nil?
what does it print when you execute that code?
@grizzled fulcrum
Heli.getHelicopter = function (x,y,z,radius,volume,soundSource)
print(soundSource)
end
Events.OnWorldSound.Add(Heli.getHelicopter)
print's nil
maybe can do something with SoundManager (unlikely) or getWorld():getFreeEmitter()
I think its possible GameSounds isn't exposed
try like
local emt = getWorld():getFreeEmitter()
if emt:isPlaying("helicopter something cool") then
-- do stuff
end
well replace it with the proper string "Helicopter" lol
not working
rip idk then
Thanks for your time
sorry if this is a dumb question, but what does the rolls variable actually do in loot distribution tables? i can't find much documentation on it so i thought i'd ask here - i found a forum post about loot distribution tables and it said it used "complex magic"... so any kind of explanation would be appreciated
i'd rather not look through the source code if i don't have to
yep
slr
there are extra entries that doesnt even get triggered btw
i didnt filter it neatly
do you know how else to get the helicopter object or the helicopter event start time?
Events.OnWorldSoun also works btw
i havent checked it let me see if i can dig up something
audio is weird
they have lots of functions for it
but doesnt even have the get functions that lets you know whats being played
public class Helicopter {
private static float MAX_BOTHER_SECONDS = 60.0F;
private static float MAX_UNSEEN_SECONDS = 15.0F;
private static int RADIUS_HOVER = 50;
private static int RADIUS_SEARCH = 100;
protected Helicopter.State state;
public IsoGameCharacter target;
protected float timeSinceChopperSawPlayer;
protected float hoverTime;
protected float searchTime;
public float x;
public float y;
protected float targetX;
protected float targetY;
protected Vector2 move = new Vector2();
protected boolean bActive;
protected static long inst;
protected static FMOD_STUDIO_EVENT_DESCRIPTION event;
protected boolean bSoundStarted;
protected float volume;
protected float occlusion;
public void pickRandomTarget() {
ArrayList var1;
if (GameServer.bServer) {
var1 = GameServer.getPlayers();
} else {
if (GameClient.bClient) {
throw new IllegalStateException("can't call this on the client");
}
var1 = new ArrayList();
for(int var2 = 0; var2 < IsoPlayer.numPlayers; ++var2) {
IsoPlayer var3 = IsoPlayer.players[var2];
if (var3 != null && var3.isAlive()) {
var1.add(var3);
}
}
}
if (var1.isEmpty()) {
this.bActive = false;
this.target = null;
} else {
this.setTarget((IsoGameCharacter)var1.get(Rand.Next(var1.size())));
}
}
public void setTarget(IsoGameCharacter var1) {
this.target = var1;
this.x = this.target.x + 1000.0F;
this.y = this.target.y + 1000.0F;
this.targetX = this.target.x;
this.targetY = this.target.y;
this.move.x = this.targetX - this.x;
this.move.y = this.targetY - this.y;
this.move.normalize();
this.move.setLength(0.5F);
this.state = Helicopter.State.Arriving;
this.bActive = true;
DebugLog.log("chopper: activated");
}
protected void changeState(Helicopter.State var1) {
DebugLog.log("chopper: state " + this.state + " -> " + var1);
this.state = var1;
}
have you seen this
theres a volume
it says protected
Got it, do you have any other ideas on how to find out if there is a helicopter event at the moment?
Hello ! im developing a mod that adds Server wide factions ( so player can join faction on character creation ) . They way im using to achieve this is by adding a trait and checking for trait on game start then adding player to faction based on the custom trait .
How could i implement custom spawn locations for each faction/trait ?
thanks in advance ! :3
this is the code im using to add player to faction :
-- Function to determine the faction based on player's traits
local function getFactionName(playerObj)
if playerObj:HasTrait("factionnomad") then
return "Nomads"
elseif playerObj:HasTrait("factionbandit") then
return "Bandits"
elseif playerObj:HasTrait("factionarmy") then
return "Army"
end
return nil
end
-- Function to add the player to a faction
local function addPlayerToFaction(playerObj)
local factionName = getFactionName(playerObj)
if not factionName then
return -- Exit if the player doesn't belong to any faction
end
local faction = Faction.getFaction(factionName)
-- If the faction doesn't exist, create it
if not faction then
faction = Faction.createFaction(factionName, playerObj:getUsername(), "Blue")
end
-- Add the player to the faction
if faction then
faction:addPlayer(playerObj:getUsername())
end
end
-- Event hook for when a new game starts
local function OnNewGame(playerObj, square)
addPlayerToFaction(playerObj)
end
-- Event hook for when the game starts (both new game and load game)
local function OnGameStart()
local playerObj = getSpecificPlayer(0)
if playerObj then
addPlayerToFaction(playerObj)
end
end
-- Register the events
Events.OnNewGame.Add(OnNewGame)
Events.OnGameStart.Add(OnGameStart)```
sorry bro
dont know much abt java side of things
Thanks for your time
i dont think you access the traits of other players if youre not admin or something like that... not 100% sure
you need to do client to server commands and stuff
it's just how many times each item in the table gets rolled for
sorry i dont think i understand clearly ( english is not my main language btw )...
im already adding new traits, checking for trait on game start and assinging player to faction based on selected trait
ahh you can have them join the factions automatically
and hook on the leave button so they cant disband
i think i kind of understand now, thanks
just from looking through some other mods
I'm making my first mod! as far i edited some mods but this is my first time doing it, i'm making a new female body inspired in my VRChat, it will include full body retexture (if possible) so any hand to help a newbie it's appreciated!
See my character from VRChat in #modeling
Hey all, I'm new to modding and have added an item, perk and recipe to my mod to keep it simple. However, none of them show up in game with the mod enabled. Any ideas why this could be?
you need to look at the pz syntax
I've been using the PZWiki and the PZ-Mod github tutorials, as well as looking at mods as a learning aid. This does seem to match exactly how I've seen it in the mod/tutorial, but there is actually a surprising lack of information for adding skills/perks. I'd appreciate a point in the right direction
i havent seen anything like this ngl
it looks like sandbox enum but the again its not
what are you trying to build
I get you. This is what I followed https://github.com/MrBounty/PZ-Mod---Doc/blob/main/Make a custom skill or perk.md
Currently I'm starting simple. I wanted to add a brick item, a recipe for the brick and a Brick laying skill. I followed the tutorial to add the recipe, item and skill. However, when I load the mod, none of them appear in the game. I can't figure out why and I don't get any errors
cool i didnt know thats how you add perk
and so now youre problem is that you cant see it?
but is it there?
Yeah. The mod is in my C:\Users\USER_NAME\Zomboid\mods folder. The new files are there in the correct structure and I can find and load the mod as normal. However, in the game, it's as if none of it exists
print(getPlayer():getPerkLevel(Perks.BrickLaying))
try that via debug
if it prints out something then it worked
yeah i believe you still need to do some stuff to actually have it shown via panels
Ah yeah it printed out level 0, so I guess it is in there. Must be a UI issue
but for now check if its there by printing that using debug console
try changing the name to something else thats not in the game
just to check
Is bricklaying in the game?
ah
if it errors then it means you successfully added custom perk
cuz pz sometimes is weird
for some reason
like earlier music maniac was looking for blood related clothing
but getBloodLevel() prints out 0
even if the clothing item cant possibly get bloodied
hmm no if I just use "x" it also says 0
so it means it doesnt matter if you have the file you added
anything you do will print out 0 as if it exists
thats funny
and yet useful info
That's strange, I'm a little surprised it would do that. I haven't changed much code, but maybe I messed something up
Is adding items as simple as just adding a items.txt with the items in the correct format. If so, then something is definitely wrong as even those don't show up
is this your first mod if ever?
if it is then i believe its not an easy one as a starting mod.
it will be better to start on easier to do stuff to get familiar with the syntax and all that..
yes
items are easiest imho
Yeah it's my first mod. I'm not sure how to do something much simpler than adding an item haha.
you can use already made assets and just change texture and stats to begin with
hmm thats worrying as it should just show up then, there must be something really wrong somewhere in my mod folder
but we all have different learning curves so what worked for me might not work for others and vice versa
tho thats how i started
lots of modders didnt do items first but ended up making complex mods
i dont think it will just show up tho i dont have experience making custom perk
i used moddata for stuff like these
but i find it useful that you can actually just call any string as perk
i might use it for something else
I'll start from scratch and start by only adding a single, simple item. Luckily I know how to code (though not lua yet) and have a bit of experience modding other games. It's mostly the syntax and game providing most of the learning curve currently, but so far it's not too bad. Some games are real rough to mod, but at least there are a good amount of resources for PZ
yeah the lua command stuff is good to know actually, it'll definitely help me debug
best of luck to you !
https://discord.com/channels/136501320340209664/1070852229654917180
might help speed things up for you
Great, thanks!
Though I actually just figured it out and its really dumb. In my mod.info, I changed everything but forgot to change the id. So it was just using the examplemod code. I changed it and now everything works ๐ฉ
Typical
happens all the time
Is there a mod that lets you sit and shoot? 
I have an issue with textures.
I have an old texture image, which does work, but it's for an outdated UV-surface.
And I have the new texture image, meant to replace it. Whenever I do actually replace it, the item just disappears.
The bit depth is correct - That was the first issue, and that shot an error message which i fixed. But now after the fixed bit depth, the backpack just appears as invisible.
Checked if the name was written wrong or so, it should be good.
Did anyone else have this issue?
Hi, just a quick question for someone who is new. If I want to patch someone else's mod (change recipe and loot distribution), can I just copy the files(loot table and recipe txt) to the patch mod and edit them? would that overwrite?
@ivory fractal check any other mod that adds new skill, would be best place to start
Driving Skill
Scavanging Skill
I think there's Blacksmith
And probably half a dozen more
yes
thank you
Anyone managed to crack the pain system ? Canโt seem to get setPain, setPainReduction to have any effect on reducing pain
You know what I want? A mod that adds cult-ish things. Robes, hoods, associated decor, etc
Edit: I want to clarify that Iโm not offering to commission anyone to make this. Iโm just putting the idea out there
I looked on the workshop, couldnโt find anything like what Iโm looking for
it should be applied to body parts i think
also look at additional pain
how do I mod in occupations
Download a mod that already does that and study it's files
got it
When you kill a zombie, can you store the time of death in the zombie's corpse table and retrieve it later? When I record it using zombie:getModData(), the data disappears when the corpse is reloaded. I don't know how to do this.
Code:
function A.OnZombieDead(zombie)
local currentTime = getGameTime():getWorldAgeHours()
local modData = zombie:getModData()
modData.deathTime = currentTime
end
Events.OnZombieDead.Add(A.OnZombieDead)
function A.TestObj(playerNum, context, worldobjects)
for _, Wobj in ipairs(worldobjects) do
local sq = Wobj:getSquare();
if sq then
for y = sq:getY()-1, sq:getY()+1 do
for x = sq:getX()-1, sq:getX()+1 do
local square = getCell():getGridSquare(x, y, sq:getZ());
if not(square) then
break;
end
for i = 0, square:getStaticMovingObjects():size()-1 do
local obj = square:getStaticMovingObjects():get(i);
if instanceof(obj, "IsoDeadBody") then
local ID = obj:getID()
local ModData = obj:getModData()
local CurrentTime = ModData.deathTime
print("ModData: "..tostring(ModData))
print("CurrentTime: "..tostring(CurrentTime))
end
end
end
end
end
end
end
Events.OnPreFillWorldObjectContextMenu.Add(A.TestObj)
I thought corpse mod data is persistent :/
me too but i guess it kind of makes sense if it isn't for zombies?
I thought they might've wanted to store corpse mod data for special events or other things, idk
Yes you can probably manage to so something like that, simply pass the corpse data and zombie data manually I guess
The above code changes the corresponding ModData.deathTime value to nil when the game is terminated, or when it comes back out of that position.
Maybe the value of isoDeadBoy is changing, but I don't know the solution.
there's nothing setting to nil here
also code block please
@bright fog
function A.OnZombieDead(zombie)
local currentTime = getGameTime():getWorldAgeHours()
local modData = zombie:getModData()
modData.deathTime = currentTime
end
Events.OnZombieDead.Add(A.OnZombieDead)
function A.TestObj(playerNum, context, worldobjects)
for _, Wobj in ipairs(worldobjects) do
local sq = Wobj:getSquare();
if sq then
for y = sq:getY()-1, sq:getY()+1 do
for x = sq:getX()-1, sq:getX()+1 do
local square = getCell():getGridSquare(x, y, sq:getZ());
if not(square) then
break;
end
for i = 0, square:getStaticMovingObjects():size()-1 do
local obj = square:getStaticMovingObjects():get(i);
if instanceof(obj, "IsoDeadBody") then
local ID = obj:getID()
local ModData = obj:getModData()
local CurrentTime = ModData.deathTime
print("ModData: "..tostring(ModData))
print("CurrentTime: "..tostring(CurrentTime))
end
end
end
end
end
end
end
Events.OnPreFillWorldObjectContextMenu.Add(A.TestObj) ```
lua
Will help you share your problem as it will make your codes easier to read, tho you've done a good job with indentation and organization here so it isn't that bad
good morning. I apologize in advance if my post breaks any discord rules and I apologize for my bad English...is there anyone who could help me in making a mod. logically when they have time to dedicate to me. the project is not complex but my skills as a modder are very limited. The mod would be used in an RP server and would be made public on the workshop. The project consists of modifying the classic zombie infection. If anyone is available contact me. have a good Sunday everyone โบ๏ธ
Hey you can make commissions on the modding Discord here:
https://discord.com/channels/136501320340209664/1125248330595848192
Hey wanted to ask, your ETW mod requires you to do specific actions to lose some traits right ? For example the fog fear would require you to stay in the fog to lose the trait ?
Also small tip: cache your values when you retrieve them multiple times
-- for example here you can cache BloodlustMeter since you end up calling it at least twice
local bloodlustMeter = bloodlustModData.BloodlustMeter
if bloodlustMeter >= 18 then -- gain if above 50%
local bloodLustProgressIncrease = bloodlustMeter * 0.1 * (1 + bloodiedClothesLevel(player)) * ((SBvars.AffinitySystem and modData.StartingTraits.Bloodlust) and SBvars.AffinitySystemGainMultiplier or 1);
bloodlustModData.BloodlustProgress = math.min(SBvars.BloodlustProgress * 2, bloodlustModData.BloodlustProgress + bloodLustProgressIncrease);
if debug() then print("ETW Logger | bloodlustTimeETW(): BloodlustMeter is above 50%, BloodlustProgress =".. bloodlustModData.BloodlustProgress) end
else -- lose if below 50%
local bloodLustProgressDecrease = bloodlustMeter * 0.1 * (1 - bloodiedClothesLevel(player)) / ((SBvars.AffinitySystem and modData.StartingTraits.Bloodlust) and SBvars.AffinitySystemLoseDivider or 1);
bloodlustModData.BloodlustProgress = math.max(0, bloodlustModData.BloodlustProgress - (3.6 - bloodLustProgressDecrease));
if debug() then print("ETW Logger | bloodlustTimeETW(): BloodlustMeter is below 50%, BloodlustProgress =".. bloodlustModData.BloodlustProgress) end
end
Yes. And ye I try to cache things, but sometimes miss here and there :)
I try to optimize my mod as much as possible, I don't even run all logic, I have logic dynamically turned on and off based on a bunch of factors
Pretty proud of it tbh

Yeah that's the way to do it, good stuff 
It's especially important for these kind of mods that tend to run the entire time
When do you do your updates ? Every minutes ? 10 minutes ?
Anywhere between one minute and one day
And one onTick
But that's only if u have a trait
That locks your pain level
Good stuff too 
now for the real test: do you actually benchmark it
how do you know you optimised anything?
I don't, I just apply rules and ask questions on what is best lol
Literally I'm not a fucking computer engineer, and there is no guide on anything like that, no shit I'm not benchmarking anything
But if you have something for that, I'm interested
Because instead of running logic all the time I run it conditionally
If I run things all the time is going to have more performance impact than if I disable half of the logic on character load because it's not needed for this character
Also idk if there's a way to benchmark pz mods
if you can run a function in isolation, you can just do:```lua
-- change this depending on how heavy the function is so it doesn't take way too long to test
local ITERATIONS = 1000000
local start = os.time()
for i = 1, ITERATIONS do
theFunction()
end
print(os.time() - start)
Yeah it's one of the many rules I try to apply
if you can't you can add a timer like this into the function but the issue there is that the timer isn't very precise and you end up massively affected by rounding errors
So just put this in a function ?
Nah, put function in this
oh
To see how much time it takes to run it 1 mil times
What if I can't run the function that way
Everything involves throwing a zombie in my functions or smthg related to it lol
you can do something similar like```lua
local totalTime = 0
local calls = 0
function theFunction()
local start = os.time()
...
totalTime = os.time() - start
calls = calls + 1
end
function printBenchmark()
print("Average time taken: ", totalTime / calls)
end
however unless the function is quite heavy this might give very crappy results
this clock is only precise to milliseconds (iirc) and an average very light function will generally take far less than a millisecond - so if the clock ticks up during a light function like that it's more of a coincidence than anything
ideally that kind of error would average out over time but it can make it unreliable
Okay I'll try to look at that a bit later when I have time
i think i wrote an automatic module profiler at some point but i'd have to give it another look over
๐
I'm sure a guide or tools to benchmarking will be more than useful for the community
yeah i should really write it down somewhere
even for my sake, i think i've written out that entire profiling boilerplate i just sent over a hundred times already
I'll probably write these 2 code snipets you shared in a misc guide on the Discord (crediting you ofc)
I'll test these out, figure out how to use them etc, and will write some tutorial on how to use them
you can just put it in a long loop
read above, this is for when you can't
well if you can't loop it then you're out of luck. Not even high resolution timer would help you with OS context switching induced jitter
you can only rely on high resolution timer for profiling on real time OSes where it's literally not allowed to interrupt your code for any reason whatsoever
(except a hardware interrupt and even then not always)
luckily we're benchmarking a scripting language and errors at that scale are not worth thinking about
you specifically said the issue is that you might need a high resolution timer
higher resolution than this is dominated by OS timing noise
most function calls return literally 0
i don't recall exactly but in C you can call nanosecond-accurate timers
it doesn't helps with accuracy if your code runs in very short amount of time
you still need to run it for combined several seconds to get low noise results
which is to say. If you need to benchmark a function that can't be looped, you rewrite it such that it can be.
Depending on what the function does exactly, you can get away with just manipulating its execution environment, so the limiting factor that prevents looping doesn't exist in this testing loop.
Calendar.getInstance():getTimeInMillis() is accurate to exactly 1 millisecond, on windows anyway
yeah that usually ends up in poorly running code. Outside of extremely trivial scenarios, you can never assume that method A is faster than method B.
You can, by doing benchmarks and knowing your shit
if you measured the execution speed, then that's not an assumption anymore ๐
Which is why I've asked for albion's help quite a lot on the matter since she knows her shit and she took the time to test a few stuff herself
huh
A useful feature Kahlua has that standard Lua does not have is array tables.
Well that's just not true.
@bronze yoke
regular lua has separate integer table part for faster access
that's not what a kahlua array is though
it behaves differently from a regular table
it's needless pedantry and not really accurate in a general sense either
well i'm looking at the kahlua source code and i'm not even seeing the separate integer table. It stores internally everything in a plain array.
And the way hash lookup works is that it maps hashable values to this array.
i'm not sure what you're looking at but kahlua (or at least the version pz uses) implements tables exclusively as a hash map and has a separate implementation that uses an array instead
Is there a way to keep cells loaded? Or atleast, load them, do stuff to them, and let them unload
Also, how far from a character until cells are unload?
Vary to more or less-
Server is 50 I believe
*I was hoping to be atleast 64 ๐ซ *
no idea, i just always see people saying that it can scale with resolution or whatever, never seen any actual testing indicating it
Well, 128x128, and maybe I can make it display if any cells were nil
What are you trying to do ?
I made an area remove thing. Bascially just a sledgehammer, but for areas x3 But, if a cell is unloaded, it just doesn't delete the objects on the cell.
I wonder actually- Maybe part of the variation is between rendered and simulated tiles?
B/c I noticed when trying to highlight, it would only do rendered tiles. But when deleting, it'd do more
i guess it is just pedantry then. It's just weird to include the statement that regular Lua doesn't have it when it in fact has pretty much the same thing for the same exact reason, except implemented differently.
Oh I could also make it acutally do- like- survival friendly I guess?
Only delete if the area is loaded ?
Heh- Idk how to check that xD
Unless it's just "sq==nil"
Well, I mean, I am only deleting if the cell is loaded, but it doesn't alert if previously selected cells in the area were unloaded
if the cell is unloaded, it effectively doesn't exist in the game - when the code that affects a cell runs, it first checks that the cell is loaded and only then proceeds (or just crashes).
You can check if the cell (square?) is unloaded and then store it into a list. When it's loaded in OnGridsquare you can run the same code on it again.
the function table.newarray() is not standard lua, nor are there tables that throw errors when you try to access non-positive or non-integer keys
saying that standard lua has the same feature because... it internally implements another feature with an array... misses the point, and isn't useful information for a reader either
I am confused what a cell and square are-
that's okay, the game's developers are too
square is an individual tile
1x1
but when what is a cell
cell is a 300x300 square area that maps are divided into, chunks are 10x10 areas that the game actually loads/unloads in, and a square is a square
OHH
cell is an area around the player that contains loaded chunks, which contain loaded squares
the IsoCell object isn't a 'map cell' but the current loaded area, the name is like that for legacy reasons
that makes more sense
Also, could I do the reload lua command if it's just 1 lua file I wanna reload? The file I'm working on x3
you can reload individual files from the lua debugger (f11)
Actually now would be the perfect chance to use debug mode instead of my fake debugger mode
depending on what you do reloading individual files it's not always useful though
i personally almost never use file reloads
they're highly unreliable for most practical cases
How do I add debug as a game again- xd
you can probably setup that one function to unhook your event callbacks and then reload them
then single file reload will actually work properly
in theory
Do I have to make a bat file or just add steam game on the exe-
you can just add the game's exe as a steam game
you're not running it on steam?
I am, but I heard ya can have a seperate thing on steam to boot into debug mode
via adding non steam game
you just need to add non-steam game, (then wait about ten minutes for the menu to actually work), and then select the game exe, steam doesn't care about 'doubles' or anything
i recall there was a proper way to make a development environment
with entirely separate saves and whatnot
yes, i recommend launch options like these -debug -cachedir="C:/Users/albion/ZomboidDebug" -modfolders mods,workshop
yea that'll happen if you crash faster than the game loads haha
not a crash, just seems to be an error x3
potato brotato๐
(i just hail from coding communities where script error = game crash)
anyway that debug screen is amazingly useless for how much stuff is implemented for it
i found myself making a game state emulator just so i can use a proper debugger
it has all of this built into the basic table, you don't need to create one via newarray to benefit from faster integer access, and it wouldn't crash if you use non-integers and still be fast if you do use them afterwards
yes - so it's different
it's differently implemented yes. But you were right when you said it's just pedantry. I guess wording like in kahlua you need to create an array table to benefit from faster integer access would be more appropriate is all. The original kinda reads like normal Lua doesn't have faster integer access. When it does have it by default, by having an array table transparently inside the normal table.
So, I grabbed this from cheat menu to destroy objects, but how would I destroy floors?
if isClient() then
sledgeDestroy(obj)
else
local sq = obj:getSquare()
sq:RemoveTileObject(obj);
--sq:DeleteTileObjectโ(obj);
sq:getSpecialObjects():remove(obj);
sq:getObjects():remove(obj);
oop- formatting yay xD
the obj needs to be the particular floor java object on that square
So, obj can just be set to sq:getFloor()?
I don't know but it might be.
what would be a no
I wonder if ClearTileObjects() would work-
no
void ClearTileObjects()
void ClearTileObjectsExceptFloor()
??????
local obj = sq:getFloor()
sq:DeleteTileObject(obj)```
this seems to work. Prob don't need to be setting a local
Should I make a bit of code that I can run to make certain things be attached to floor tile, or make build menu extension ๐ค
The attach might be easier in terms of how long it takes, but the extension might be nicer to use xD
Might do attach thing, then work on extension later
by the time you make the code that does it, making a menu extension is very trivial
because the actual code is already done
Oh nah, I mean adding the building menu mod
This is 1 object added to the menu.
And the stuff I'd want to add would be like- idk- alot xD
seems like boilerplate code, which means you can add it in a loop from a table
Yee, but still might take a hot moment. Unless I write code to write the code? :O
Oh, side task! What if I made the code that does area removal from my- well- area removal mod able to be used by other mods?
you can use any mod code from any other mod
I know
More like "I could do xyz, then that'd let me do abc easier!" x3
Instead of it being specifically for removal, call it to start area selection, once area selecting is done, run a function given. If cancelled, run another function.
I might make a note to do that
is there some func that gives me the type of userdata?
you can use instanceof(obj, "ClassName") to test type
ill try next time
turns out tostring does exactly what i need
didnt really expect it to work but it actually did xd
Hello everyone, I'm new here!
I'm trying to write a "simple" mod to add a keybind for a certain action.
Question: Is it possible to retrieve an item when the player clicks on it? ie: I open the inventory and click on a cereal, then press my keybinding so that it gets the cereal as a parameter, and finally do an action with that item. Is this possible?
Actually not, I want to do another thing with the Item, for example, pour into the ground. So in my code I need to check the ItemCategory, and if the condition matches try to pour it with an hotkey. So, I click on a Bourbon, press Numpad9, perform "pour into the ground". Is it clear ?
Sounds like something that should be possible
Yea, I'm looking this repo right now (https://github.com/rm-code/convenient-bags) and starting to understand better. From a frontend developer, I think I'm making progression 
Oooh keybinds within the context menu ?
i really want to make a mod. i can learn lua, but the subtle nuances of it is what i am worried about. and art but one step. are there any good youtube channels you'd recommend for visual learning? i'm already reading lua.org's free online book, but i learn better through seeing things done. thanks in advance.
https://pzwiki.net/wiki/Modding
this is helping but like i said, visual learner
I won't use the context menu, it doesn't make sense, the purpose of the keybind is to make the action faster.
Hi guys, got a question regarding folders in mods. Thanks in advance for the help.
I'm working on a mod that requires a part of it to be installed manually by replacing a file.
I just wan't to be sure that the mod won't try to install this part automatically when you activate it from the mod list inside the game
Will it sufice if I change the name of the folder inside the contents folder to something that is unfamiliar with the game structure (name it something that is not "lua" or "scripts") or is that gonna cause issues?
So equip the item and then keybind ?
@ivory fractal
hey man i did reserach
researching about Perks
i plan to use it for a mod
so far this i is what i got
PerkFactory
class: class zombie.characters.skills.PerkFactory
init: function 0x1185104872
Reset: function 0x1304064705
initTranslations: function 0x1571618915
AddPerk: function 0x825651529
getPerkName: function 0x1842796676
getPerk: function 0x1935971205
getPerkFromName: function 0x1182739346
PerkList: [Combat, Axe, Blunt, SmallBlunt, LongBlade, SmallBlade, Spear, Maintenance, Firearm, Aiming, Reloading, Crafting, Woodwork, Cooking, Farming, Doctor, Electricity, MetalWelding, Mechanics, Tailoring, Survivalist, Fishing, Trapping, PlantScavenging, Passiv, Fitness, Strength, Agility, Sprinting, Lightfoot, Nimble, Sneak]
new: function 0x1153545773
class: class zombie.characters.skills.PerkFactory$Perks
fromIndex: function 0x882659023
FromString: function 0x1875680214
getMaxIndex: function 0x354465001
None: None
MAX: MAX
new: function 0x278891778
print(PerkFactory.getPerkFromName('Survivalist')) -- returned the perk Survivalist
print(PerkFactory.getPerkFromName('custom')) -- returned nil
print(getPlayer():getPerkLevel(Perks.Lightfoot)) -- returned 10
print(getPlayer():getPerkLevel(Perks.custom)) -- returned 0 even tho PerkFactory.PerkList doesnt have it
--this is how i checked
print(PerkFactory.PerkList:contains(Perks.Lightfoot)) -- returned true
print(PerkFactory.PerkList:contains(Perks.custom)) -- returned false
print(Perks.custom) -- returned nil
--then i added it
Perks.custom = PerkFactory.new("custom", "custom")
print(Perks.custom) -- then it printed this zombie.characters.skills.PerkFactory@7b04f8a7
--btw i used this to save it to Clipboard
local toclip = Perks.custom
Clipboard.setClipboard(tostring(toclip))
--i then checked PerkFactory.PerkList again still doesnt have the custom perk
print(PerkFactory.getPerkFromName("custom")) --still prints nil
print(PerkFactory.PerkList:contains(Perks.custom)) -- still returns false
--i did reserach and found this
public static PerkFactory.Perk AddPerk(PerkFactory.Perk perk,
String translation,
PerkFactory.Perk parent,
int xp1,
int xp2,
int xp3,
int xp4,
int xp5,
int xp6,
int xp7,
int xp8,
int xp9,
int xp10,
boolean passiv)
--first attempt failed
PerkFactory.AddPerk(Perks.custom, "custom", Perks.Survivalist, 75, 150, 300, 750, 1500, 3000, 4500, 6000, 7500, 9000, false)
--2nd attempt failed
Perks.custom = PerkFactory.new("custom", "custom")
local parentPerk = PerkFactory.getPerkFromName("Survivalist")
PerkFactory.AddPerk(Perks.custom, "custom", parentPerk, 75, 150, 300, 750, 1500, 3000, 4500, 6000, 7500, 9000, false)
--3rd attempt failed
PerkFactory.AddPerk(PerkFactory.new("custom", "custom"), "custom", PerkFactory.getPerkFromName("Survivalist"), 75, 150, 300, 750, 1500, 3000, 4500, 6000, 7500, 9000, false)
--more prints
print(PerkFactory.getPerkFromName("Survivalist")) -- Survivalist
print(Perks.Survivalist) -- Survivalist
print(PerkFactory.getPerkFromName("custom")) -- nil
print(Perks.custom) -- zombie.characters.skills.PerkFactory@7b04f8a7
print(type(PerkFactory.getPerkFromName("Survivalist"))) -- userdata
print(type(Perks.Survivalist )) -- userdata
print(type(Perks.custom)) -- userdata
print(type(PerkFactory.getPerkFromName("custom"))) -- nil
i still failed tho
What are you even doing
trying to add custom perk
Perk, trait, or skill ?
There's a lot of mods that add their own skill if that's what you are trying
ok thnx
im also just generally curious
Should be easier to learn if you base yourself on existing stuff
need some help with food items if anybody has knowledge. gonna brute force in the meanwhile
I have a food item in a container and i want to make to so that when you drink out of the container it gives you the empty container. i have the full empty and full of water containers added with full functions but wont give empty when drinking from it
Isn't it a thing like "OnConsume" or idk
In the item script
Check opened canned food scripts
yeah, there's ReplaceOnUse
yeah, you use deplete on drainable item types
so if it had water inside not milk makes sense
like thread, candles and water containers
could I add on a question since we are here
yea
theres type = food but could I also do type = drainable on the same item
or how could I do both for a drainable milk jug
i get why would you drain it but
im insane so
pouring milk everywhere
Nah needs to be food I think
sadge
let me just try ingame rq see if it gives me the empty jug now
does let me pour on ground tho thats cool
does give me the empty jug now but i messed up the icon lol
thank you
wait there was also a comment on my mod awhile ago
idk what couldve caused this as my mod is pretty simple
yeah only 1 though. it only occurs when drinking from the base item not the regular water bottles
ill post what it looks like here
And your sound is short right ?
drinkingfromchocolate is only used by the base item and its decently short
as long as it takes to drink the whole bottle of milk
in vanilla
Talking about the file itself here
lemme check
would be easy to trim down
ah its a minute and forty seconds
could be it
only takes like 10 seconds to drink
OOF
ill trim it right away
Go download Audacity and fix that shit rn lmao
Yea so basically whenever anyone drinks, I get no other sounds can play for the player idk
like 20seconds should be fine right?
Just the length of your sound
i dont exactly know how long it takes to drink milk
No point in making it last ages
ill time it ingame ig
It sure doesn't take 20 fucking seconds lmao
just make it last an hour atp lmao
Maybe check vanilla sounds how they are
yeah maybe
Check the vanilla drinking sound if you can access it (if it's not in the bank file)
(also why do you not use the base game sound of drinking ?)
its a joke mod
so it plays a youtubers intro
hes a bodybuilder who drinks alot of chocolate milk
ok lol
most of my mods are small changes for comedic effect between friends
trying to find drinkingfromcarton file is agony
tastes bout 12 seconds to drink
only thing I need now are ingame models which I dont know how to make
and perhaps how to make the chocolate milk spawn rarer then it is
I want it to be like pretty rare
I think I got how to edit the rarity but like what number is considered rare lol
guess ill just make them all 1 and trial and error it up or down
The item doesn't have to be equipped necessarily. I just want to catch 1..N items selected in the inventory...
So select items within the inventory, then press a keybind and it will empty them ?
Yep ๐
Interesting
Well idk how selecting items works
Idk if you can retrieve the selected items in a way, but if you can, you can simply use Mod Options to add custom keybinds, link a function which will retrieve the selected items, and check their types and if they can be emptied out, queue timed actions for each items to empty the items out
hmmm, sounds good to me this plan, I'll try to split into parts and try it
Another question @bright fog, where can I find an API doc ? For example, where I can find what getPlayerData() does. Idk if I'm being annoying, but I'm trying to know more about modding...
https://projectzomboid.com/modding
it won't tell you what it does tho, for that you need to decompile the java
package index
Decompiling is very easy to do
you don't necessarily need mod options to add custom keybind this is how i add it in one of my mods
local bind = {};
bind.value = "[GaussFirearms]";
table.insert(keyBinding, bind);
bind = {};
bind.value = "GaussFirearms_InsertAndRemove";
bind.key = Keyboard.KEY_V;
table.insert(keyBinding, bind);
bind = {};
bind.value = "GaussFirearms_InsertOneRound";
bind.key = Keyboard.KEY_Z;
table.insert(keyBinding, bind);
No you don't, but I would suggest using it because of how easy it is to with mod options + everyone has mod options activated in their games
I personally don't bother with it and just use mod options bcs everyone uses it
@bright fog if there a limit on death sounds? max length im using is about a minute thirty ive seen some mods make it 3 minutes
some are only a couple seconds
To play a music on death ? No idea
sadge
yeah like one of mine adds about 7 different sounds that play at random
ive tested it and as far as i see it doesnt cause an issue. but i assume it could be the same problem as before where if you die and go straight to playing again maybe it wont reset the sounds
idrk
resets default death theme so i assume it resets all
hmm I feel like it would reset the music, either way you can stop the emitters so it stops the song
yeah
forgot to add it to the description of the mod but I will also be adding a collection of faygo sodas
https://steamcommunity.com/sharedfiles/filedetails/?id=3323139018 Just created this mod to allow more search focuses for more foraging categories. I'm a pretty inexperienced modder so I was pretty proud I made something actually effect a gameplay mechanic that much
looks neat dude great work
That's pretty good, based on the level in foraging that's great
Ah, I can't use the modding server anymore because I don't have my phone number linked with this account...
"2.6. Hidden / Unexpected Content. Any hidden or unexpected content and/or messages made in updates to mods that are not flagged on the Steam Workshop description / pages or isnโt evident in the mod itself must have attribution VISIBLE as to where (and from whom) said content has originated."
so does this mean i cannot put in an easter egg if the character does something special
if it has nothing to do with the rest of your mod, then probably not
for the tick/lice mod (doing research now), i wanted an ester egg to where if the character gets lyme disease and dies from a bite, the reanimated corspe is able to use the weapons left on them
right now doing research on KY ticks and distribution, life cycles and transmission
I wouldn't worry too much about that descriptor - it's mostly to be used on a case by case basis if an update to a mod causes an severe enough issue that TIS has to step in.
Basically legalese for 'we told them not to do X'
:notes taked:
it's like those Forza Horizon skins that look cool on the preview because it always shows front-left angle, but the actual car has a swastika on the right side.
so it's basically so you can't pull a fast one on people
oooooo
hot coffee
so i can't have the tick be able to be clipped through and there is a picture of hentai on the inside of the tick
does anyone know how to get the inventory of a dead body?
get the dead body, and getInventory() ?
smthg like that ?
Shouldn't be too hard
isoDeadBody:getContainer()
Yeah getContainer
Hi, i admittedly have not dug too too deeply into this, I can't seem to find any good videos explaining things that get me info quickly.
I just wanna create a script of some kind, which spawns hordes of zeds in increasing quantities. start with basic civilians, slowly add a chance of better zeds (and after a point remove basic civilians), and also slowly increase the amount of zeds spawned. Based on IRL time, not game time. Option to have them already defeated, or still moving.
I found the SpawnerAPI and thought about trying to understand it but just wanted to double check if that was the best option for this, and also how exactly i would set up this kind of mod? Or if I even need to write a mod for it, if i could write an external script to do this?
(please ping me so i know the red dot is a response, apologies)
what resources do you guys use for pixel art for asset representation? (what do you use to make the 8bit items for icons?)
Look into Horde Night mod, it does exactly this
Thing is that i am wanting to do this in a creative-debug-world, not in survival, as part of a thing i am testing
Ye, but what I mean is look at the code
Also if you jsut need horde to test things, in debug mode there is a horde spawner tool
-wants it to be afk'able-
yeah i'll look into the mod, thx
Hi everyone,
I'm working on a clothing mod for Project Zomboid and I'm running into an issue. I've edited a 3D model for the mod and when I export it to FBX, the model appears in the game for a brief moment and then disappears, becoming invisible
Does anyone know why? I'm using Blender and I've tried exporting in several ways
probably better place for that
If I overwrite base game function to insert my stuff into it and original function hits return, will my func end too?
aka
-- base game func
function ISVehicleMechanics:doPartContextMenu(part, x,y)
if UIManager.getSpeedControls():getCurrentGameSpeed() == 0 then return; end
...
end
--my stuff
local original_doPartContextMenu = ISVehicleMechanics.doPartContextMenu
function ISVehicleMechanics:doPartContextMenu(part, x,y)
original_doPartContextMenu(self);
--my code
end```
if original hits return will it end the original function only? Or my func will end too? Not sure how lua handles this stuff
it only returns the original function
thought so, ty
if returning in a function ended all code execution they wouldn't be very useful ๐
ye
Is there a good way of figuring types of function argumetns in source code?
Like for example
function ISVehicleMechanics.onRepairEngine(playerObj, part)
if playerObj:getVehicle() then
ISVehicleMenu.onExit(playerObj)
end
local typeToItem = VehicleUtils.getItems(playerObj:getPlayerNum())
local item = typeToItem["Base.Wrench"][1]
ISVehiclePartMenu.toPlayerInventory(playerObj, item)
ISTimedActionQueue.add(ISPathFindAction:pathToVehicleArea(playerObj, part:getVehicle(), part:getArea()))
local engineCover = nil
local doorPart = part:getVehicle():getPartById("EngineDoor")
if doorPart and doorPart:getDoor() and doorPart:getInventoryItem() and not doorPart:getDoor():isOpen() then
engineCover = doorPart
end
local time = 300;
if engineCover then
-- The hood is magically unlocked if any door/window is broken/open/uninstalled.
-- If the player can get in the vehicle, they can pop the hood, no key required.
if engineCover:getDoor():isLocked() and VehicleUtils.RequiredKeyNotFound(engineCover, playerObj) then
ISTimedActionQueue.add(ISUnlockVehicleDoor:new(playerObj, engineCover))
end
ISTimedActionQueue.add(ISOpenVehicleDoor:new(playerObj, part:getVehicle(), engineCover))
ISTimedActionQueue.add(ISRepairEngine:new(playerObj, part, item, time))
ISTimedActionQueue.add(ISCloseVehicleDoor:new(playerObj, part:getVehicle(), engineCover))
else
ISTimedActionQueue.add(ISRepairEngine:new(playerObj, part, item, time))
end
end
By looking at the rest of the file I got that playerObj is IsoPlayer but can't figure part yet, and my closest guess that it's VehiclePart
Is there a better way?
if you can just edit the function, print it and see
print(part)
I see
the print message will be its type and a memory offset you don't need to worry about
Alternitively jsut figured to look up the method thats called on part
Javadoc Project Zomboid Modding API declaration: package: zombie.vehicles, class: VehiclePart
xd
part:getVehicle()
unfortunately since lua is dynamically typed and tis don't use any kind of type annotation any direct type information usually doesn't exist
xd
I havent used annotations in lua before either
but with umbrella its kinda enjoyable

also im hijacking the wrong function anyway, I need ISRepairEngine:perform() and not ISVehicleMechanics.onRepairEngine(playerObj, part)

Question, function ISRepairEngine:perform() sends a client command. I tried hijacking it to catch by how much engine was repaired but
function ISRepairEngine:perform()
local player = getPlayer();
local modData = ETWCommonFunctions.getETWModData(player);
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): caught") end
local conditionBefore = self.part:getCondition();
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionBefore" .. conditionBefore) end
original_ISRepairEngine_perform(self);
local conditionAfter = self.part:getCondition()
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionAfter" .. conditionAfter) end
end```
says part wasnt changed. I assume it's because the function sends the command to the client
```lua
local args = { vehicle = self.vehicle:getId(), condition = self.part:getCondition(), skillLevel = skill, numberOfParts = numberOfParts }
args.giveXP = self.character:getMechanicsItem(self.part:getVehicle():getMechanicalID() .. "2") == nil
sendClientCommand(self.character, 'vehicle', 'repairEngine', args)
I have found the server function responsible for this so my question if I want to override it to catch the repair percentage, do I just follow the same idea?
Do I need to do something differently cuz this code is in server folder?
function Commands.repairEngine(player, args)
local vehicle = getVehicleById(args.vehicle)
if vehicle then
local part = vehicle:getPartById("Engine")
if not part then
noise('no such part Engine')
return
end
local condPerPart = 1 + (args.skillLevel / 2)
if condPerPart > 5 then condPerPart = 5 end
local done = 0
for i=1,args.numberOfParts do
part:setCondition(part:getCondition() + condPerPart)
done = done + 1
if part:getCondition() >= 100 then
part:setCondition(100)
break
end
end
if done > 0 then
if args.giveXP then
player:sendObjectChange('addXp', { perk = Perks.Mechanics:index(), xp = done, noMultiplier = false })
end
player:sendObjectChange('removeItemType', { type = 'Base.EngineParts', count = done })
vehicle:transmitPartCondition(part)
end
player:sendObjectChange('mechanicActionDone', { success = (done > 0), vehicleId = vehicle:getId(), partId = part:getId(), itemId = -1, installing = true })
else
noise('no such vehicle id='..tostring(args.vehicle))
end
end```
how do I even override it? Commands is a local array
i mean you don't really need to right
it's triggered by a client command, you can just listen for the same command
there is some trickery you can do if you absolutely need to overwrite it but
But I want to catch engine condition after command is done
well load order guarantees your event listener fires after theirs does so you can do that fine
ye but how would that get me the conditon after repair? If I listen to same command? both vanilla function and my own function will recieve same set of arguments, no?
Or am I missing something?
just do part:getCondition()
I tried tho?
function ISRepairEngine:perform()
local player = getPlayer();
local modData = ETWCommonFunctions.getETWModData(player);
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): caught") end
local conditionBefore = self.part:getCondition();
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionBefore" .. conditionBefore) end
original_ISRepairEngine_perform(self);
local conditionAfter = self.part:getCondition()
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionAfter" .. conditionAfter) end
end```
in a client command listener
you mean sth like this?
local Commands = {}
function Commands.repairEngine(player, args)
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'vehicle' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)
so i get same command and then get condition from there?
yeah
and call it after 1st command?
vanilla files always load first and event listeners execute in the order they were added so when that command is sent the vanilla function will run and then yours
or so they will be queued?
aka my command wont start running its code until 1st command is done?
yeah
I see
there's no concurrency in lua
No I mean I know that but like does it include waiting for player to repair the engine
Anyway I'll jsut write it and see
xd
tyty
so basically what happens here is ISRepairEngine.perform sends a command to the server to update the engine's condition, the server when it receives that command then calculates and updates the condition and sends it to the clients
ah
you would be running your code after that update has been made
Separate question, can I require lua from client folder in server folder?
yesss but you shouldn't
if it's not client code don't put it in client and vice versa
But I have a neat file where I keep my commonly used functions
oh
yea im not sure about client-server architecture, barely had to work with it in pz
files in client/ aren't supposed to even run on the server but require ignores that
function ISRepairEngine:perform()
local player = getPlayer();
local modData = ETWCommonFunctions.getETWModData(player);
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): caught") end
local conditionBefore = self.part:getCondition();
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionBefore" .. conditionBefore) end
original_ISRepairEngine_perform(self);
local conditionAfter = self.part:getCondition()
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): conditionAfter" .. conditionAfter) end
local args = { vehicle = self.vehicle:getId(), condition = self.part:getCondition()}
sendClientCommand(self.character, 'vehicle', 'checkEngineCondition', args)
local Commands = {}
---@class EngineCheckArgs
---@field vehicle BaseVehicle
---@field condition number
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
if detailedDebug() then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. args.condition) end;
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'vehicle' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)
ETW Logger | ISRepairEngine:perform(): conditionBefore10
ETW Logger | ISRepairEngine:perform(): conditionAfter10
VehicleCommands: received vehicle repairEngine zombie.characters.IsoPlayer@304918b3 vehicle=251 condition=10 skillLevel=2 numberOfParts=10 giveXP=true
ETW Logger | Commands.checkEngineCondition(): args.condition: 10
receiveObjectChange addXp
receiveObjectChange removeItemType
receiveObjectChange mechanicActionDone```
aint working

I send same arguments
I dont see why would it be different
Or am I doing something wrong?
i don't see args.condition used in the original function
POG
ETW Logger | ISRepairEngine:perform(): conditionBefore38
ETW Logger | ISRepairEngine:perform(): conditionAfter38
VehicleCommands: received vehicle repairEngine zombie.characters.IsoPlayer@6e60f13e vehicle=253 condition=38 skillLevel=2 numberOfParts=4 giveXP=true
ETW Logger | Commands.checkEngineCondition(): args.condition: 46```
local original_ISRepairEngine_perform = ISRepairEngine.perform;
---Overwriting ISRepairEngine:perform() here to insert ETW logic catching player doing engine repairs
---@diagnostic disable-next-line: duplicate-set-field
function ISRepairEngine:perform()
if detailedDebug() then print("ETW Logger | ISRepairEngine:perform(): caught") end
original_ISRepairEngine_perform(self);
local args = { vehicleID = self.vehicle:getId() }
sendClientCommand(self.character, 'vehicle', 'checkEngineCondition', args)
local Commands = {}
---@class EngineCheckArgs
---@field vehicleID number
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
local vehicle = getVehicleById(args.vehicleID)
local part = vehicle:getPartById("Engine")
if not part then return; end
if detailedDebug() then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. part:getCondition()) end;
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'vehicle' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)

works
ty
If I have a function in client folder that checks some player stuff do i need to make some server-client command now to run it?
Most things will work fine like paint.net or photoshop or even some online ones (dont use them so I can't recommend specific ones) but definitely the best (I am biased towards it) is Aseprite (can buy on Steam too). Do know that Aseprite is 20 USD on their website, so it isn't something I'd buy if you don't use it often.
Overall it doesn't really matter, as long as you can paint pixels it will work just fine
would need more information on what you need to do with it to be sure
function ETWActionsOverride.mechanicsCheck()
local player = getPlayer();
local modData = ETWCommonFunctions.getETWModData(player);
if player:getPerkLevel(Perks.Mechanics) >= SBvars.MechanicsSkill and modData.VehiclePartRepairs >= SBvars.MechanicsRepairs then
if not SBvars.DelayedTraitsSystem or (SBvars.DelayedTraitsSystem and ETWCommonFunctions.checkDelayedTraits("Mechanics")) then
player:getTraits():add("Mechanics");
ETWCommonFunctions.applyXPBoost(player, Perks.Mechanics, 1);
ETWCommonFunctions.addRecipe(player, "Basic Mechanics");
ETWCommonFunctions.addRecipe(player, "Intermediate Mechanics");
if notification == true then HaloTextHelper.addTextWithArrow(player, getText("UI_trait_Mechanics"), true, HaloTextHelper.getColorGreen()) end
end
if SBvars.DelayedTraitsSystem and not ETWCommonFunctions.checkIfTraitIsInDelayedTraitsTable("Mechanics") then
if delayedNotification() then HaloTextHelper.addTextWithArrow(player, getText("UI_ETW_DelayedNotificationsStringAdd")..getText("UI_trait_Mechanics"), true, HaloTextHelper.getColorGreen()) end
ETWCommonFunctions.addTraitToDelayTable(modData, "Mechanics", player, true)
end
end
end```
nearly everything to do with players is client-sided so you usually don't need to actually transmit things you do to players
just gives player a trait
yeah you can just do that on the client fine
I already got it on the client, but if I wanna fire it
local Commands = {}
---@class EngineCheckArgs
---@field vehicleID number
---@field conditionBefore number
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
local vehicle = getVehicleById(args.vehicleID)
local part = vehicle:getPartById("Engine")
if not part then return; end
if detailedDebug() then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. part:getCondition()) end;
--- here <----------
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'ETW' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)
can i do that?
ah, yeah, you'd need to trigger it with a server command
sigh
btw if I do something with player moddata on server (for example, in that checkEngine command, since we do pass player as one of args), it works ye? or do i need to send stuff around even then?
nope, player moddata is unsynchronised

and only the moddata on that client is the one that saves
so usually using player moddata from other clients/the server is not worthwhile
Wait but when I was testing this
local original_oneat_cigarettes = OnEat_Cigarettes;
---Overwriting OnEat_Cigarettes here to insert ETW logic catching player interaction with cigarettes
---@param food any
---@param character any
---@param percent any
function OnEat_Cigarettes(food, character, percent)
if isClient() or (not isClient() and not isServer()) then
if detailedDebug() then print("ETW Logger | OnEat_Cigarettes(): detected smoking") end
local modData = character:getModData().EvolvingTraitsWorld;
local smokerModData = modData.SmokeSystem; -- SmokingAddiction MinutesSinceLastSmoke
local timeSinceLastSmoke = character:getTimeSinceLastSmoke() * 60;
if detailedDebug() then print("ETW Logger | OnEat_Cigarettes(): timeSinceLastSmoke: "..timeSinceLastSmoke..", modData.MinutesSinceLastSmoke: "..smokerModData.MinutesSinceLastSmoke) end
local stress = character:getStats():getStress(); -- stress is 0-1, may be higher with stress from cigarettes
local panic = character:getStats():getPanic(); -- 0-100
local addictionGain = SBvars.SmokingAddictionMultiplier * (1 + stress) * (1 + panic / 100) * 1000 / (math.max(timeSinceLastSmoke, smokerModData.MinutesSinceLastSmoke) + 100);
if SBvars.AffinitySystem and modData.StartingTraits.Smoker then
addictionGain = addictionGain * SBvars.AffinitySystemGainMultiplier;
end
smokerModData.SmokingAddiction = math.min(SBvars.SmokerCounter * 2, smokerModData.SmokingAddiction + addictionGain);
if debug() then print("ETW Logger | OnEat_Cigarettes(): addictionGain: "..addictionGain..", modData.SmokingAddiction: "..smokerModData.SmokingAddiction) end
smokerModData.MinutesSinceLastSmoke = 0;
end
original_oneat_cigarettes(food, character, percent);
end
which is server function (I think??? It's in server folder) it was working as expected
even though i edit moddata in it
your function includes a check so that it can never run on the server
wait so does it work in multiplayer?
yeah
sorry im not sure how this whole server thing works
this is a fairly annoying part of reading vanilla code: most of the stuff in the server folder is literally just client code
like most of it doesn't even run on the server at all
and you saying i cant edit moddata in my commands cuz commands are actually ran on server, ye?
yeah
OnEat callbacks are only called on the client that eats the item
Got a suggestion on which file to take a look at in regards sending back info to client?
oh wait I found it, it's like 2 commands
if not isClient() then return end
local ServerCommands = {}
local Commands = {}
Commands.player = {}
Commands.player.setWeight = function(args)
getPlayer():getNutrition():setWeight(args.weight)
getPlayer():getNutrition():setCalories(1000)
end
Commands.player.syncWeight = function(args)
getPlayer():getNutrition():syncWeight()
end
ServerCommands.OnServerCommand = function(module, command, args)
if Commands[module] and Commands[module][command] then
local argStr = ''
for k,v in pairs(args) do argStr = argStr..' '..k..'='..tostring(v) end
print('received '..module..' '..command..' '..argStr)
Commands[module][command](args)
end
end
Events.OnServerCommand.Add(ServerCommands.OnServerCommand)

sendClientCommand sendServerComman OnServerCommand OnClientCommand
discord trippin
so, this is my server
local debug = function() return EvolvingTraitsWorld.settings.GatherDebug end
local detailedDebug = function() return EvolvingTraitsWorld.settings.GatherDetailedDebug end
local Commands = {}
---@class EngineCheckArgs
---@field vehicleID number
---@field conditionBefore number
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
local vehicle = getVehicleById(args.vehicleID)
local part = vehicle:getPartById("Engine")
if not part then return; end
local condition = part:getCondition();
if detailedDebug() then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. condition) end;
local serverArgs = { repairedPercentage = condition - args.conditionBefore };
sendServerCommand(player, "player", "carRepairCheck", serverArgs)
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'ETW' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)
and this is my client
if not isClient() then return end
local debug = function() return EvolvingTraitsWorld.settings.GatherDebug end
local detailedDebug = function() return EvolvingTraitsWorld.settings.GatherDetailedDebug end
local Commands = {}
Commands.player = {}
---@class CarRepairCheckArgs
---@field repairedPercentage number
---comment
---@param args CarRepairCheckArgs
Commands.player.carRepairCheck = function(args)
if detailedDebug() then print("ETW Logger | Commands.player.carRepairCheck: args.repairedPercentage: " .. args.repairedPercentage) end;
end
Commands.OnServerCommand = function(module, command, args)
if Commands[module] and Commands[module][command] then
local argStr = ''
for k,v in pairs(args) do argStr = argStr..' '..k..'='..tostring(v) end
print('received '..module..' '..command..' '..argStr)
Commands[module][command](args)
end
end
Events.OnServerCommand.Add(Commands.OnServerCommand)
bit it wont print anything from client lua
Am I missing something?
As far as I understand 1st argument is IsoPlayer
From looking at LuaNet.lua, at least
hmm
are you testing in multiplayer?
no
yeah, sendServerCommand doesn't do anything in singleplayer
even though sendClientCommand does
wait so how do I update moddata then
i mean in singleplayer you don't need to send it to the client at all because the server is the client
but in multiplayer this looks like it should work
oh so I should do something like
local Commands = {}
---@class EngineCheckArgs
---@field vehicleID number
---@field conditionBefore number
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
local vehicle = getVehicleById(args.vehicleID)
local part = vehicle:getPartById("Engine")
if not part then return; end
local condition = part:getCondition();
if detailedDebug() then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. condition) end;
if isClient() then
-- update moddata here
else
local serverArgs = { repairedPercentage = condition - args.conditionBefore };
sendServerCommand(player, "player", "carRepairCheck", serverArgs)
end
end
Commands.OnClientCommand = function(module, command, player, args)
if module == 'ETW' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)
``` right?
yeah something like that
yeah
cheers
do I even need if not isClient() then return end at the top of my Commands lua in client folder?
I only put it there cuz vanilla file has it
it doesn't hugely matter
that mostly just stops the file from running if it's singleplayer
which doesn't really do anything since the command event doesn't get fired in singleplayer anyway, it just saves a tiny bit of memory
Hi guys, I have recently decided to get into moding this game but deciding where to start from is kind of a struggle for me
Are there any advice you could give me? Any templates and guides that I can follow?
~~Which line in .editorconfig is responsible for breaking down long lines?
It keeps breaking
if detailedDebug() then print("ETW Logger | Commands.player.carRepairCheck: args.repairedPercentage: " .. args.repairedPercentage) end
into 2 lines.
I've set max_line_length = unset in it but it doesnt change the behaviour.
Do you know which one by any chance?~~
Edit: nevermind, its not .editorconfig, idk whats doing it but not it
There should be some guides that someone will link (I don't have any). I recommend looking at existing mods and exploring their code, it helps a lot
Thank you a lot :)
Are there any particular mods that you have used for yourself? Heard that there is a mod template from kriger but there goes nothing having more than one example code
Depends what you wanna do. Do you have an idea for a mod that you wanna write?
Because making a trait is easy, making a vehicle is far from begginer task
As an example
Hmm, my final goal is to make a vehicle with all the models and such but I was thinking of starting with something much simpler like trait coding or small item additions that does not have complicated functionalities
Then grab a trait mod from workshop and dig in :) Preferably with least amount of content.
has a bunch of very simple traits
and few with actual game logic behind them
More Traits has a bunch of more advanced traits but the code is pain to look at, it needs major refractor
Evolving Traits World is my stuff, its very readable code and has a bunch of simple and complex traits and dabbles around in different game mechanics
Thank you a lot! Going to take a look :)
Does playSound() plays sound only for player to hear or do other ppl/zombies hear it?
https://zomboid-javadoc.com/41.78/zombie/characters/IsoGameCharacter.html#playSound(java.lang.String)
(I wanna play a sound for player only)
You're a godsend
<3
Just to double check, you said that if you SP server luas are pretty much run on client. Does this mean that IF the game is in SP I can run client code in server luas without problem?
yeah that's fine

in singleplayer there is no server and client, it's all one process - it doesn't use an internal server like some other games do
I see
Here's the finalized code in case someone will stumble upon need to send commands back and forth.
Overwriting original repair to send needed commands (this is client file)
local original_ISRepairEngine_perform = ISRepairEngine.perform;
---Overwriting ISRepairEngine:perform() here to insert ETW logic catching player doing engine repairs
---@diagnostic disable-next-line: duplicate-set-field
function ISRepairEngine:perform()
local detailedDebugOn = detailedDebug();
if detailedDebugOn then print("ETW Logger | ISRepairEngine:perform(): caught") end
local conditionBefore = self.part:getCondition();
if detailedDebugOn then print("ETW Logger | ISRepairEngine:perform(): conditionBefore" .. conditionBefore) end
original_ISRepairEngine_perform(self);
local args = { vehicleID = self.vehicle:getId() , conditionBefore = conditionBefore, detailedDebug = detailedDebugOn};
sendClientCommand(self.character, 'ETW', 'checkEngineCondition', args)
end
Server recieving commands (server .lua file):
local ETWActionsOverride;
local ETWCommonLogicChecks;
if not isClient() and not isServer() then
ETWActionsOverride = require "TimedActions/ETWActionsOverride";
ETWCommonLogicChecks = require "ETWCommonLogicChecks";
end
local Commands = {}
---@class EngineCheckArgs
---@field vehicleID number
---@field conditionBefore number
---@field detailedDebug boolean
---Function to check by how much engine was repaired. If singleplayer - updates relative moddata and checks traits. If Multiplayer - sends command back to client
---@param player IsoPlayer
---@param args EngineCheckArgs
function Commands.checkEngineCondition(player, args)
local vehicle = getVehicleById(args.vehicleID)
local part = vehicle:getPartById("Engine")
if not part then return; end
local condition = part:getCondition();
local repairedPercentage = condition - args.conditionBefore
if args.detailedDebug then print("ETW Logger | Commands.checkEngineCondition(): args.condition: " .. condition) end;
if not isClient() and not isServer() then
local modData = player:getModData().EvolvingTraitsWorld;
---@cast modData EvolvingTraitsWorldModData
modData.VehiclePartRepairs = modData.VehiclePartRepairs + repairedPercentage;
if args.detailedDebug then print("ETW Logger | Commands.checkEngineCondition(): modData.VehiclePartRepairs: " .. modData.VehiclePartRepairs) end;
if ETWCommonLogicChecks.BodyWorkEnthusiastShouldExecute() then ETWActionsOverride.bodyworkEnthusiastCheck() end
if ETWCommonLogicChecks.MechanicsShouldExecute() then ETWActionsOverride.mechanicsCheck() end;
else
local serverArgs = { repairedPercentage = repairedPercentage };
sendServerCommand(player, "ETW", "carRepairCheck", serverArgs)
end
end
...
...
Commands.OnClientCommand = function(module, command, player, args)
if module == 'ETW' and Commands[command] then
local argStr = ''
args = args or {}
for k,v in pairs(args) do
argStr = argStr..' '..k..'='..tostring(v)
end
Commands[command](player, args)
end
end
Events.OnClientCommand.Add(Commands.OnClientCommand)```
Client recieving commands from server (client .lua file):
if not isClient() then return end
require "ETWModData";
local ETWCommonLogicChecks = require "ETWCommonLogicChecks";
local detailedDebug = function() return EvolvingTraitsWorld.settings.GatherDetailedDebug end
local Commands = {}
Commands.ETW = {}
---@class CarRepairCheckArgs
---@field repairedPercentage number
---After engine was repaired on server side, client gets information from it and update relevant mod data and fire functions to check if player gets the trait.
---@param args CarRepairCheckArgs
Commands.ETW.carRepairCheck = function(args)
local player = getPlayer();
local modData = player:getModData().EvolvingTraitsWorld;
---@cast modData EvolvingTraitsWorldModData
if detailedDebug() then print("ETW Logger | Commands.player.carRepairCheck: args.repairedPercentage: " .. args.repairedPercentage) end;
modData.VehiclePartRepairs = modData.VehiclePartRepairs + args.repairedPercentage;
if ETWCommonLogicChecks.BodyWorkEnthusiastShouldExecute() then ETWActionsOverride.bodyworkEnthusiastCheck() end
if ETWCommonLogicChecks.MechanicsShouldExecute() then ETWActionsOverride.mechanicsCheck() end;
end
Commands.OnServerCommand = function(module, command, args)
if Commands[module] and Commands[module][command] then
local argStr = ''
for k,v in pairs(args) do argStr = argStr..' '..k..'='..tostring(v) end
print('received '..module..' '..command..' '..argStr)
Commands[module][command](args)
end
end
Events.OnServerCommand.Add(Commands.OnServerCommand)```
Ty Albion :)
Are there any tools or guides that help with creating mods?
is it possible to cause an explosion using a lua script?
Is there a way to stop VSCode from screwing up translation files encoding? It keeps resetting files to UTF-8 even when I save files in correct encoding
Makes me miss IntelliJ

Guys hi, I was working on replacing some of the games sound files such as zombie groans using mods
Is there a way to do it, if so can anyone help me do it?
i think this mod does that, i bet you could look at the files and figure how to do it
looks like you need to replace some stuff in (this is from the ws mods page):
u need find file ZomboidSound.bank and copy in Steam\steamapps\workshop\content\108600\2683001152\mods\media\bank
then open game local files ProjectZomboid\media\sound\banks\Desktop and paste ZomboidSound.bank
so i bet the thing youre looking for is there
hmm, so I think it is not possible to change every player's zombie groans using only mods without a change that is done by players?
yeah i mean probably
I see, thank you a lot!
Anyone? I can't copypaste 50 translation files every time I want to make an update 
Probably sumnekolua doing weird shit as always
Heyo. Looking to get into modding soon. I had two questions about support for something I'd like to make:
- Does PZ have any functionality for selecting a random room/random building/random container within room/etc.?
- Is there any support for disabling spawns in a specific room or building?
Appreciate any replies ๐
www.aseprite.org
ok, i like the UI. thanks
i can barely paint with a roller
i guess i'd need to shop goodwill for a drawing tablet
- Yes (tho you can't access the list of buildings so you can't retrieve them out of nowhere)
- Not sure
There's a mod that add truly random spawn of the player within any building
Oh interesting, so you can only retrieve a list of rooms, not buildings? Or you mean you need to know the building name to grab a random room from it?
You can retrieve the rooms within a building, or random pick one directly
You need to know the building
Ah okay cool. That's fine, I guess
Is there an explicit way to select a random building then? Like manually declaring an array of their IDs or something and rolling between them?
Appreciate the info btw!
I suppose I can take a look and see how they do it
I'm really not sure ngl ....
There is no list of buildings in the game
The only way to have a list of buildings is to load every area on the map and list every buildings in a table
And that's absolutely not doable
Hm, I see. I suppose I'm not looking for absolutely every building
So long as there's a way of looking up IDs of buildings on the map I think I'll be okay
I just want a little bit of variation, nothing crazy
I'm basically looking to make some lightweight lock-and-key stuff
In the vein of: find item in random location of police station in rosewood -> use it to unlock room in muldraugh police station -> find another item in that room -> take it somewhere in louisville
Etcetc
Huh... Looking at this mod: https://youtu.be/foe78LkXOzU
With this mod, zombies will now populate into a building once they enter you chunk, instead of when you see inside of the building.
Big shout out to "and Duck is the Game"! Modder's make good games great, breathing new life into them.
-- Get the Mod here --
https://steamcommunity.com/sharedfiles/filedetails/?id=2961467351
#projectzomboid
M...
Looks like zombies by default only spawn in buildings once you enter them?
Didn't know that if so
Can probably make for some good custom behaviour
yea
wdym ?
You can't
If it's something that can be overridden, then you wouldn't have to worry about where the player is
You can't
Oh. Damn, that's a huge shame
This thing was fixed with a java mod, that's it
Idk what you would expect to do with such a behavior in comparison to what you are trying to achieve ngl
One is about zombie spawn
The other is about spawning an item linked to another building
Are java mods harder to do?
Yes and they require manual installation
The truth is that you can't access any building if the area they are in is not loaded by the client
I just want to create some extremely lightweight questing for singleplayer, similar to Wolf Extraction
Well, whatever is easiest I guess
I was, at first, hoping to choose a random room between a few buildings
I was hoping if those two things I mentioned were possible, I could:
- clear out a room so a static npc could be put there with some dialogue
- choose a random room from a list to spawn a fetch-quest item
You can set a few selected building yeah
You can simply store coordinates of the building and retrieve the building at those coordinates once it's loaded in
Oh cool. That sounds convenient
Then you can chose a room randomly, which is extremely easy to do
So what you can do is:
- Store coordinates of a few selected building
- Chose randomly in the list a building that the player will have to get the key from
- Every minute or 10 minutes, get the square at these coordinates, check if square exists, it means it's loaded
- Get the building
square:getBuilding() - get a random room in the building
building:getRandomRoom() - get containers in this room
room:getContainer() - chose a random container
- spawn the key in it
byotiful. thanks for the rundown. will save this
On top of that you can most likely add a marker on the player map
I suppose I would have to go with static locations for NPCs. It's a shame you can't override the OnLoadedBuilding function or whatever it would be called, because then you could make sure the quests have some locality
Oh is that supported? Nice. Was hoping so
I think so ? Or you could just make a custom map possibly
I've seen there's already a framework for making static npcs that can talk. I'm not even particularly interested in making portraits and multiple choices and all that - I just want a dude standing in a room with text that appears above their head, pretty much
and the trigger to spawn loot in x location
but if it's possible to add a map marker that would be a huge bonus
ooh. yoink
@bright fog , how you doin'? Would you help me with an event? I'm trying to find an event or something related to catch when the player select an item ou multiple items with shift ou ctrl (Only inside the inventory panel). Is there anything like that ?
PS.: I need this to store the items in a variable and then perform an action.
No idea
Why me ?
Does anyone know if it's possible to mod in new "zone events"?
Wow thats really useful. I managed to get the perk working in the end using my original code after fixing my mod.info file. Now I've got other little issues that I'm ironing out, but I'm sure I'll get it working at some point ๐
Like the helicopter? Yes. There is a sniper event on workshop. I would ask the developer for more info.
I think that is a meta event? I more meant stories like the fishing trip
How hard would it be to make npc's with some sort of chat gp governing their dialogue?
chat gpt? that's actually a fascinating question lol
It's not the type of thing I'm looking to make, but would love to see it done
Thanks, I know I seen someone make npcs in Skyrim the ability to use some sort of form of ai generated dialogue
I think there are already a bunch of tools out there for packaging chatgpt prompts in several languages, so if there's a way to trigger external code from zomboid's lua, maybe
or if you can replace java files
Yeah I've seen that too. Very cool
Wow that doesn't sound like it's too far off from a possibility
What mods do u make? @light crater
None yet - I've just arrived ๐
I'm a game developer by occupation though
https://pzwiki.net/wiki/Randomized_stories This is what I was referring to by the way
It seems like a fantastic system, and I had no idea it existed
Nice im new here too, joined so I could learn how to host my modded server and make my modlist perfect
I thought the reason that 99% of the mods on steam being items/vehicles/content was that's what people enjoy adding, but starting to wonder if mod support is part of the reason lol
oh nice. how's that goin?
Well, I'd say about 25-40% of them are working, ive got alot of research to do lol
what about the skill panel. did it auto show up? or do you still need to code that part?
you don't need to do any weird code to add skills
you just write a skill script and it's there
wow thats good to know
the only things you need lua for are, you know, making it do something and giving xp for it
yep and adding exp would be the same way i assume? and would also trigger the Level event?
yeah
Ah fair. Does sound like a pain getting mods to play fair
Some people seem to have that as a hobby in itself
Enjoying the experience of getting mods to work more than playing them lmao
Sounds like I've got a new hobby. Maybe I can put mod tester on my resume now. Lol.
Actually, yes
Too many people don't use their personal experiences and skills they've developed outside of their job
Depending on the job you apply to, it can be even more important
Yup! It just shows up automatically, it was fairly simple in the end
This was the final code, though I'll have to put xp that makes sense
Interesting, it's just a script file ?
Hey I had a quick question for everybody. Is there any way to add admin commands inside of weapons?
Basically trying to see if itโs possible to make a teleporter gun, so you can use it specifically to return to your safe house
yep it worked
im doing a rank mod that is based on the vanilla perks only and doesnt include the parent perks
thats doable
use weaponswing event
then on the function check the weapon if its the mod weapon you want to assign the function
then do the teleport command
might need to uncheck some anticheats tho
anyone have experience adding more than one context menu option to a single item
I can't figure out what I've done wrong, and the errors keep saying "is not a valid parameter"
I defined it in ContextMenu_EN and both contextmenu options are included in my items.txt
Show code
ContextMenu_EN = {
ContextMenu_JYTsnus_popjyt = "Pop an uppy decky",
ContextMenu_JYTsnus_popdoublejyt = "Pop a double decky",
}```
CustomContextMenu = JYTsnus_popjyt, JYTsnus_popdoublejyt,```
@bright fog
require "TimedActions/ISBaseTimedAction"
local _Food = nil;
local _Character = nil;
local _Percent = nil;
local _hoursCount = 2;
function OnEat_Smokeless(food, character, percent)
_Food = food;
_Character = character;
_Percent = percent;
OnEat_Cigarettes(_Food, _Character, _Percent);
local curWeight = _Food:getWeight();
curWeight = curWeight - .01;
food:setWeight(curWeight);
food:setActualWeight(curWeight);
food:setCustomWeight(true);
if(math.floor(curWeight * 100) <= 0) then
local usedItem = food:getContainer():getParent()
food:getContainer():Remove(food)
end
end
function OnEat_DoubleUppyDecky(food, character, percent)
_Food = food;
_Character = character;
_Percent = percent;
OnEat_Cigarettes(_Food, _Character, _Percent);
local curWeight = _Food:getWeight();
curWeight = curWeight - .02;
food:setWeight(curWeight);
food:setActualWeight(curWeight);
food:setCustomWeight(true);
if(math.floor(curWeight * 100) <= 0) then
local usedItem = food:getContainer():getParent()
food:getContainer():Remove(food)
end
end
function HandleContextMenu(option, food, character)
if option == "JYTsnus_popjyt" then
OnEat_Smokeless(food, character, 1)
elseif option == "JYTsnus_popdoublejyt" then
OnEat_DoubleUppyDecky(food, character, 2)
end
end
Events.OnFillInventoryObjectContextMenu.Add(HandleContextMenu)
@bright fog
Thats actually pretty cool!
Where did you define your options ?
I'm not familiar with inventory context menu so I'm not sure what OnFillInventoryObjectContextMenu is triggered by
Are options defined in the script item ?
If I uncheck the anti cheats can I prevent people from being able to use the teleport command without the item? Like Iโd like to have the teleport gun but Iโd also like it so if you donโt have it, you canโt just use the teleport to safe house anyways
how will they do that?
the anticheat will disconnect the player
Well does it mean itโs at least limited to admins only otherwise right?
Like either that tool or the admin console?
Not sure I understand here, you have an item to teleport somewhere, you want only admins to be able to use it ?
For that you can simply have the function triggered when using the weapon to check if the player is admin and then TP them, else don't
Deactivating the anti-cheat for teleporting is necessary, it just means if any players has a mean of teleporting, be it feature or cheat, they won't be detected and kicked
So you make the server a little bit more vulnerable to teleportation cheats but that's it
Oh gotcha
Im being confusing my bad.
Essentially I want one of two conditions:
Admin to use the teleport commands if they choose to.
Otherwise any player can combine: remote control, with a battery and a scrap electronic to make a one use teleport to safe house tool usable by any player.
Only two conditions I would like though, Iโd rather not have the average player be able to hit teleport just whenever
for the combine remote thing you need to create recipe scripts
flr the admin to have the ability to use it while preventing players from using it, you just need to do a check if the player is admin then allow it use the function
you can even do the item interaction via recipe too so that it would be easier since youre already there.
you then need the checkee function to determine if player has safehouse and then get the safehouses coordinate
then the teleport function
sorry im afk so i cant provide snippets en
these are the lua files that contain teleport related syntax
heres for the safehouse
declaration: package: zombie.iso.areas, class: SafeHouse
goodluck
Hey guys, any easy way to retrive the current attached backpack ? I know that if use getPlayerInventory(0).inventoryPane.inventoryPage.backpacks should return a list. But I want just the attached to back container...
I found it:
player:getClothingItem_Back();
Within the scope of zomboids api to force disconnect then reconnect a client to another server?
most similar thing I can think of is a proxy like bungee for minecraft but skipping the middleman of well, a proxy
ie:
-Server A sends disconnect signal to client with installed mod
-Client is kicked from server A
-Client connects to server B without connection menu or any manual input
I hazard a guess that you can check out main menu code to see how the join screen works and use similar code.
the specific logic for selecting alternate servers is up to you
I just wanted to say thank you so much and Iโm going to try to figure it out. I really want to add a โportal gunโ to the game because me and my friend were playing this weekend and it was probably the most used action I wished for. Not really true lore obviously but gameplay wise it was perfect, and I think with some high barrier of cost it could be a cool get out of jail free card.
I also wanna do rolling stats eventually. Losing all your stats is absolutely depressing and even if it doesnโt fit the lore of being a new person, itโs just frustrating and Iโd love to change it on a personal server.
But thank you so much for all your help! Iโve been at work so Iโve been slow to respond too.
Yeah, I got that down
essentially trying to recreate foxholes map system and split the map into two seperate servers to surpass the 127 hardcoded player limit
Server that can gather more than 100 people exist?
Like, capable of find such amount of people that can play at one time.
yeah one of em is aftermath server
https://www.youtube.com/watch?v=q0mgNQlOs1E&t=623s
I trapped 100 players in a zombie-infested mall, how will they survive? Will they share and ration their limited supplies? Or just turn this mall into a mass graveโฆ
Check out my other civilization video/Project Zomboid channel! - https://www.youtube.com/@HarvestZ
Join my event discord to play in events like these! Apply to play in events in t...
nurse also hosts 100 players events
is it possible to force, via mod, the duration of some conditions such as stress, fatigue, stomachache, etc. etc.???
or apply negative traits or take away exp??
yes all of those
i would recommend looking at the general debugger panel
it has all of the options for the stats
for injury refer to the health menu cheat
it allows admins to right click then generate injury or heal it
so it should have all the syntax you need
as well as examples as to how you apply them
thanks I'll try as you suggest! I've never done it....I'll get busy ๐ thanks a lot
did anyone have a problem where their model and icon dont show up in game?
i dont know what i did wrong
for icons you should name them with prefix Item_
if the icon youre refering to is for inventory items
Icon = Item_Crossbow,
something like this?
yeah but i suggest you add something to that
cuz something generic as Crossbow will sure to overwrite some stuff from other mods
its a placeholder dont worry
you dont add "item_" to Icon= in script file, thats only needed for image file.
still fixed my issue tho
how do i get the model to work?
There is few things that could go wrong, but i just got here and i dont see you posting anything model releated?
yeah i just got to that problem
what should i send/
i scaled the model down and applied location and rotation
is it invisible without textures?
also is it possible to export a .blend file as a .x file in blender 3.6?
how do mod makers export their models as .x files?
the model doesnt appear in game
Do not use X files... Game supports FBX and most modders encourage to use them.
every mod uses .x files tho
the fbx file also doesnt work
the model either inst there or its invisible
Many mods i use do use fbx, i myself use fbx models in my mods. FBX do work. Do you use debug mode to see if you maybe get errors in console about your model?
invisible model
is it because i have no textures?
if i add a black square as textures will the model be visible?
oh really
you can put the prefix in the script too? i didnt know that
sorry i forgot to tell you not to put the prefix on the script but atleast it worked and we all learned something
yeah im the only one who prefers x files
cuz i dont have to restart the game everytime i make changes
Im pretty sure most of fbx files will actually reload
both for models and animations
i saved alot of time cuz of x files
i hate restarting the game all the time
Unless its complex i think?
nope
well maybe you know something i dont
how do you reload it? is there a way to do it?
that will also be useful
idk
ive tried before didnt reload
both models and animation cases
It does it by itself, but i belive if you have lots of mods enabled, even in menu, it wont work, at least not as fast.
Animations in fact do reload in like few seconds
oh and xml files for anim also reloads
but not sure abt clothing
Yeah, xml and fbx animations reload pretty much in a few seconds
i dev isolated anyways
only other mod thats running is my personal debug tool mod
Models thought not always, but as i said its probably due to compelxity of model/ amount of mods loaded or other things im not aware of
so any idea why my models are invisible?
What is your model? Gun?
ok then
i guess something went wrong before when it didnt do that for me
owell now i know
maybe the size
import another model and compare them
already imported a m16 from base game
Why do you have no texture?
didnt make it yet
Now think why its invisible, if it has no texture
i asked this question two times 
Well sorry to not read everything everytime on every discord server
Try that black square or use any texture
You could also show actuall model in blender or wherever
now we know why it wont show up lol
This has been amusing to witness
hello guys, who can help me with creating car mod?
can I provide argument when making an event?
for example,
local function catEyes(isKill)
local isKill = isKill or false;
end
Events.EveryOneMinute.Add(catEyes)
Events.OnZombieDead.Add(catEyes(true))```
will something like this work?
Events.OnZombieDead.Add(function() catEyes(true) end)
albion to the rescue as always

ty
just to make sure if its called without argument from EveryOneMinute, isKill is going to be nil, right?
aka false based on a snippet above
yeah
cheers
to remove it I don't need to outline arguments, right? name is enough as in other cases, ye?
aka
---Function responsible for setting up events
---@param playerIndex number
---@param player IsoPlayer
local function initializeEventsETW(playerIndex, player)
Events.EveryOneMinute.Remove(catEyes);
Events.OnZombieDead.Remove(catEyes);
if ETWCommonLogicChecks.CatEyesShouldExecute() then
Events.EveryOneMinute.Add(catEyes)
Events.OnZombieDead.Add(function() catEyes(true) end);
end
...
end```
you need to store that function if you want to remove it later
Events.OnZombieDead.Remove(catEyes) doesn't work because you never added catEyes to that event, you added this function function() catEyes(true) end
oh
OOOH
I get it
cheers
gonna leave this here for someone to stumble on
---Function responsible for managing Cat Eyes trait
---@param isKill boolean
local function catEyes(isKill)
local isKill = isKill or false;
...
end
---Helper function to fire catEyes() on zombie kill
local function catEyesKill()
catEyes(true);
end
---Function responsible for setting up events
---@param playerIndex number
---@param player IsoPlayer
local function initializeEventsETW(playerIndex, player)
Events.EveryOneMinute.Remove(catEyes);
Events.OnZombieDead.Remove(catEyesKill);
if ETWCommonLogicChecks.CatEyesShouldExecute() then
Events.EveryOneMinute.Add(catEyes)
Events.OnZombieDead.Add(catEyesKill);
end
...
end
@bronze yoke @dull moss, I'm new modder, trying to develop a QoL mod, I already decompiled pz code etc. But I still have some questions because is very hard to understand somethings, do you mind if I need to send those questions in particular ?
lol hahahah
40s read, highly recommend ๐
Is there a better way of firing a function when a client kills a zombie? Currently all I can think of is OnWeaponHitCharacter and checking if its zombie and if damage is enough to kill a zombie
ive hosted 110 player everts, so yes it is possible
Ok let's try:
- How am I declare a dependency mod, I am going to use ModOptions, is it on mod.info file?
- I did Events.OnKeyPressed.Add(KeyUp), to create new keybind, is there an event correlated to MouseButtons ?
- Could you please explain more how I use the Debug menu (F11)?? I managed to put a breakpoint e see some locals variables, but I think it has more to learn...
- About Lua: Is there a difference between getPlayerInventory(0).inventoryPane.selected and getPlayerInventory(0):inventoryPane:selected ?
These are some question, I really appreciate if anyone answers ๐
use OnZombieDead - you can check who killed the zombie with```lua
local player = zombie:getAttackedBy()
if not player or not player:isLocalPlayer() then return end
Example of modinfo
poster=poster.png
require=MoodleFramework,KillCount,modoptions,TchernoLib
url=https://steamcommunity.com/sharedfiles/filedetails/?id=2914075159
id=EvolvingTraitsWorld
versionMin=41.78
modversion=8.1.1
icon=icon.png
description=Makes majority of vanilla traits dynamic (meaning you can earn them as you play). Additionally, adds a few traits, making all of them (optionally) dynamic.
authors=MusicManiac```
for 4, the difference is the latter is not valid syntax and won't compile ๐
you can only use : for declaring/calling functions, because its purpose is to implicitly pass/declare self as an argument ( myObject:function() is equivalent to myObject.function(myObject))
for 3, look at OnMouseDown, OnMouseUp, OnRightMouseDown, OnRightMouseUp
- I saw some mods using
ISTimedActionQueue.add(ISInventoryTransferAction:new(player, item, item:getContainer(), back))to move items between containers. But can I use thefunction ISInventoryPane:transferItemsByWeight(items, container)? For me its a way to not repeat and reuse code...
But what if I want to get Mouse4Button, is it possible ?
no idea but that probably fires the keyboard event
yes, they are basically equivalent
considering key binds wont register mouse4 or any other bonus mouse buttons I'm not sure
oohh really thanks albion ๐
im using mouse software to be able to bind my bonus mouse keys 
Oh, actually, while you're here, albion, did you ever have this problem in VSCode?
#mod_development message
To prevent VS Code from automatically switching your files to UTF-8 (even when youโve painstakingly saved them in the correct encoding), follow these steps:
Open User Settings:
Click on โFileโ in the top menu.
Choose โPreferencesโ and then โSettings.โ
Alternatively, you can use the shortcut Ctrl + , (or Cmd + , on macOS) to open the settings directly.
Add or Update the Encoding Setting:
In the settings search bar, type โfiles.encoding.โ
Youโll see an option called โEditor: Default Encoding.โ
Click the โEdit in settings.jsonโ link next to it.
Add (or update) the entry to specify your desired encoding. For example:
JSON
"files.encoding": "windows1252"
AI-generated code. Review and use carefully. More info on FAQ.Replace "windows1252" with the encoding you want (e.g., "utf8" or "iso88591").
Save the settings file.
Now VSCode Will Respect Your Choice:
With this setting in place, VS Code will open all text files using the specified encoding (in this case, Windows-1252) when thereโs no explicit encoding information set in the file.
No more surprisesโyour files will stay put in the encoding youโve chosen! ๐
i remember not really being able to save files with the right encoding but i don't write the non-english translations myself anyway
if you think I didnt try chatgpt you'd be wrong. I need 3 different encodings, not 1
neither do I, they jsut send me translation files
but IDE keeps bricking them
why are you re-saving them?
ok man, just trying to help...
Mostly formatting and stuff, sometimes change a number in translations, stuff like that
Is there an Indie Stone dev that could explain to me the ZomboidRadio class? I am guessing it's recording every radio either put on the Iso grid of in a vehicle so we can iterate over them and it writes the content in a RADIO.TXT file to keep the cache persistent after a reboot. But when I tried to use it getDevices() had 0 member.
I'm curious. Why do you need something else than UTF-8?
My translation files are being weird
non-english language files are saved in different encodings
- The events are badly named, the OnKeyStartPressed is for a key pressed and OnKeyPressed for a key released.
Events.OnKeyStartPressed.Add(yourMethodOnKeyPressed)
Events.OnKeyPressed.Add(yourMethodOnKeyReleased)
- It's bad, basically. ๐ฌ
:is a syntactic sugars, writinga:method()is exactly the same asa.method(a). The object is passing its own value as a first parameter of the function. This is to emulate Object Oriented Programming.
Which ones? Why? What happens if you save them in UTF-8?
if you save them in utf-8 the game will still try to interpret them as their correct encoding resulting in the wrong characters

i don't know which ones exactly but iirc it's pretty much anything that uses non-roman characters
It's good to know, and a little infuriating at the same time :'D
Would you know how to ask questoins to Indie Stone devs?
^
@inland gull Could you help me with this or redirect me to a dev who worked on this?



