#mod_development
1 messages ยท Page 18 of 1
that's correct
you could try using a float, I forget if it requires integral values or not
probably not though
Ill be messing with that as lighters dont use that much fuel, least not enough to fill a quarter of a car lol
Very handy tips mate, learning a lot from asking in here and reading some of the code in media/
yeah, the units of drainables is a bit arbitrary at the moment and doesn't make sense, especially when you compare it to weight
but, build 42 is going to fix all that
Amazing maybe then i can pass in 0.1 units of gas per refil or something
containers will be able to hold mixes of fluids
so I'm expecting we'll actually have proper units of volume you can tell a container to lose
it does also mean that you'll have to deal with someone who filled a can with 10% petrol and 90% water
Looking forward to that, proper ml, l, pints etc
so i did some rotating, deleting of polygons, and squishing and shifting of the handle, and now i have a sawed off stock, but the textures have vanished and its just grey now
in game i mean, it was always grey in blender
you might have broken the UV map
go into the UV part of blender and see how it's laid out
Working like a charm
i see a square
yeah, that's just a blank area where you can put an image
just make a new one that's all white and start selecting geometry
it'll show you where on the image a particular polygon is textured from
doing a select all in edit mode brings up what i assume is the 2d net
Got another question, can you reload mods while in debug mode SP, ima assume not but just wondering
I usally back in and out
ok its now in the square
you can get it to "reload" a Lua file, however, don't consider this a reload, consider it as simply executing the same code again
Ok cool no prob, ill keep reloading it fully back to menu and new save
so, depending on how you structured your code, it can be anything from absolutely fine, to not at all
unless you really understand how the re-execution of your code is going to affect the lua state, don't do it, just go back to the main menu
Yep not a clue xD back to menu it is
indian youtube tutorial man taught me how to texture paint
i really hope this works
i put in way too much effort in the painting
yay, it doesnt fucking work
zomboid didnt load the fucking UV map
How many UV maps you have?
material only one?
uh, the youtube tutorial i followed said select smart UV project? and then i used texture paint on the model
ima be honest i know nothing about blender im just fumbling my way through this
where should i check for "material only"
Hmmm. Try another tutorial, I think it will help
Also you saved UV map?
*Object after change UV
i've saved the project as a .blend file? im guessing thats not the right thing
need fbx
oh, i did export it as a .fbx, and put it into my mod
thats what produced the broken texture mess
that i posted
also i know its 10x the size but its hard to work on a tiny model
Hmmmm. Can you send me mod in PM? I will try help
I'm trying to start working with a simple script mod. I think I did lua scripting once like 10 years ago with gmod so I'm a little out of my element here. I'm trying to make a mod that sets all vehicles in the world to have a rust value of "1" for those months/years later playthroughs. Where do I start/what file am I looking to modify?
I think you can connect to function Vehicles.Create.#### and set Rust for vehicle in that func
thanks for the help Aiteron, i have credited you in the mod description on its workshop page
what was the problem btw?
the problem was i had no idea what i was doing, and the textures of the gun were broken or missing
the model did not have textures, so it seems like it was trying to apply the default shotgun texture to the changed model
its on the workshop now under the name One-Handed Sawed-Off Double Barrel Shotgun, so you can download it and see for yourself how aiteron fixed it, i cant take any credit for getting the textures working
I'm sorry, I'm still pretty confused. I've only done some cursory glances into the game's lua files. is that for the individual vehicles' scripts? I thought there'd be something I could modify related to the server or how the world generates vehicles. Like how you can specify what overall condition you want vehicles at when you start a custom game, if that makes sense
Send link because I need to learn that too
for MP check how set rust by admin tool
local playerObj = getSpecificPlayer(_player)
local playerInv = playerObj:getInventory()
local Item = playerInv:FindAll("Coffee2")
Item:delete()
Yep, you didn't read what I said
Not only did I say that you call it on the item container, I said the function is called Remove
So you have somehow managed to completely ignore me and just invent what you think the code should be
Never mind the fact that FindAll returns an array
And because, actually, I'm trying to do this as a test. Because my current error is with TimedAction, which is giving some error and I suspect it was because of the item, which in the action has "self.item:delete()" in the "local function MyAction:perform()" function, so I thought which could be giving an incorrect value. I don't know how to solve this problem :/
I just brought that as an example to explain what I'm trying to do. My goal is to make a mod that sets all the cars in the world to have max rust
No, I'm smoking cigars and drunk as a skunk.
Fair enough, I will commit summoning rituals at a future time then
(you can try, but don't expect much from me)

Does anyone know where can I get free(or low cost) low poly-ish 3d models of military webbing and pouches? ๐ค
I would like to make a simple mod that adds simple gear to the game without too much bloat and dependencies
Personally I'm asking similar for a portable hand crank
Tho I might just have to model it myself
How do I add an option to an item's context menu?
I want to have a "Charge Battery" option to the Hand Crank, but I'm unsure if recipes will work properly for it or not (?)
Actually it might nvm
I need to find the name of the item in my inventory, but FindAll("item"):getName() doesn't work, is there a specific get for that?
Wouldn't FindAll be a table/array?
Ohh lets see
If you want the name specifcally with it's module as well then do :getFullType()
IF you only need name, IE "Battery", it's just :getType()
If you need the module its inheriting from, IE "Base.Battery", it's :getFullType()
๐ค
getType and getFullType are not working, it gives an error when I try to put it in FindAll(): > get <
Hm
and now? :(
Has someone made a mod with all the TWD clothing
you said nvm so I figure the recipe stuff was fine, but in case in future you want to add your own options, I find the easiest way is using OnFillInventoryObjectContextMenu event. here is an example.
InFridgeMenu.doMenu = function(player, context, items)
for i,v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:getType() == "HCCooler" or item:getType() == "HCIcechest" then
local container = item:getItemContainer();
if container:getType() == "fridge" then
context:addOption("Take Coldpack out of "..item:getName(), item, InFridgeMenu.toggleCooler, player);
else
if getSpecificPlayer(player):getInventory():contains("Base.Coldpack") then
context:addOption("Put Coldpack into "..item:getName(), item, InFridgeMenu.toggleCooler, player);
end
end
end
end
end
Events.OnFillInventoryObjectContextMenu.Add(InFridgeMenu.doMenu);
Ahh cool, my doubt is now another ๐
How do I make the player equip an item in hand?
pls hellp. how do i improve my code.
if not player:getNearVehicle() == nil then
local car = player:getVehicle();
else
local car = player:getNearVehicle();
end
car:repair();
car:getPartById("Battery"):getInventoryItem():setUsedDelta(100);
car:getPartById("GasTank"):setContainerContentAmount(100);
for i = 0, car:getPartCount() -1 do local part = car:getPartByIndex(i)
if part:getCondition() > 0 then part:setCondition(100);
end
end
end ```
@nimble valley
hi
did it work? the generator thing?
I don't think the recipe would work, at least not cleanly, so I'll invesitage this. Thank you!
Also, robot, how would I make it hook to my custom Timed Event?
Is there an event for knowing when an InventoryObjectContext is activated or will I have to find another way?
is there any big modpacks that i should try out?
How do i add new animations to zombies (Don't want to replace already existing ones, i want to add new ones)
Is it possible to create a sound emitter in a specific square?
Found this in testtimed.lua in luaexamples
getSoundManager():PlayWorldSound("explode", square, 0, 20, 1.0, false);
Seems you can provide a specific square rather easily
Thank you!
Yeye!
local module = "Base"
local name = "MxDebug"
local displayname = "MxDebugName"
local type = "Clothing"
local inventoryIcon = 'WatermelonSmashed'
local item = createNewScriptItem(module, name, displayname, type, inventoryIcon);
item:DoParam("DisplayCategory = Clothing")
item:DoParam("Type = Clothing")
item:DoParam("DisplayName = Bikini")
item:DoParam("ClothingItem = Bikini_TINT")
item:DoParam("BodyLocation = Underwear")
item:DoParam("Icon = Bikini_White")
item:DoParam("Weight = 0.2")
item:DoParam("WorldStaticModel = Bikini_Ground")
print(tostring(item))
print(tostring(item:isHidden()))
print(tostring(item:getObsolete()))
Events.OnGameStart.Add(function ()
getPlayer():getInventory():AddItem("Base.MxDebug");
end);
Please anyone from TIS Im getting this long error everytime I hove the mouse over the item I created, can some of you help me with this? I attached the error log as a file. I tried to ask other modders but no one was able to help me and I have been stuck on this for a week now
so when youve made your custom action, you want to add it to the timedactionQueue using the following:
ISTimedActionQueue.add(ISHarvestHoneyAction:new(playerObj, beehive, 200))
obviously instead of ISHarvestHoneyAction, you would put your action, and whatever arguments it needs
Is there a has tag function?
wait thats a dumb question there probably is
I know how to add a timed event, I just dont know how to hook it into my system
context:addOption("Take Coldpack out of "..item:getName(), item, InFridgeMenu.toggleCooler, player);
Would I just replace InFrigeMenu.toggleCooler with something like BetterBatteries.doChargeAction() and have that inititate the timedactionqueue?
function BetterBatteries.doChargeMenu(player, context, items)
for i,v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:hasTag("HandCrank") then
context:addOption("Charge Battery with "..item:getName(), item, BetterBatteries.doChargeAction, player);
end
end
end
function BetterBatteries.doChargeAction()
ISTimedActionQueue.add(ISChargeBattery:new(player, item, 70 + (item:getUsedDelta() * 40)));
end
yep exactly that
np
Wait, would my doChargeAction be supplied with any parameters?
So just.. BetterBatteries.doChargeAction(player, item)
Ok perfect
How would I go about determining if the character has max exertion so I can prevent them from starting an action / quit the action early?
I have self.character:getMoodles() and I found the moodle class which lets me use "getMoodleLevel"
But I dont know how to supply a MoodleType for getMoodleLevel
Nor do I know if intensity is like "4" for max exertion or something like "0"
Found a way
It pops up now, but I had to remove the () and the args supplied to doChargeMenu
@shadow geyser Any ideas?
wheel FrontRight
{
front = true,
offset = -1 -0.26 1.63,
radius = 0.15f,
width = 0.2f,
ayo im tryna tweak something, which of these settings is basically the wheel going up and down, x/y?
is offset xyz?
ah yeah, there is a weird format I think to make it work. let me try to find it
its basically because you need to pass the function, but its a big weird to pass also some arguments for it
bit*
I think I figured it out (?)
Everything following the function seems to be params fed into said function
Up to 10 params
Not sure why they didnt do ... for virtually endless params but whatever lol
yeah thats right
was trying to find a good example for it, but youve figured it out yourself
Seems to be erroring regardless, probably some of the data im feeding it
also idk if youve already fixed it, but you need to have the arguments in the function definition
try the following
context:addOption("Charge Battery with "..item:getName(), player, BetterBatteries.doChargeAction, item);
idk why. its weird, but its what I see everywhere. the var before the function is the first param, then the ones after follow it
its super wierd, and I don't know why its done like that. but it is
you can see in line 90 in ISContextMenu
option.onSelect(option.target, option.param1, option.param2, option.param3, option.param4, option.param5, option.param6, option.param7, option.param8, option.param9, option.param10);
then the addOption is also formatted that way.
function ISContextMenu:addOption(name, target, onSelect, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10)
super weird and I don't see the logic about it. but thats just how it is
Ok so getSoundManager():PlayWorldSound() works but it sucks. I can't hear the sound unless I am very close to it regardless of the parameters apparently
Aw heck, I'm sorry.
I wanted to be able to hear it from far away
I couldn't find what the parameters mean exactly, I assume it's name, square, minRange, maxRange, Volume, loop ? But I tried setting it to 0 min and 5000 max and it didn't work, 500 min 1500 max didn't either and so on
I can look into the params if you'd like
This may be the way, just with wonky params or something
Do you know what's the difference between PlayWorldSound and PlayWorldSoundImpl ?
There's so many functions oh my god
PlayWorldSound, PlayWorldSoundImpl, PlayWorldSoundWav, PlayWorldSoundWavImpl
Oh boy
There does appear to be an optional 7th argument in some of the duplicate functions

..and some of the Impl have up to 9 args

none of which are labelled
aside from "var 1, var2, var3" etc..
Literal nightmare fuel
I get errors when trying to use Impl for some reason
Impl seems to want generally more args compared to just regular
9 vs 7
Oh I see now
Impl wants the uhh
Coordinates
Not the grid square
PlayWorldSound uses Impl anyways
So just stick with it for now
Straight up copying an example with Impl doesn't work for some reason
Yeah me too why does stuff never just work 
Me too but it's starting to get old
I feel that
i definitely got a bit burnt out as well
i wish we had documented java code with variable names
I don't want to have to play this on the player
more accessibility from lua you mean?
Yea I think
not sure but that would be nice
Fingers crossed someone answered them
oh my god
lol my first thought there is to just play the same sound at multiple points if it can only spread that far
but play it at the same time
I bet chuck knows something
Hey @sour island, if you're on, any idea of how to get a sound to play in world space further than like 15 tiles? Braven is having trouble with :PlayWorldSound()
I feel like he'd know something because of his snazzy heli mod, you can usually hear the heli from far off.
Though now that I think about it, that could've been using an interesting solution that just popped into my head.
@heady crystal, this is stupid, and obv wait until chuck responds, but I had an idea.
If you could somehow get the direction of the sound source, you could assign a tile about 15 units away in the direction of said sound source, and adjust the volume based on distance.
Hacky, yes, but it'd work assuming I understand how the system works
I'd recommend waiting on Chuck though, I imagine he knows something cleaner unless he used that method.
That'd be incredibly complicated since a loud enough sound would be audible in a 360 degree radius for quite the distance
I'd have to play sound in so many places lol
hmm
Well I guess if there's no other way I'll have it play on the player directly and if they're outside range I suddenly cut it off
That's so stupid tho
I am new to modding Project Zomboid so this is a stupid question, but how do I pass a variable from one function to another, or is this not possible?
Use arguments and parameters. Just an example:
function A()
local test = "Hey!"
B(test)
end
function B(someVariable)
print(someVariable)
end
Function B has a parameter. When it is executed, it prints whatever it received. LUA is not fully type safe so when you declare a variable it can be anything really. So I can send anything to function B. In this example, A is sending a string variable named test to B. So the variable passes from one function to the other.
I suck at explaining, I hope that's understandable.
Thank you for trying to explain. I'm going to try this out. I'm trying to read someone else's mod to learn and I'm not sure how they're able to pass the variable.
You can also have variables declared on the instance of your script that are "global" in the scope of that instance like
local test = "Hey!"
function A()
print(test)
end
function B()
print(test)
end
Both will result in "Hey!" as they print test, which can be accessed from anywhere within the code so long as whatever is accessing it is below the declaration.
You can also call a function from another script
I don't know much about LUA tho, this is mostly based on what I know of programming in general.
I'd watch a few LUA tutorials if I were you, to get the hang of it. It can be a very annoying language to try to learn on your own.
LUA isn't beginner friendly
Thanks. I've been at this for days lol I read up on it and I've started to get some things to work, but some things are annoying me.
if you're looking at an existing mod you'll probably notice they are using callback functions on events too. I'd highly recommend taking a look at https://github.com/FWolfe/Zomboid-Modding-Guide and https://pzwiki.net/wiki/Modding
and when you add a listener to an event the event will pass vars to the functions as well
hey qq, trying to read the server stats with getServerStatistics() but I can't enable the server stats with setServerStatisticEnable(true). Any ideas? ๐ค
Does this game seriously not have a distance from player to square method? Come on
I'll have to go back and reread this. I must have missed something. This helped me initially. Thank you.
@shadow geyser Does the OnFillInventoryObjectContextMenu and the function it connects to have to be client side for the timed action to work?
yeah
the server doesn't do anything for OnFilInventoryObjectContextMenu, and all the timed actions in vanilla are also in client side, so server shouldn't need any of it
nvm. can only be used on client
I'm pretty sure this is set up correctly.
function BetterBatteries.doChargeAction(item, player)
print(tostring(ISChargeBattery))
ISTimedActionQueue.add(ISChargeBattery:new(player, item));
end
It's not detecting ISChargeBattery as a valid thing though.
require "TimedActions/ISBaseTimedAction"
ISChargeBattery = ISBaseTimedAction:derive("ISChargeBattery");
function ISChargeBattery:isValid()
return (self.character:isPrimaryHandItem(self.handCrank) or self.character:isSecondaryHandItem(self.handCrank)) and self.handCrank:getUsedDelta() < 1 and self.character:getMoodles():getMoodleLevel(MoodleType.Endurance) < 4
end
function ISChargeBattery:waitToStart()
return false
end
function ISChargeBattery:update()
self.character:setMetabolicTarget(Metabolics.HeavyDomestic);
end
function ISChargeBattery:start()
self:setActionAnim("Craft")
-- Don't call setOverrideHandModels() with self.petrol, the right-hand mask
-- will bork the animation.
self:setOverrideHandModels(self.handCrank:getStaticModel(), nil)
self.sound = self.character:playSound("GeneratorRepair")
end
function ISChargeBattery:stop()
self.character:stopOrTriggerSound(self.sound)
ISBaseTimedAction.stop(self);
end
function ISChargeBattery:perform()
self.character:stopOrTriggerSound(self.sound)
while self.handCrank and self.handCrank:getUsedDelta() < 1 and self.character and self.character:getMoodles():getMoodleLevel(MoodleType.Endurance) < 4 do
self.handCrank:setUsedDelta(self.handCrank:getUsedDelta() + 0.01)
self.character:getStats():setEndurance(self.character:getStats():getEndurance() - 0.0002)
end
if self.character:getMoodles():getMoodleLevel(MoodleType.Endurance) >= 4 then
self.character:Say("I'm too tired to keep doing this..")
end
-- needed to remove from queue / start next.
ISBaseTimedAction.perform(self);
end
function ISChargeBattery:new(character, handCrank, time)
local o = {}
setmetatable(o, self)
self.__index = self
o.character = getSpecificPlayer(character);
o.handCrank = handCrank;
o.stopOnWalk = false;
o.stopOnRun = true;
print("Doing some cool stuff! Yeaaaah!")
o.maxTime = time;
--if o.character:isTimedActionInstant() then o.maxTime = 1; end
return o;
end
pleh I need to get funny uhhh
thing set up
Yo the man is here!!
@heady crystal sounds can be scripted much like items. You can set min and max distance. I use world emitters for EHE.
Wait a second
You're right
I was so focused on it not working that I never stopped to think that maybe the sound itself was limiting it
Which is still a dumb concept, I'll die on this hill
But let's see if it works lol
I can't make it compatible with true music this way I imagine tho, I'll have to stick with having it play on the player I guess
ISChargeBattery isn't being recognized as a thing despite the fact it's in a similar directory, derives from ISBaseTimedAction, and is a global

try requiring the file for your custom action in the UI file
UI stuff is funky. if the UI is created calling the ISChargeBattery before the ISChargeBattery is declared in its file, I think it will stay nil, because of the funky UI behavior. so even if you change the ISChargeBattery so something valid later, it broke because it wasn't valid beforehand
anyone know a good mod that increases item transfer speed
In the UI file?
yep, the one where you are adding the context menu
the one with this inside
Ohh ok
anyone online in here to help me with a clothing item script, dm me pls โค๏ธ
you have the wrong number of parameters
I think lua resolves it differently depending on the number of parameters you give
but im not sure, but atleast that should be fixed
your new is defined as following
function ISChargeBattery:new(character, handCrank, time)
but you are only giving the following
ISTimedActionQueue.add(ISChargeBattery:new(player, item));
need to pass the hand crank as well
Still got the same error
Also heck, if you gotta go sleep then go sleep lol
Dont let me keep you upp
can you show the entire file for the UI part please
yeah
lemme do it on pastebin or something
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
thats youre ISChargeBattery file. Also i don't think the require "ISChargeBattery" is doing anything. it should be in the file making the context menu
How do i add new animations to zombies (Don't want to replace already existing ones, i want to add new ones)
oh im dumb mb
BetterBatteries = {}
function BetterBatteries.doChargeAction(item, player)
print(tostring(ISChargeBattery))
ISTimedActionQueue.add(ISChargeBattery:new(player, item, 100));
end
function BetterBatteries.doChargeMenu(player, context, items)
for i,v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:hasTag("HandCrank") and not item:getModData().batteryRemoved then
context:addOption("Charge Battery with "..item:getName(), item, BetterBatteries.doChargeAction, player);
end
end
end
Events.OnFillInventoryObjectContextMenu.Add(BetterBatteries.doChargeMenu);
also might as well put that file into the TimedActions folder, just for organization purposes
(just letting you know that we're not ignoring you, odds are we just dont know what to do either)
yeah put the require "ISChargeBattery" at the top of this file and give it a try.
Still nada, mfw
same error?
should be fine as long as you give the path properly in the require statement
I changed it to TimedActions/ISChargeBattery
so if it is inside TimedActions, it would be require "TimedActions/ISChargeBattery"
Aaaand it still borked
I'm open to just trying this tomorrow if you wanna sleep btw lol
yeah. Ill try to think about it tomorrow with some more sleep in me
Hey. Am currently looking for mods that people write extended mods requiring them. I'm looking to write typings for those mods. Please let me know if you think of one that is popular and that'll help me out a lot. Thanks.
What about profession framework? ๐ค
@gilded hawk I'll look it up! Thanks!
The idea is to write typings to help people who might be interested in writing Typescript mods.
Pipe wrench gang? ๐ค
๐ง
I know, just making sure it doesn't get buried too much so if someone does they can respond
my mods wont load
do you guys know if there's something I have to do to get player:setX() to do something? I can't see a visible change and it doesn't update the value
does it have to be serverside or something?
i would have thought in singleplayer it would still work in a client script though
Mmmm I think You have to send the packet too.
Either way the client sends the next coordinates until instructed otherwise.
All setX() does is set the variable for the server to track where it thinks the player is at.
(IIRC)
So either send the teleport packet or send the client via Lua command API to set there.
ahhhh I see that actually makes so much sense thank you
would the lua command api be the sendServerCommand() way? is that what you mean?
Yeah.
I just double-checked and the teleport commands only sends packets to instruct the client the new coordinates.
ahhh I see
so if I set the coords client side and then called the server to set them serverside would that suffice?
rather than sending the teleport packet?
The client is the authority for player's position coordinates.
Send the info to the client and then set the coordinates there. I believe that should work.
okay so a onServerCommand or whatever it is and then player.setX/Y in there?
Yeah.
weirdddd okay
if the client is the authority i would have though I could just set it clientside. guess I still have a lot to learn lol
sendServerCommand(isoPlayerObject, 'my_module_id', 'teleport_player', {x, y, z});
is that using the built in teleport method?
and that would be from the client itself?
Nope. It's me sending over coordinates to the client.
That would be going to the client.
so OnServerCommand listens for sendServerCommand. This is the same for client commands.
Ohhhh gotcha okay
Wait so if the client manages worldpos why couldnโt I just set it in client?
All that is basically sending data Client <-> Server.
How does receiving from the server change that?
If you have it on the client-side, then simply set it there.
I assumed you were operating on the server-side.
I was just messing in sp
Ahhhh.
And I have a key press that updates the x pos by the previous + 10
All good! I didnโt explain very well haha
I mean thatโs good to know for the future still
But yeah updating the coords doesnโt change anything on client
function addLift(key:number){
if (!(key === Keyboard.KEY_Q)){
return;
}
let player = getPlayer();
player.setX(player.getX() + 10);
}
onKeyPressed.addListener(addLift);```
pipewrench ๐
player.setPosition(x, y, z);
Try that.
It sets a few fields in IsoPlayer, which might be what allows the player to be teleported properly.
Iโll see thanks!
Are you trying to make the player go up in the air? (Looking at the function's name)
If so, that'd be the Z axis.
I was at first but then that wasnโt working so I tried X
Z will be that axis.
X,Y are lon and lat basically but in world coords.
You'd be teleporting a player above the highest floor IIRC. (0-7)
Is there a way to set access level other than these 2 methods? If your client is not admin, then they will not work.
playerObj:setAccessLevel("admin");
and this:
local command = string.format("/setaccesslevel %s admin", tostring(playerObj:getUsername())); SendCommandToServer(command);
I'm making my first mod. I'm trying to make a temporary effect based on which item a zombie was killed with.
Anyone know which event to use and how to get that information?
I found onZombieDead event, but i don't know how to get the info i need regarding the weapon used to kill it, or the player who killed it.
setAdmin();
there is OnZombieDead, which triggers on a zombie who dieing, but I don't know how to detect which weapon killed it there. i think you might have better luck using OnHitZombie, as that makes it easy to see what weapon hit it. Then just check the health of the zombie to see if that hit killed the zombie
Ya, Just found that actually. I'm starting to test with it.
I'm trying to figure how to check for the health now ๐
I found isAlive(), but I'm also trying to figure out lua syntax, so it's taking a bit longer than I'd like
ok, I'm up again. do you mind just uploading it on private then just sending me a link to it, that way I can just see it all and test it locally? or if you have it on github that would be good too.
Question:
Am I using this isAlive() correctly?
I'm not getting any errors in my debug, but it's not reading the if else
local function onHit(zombie, player, bodyPartType, weapon)
if zombie:isAlive()
player:Say("Hyaa")
else
player:Say("Got'em")
end
Events.OnHitZombie.Add(onHit)
guys help how to disable a script using LUA.
delete C:\Users\%USERNAME%\Zomboid\Lua
no not deleting the script.txt
but disable it so it can't be called.
manifest your intentions or give an example of what are you trying to do
example: i want this script disable without deleting it.
so you are going to create a mod that patch this specific mod, right?
yes
you have to make this mod as a requirement to ensure load order
then create a script file with the same name, but remove all items scripts in that file
never do this myself but I assume it should work lol
ok i will try it myself.
but there can be many ways to make this thing work, my solution might not be the best
it's not illegal to make an add-on right?
who gonna sue you? ๐
i just want to be sure.
Any updates on this, pal?
contact the author of the original mod to ask for permission
got it.
no rather i will ask him.
I've been able to correct my syntax issues by looking at some other mods.
local function onHit(zombie, player, bodyPartType, weapon)
if zombie:isAlive() then player:Say("Hyaa");
else player:Say("Got'em")
end
end
Events.OnHitZombie.Add(onHit)
However, now I know isAlive() isn't what I'm looking for because it always returns true since the zombie never dies before OnHitZombie is invoked.
Anyone know how I can get if the zombie died from the attack?
try checking the health. of the zombie maybe?
I don't think the health updates before the call is invoked, but i can give it a shot
or you could do something more fancy. have a table on which you store the zombie you attacked. So you end up using 2 events. The OnHitZombie one, to get the weapon, then store it in the table. then use the OnZombieDie. from there, you check what that zombie was hit with from your table to do what you want.
would just need to figure out some sort of identifier for the zombie. I'm not sure if they are hashed, but might be worth looking into
I was just trying to figure out how to do that, but I was trying to use a global variable ๐
Do you mean table as in a DB table? or is this something specific to lua?
don't use a global table. just use a require to grab the table.
zombietracker.lua
local tracker = {}
return tracker
then in file you want to use it, do the following
blah blah code
local tracker = require "zombietracker"
blah blah stuff using that tracker table
you can have as many lines of code using the local tracker = require "zombietracker" and the table will be the same shared table
Interesting.. I'll need to look up how tables work. Then I'll need to figure out how to update the table to make sure I'm only getting the zombie I need, since i'm trying to make it for MP
Thanks for the idea
yeah would be interesting to make it work in MP. Im not sure where the onzombiedead and onzombiehit are called in MP, if client or server. I would think on client side but im not sure
I would definitely have thought that the devs would at least have a function to get the character that killed another. Aren't there mods that have that though? Like some of the log outputs can tell admins who killed who or what.. So I'm curious why that's not a public function ๐ค
I've seen getAttackedBy(), but it's null when OnZombieDead event is called
thanks man your method work.
I'm making gun attachment but when i upgrade my gun with it ,the attachment model don't appear, anyone knows it?
flip it's normals
I was about to ask how to add custom menu items to specific items, is this a similar approach i can take?
guys how to play sound using LUA code.
So... it turns out, getAttackedBy() does indeed work when getting the character who killed the zombie on OnZombieDead.
The first time I tried it, I must've been using the wrong syntax or something.
local function onDead(zombie)
local player = zombie:getAttackedBy()
player:Say("Got'em")
end
Events.OnZombieDead.Add(onDead)
This was all that was required. I thought something was fishy if we couldn't access something like that lol
it didn't work
You referring to this?
setAdmin(); if getAccessLevel() == "admin" then playerObj:Say("Is Admin."); end
did you add this on your script?
model (your attachment)
{
mesh = Weapons/parts/(your attachment model),
texture = Weapons/parts/(your attachment texture),
}
this is not a WorldItem Model but a Static one
I already added it .However I solved it , seems the attachment and weapon's models should in the same module so the game could load them
Hey don't suppose someone could give me advice how i can get reference to the First petrol container with some used delta left, this is my first attempt but i cant seem to access it
CraftAndRefillLighters = {}
function CraftAndRefillLighters.doFillGasAction(item, player)
end
function CraftAndRefillLighters.doCreateMenu(player, context, items)
local petrolContainerToUse;
for i,v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:getType() == "WinePetrol" then
petrolContainerToUse = item;
end
end
-- Find lighter items to add Refil context menu to
for i,v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:getType() == "Lighter" then
if item:getUsedDelta() < 1 then
context:addOption("Refill Lighter", item, CraftAndRefillLighters.doFillGasAction, player);
if petrolContainerToUse then
context:addOption("Refill Lighter with " + petrolContainerToUse:getName() , item, CraftAndRefillLighters.doFillGasAction, player);
end
end
end
end
end
function CraftAndRefillLighters.DepleteGas(items, result, player)
result:setUsedDelta(0);
end
Events.OnFillInventoryObjectContextMenu.Add(CraftAndRefillLighters.doCreateMenu);
Is there another way i can get hold of it more efficiently than this ? ๐
You can see adding to the menu works, but when i want to reference an item im trying to find im having issues
if petrolContainerToUse then
context:addOption("Refill Lighter with " + petrolContainerToUse:getName() , item, CraftAndRefillLighters.doFillGasAction, player);
end
Wait did you get the action working @quaint mirage?
I've been encountering an error that prevents it from executing
Also @shadow geyser I'll be back later, I have Sunday chores to deal with
Ur code helped me add a custom menu item based on whats in my inv but havent done any logic on the event yet
Ah I see
I want to pair it with needing any type of Petrol container, it doesnt seem to either set the local variabble or create the item with concatenated item name
Fill Lighter with Bottle Of Gasoline is what i want
I think I see your problem
You're indexing a specific type of gas container instead of using the gas container tag
You're using "WinePetrol" which if I'm assuming correctly is a wine bottle full of... petrol.
It won't identify regular bottles or gas cans.
Yep that was for testing i tried hasTag("Petrol")
Ah I see
In lua you concat with .. is that right? ๐
Correct
Ill look more into probably something minor, banging my head againt the wall on it
Just make sure you use tostring() because otherwise it can get angry
(unless it's already a string then it won't cause problems)
what is it tht ur trying to do?
@quasi kernel only ever finds the item i right click on by looks of it, is there another way to search inventory only at same time
Yeah I think so
getSpecificPlayer(player):getInventory()
Then you can loop through the inv for an item that matches your criteria
Thanks
(thank you robot I shamelessly ripped that code lol)
Does this need ipairs like the other loops at all?
Thanks again
Np!
my new mod is released https://steamcommunity.com/sharedfiles/filedetails/?id=2854697788
@shadow geyser ready when you are
Actually, @thin hornet, may I call upon your wisdom once more?
I searched through discord to see if anyone had any knowledge on TimedActions and you seem to know a thing or two
yeah. do you wanna just send a github link or upload it onto steam as a private mod?
sure. idk if you can send in this channel, if not just dm it to me
Ill send it via DMs, gimme a second
I finally got it working thanks to this
CraftAndRefillLighters = {}
-- When the Refill lighter action is clicked
function CraftAndRefillLighters.doFillGasAction(item, player)
-- Todo
end
-- Create the context menu for a specific item, when lighter we want to allow refils from gas cans, so both need to be within the inventory.
function CraftAndRefillLighters.doCreateMenu(player, context, items)
-- Find lighter items to add Refil context menu to
for i, v in ipairs(items) do
local item = v;
if not instanceof(v, "InventoryItem") then
item = v.items[1];
end
if item:getType() == "Lighter" then
if item:getUsedDelta() < 1 then
local petrolItem = nil;
local playerInv = getSpecificPlayer(player):getInventory();
for x = 0, playerInv:getItems():size() - 1 do
local vItem = playerInv:getItems():get(x);
print(tostring(vItem:getName()));
if (vItem:hasTag("Petrol") or vItem:getType() == "PetrolCan") and vItem:getUsedDelta() > 0 then
context:addOption("Refill Lighter with " .. vItem:getName(), item, CraftAndRefillLighters.doFillGasAction, player);
end
end
end
end
end
end
-- As soon as a player crafts a lighter, set usedDelta to 0
function CraftAndRefillLighters.DepleteGas(items, result, player)
result:setUsedDelta(0);
end
Events.OnFillInventoryObjectContextMenu.Add(CraftAndRefillLighters.doCreateMenu);
Ohh I see how, you didn't make a custom timed action
Not yet, thats the next bit xD
Anyone know what does getPlayer() give me when I use it in script in the server folder?
Or is there a way to check if a player is local?
in the OnPlayerUpdate event
is isLocalPlayer reliable to have scripts only run on the player that the current client controls?
Think i need to figure out timed actions too, i followed a guide but cant seem to get them working, just errors out here
in media/lua/TimedActions
require "TimedActions/ISBaseTimedAction"
LighterRefillAction = ISBaseTimedAction:derive("LighterRefillAction");
function LighterRefillAction:isValid() -- Check if the action can be done
return true;
end
function LighterRefillAction:update() -- Trigger every game update when the action is perform
print("Action is update");
end
function LighterRefillAction:waitToStart() -- Wait until return false
return false;
end
function LighterRefillAction:start() -- Trigger when the action start
print("Action start");
end
function LighterRefillAction:stop() -- Trigger if the action is cancel
print("Action stop");
ISBaseTimedAction.stop(self);
end
function LighterRefillAction:perform() -- Trigger when the action is complete
print("Action perform");
ISBaseTimedAction.perform(self);
end
function LighterRefillAction:new(character) -- What to call in you code
local o = ISBaseTimedAction.new(self, character);
o.character = character;
if o.character:isTimedActionInstant() then
o.maxTime = 1;
else
o.maxTime = 30;
end
return o;
end
-- When the Refill lighter action is clicked
function CraftAndRefillLighters.doFillGasAction(item, player)
ISTimedActionQueue.add(LighterRefillAction:new(player));
end
I found this?
how can I iterate over an array like this? (https://projectzomboid.com/modding/zombie/characters/Moodles/MoodleType.html#values--) It's not a Java ArrayList but I can't figure out how to iterate over it with Lua Oo
Check when you create new Action. I think in new(...) you give null
You can access only like that: MoodleType.Panic
If you need all types, you can check in decompiled source code
kk just thought someone might know ๐
Thank you, i'll check it over again, am passing character / player in but maybe that is null xD
How does one get the player's current strength?
I'm looking in the :getStats() docs but there doesn't appear to be a :getStrength() method
There's a :getFitness() but that's not what I need
playerObj:getPerkLevel(Perks.Strength)
Tysm
So when i pass player in it's 0, do i need to run through getSpecificPlayer first?
OG : General , 1661703756456> Bottle of Gasoline
LOG : General , 1661703756456> Gas Can
LOG : General , 1661703756457> Gas Can
LOG : General , 1661703756457> Lighter
LOG : General , 1661703756457> Lighter
LOG : General , 1661703757383> Do the gas action, try prining the player...
LOG : General , 1661703757383> 0
LOG : General , 1661703757383> -----------------------------------------
STACK TRACE
-----------------------------------------
function: new -- file: LighterRefillAction.lua line # 39 | MOD: Craft and Refill Lighters
function: doFillGasAction -- file: lighter.lua line # 10 | MOD: Craft and Refill Lighters
function: onMouseUp -- file: ISContextMenu.lua line # 90 | Vanilla
LOG : General , 1661703757383> Object tried to call nil in new
ERROR: General , 1661703757384> ExceptionLogger.logException> Exception thrown java.lang.RuntimeException: Object tried to call nil in new at KahluaUtil.fail line:82.
ERROR: General , 1661703757384> DebugLogStream.printException> Stack trace:
java.lang.RuntimeException: Object tried to call nil in new
Believe so
-- When the Refill lighter action is clicked
function CraftAndRefillLighters.doFillGasAction(item, player)
print("Do the gas action, try prining the player...");
print(tostring(getSpecificPlayer(player)));
ISTimedActionQueue.add(LighterRefillAction:new(getSpecificPlayer(player)));
end
ok giving it a spin
Think i'm in business now thanks @tame mulch and @quasi kernel
why does it chuck errors at me for running transmitModData after getting and changing some mod data via indexing into it?
the error doesn't really specify a problem just the line
if hb_ItemProvidesSlot(pack,slotDef.type) then -- does our backpack provide this attachment?
item:getModData().hbSlot = ""..tostring(slotDef.type)
table.insert(itemsToMove,item)
item:transmitModData()
end```
it just goes "yeah the line where u transmit the mod data, that's an error"
neither imo but if u were gonna then fitness
if u mean for a flashlight
they don't have much resistance ive used em
Fair point
It's for a battery charger
I don't 100% know how much effort would have to go into fully charging a battery
Ok one more question and i think it might be the last for now ๐
-- When the Refill lighter action is clicked
function CraftAndRefillLighters.doFillGasAction(ligher, player, fuelSource)
ISTimedActionQueue.add(LighterRefillAction:new(getSpecificPlayer(player), ligher, fuelSource));
end
and
context:addOption("Refill Lighter with " .. vItem:getName(), item, CraftAndRefillLighters.doFillGasAction(item, player, vItem), player);
If i manually pass parameters like this the context menu doesn't close, is there a way for me to stop this or provide the data to the timed action in another way?
Don't pass params like that
addOption functions starngely
The "item" you pass first is the first param
Everything after CraftAndRefill are params 2-10
Yeah i get what its doing the params passed anon but i wondered how i can pass extra stuff
So treat the arg before CraftAndRefill as param 1
context:addOption("Refill Lighter with " .. vItem:getName(), item, CraftAndRefillLighters.doFillGasAction, player, vItem);
So currently it renders like this, which is ideal because later i want to have it show how many units are left
Maybe i can find a way to group them later kind of like the Attach to belt stuff
hm
mayb
I do have a question of my own though, is it at all possible to adjust the maxTime dynamically?
I static coded one in but looks like you can
I need to do so since my action will take an indeterminate amount of time, as it changes based on strength, fitness, current exertion, and current battery charge.
I wondered if i can pass the event down to tell the UI to close, not much else errors there
@shadow geyser any ideas?
Just gotta get this one thing done and I can make the other hand crank texture, soup it up real nice, then make battery packs
Then the thing is basically done
Ok think i get it now thanks for clarifying
yeye
Would it work to take this from the base and override it in your timed action?
function ISBaseTimedAction:adjustMaxTime(maxTime)
if maxTime ~= -1 then
-- add a slight maxtime if the character is unhappy
maxTime = maxTime + ((self.character:getMoodles():getMoodleLevel(MoodleType.Unhappy)) * 10)
-- add more time if the character have his hands wounded
if not self.ignoreHandsWounds then
for i=BodyPartType.ToIndex(BodyPartType.Hand_L), BodyPartType.ToIndex(BodyPartType.ForeArm_R) do
local part = self.character:getBodyDamage():getBodyPart(BodyPartType.FromIndex(i));
maxTime = maxTime + part:getPain();
end
end
-- Apply a multiplier based on body temperature.
maxTime = maxTime * self.character:getTimedActionTimeModifier();
end
return maxTime;
end
oo I didnt even know that was a thing
Set a player to admin without having to already be admin or have an admin online.
lol, meant to respond to this
Is there a maximum to how much pain a limb can experience?
If so, I'd like to balance my multiplier based off of that, so my charge speed is slower the more pain my hand is in
How do I do an if to check if I have one of the items in my inventory from a table?
can you get player info of offline players? ๐ค
Nop
I want to check items
In an if, to know whether or not this item is in the player's inventory
Well, I think doing:
if playerInv:contains("item1") or playerInv:contains("item2") or playerInv:contains("item3") then end
I don't think it's that efficient :(
So, I wanted to check in an IF somehow if there is this item in the player's inventory, like this:
local items = {
"Item1",
"Item2",
"Item3"
}
if playerInv:contains(Items) then end
but this method doesn't work :( so is there a correct way to do this?
local hats = {
"hat1",
"hat2",
"hat3"
}
for i=0, items:size()-1 do
for j=0 hats:size()-1 do
if(items:get(i):getType() == hats:get(j):getType()) then
--do something
end
end
end
wow, thanks. i will test here
Wouldn't something like ["hat1"] = true and hats[items:get(i):getType()] be more efficient due to dictionary indexing?
(Not that I'm saying this doesn't work, dictionaries are just muy epic)
Ive never really used them I guess
Valid
How would that work>
Basically, how an dictionary works is it uses "keys" and "definitions"
Think of an actual dictionary.
You look up a word, you get it's definition
So if you do hats["hat1"] and the definition in the dictionary of hats1 is true, you'd get true
So for example
local hats = {
["hat1"] = true;
end
print(tostring(hats["hat1"])) -- true
print(tostring(hats["hat2"])) -- nil
I hope that makes a bit of sense
This is just an optimization suggestion, alternatively you could make use of zomboid's tag system, but that's a whole other thing.
It does make sense.
Yeye!
Appreciate that, I may have use for it yet
Hehe np
sorry not quite sure what your question is?
I need to adjust maxTime dynamically so my action won't get cut off after like 5 seconds of charging
I want the player to keep charging
why don't you just set it -1 . I think -1 stops it from doing anything
then the action will just last however long you tell it to last in the beginning
Yeah but that's the problem

I'm gonna need some stupid equation just to calculate the time it'd take, and it wouldn't even be reliable
anybody here take commissions?
well, you need to do that anyways if you want the progress bar to be meaningful
@jagged ingot
Is there not a setProgressBar method or something I can use?
Because then I can just make the progress bar correspond to my battery charge.
The entire problem is that it changes endurance as it like
Charges
And the endurance modifies how much is charged
ntm the player can walk and do the action at the same time which can also drain endurance depending on the load
found it
What would be the value of "items" ?? is the inventory?
self.action:setTime(math.max(self.object:getWaterAmount(), 100))
hello can someone help me i have a few questions about modifying a mod
the mod noir does not support some authentic z backpacks and to add the backpack what do i need to do i am looking at the structure of one back and it looks something like this
oh I see. well then im not sure how you would get a proper progress bar, you might have better luck making repeated Timed actions, andyou would recalculate it every time. so you would have one action for each unit charged
can i copy the whole script and just change the name for the one of the backpack i want or does it not work like this
function ISAddPollenAction:perform()
local inv = self.character:getInventory()
local count = inv:getItemCount("Hydrocraft.HCPollen")
local args = { x = self.beehive.x, y = self.beehive.y, z = self.beehive.z}
inv:Remove("HCPollen");
sendClientCommand(self.character, 'Beehive', 'addPollen', args)
-- needed to remove from queue / start next.
ISBaseTimedAction.perform(self);
count = count - 1
-- add 2 week_unit to check if new action is needed because beehive.pollenAmount wont update immediately
if ((self.beehive.pollenAmount + 2*Beehive.week_unit) <= self.beehive.honeyMax and count > 0) then
-- queue up another pollen action if the beehive has the space for it.
ISTimedActionQueue.add(ISAddPollenAction:new(self.character, self.beehive, 100))
end
end
just do it like this to make the repeated actions. obvs you would be recalculating the time for the action as well
oo i see
How do I get it to respect game time?
In other words, faster game speed make it go nyoom
There's gotta be a way to get elapsed time to calculate speed right-
I don't believe os.clock() would be reliable since it's not dependant on game speed
I need a time variable that is dependant on game speed.
so uh, you're trying to make the action work even when the player is running/sprinting around instead of walking?
I'm not too worried about that anymore
I only wanted it to be walking lol
Robot found a solution that satisfies me
OK, cool, because that would be a lot of additional complexity for not much real gain
Now I'm just worried about adjusting :update() to game speed
Because it's per tick, but ticks don't update based on game speed
anyway, as for making the operation take the correct amount of time; the code for refuelling from a gas pump does this
And nor does os.clock (I don't even know if Kahlua respects os.clock)
yeah, don't use os.clock - look at how they do the time calculation for refuelling, that's all you need
"ISAddFuel"?
I think that's for gens-
Probably something else
Ah, ISTakeFuel
Seems to be using :getJobDelta()
well yeah, because that delta value essentially represents the increment between the last call to update() and the current call to update
AKA, the delta ๐
I believe the value depends on how quickly the game is running, and also how frequently the game is able to invoke your update function
print the value of getJobDelta to the console and you'll see
(and print it from your update function)
It seems to be more like a "job completion" delta more than anything
Can anyone tell me how to add custom occupations in current cities? I mean they do spawn as unemployed, but I want to add custom ones to them with default "city spawns".
I tried to find mod analogue but can't somehow
what do you see when you print the value out?
a 0-1 value
Nothing more, nothing less.
Likely representing the progressbar completion.
show me a few lines of output
It just progressively increases until it strikes 1, then resets because a new job is called.
ah OK, yes. that should be dependent on what you configure in your start() using self.action:setTime()
Well, until it strikes one or the action ends prematurely.
Isn't set time just the action duration?
I dunno if what I have is even compatible with getJobDelta because of how it's set up
function ISChargeBattery:update()
print(self:getJobDelta())
local strength = self.character:getPerkLevel(Perks.Strength)
local currEnduranceLevel = self.character:getMoodles():getMoodleLevel(MoodleType.Endurance)
if self.handCrank and self.handCrank:getUsedDelta() < 1 and self.character and currEnduranceLevel < 4 then
local unhappiness = (1 - self.character:getMoodles():getMoodleLevel(MoodleType.Unhappy)/4)
self.handCrank:setUsedDelta(self.handCrank:getUsedDelta() - ((self.handCrank:getUseDelta() * ((0.002 * (math.pow(strength, 2)) + 0.17 * strength + 0.1)) * (1 - (currEnduranceLevel/4) * (1/(unhappiness+1))))) * getGameSpeed())
self.character:getStats():setEndurance(self.character:getStats():getEndurance() - 0.00005 * getGameSpeed())
end
end
It gets the strength, current endurance level, current unhappiness level, and goes.
at the start of the action, you should calculate the total amount of time it will take to completely fill the battery and pass that to setTime
Don't mind game speed, that was an old solution.
then, in your update function, getJobDelta() is essentially the fraction of completion
That's the problem, how do I do that? The time can vary greatly and will increase/decrease because of endurance and the like.
I'd have to do some over the top formula, and there's still a risk it could end before it's supposed to be finished because the character could be walking with a heavy load, further reducing endurance more than expected
And preventing the player from walking would just be awkward with something like this
so, the way I would suggest doing it is like this:
at the start, compute a modifier value based on current exertion and remember what their exertion was.
If at any time during a call to update() you find that their tiredness has changed, requeue your action so that start() will be called and you can end the current one
this will result in the user seeing a fresh progress bar, but this makes more sense because the amount of time it's going to take has changed anyway
hm
What even is "time" anyways? Is it ticks? Elapsed in-game time? Elapsed computer time..?
I'd need to base it around whatever it is correctly
it corresponds to the in-game clock
Ok, so 60 is an in-game minute.
the only thing you should be doing is computing the value you want to pass to setTime()
you don't need to care about game speed or anything like that because getJobDelta() is the representation of how much time has elapsed relative to how long you said it should take to complete
just make it work without considering endurance first
So only considering unhappiness and strength?
no, don't consider any of that crap
Ok
because you're talking about applying a penalty as a factor of... three stats?
endurance, unhappiness and strength?
OK, so, once it works without considering any of them, applying the modifiers should be fairly straightforward math. start with strength first
So let's say the base time is 600 seconds, or 10 minutes to charge a single battery.
That sounds like a long time but in-game time passes fast
And this is a dinky little charger anyways
sure, and at strength level 0, your multiplier is 1 (i.e. unchanged)
Oh, I'd figure it'd give a negative multiplier and we'd change based off of 5
So 5 would be our mulitplier of 1 since that's generally "default"
what? no, don't do that
just decide what the multiplier for strength level 1 is, and level 10
10 should be 2, 0 should be like, I guess 1 or something lower.
(Yes strength 0 is possible)
no, don't express it like this
strength 0 is obvious, it's no change
say, strength 1 gives you a 10% speedup and strength 10 gives you a 90% speedup
well, you tell me, what is the min %age speedup and max that you want?
At 10 I know I want it to go twice as fast, so 100%
that would be 50%
?
going twice as fast is either divide by 2, or multiply by 0.5
the code will be easier to make sense of by using multiplication rather than division
once you decide what the speedup for level 1 and level 10 is, we can derive a formula - obviously you could also manually choose a value for every level, but now you've got to write code for every damn strength level
as an example, let's say you choose that it's 5% up to 50%, you simply do baseTime * (1 - (0.05 * strengthLevel))
Oh, so it's just (1 - (.1 * strengthLevel))..?
Sorry, I've never been good at making formulas.
huh? I gave you the formula right there
or are you now saying you want it to range from 10% to 50% speedup?
Hold on im trying to wrap my head around this, I've been okay with the logic side of programming but math has never been my strong suit, hence why I never entered the field.
Just kinda do it as a hobby.
I can make really basic formulas but it takes me a second to read them and make sense of them, so apologies
then perform a substitution: at strength level 1, it would look like baseTime * (1 - (0.05 * 1))
So basetime is 600, (1 - (0.05 * 10)) is 1 - (.5) which is .5 in the end result, so it'd be 600 * .5 which is 300
That'd be with strength 10
which then becomes baseTime * (1 - 0.05) and finally baseTime * 0.95
Oo that makes sense now!
Okay
Thank you for your patience
I'm a little slow sometimes

Alright, that formula makes sense to me now.
so
InventoryItem has getModData, and you can put mod data in there
but it does not have transmitModData
wait what
so.. what do you do to ensure mod data gets propagated
Does it get automatically transmitted or something?
idk im gonna have to dig in the source if nobody knows
Okay okay, hold on, unhappiness should be the next one.
I thought it just gets set since itโs a lua table
@weak sierra correct, because it's not a world object
Unhappiness is a range of 0 to 4.
Or do you mean like transmitted to the server or something
4 being worse case scenario, 0 means perfectly content with life.
server yes
so there's a mod i use
and it saves some stuff and works fine in SP
but on MP the items it relates to despawn when u relog
and i noticed no transmit lines, so i added some
maybe this particular one isn't needed
but
now i want to understand how ur supposed to ensure transmission of moddata for inventory items
Let's say maximum depression is 200%, or 2
ok so the java for getModData just literally gives a table if it exists, if not it gives a new one
looks like InventoryItem:save does the thing
that's when the game is getting saved, unsurprisingly
if i can call that that'd be fine
but
seems odd
so, here's the specific case:
"Save Backpack Attachments" mod
forces items attached to backpacks (with one of several mods)
into the pack, disregarding weight limits
saves info about them in the pack's moddata
and/or in the items' moddata
and in the player moddata
relog -> the attached items are deleted from the bag somehow
AFAIK, inventory item mod data was never designed to be shared across players; the worldItem of the inventory Item can though, since it's a class that derives from IsoObject
which now that im talking through it seems more like the inventory update isn't being saved
and is only clientside somehow?
function SavePackAttachments(pack,player)
local items = {}
-- loop through all attached items, and find ones provided by the backpack
local hotbar = getPlayerHotbar(player:getPlayerNum());
if hotbar ~= nil then
--SA_ClearOldPacks(pack)
local itemsToMove = {}
for i,item in pairs(hotbar.attachedItems) do
local slot = hotbar.availableSlot[i]
local slotDef = slot.def
if hb_ItemProvidesSlot(pack,slotDef.type) then -- does our backpack provide this attachment?
item:getModData().hbSlot = ""..tostring(slotDef.type)
table.insert(itemsToMove,item)
end
end
if #itemsToMove > 0 then
for mi,mitem in pairs(itemsToMove) do
-- put them in the bag and set mod data.
hotbar:removeItem(mitem, false)
if mitem.isEquipped and mitem:isEquipped() then
player:removeWornItem(mitem)
end
pack:getItemContainer():AddItem(mitem)
--player:getInventory():Remove(mitem)
end
end
end
end```
here's the function that manages the indiviual items to be saved/moved
so it's storing what slot they go in in the moddata
but the items are disappearing on relog, so it's not just missing moddata
pack:getItemContainer():AddItem(mitem)```
is this insufficient?
i haven't messed with inventory code much yet
are there item scripts for these things or are they getting generated on the fly?
they're existing items in the game
anything that happens to be attached to the apck
could be a wrench, a spiffo plushie
whatever
it sounds suspiciously to me like the code is creating the item definitions on the fly rather than having them defined in media/scripts
it's base game items even
idk what u mean
it gets item references from the hotbar
and operates on those
u can see it above
there are two ways to define an item: the default is media/scripts, the "custom" way is to write lua code that defines it. In either case, they get added to the world dictionary of the game's save
yes i know
but these are not items from this mod
at all
they are items from any mod and the base game
as i said
my examples included a wrench
it doesn't matter what the item is
so it can't matter how it's defined
yeah, but it sounds to me like they're actually different items which are generated on the fly. this will fail in multiplayer because the server has no idea about them. so when you rejoin the server, your world dictionary will be re-downloaded
but fwiw i don't think any dynamically generated items are going on
since those on-the-fly items don't exist in the world dictionary, they get deleted
OK, then they shouldn't be getting deleted
actually, do this, use Edit Item on any item that is getting deleted, what is its fully qualified name?
it'll be something like Base.BlahBlah
OK, so reproduce the bug, and before you sign off, examine the fully qualified name of the item
no, I want to rule it out
Doesn't work. ๐
it's far more sensible to verify it's not the most common cause of items disappearing before diving deeper
ive read all the code for the mod
it's not making new items at all
it just uses the existing items
and moves them around
adding/removing them from inventories
never makes a new one
well, you've read all the code, sure. Yet here you are
link to the mod?
has anyone ever tried to pass an param of type ByteArray?
one file does all the heavy lifting, the other displays little yellow dots by the icons in teh inventory
lua files that is
taking some time to test, have to remove the patch mod from my local test dedicated, reboot it, join
so u can't edit items while they're in a bag on the ground
hm
maybe using SAC i can access them while they're in the bag but within my inventory
hm, I'm slightly suspicious as to how it's presenting the items client-side. I've seen mods that present additional items client side based on traits and the additional items vanish as soon as you attempt to move them because the server disagrees about their existence - one way to verify this is to instead dump the item out onto the ground and see if it does remain
ok yeah i looked at it thru SAC
same ID
as i said it just removes it from the attachment and adds it into the bag
the item is just an item
with some metadata
yeah u can take the items out
sometimes the markers glitchily stay on them
but
let's see
yup the two plushies i tried with appeared on the ground fine
yeah, it's some anticheat they added a while back
server doesn't think the items are really "there"
no, I never looked into it, try turning them all off and see if the problem goes away, though I have the suspicion that it won't
I don't think this particular "item accounting" was ever exposed as a server var
what do u think is breaking anyway?
do u think the server doesn't "know" that the items are in the bag?
so they're phantoms on the client?
but if that's the case they would have disappeared no?
when dragging to floor
cuz that triggers a command on the server i think
it does, but it's different
to place the world object
if you have a mod that creates client-side items, you can always make them not get deleted by first dragging them to the ground
but, whenever you pull them straight to your inventory, server nukes them
ill also test that
i did experience that at one point i vaguely recall in the past
but that was fixed at some point
without an update to the mod
i think something else was breaking that previously
I still get it when I play on servers with the scavenger skill mod
nod
yeah im familiar with that
generates extra items based on skill
and does it on client end cuz written with SP in mind
or without MP in mind
whichever u wanna think of it as
the shitty thing is that to test this i have to reboot a server every time to give myself the ability to log in and out lmao
makes each test cycle slow
which is why i sought help instead of just troubleshooting it endlessly
what do you mean by restart the server every time to login and out?
if i change stuff
obviously not if i dont have to change stuff
:p
to change code or settings, etc
if you're changing the server code, yeah, you have to restart the server
baseTime * (1 - (0.125 * unhappiness)) I think?
It took me way too long to finish that I got distracted
and i have to publish it
if you're changing the client code, you don't if you disable the lua checksum option
you don't have to publish it, you can make the server run mods in your Zomboid/Workshop folder
that's how I test all my own mods, I don't first publish them
i run it from a separate folder cuz im on linux and run the client in wine
i could copy it
ig
or symlink
im not sure if any of this runs on the server end, it has code in the server folder so it should be performing this stuff on the server end
if that's how that works
why? most of the game is java
and some textures/etc. missing probably due to path interpretation stuff
there's just a few native libs that are JNI'd
interesting, you should try it on a case-insensitive mount point
never considered that tbh
but that's a thing for anothr day
well, after dragging them to the ground and putting them back in
they dont disappear but the moddata is discarded
so they dont re-attach themselves either
im guessing those are not related issues though
Okay so for Endurance..
0 would be 1, or 100%
4 would be 0, or 0%
but the IDs were fine
(Dont mind me)
so what does that mean
DEBUG: Multiplayer , 1661721780910> 1,698,334,344> ItemTransactionManager.receiveOnServer> set accepted [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721781127> 1,698,334,560> ItemTransactionManager.receiveOnServer> remove processed [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721817421> 1,698,370,854> ItemTransactionManager.receiveOnServer> set accepted [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721819494> 1,698,372,927> ItemTransactionManager.receiveOnServer> remove processed [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721897872> 1,698,451,305> ItemTransactionManager.receiveOnServer> set accepted [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721898077> 1,698,451,510> ItemTransactionManager.receiveOnServer> remove processed [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661721901470> 1,698,454,903> ItemTransactionManager.receiveOnServer> set accepted [ 308852067 : 315655877 => -1 ]
DEBUG: Multiplayer , 1661721901556> 1,698,454,989> ItemTransactionManager.receiveOnServer> remove processed [ 308852067 : 315655877 => -1 ]
DEBUG: Multiplayer , 1661721903304> 1,698,456,737> ItemTransactionManager.receiveOnServer> set accepted [ 418050617 : 315655877 => -1 ]
DEBUG: Multiplayer , 1661721903390> 1,698,456,823> ItemTransactionManager.receiveOnServer> remove processed [ 418050617 : 315655877 => -1 ]
LOG : General , 1661721933945> 1,698,487,378> watering plants
DEBUG: Multiplayer , 1661722104009> 1,698,657,442> ItemTransactionManager.receiveOnServer> set accepted [ 308852067 : -1 => 315655877 ]
DEBUG: Multiplayer , 1661722104489> 1,698,657,922> ItemTransactionManager.receiveOnServer> remove processed [ 308852067 : -1 => 315655877 ]
DEBUG: Multiplayer , 1661722104489> 1,698,657,922> ItemTransactionManager.receiveOnServer> set accepted [ 418050617 : -1 => 315655877 ]
DEBUG: Multiplayer , 1661722105014> 1,698,658,447> ItemTransactionManager.receiveOnServer> remove processed [ 418050617 : -1 => 315655877 ]```
guessing that's it being well aware of the movement of items
lets try without putting it on the floor and seeee
DEBUG: Multiplayer , 1661722621110> 1,699,174,543> ItemTransactionManager.receiveOnServer> set accepted [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661722623190> 1,699,176,624> ItemTransactionManager.receiveOnServer> remove processed [ 315655877 : -1 => -1 ]
LOG : General , 1661722685581> 1,699,239,014> watering plants
DEBUG: Multiplayer , 1661722787409> 1,699,340,842> ItemTransactionManager.receiveOnServer> set accepted [ 315655877 : -1 => -1 ]
DEBUG: Multiplayer , 1661722787626> 1,699,341,060> ItemTransactionManager.receiveOnServer> remove processed [ 315655877 : -1 => -1 ]```
I would be curious to know what happens if you move the server code to shared instead
probably a different kind of breakage, but at least server and client would be "doing the same thing"
dunno, try it
ill have to move the whole mod into my fix copy then for now
and copy it to both spots..
will take a few mins
or
edit both workshop copies
i should see if this happens in SP, too
i just assume it doesnt but who knows
unlikely, the client and server folders become meaningless in SP
all code from all 3 folders is executing in one lua state
gonna rule that out before i continue
as a sanity check
make sure it isnt a fundamental issue with the mod rather than a syncrhonization one
you mean you didn't check if it was also broken in SP?
I doubt it would be broken in SP
due to the behavior only occuring on logout
and login
but
who knows
maybe quit-reload save
let's find out
Hey oli, would I check to see if things changed in update?
Does anyone know how I get a zomboid sound? A sound effect you already have in zomboid?
well, since their fatigue could certainly change, yes
if you really want to be consistent, you could also check unhappiness but I'd consider it a bit of overkill
imo unhappiness isn't that unrealistic to check
Esp with smoker without cigarettes existing
it's not at all unrealistic, just more work for little gain
What would be overkill is checking strength LOL
letting them get away with crossing over a boundary for unhappiness isn't that big of a deal
huh?
the items do not disappear in SP but the moddata is still lost after a reload
What vehicle are you supposed to be using for the ISO gasoline tank?
what?
#mod_support , but any - pick one with high engine power to weight ratio.
there is no IsoGasolineTank
it's from a mod.
ah
containers i think
thing has no wheels, barely moves when full
heh
alright, now gonna test making that stuff be in shared instead of server
well nothing weird happened on the first part, relogging..
ok well that seems to have fixed that, unless i've lost my mind, which after enough tests that can happen
moddata still lost but that's a smaller problem
figures
so back to the original problem i suppose
the moddata is not saved
stuff is stored on the player and on the items
provided the player moddata is being synchronized OK
could move the other stuff into a table within that moddata
but then it'd be annoying to render the icons, have to mess with that too



