#mod_development

1 messages ยท Page 259 of 1

grizzled fulcrum
#

like ```json
{
"Lua.diagnostics.enable": false
}

#

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/

grizzled fulcrum
#

because tehre's no way in vscode to disable an extension for a workspace folder specifically, only per-workspace

grizzled fulcrum
dull moss
dry chasm
# dull moss tried this too
    "Lua.workspace.ignoreDir": [
        "lua",
        ".vscode"
    ],
    "Lua.diagnostics.ignoredFiles": "Disable",
```works on my end
dull moss
#

Am I doing something wrong?

#

its whatever

#

fuck it

#

I'll just have it in separate window

dry chasm
#

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)

dry chasm
#

did you give it time to refresh diagnostics? (It does it automatically upon saving said file on my end, did take a few seconds)

dull moss
#

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 HUH

#

Umbrella on both sides

dry chasm
bronze yoke
#

was umbrella definitely enabled for this workspace? you need to enable it in each one if you aren't aware

dull moss
#

SumnekoLua on both

dry chasm
dull moss
#

And yes umbrella is on, just re-enabled it to make sure

dull moss
#
  • same warn on top
dry chasm
dull moss
#

Oh ffs why is that enabled

#

Your usual stupid Clueless

#

wait because of that it was probably fucking up my problems

dry chasm
#

Guess your issues are solved. For now spiffo

dull moss
#

Only costed me half of my sanity and unnessesary bothering of good ppl in here PepeLaugh

dry chasm
dull moss
#

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 PepeLaugh

dull moss
#

@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

dull moss
#

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
ancient grail
#

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

ancient grail
dull moss
#

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```
ancient grail
#

oh so being bloody is a booster
nice

dull moss
ancient grail
#

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

dull moss
#

Moodle framework is goated

muted garnet
#

@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?

ancient grail
#

the trait idea is good cuz they can see it
but moodles should be better

ancient grail
muted garnet
ancient grail
#

check out goose zed mod

dull moss
muted garnet
grizzled fulcrum
#

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?

muted garnet
#

@grizzled fulcrum


Heli.getHelicopter = function (x,y,z,radius,volume,soundSource)

   print(soundSource)
end

Events.OnWorldSound.Add(Heli.getHelicopter)

print's nil

grizzled fulcrum
#

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

muted garnet
#

not working

grizzled fulcrum
#

rip idk then

muted garnet
#

Thanks for your time

rugged vigil
#

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

ancient grail
#

slr

#

there are extra entries that doesnt even get triggered btw
i didnt filter it neatly

muted garnet
# ancient grail yep

do you know how else to get the helicopter object or the helicopter event start time?

ancient grail
#

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

muted garnet
#

Got it, do you have any other ideas on how to find out if there is a helicopter event at the moment?

karmic mesa
#

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)```
ancient grail
muted garnet
ancient grail
bronze yoke
karmic mesa
ancient grail
#

ahh you can have them join the factions automatically
and hook on the leave button so they cant disband

rugged vigil
#

just from looking through some other mods

vague dragon
#

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!

ivory fractal
#

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?

ancient grail
ivory fractal
#

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

ancient grail
#

i havent seen anything like this ngl

#

it looks like sandbox enum but the again its not

#

what are you trying to build

ivory fractal
#

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

ancient grail
#

cool i didnt know thats how you add perk

and so now youre problem is that you cant see it?
but is it there?

ivory fractal
#

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

ancient grail
#
print(getPlayer():getPerkLevel(Perks.BrickLaying))
#

try that via debug

#

if it prints out something then it worked

ancient grail
ivory fractal
#

Ah yeah it printed out level 0, so I guess it is in there. Must be a UI issue

ancient grail
#

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

ivory fractal
#

Is bricklaying in the game?

ancient grail
#

nope what i mean is

#

try if it errors

ivory fractal
#

ah

ancient grail
#

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

ivory fractal
#

hmm no if I just use "x" it also says 0

ancient grail
#

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

ivory fractal
#

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

ancient grail
#

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..

ivory fractal
#

Yeah it's my first mod. I'm not sure how to do something much simpler than adding an item haha.

ancient grail
#

you can use already made assets and just change texture and stats to begin with

ivory fractal
ancient grail
#

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

ancient grail
ivory fractal
#

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

ivory fractal
ancient grail
#

best of luck to you !

ivory fractal
#

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

ancient grail
#

happens all the time

tulip valve
#

Is there a mod that lets you sit and shoot? pepeafraid

karmic fog
#

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?

upbeat birch
#

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?

dull moss
#

@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

upbeat birch
#

thank you

prisma gale
#

Anyone managed to crack the pain system ? Canโ€™t seem to get setPain, setPainReduction to have any effect on reducing pain

primal tendon
#

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

ancient grail
blissful inlet
#

how do I mod in occupations

pine patio
blissful inlet
#

got it

inner cobalt
#

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)

grizzled fulcrum
#

I thought corpse mod data is persistent :/

bronze yoke
#

me too but i guess it kind of makes sense if it isn't for zombies?

grizzled fulcrum
#

I thought they might've wanted to store corpse mod data for special events or other things, idk

bright fog
inner cobalt
#

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.

bright fog
#

also code block please

inner cobalt
#

@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) ```
bright fog
#

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

silk pike
#

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 โ˜บ๏ธ

bright fog
# dull moss ```lua if bloodlustModData.BloodlustMeter >= 18 then -- gain if above 50% ...

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
dull moss
bright fog
#

np ๐Ÿ‘Œ

#

Ok thx for the answer

dull moss
#

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

bright fog
#

Yeah that's the way to do it, good stuff ShibaThumbUp

#

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 ?

dull moss
#

Anywhere between one minute and one day

#

And one onTick

#

But that's only if u have a trait

#

That locks your pain level

bright fog
#

Good stuff too ShibaThumbUp

bronze yoke
#

now for the real test: do you actually benchmark it

bright fog
#

I don't

#

Bcs I have no fucking idea how you do that

bronze yoke
#

how do you know you optimised anything?

bright fog
#

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

dull moss
#

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

bronze yoke
#

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)

bright fog
#

Yeah it's one of the many rules I try to apply

bronze yoke
#

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

bright fog
dull moss
#

Nah, put function in this

bright fog
#

oh

dull moss
#

To see how much time it takes to run it 1 mil times

bright fog
#

What if I can't run the function that way

#

Everything involves throwing a zombie in my functions or smthg related to it lol

bronze yoke
#

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

bright fog
#

Okay I'll try to look at that a bit later when I have time

bronze yoke
#

i think i wrote an automatic module profiler at some point but i'd have to give it another look over

bright fog
#

๐Ÿ‘Œ

#

I'm sure a guide or tools to benchmarking will be more than useful for the community

bronze yoke
#

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

bright fog
#

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

drifting ore
bronze yoke
#

read above, this is for when you can't

drifting ore
#

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)

bronze yoke
#

luckily we're benchmarking a scripting language and errors at that scale are not worth thinking about

drifting ore
#

you specifically said the issue is that you might need a high resolution timer

bronze yoke
#

you might need higher resolution than this

#

it's very poor

drifting ore
#

higher resolution than this is dominated by OS timing noise

bronze yoke
#

most function calls return literally 0

drifting ore
#

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.

drifting ore
drifting ore
bright fog
drifting ore
#

if you measured the execution speed, then that's not an assumption anymore ๐Ÿ˜›

bright fog
#

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

drifting ore
#

A useful feature Kahlua has that standard Lua does not have is array tables.
Well that's just not true.

bright fog
#

@bronze yoke

bronze yoke
#

i'm not sure what point you're trying to make here

#

lua has tables ๐Ÿคฏ

drifting ore
#

regular lua has separate integer table part for faster access

bronze yoke
#

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

drifting ore
#

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.

bronze yoke
#

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

stoic kayak
#

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?

bronze yoke
#

no unhappy

#

about 100 squares but it can supposedly vary

stoic kayak
#

Vary to more or less-

bright fog
#

Server is 50 I believe

stoic kayak
#

*I was hoping to be atleast 64 ๐Ÿซ  *

bronze yoke
#

no idea, i just always see people saying that it can scale with resolution or whatever, never seen any actual testing indicating it

bright fog
#

No idea

stoic kayak
#

Well, 128x128, and maybe I can make it display if any cells were nil

bright fog
#

What are you trying to do ?

stoic kayak
#

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

drifting ore
stoic kayak
#

Oh I could also make it acutally do- like- survival friendly I guess?

bright fog
stoic kayak
bright fog
#

Yeah

#
-- check square exists
if square then
    -- do your thing
end
stoic kayak
#

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

drifting ore
bronze yoke
#

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

stoic kayak
#

I am confused what a cell and square are-

bronze yoke
#

that's okay, the game's developers are too

drifting ore
#

1x1

stoic kayak
#

but when what is a cell

bronze yoke
#

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

stoic kayak
#

OHH

drifting ore
#

cell is an area around the player that contains loaded chunks, which contain loaded squares

bronze yoke
#

the IsoCell object isn't a 'map cell' but the current loaded area, the name is like that for legacy reasons

stoic kayak
#

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

bronze yoke
#

you can reload individual files from the lua debugger (f11)

stoic kayak
#

Actually now would be the perfect chance to use debug mode instead of my fake debugger mode

drifting ore
#

depending on what you do reloading individual files it's not always useful though

bronze yoke
#

i personally almost never use file reloads

#

they're highly unreliable for most practical cases

stoic kayak
#

How do I add debug as a game again- xd

drifting ore
#

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

stoic kayak
#

Do I have to make a bat file or just add steam game on the exe-

bronze yoke
#

you can just add the game's exe as a steam game

drifting ore
stoic kayak
#

I am, but I heard ya can have a seperate thing on steam to boot into debug mode

#

via adding non steam game

bronze yoke
drifting ore
bronze yoke
#

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

drifting ore
#

i recall there was a proper way to make a development environment

#

with entirely separate saves and whatnot

bronze yoke
#

yes, i recommend launch options like these -debug -cachedir="C:/Users/albion/ZomboidDebug" -modfolders mods,workshop

stoic kayak
#

The button sprites dont appear when I first load the game <.<

drifting ore
#

yea that'll happen if you crash faster than the game loads haha

stoic kayak
#

not a crash, just seems to be an error x3

drifting ore
#

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

drifting ore
bronze yoke
#

yes - so it's different

drifting ore
#

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.

stoic kayak
#

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

drifting ore
stoic kayak
#

So, obj can just be set to sq:getFloor()?

drifting ore
#

I don't know but it might be.

stoic kayak
#

what would be a no

stoic kayak
#

I wonder if ClearTileObjects() would work-

#

no

#
void ClearTileObjects()
 
void ClearTileObjectsExceptFloor()

??????

stoic kayak
#
local obj = sq:getFloor()
sq:DeleteTileObject(obj)```
#

this seems to work. Prob don't need to be setting a local

stoic kayak
#

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

drifting ore
#

by the time you make the code that does it, making a menu extension is very trivial

#

because the actual code is already done

stoic kayak
#

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

drifting ore
#

seems like boilerplate code, which means you can add it in a loop from a table

stoic kayak
#

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?

drifting ore
#

you can use any mod code from any other mod

stoic kayak
#

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

scarlet geode
#

is there some func that gives me the type of userdata?

bronze yoke
#

you can use instanceof(obj, "ClassName") to test type

scarlet geode
#

ill try next time
turns out tostring does exactly what i need
didnt really expect it to work but it actually did xd

vast nimbus
#

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?

vast nimbus
dull moss
#

Sounds like something that should be possible

vast nimbus
bright fog
drifting ore
#

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.

vast nimbus
limber onyx
#

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?

bright fog
ancient grail
#

@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

bright fog
#

What are you even doing

ancient grail
bright fog
#

Perk, trait, or skill ?

#

There's a lot of mods that add their own skill if that's what you are trying

ancient grail
ancient grail
#

ok thnx
im also just generally curious

bright fog
#

Should be easier to learn if you base yourself on existing stuff

sudden kestrel
#

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

bright fog
#

Isn't it a thing like "OnConsume" or idk

#

In the item script

#

Check opened canned food scripts

sudden kestrel
#

heres what it looks like atm

#

ill check opened canned

tacit plover
#

yeah, there's ReplaceOnUse

sudden kestrel
#

ah not replace on deplete

#

what is deplete used for perhaps

tacit plover
sudden kestrel
#

so if it had water inside not milk makes sense

tacit plover
#

like thread, candles and water containers

sudden kestrel
#

could I add on a question since we are here

bright fog
#

yea

sudden kestrel
#

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

bright fog
#

Nah needs to be food I think

sudden kestrel
#

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

bright fog
#

Could also be a wrong report

#

Are you using custom sounds ?

sudden kestrel
#

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

bright fog
#

Could be your sound has a problem

#

Did you replace a sound script ?

sudden kestrel
bright fog
#

And your sound is short right ?

sudden kestrel
#

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

bright fog
#

Talking about the file itself here

sudden kestrel
#

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

bright fog
sudden kestrel
#

ill trim it right away

bright fog
#

Go download Audacity and fix that shit rn lmao

sudden kestrel
#

got audacity already in it lol

#

short oversight on my part

bright fog
#

Yea so basically whenever anyone drinks, I get no other sounds can play for the player idk

sudden kestrel
#

like 20seconds should be fine right?

bright fog
#

Just the length of your sound

sudden kestrel
#

i dont exactly know how long it takes to drink milk

bright fog
#

No point in making it last ages

sudden kestrel
#

ill time it ingame ig

bright fog
#

It sure doesn't take 20 fucking seconds lmao

sudden kestrel
bright fog
#

Maybe check vanilla sounds how they are

sudden kestrel
#

yeah maybe

bright fog
#

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 ?)

sudden kestrel
#

its a joke mod

#

so it plays a youtubers intro

#

hes a bodybuilder who drinks alot of chocolate milk

bright fog
#

ok lol

sudden kestrel
#

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

vast nimbus
bright fog
bright fog
#

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

vast nimbus
#

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...

bright fog
#

Decompiling is very easy to do

indigo pasture
# bright fog Idk if you can retrieve the selected items in a way, but if you can, you can sim...

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);
bright fog
#

I personally don't bother with it and just use mod options bcs everyone uses it

sudden kestrel
#

@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

bright fog
sudden kestrel
#

sadge

bright fog
#

There's a few mods that add song for the death

#

You can check these out

sudden kestrel
#

yeah like one of mine adds about 7 different sounds that play at random

sudden kestrel
#

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

bright fog
sudden kestrel
#

yeah

sudden kestrel
#

forgot to add it to the description of the mod but I will also be adding a collection of faygo sodas

safe seal
bright fog
teal slate
#

Ah, I can't use the modding server anymore because I don't have my phone number linked with this account...

drifting ore
#

"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

bronze yoke
#

if it has nothing to do with the rest of your mod, then probably not

drifting ore
#

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

sour island
#

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'

drifting ore
drifting ore
#

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

outer crypt
#

does anyone know how to get the inventory of a dead body?

bright fog
#

smthg like that ?

#

Shouldn't be too hard

drifting ore
#

isoDeadBody:getContainer()

bright fog
#

Yeah getContainer

tall solar
#

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)

drifting ore
#

what resources do you guys use for pixel art for asset representation? (what do you use to make the 8bit items for icons?)

dull moss
tall solar
dull moss
#

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

tall solar
nimble hemlock
#

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

dull moss
#

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
bronze yoke
#

it only returns the original function

dull moss
#

thought so, ty

bronze yoke
#

if returning in a function ended all code execution they wouldn't be very useful ๐Ÿ˜…

dull moss
#

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?

bronze yoke
#

if you can just edit the function, print it and see

dull moss
#

just shove it into tostring()?

bronze yoke
#

print(part)

dull moss
#

I see

bronze yoke
#

the print message will be its type and a memory offset you don't need to worry about

dull moss
#

Alternitively jsut figured to look up the method thats called on part

#

xd

#

part:getVehicle()

bronze yoke
#

unfortunately since lua is dynamically typed and tis don't use any kind of type annotation any direct type information usually doesn't exist

dull moss
#

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)

dull moss
#

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```
dull moss
#

how do I even override it? Commands is a local array

bronze yoke
#

i mean you don't really need to right

#

it's triggered by a client command, you can just listen for the same command

dull moss
#

oh

#

hm

bronze yoke
#

there is some trickery you can do if you absolutely need to overwrite it but

dull moss
#

But I want to catch engine condition after command is done

bronze yoke
#

well load order guarantees your event listener fires after theirs does so you can do that fine

dull moss
#

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?

bronze yoke
#

just do part:getCondition()

dull moss
#

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```
bronze yoke
#

in a client command listener

dull moss
#

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?

bronze yoke
#

yeah

dull moss
#

and call it after 1st command?

bronze yoke
#

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

dull moss
#

or so they will be queued?

#

aka my command wont start running its code until 1st command is done?

bronze yoke
#

yeah

dull moss
#

I see

bronze yoke
#

there's no concurrency in lua

dull moss
#

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

bronze yoke
#

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

dull moss
#

ah

bronze yoke
#

you would be running your code after that update has been made

dull moss
#

Separate question, can I require lua from client folder in server folder?

bronze yoke
#

yesss but you shouldn't

#

if it's not client code don't put it in client and vice versa

dull moss
#

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

bronze yoke
#

files in client/ aren't supposed to even run on the server but require ignores that

dull moss
#

guess I'll fuck around and find out xd

#

i see

dull moss
#
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?

bronze yoke
#

i don't see args.condition used in the original function

dull moss
#

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?

grizzled fulcrum
#

Overall it doesn't really matter, as long as you can paint pixels it will work just fine

bronze yoke
dull moss
#
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```
bronze yoke
#

nearly everything to do with players is client-sided so you usually don't need to actually transmit things you do to players

dull moss
#

just gives player a trait

bronze yoke
#

yeah you can just do that on the client fine

dull moss
#

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?

bronze yoke
#

ah, yeah, you'd need to trigger it with a server command

dull moss
#

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?

bronze yoke
#

nope, player moddata is unsynchronised

dull moss
bronze yoke
#

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

dull moss
#

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

bronze yoke
#

your function includes a check so that it can never run on the server

dull moss
#

wait so does it work in multiplayer?

bronze yoke
#

yeah

dull moss
#

sorry im not sure how this whole server thing works

bronze yoke
#

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

dull moss
#

and you saying i cant edit moddata in my commands cuz commands are actually ran on server, ye?

bronze yoke
#

yeah

dull moss
#

unlike ciagarettes

#

I see

bronze yoke
#

OnEat callbacks are only called on the client that eats the item

dull moss
#

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)
drifting ore
#

sendClientCommand sendServerComman OnServerCommand OnClientCommand

dull moss
#

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

bronze yoke
#

that's right

#

but keep in mind LuaNet is unused, you should probably ignore it

dull moss
#

hmm

bronze yoke
#

are you testing in multiplayer?

dull moss
#

no

bronze yoke
#

yeah, sendServerCommand doesn't do anything in singleplayer

#

even though sendClientCommand does

dull moss
#

wait so how do I update moddata then

bronze yoke
#

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

dull moss
#

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?
bronze yoke
#

yeah something like that

dull moss
#

should be not client and not server for sp, right?

bronze yoke
#

yeah

dull moss
#

cheers

dull moss
#

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

bronze yoke
#

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

split dune
#

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?

dull moss
#

~~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

dull moss
split dune
dull moss
#

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

split dune
#

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

dull moss
#

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

split dune
#

Thank you a lot! Going to take a look :)

dull moss
#

(I wanna play a sound for player only)

bronze yoke
#

other players will hear it

#

zombies do not hear these sounds

#

use playSoundLocal

dull moss
#

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?

bronze yoke
#

yeah that's fine

dull moss
bronze yoke
#

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

dull moss
#

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 :)

silk pike
#

Are there any tools or guides that help with creating mods?

past urchin
#

is it possible to cause an explosion using a lua script?

dull moss
#

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

split dune
#

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?

civic tree
#

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

split dune
#

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?

split dune
#

I see, thank you a lot!

dull moss
#

Probably sumnekolua doing weird shit as always

light crater
#

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 ๐Ÿ™‚

drifting ore
#

i guess i'd need to shop goodwill for a drawing tablet

bright fog
#

There's a mod that add truly random spawn of the player within any building

light crater
bright fog
#

You need to know the building

light crater
#

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!

light crater
bright fog
#

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

light crater
#

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...

โ–ถ Play video
#

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

light crater
# bright fog wdym ?

If it's something that can be overridden, then you wouldn't have to worry about where the player is

bright fog
#

You can't

light crater
#

Oh. Damn, that's a huge shame

bright fog
#

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

light crater
#

Are java mods harder to do?

bright fog
#

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

light crater
bright fog
#

Is it always the same building ?

#

Or meant to be random ?

light crater
#

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
bright fog
#

You can simply store coordinates of the building and retrieve the building at those coordinates once it's loaded in

light crater
#

Oh cool. That sounds convenient

bright fog
#

Then you can chose a room randomly, which is extremely easy to do

light crater
#

๐Ÿ”ฅ

#

That sounds pretty good for key item generation

bright fog
#

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
light crater
bright fog
#

On top of that you can most likely add a marker on the player map

light crater
#

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

light crater
light crater
#

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

vast nimbus
#

@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.

vast nimbus
#

Idk, lol, it's look like you know a lot about modding

#

๐Ÿ˜… ๐Ÿ˜…

light crater
#

Does anyone know if it's possible to mod in new "zone events"?

ivory fractal
zealous monolith
light crater
zealous monolith
light crater
#

It's not the type of thing I'm looking to make, but would love to see it done

zealous monolith
light crater
#

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

light crater
zealous monolith
#

Wow that doesn't sound like it's too far off from a possibility

#

What mods do u make? @light crater

light crater
#

None yet - I've just arrived ๐Ÿ™‚

#

I'm a game developer by occupation though

#

It seems like a fantastic system, and I had no idea it existed

elfin laurel
light crater
#

they're improving mod support in 42 right?

zealous monolith
light crater
#

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

zealous monolith
#

Well, I'd say about 25-40% of them are working, ive got alot of research to do lol

ancient grail
bronze yoke
#

you don't need to do any weird code to add skills

#

you just write a skill script and it's there

ancient grail
#

wow thats good to know

bronze yoke
#

the only things you need lua for are, you know, making it do something and giving xp for it

ancient grail
#

yep and adding exp would be the same way i assume? and would also trigger the Level event?

bronze yoke
#

yeah

light crater
#

Some people seem to have that as a hobby in itself

#

Enjoying the experience of getting mods to work more than playing them lmao

zealous monolith
bright fog
#

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

ivory fractal
#

This was the final code, though I'll have to put xp that makes sense

bright fog
#

Interesting, it's just a script file ?

maiden flower
#

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

ancient grail
#

yep it worked

ancient grail
#

im doing a rank mod that is based on the vanilla perks only and doesnt include the parent perks

ancient grail
#

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

hardy drift
#

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

hardy drift
#
ContextMenu_EN = {
    ContextMenu_JYTsnus_popjyt = "Pop an uppy decky",
    ContextMenu_JYTsnus_popdoublejyt = "Pop a double decky",
}```
#
CustomContextMenu = JYTsnus_popjyt, JYTsnus_popdoublejyt,```
#

@bright fog

bright fog
#

I meant, the lua

#

It's not bcs of your translation

hardy drift
#
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

bright fog
#

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 ?

maiden flower
# ancient grail might need to uncheck some anticheats tho

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

ancient grail
#

the anticheat will disconnect the player

maiden flower
#

Like either that tool or the admin console?

bright fog
#

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

maiden flower
# bright fog Not sure I understand here, you have an item to teleport somewhere, you want onl...

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

ancient grail
# maiden flower Im being confusing my bad. Essentially I want one of two conditions: Admin t...

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

#

goodluck

vast nimbus
#

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...

vast nimbus
woven brook
#

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

drifting ore
#

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

maiden flower
# ancient grail for the combine remote thing you need to create recipe scripts flr the admin to...

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.

woven brook
#

essentially trying to recreate foxholes map system and split the map into two seperate servers to surpass the 127 hardcoded player limit

dire oracle
ancient grail
# dire oracle Server that can gather more than 100 people exist? Like, capable of find such a...

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...

โ–ถ Play video
#

nurse also hosts 100 players events

silk pike
#

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??

ancient grail
#

yes all of those

ancient grail
#

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

silk pike
weary compass
#

did anyone have a problem where their model and icon dont show up in game?

#

i dont know what i did wrong

ancient grail
#

if the icon youre refering to is for inventory items

weary compass
#

Icon = Item_Crossbow,

weary compass
ancient grail
#

yeah but i suggest you add something to that
cuz something generic as Crossbow will sure to overwrite some stuff from other mods

tranquil kindle
weary compass
#

how do i get the model to work?

tranquil kindle
weary compass
#

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?

weary compass
#

how do mod makers export their models as .x files?

#

the model doesnt appear in game

tranquil kindle
#

Do not use X files... Game supports FBX and most modders encourage to use them.

weary compass
#

the fbx file also doesnt work

#

the model either inst there or its invisible

tranquil kindle
weary compass
#

invisible model

#

is it because i have no textures?

#

if i add a black square as textures will the model be visible?

ancient grail
# weary compass still fixed my issue tho

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

ancient grail
tranquil kindle
#

Im pretty sure most of fbx files will actually reload

ancient grail
#

both for models and animations

i saved alot of time cuz of x files

i hate restarting the game all the time

tranquil kindle
#

Unless its complex i think?

ancient grail
#

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

tranquil kindle
#

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

ancient grail
#

oh and xml files for anim also reloads

but not sure abt clothing

tranquil kindle
#

Yeah, xml and fbx animations reload pretty much in a few seconds

ancient grail
tranquil kindle
#

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

weary compass
#

so any idea why my models are invisible?

tranquil kindle
#

What is your model? Gun?

ancient grail
ancient grail
weary compass
weary compass
tranquil kindle
#

Why do you have no texture?

weary compass
tranquil kindle
#

Now think why its invisible, if it has no texture

weary compass
tranquil kindle
#

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

ancient grail
cloud drift
#

This has been amusing to witness

eager pond
#

hello guys, who can help me with creating car mod?

dull moss
#

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?

bronze yoke
#

Events.OnZombieDead.Add(function() catEyes(true) end)

dull moss
#

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

bronze yoke
#

yeah

dull moss
#

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```
bronze yoke
#

you need to store that function if you want to remove it later

dull moss
#

hm

#

as in?

bronze yoke
#

Events.OnZombieDead.Remove(catEyes) doesn't work because you never added catEyes to that event, you added this function function() catEyes(true) end

dull moss
#

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
vast nimbus
#

@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 ?

vast nimbus
#

lol hahahah

dull moss
#

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

woven brook
vast nimbus
#

Ok let's try:

  1. How am I declare a dependency mod, I am going to use ModOptions, is it on mod.info file?
  2. I did Events.OnKeyPressed.Add(KeyUp), to create new keybind, is there an event correlated to MouseButtons ?
  3. 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...
  4. 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 ๐Ÿ™‚

bronze yoke
dull moss
# vast nimbus Ok let's try: 1. How am I declare a dependency mod, I am going to use ModOptions...

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```
bronze yoke
#

for 3, look at OnMouseDown, OnMouseUp, OnRightMouseDown, OnRightMouseUp

vast nimbus
#
  1. I saw some mods using
    ISTimedActionQueue.add(ISInventoryTransferAction:new(player, item, item:getContainer(), back)) to move items between containers. But can I use the function ISInventoryPane:transferItemsByWeight(items, container) ? For me its a way to not repeat and reuse code...
vast nimbus
bronze yoke
#

no idea but that probably fires the keyboard event

bronze yoke
dull moss
vast nimbus
dull moss
#

im using mouse software to be able to bind my bonus mouse keys Sadge

vast nimbus
# dull moss Is there a way to stop VSCode from screwing up translation files encoding? It ke...

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! ๐ŸŽ‰

bronze yoke
#

i remember not really being able to save files with the right encoding but i don't write the non-english translations myself anyway

dull moss
dull moss
#

but IDE keeps bricking them

bronze yoke
#

why are you re-saving them?

vast nimbus
dull moss
#

Mostly formatting and stuff, sometimes change a number in translations, stuff like that

digital sail
#

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.

digital sail
dull moss
#

My translation files are being weird

bronze yoke
#

non-english language files are saved in different encodings

dull moss
#

and that ^

digital sail
#
  1. It's bad, basically. ๐Ÿ˜ฌ
#
  1. : is a syntactic sugars, writing a:method() is exactly the same as a.method(a). The object is passing its own value as a first parameter of the function. This is to emulate Object Oriented Programming.
digital sail
bronze yoke
#

if you save them in utf-8 the game will still try to interpret them as their correct encoding resulting in the wrong characters

digital sail
bronze yoke
#

i don't know which ones exactly but iirc it's pretty much anything that uses non-roman characters

digital sail
#

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?

digital sail
dull moss
#

Lemme just quickly ping a random dev PepeLaugh