#mod_development
1 messages ยท Page 64 of 1
I was about to say, that's pretty much every single mod that uses sandbox options
I mean here's sandbox hits in log
https://pastebin.com/L8hvSEmK
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.
looks fine to me
hm
I guess I could try disabling mods that create sandbox options in bunch see if it fixes issue
but idk
this is plain stupid why would a sandbox error in one mod fuck up my page
Any strack traces?
no errors
Odd
so whos gonna make a christmas tree mod
i was thinking about modeling + texturing some presents
it would be cool if you could wrap the thing you want with wrapping paper and you had to unwrap it to get whatever it was out of it
instead of it being a container
kind of like how the MRE's work i guess?
that shouldn't be too difficult
idk how to do any coding stuff but
if i model some presents n wrapping paper things would someone be down to make it for christmas
we have to have a zomboid christmas
i've been a bit busy recently, but i do love christmas...
Super Weird Helis has a Santa Clause event - triggers on real life Christmas week and in-game Christmas at a higher rate
Forgot about it - can't wait to get bug reports for extra events lol
i think it can be done pretty simply, i'm sure i could find time to write it
im gonna model like 5 diff shaped boxes
w textures
ill just use some royalty free seamless textures and slap em on with a ribbon texture
the hardest part is gonna be modeling the ribbon
LOL
Shitty Ribbon
Honestly, for Zomboid's style and camera distance, you're basically done
Found the culprit. Somehow these 40 lines of code fuck it up.
local fn_false = function()
return false
end
--require "ISUI/ISUIElement"
--ISUIElement.getKeepOnScreen = fn_false
--ISPanel>ISItemsListTable
--ISPanel>ISPlayerStatsUI
local NORMAL = {'ISCollapsableWindow', 'ISPanelJoypad', 'ISWindow', 'ISPanel',
'ISDebugPanelBase','ISDebugMenu'}
local ERRORS = nil
for _,v in pairs(NORMAL) do
--require('ISUI/'..v)
if _G[v] then
_G[v].getKeepOnScreen = fn_false
else
ERRORS = ERRORS or {}
table.insert(ERRORS, v)
end
end
------------ EXCEPTIONS ------------
local fn_true = function()
return true
end
local EXCEPTIONS = {'ISVehicleDashboard','ISToolTip','ISTextEntryBox',
'ISContextMenu','ISChat','ISInventoryPage',}
for _,v in pairs(EXCEPTIONS) do
if _G[v] then
_G[v].getKeepOnScreen = fn_true
else
ERRORS = ERRORS or {}
table.insert(ERRORS, v)
end
end
if ERRORS then
for _,v in ipairs(ERRORS) do
print('ERROR in WindowsEverywhere: module "' .. v .. '" not found!')
end
error('WindowsEverywhere has to be fixed!')
end```
from this mod
it has 1 lua file
fuck I really liked that mod

if you saw the UV texture for this thing youd think im the worst person alive
i bet
lol
Lol, I love it
HEATHEN
I have no clue how to effectively UV map
I'm not gonna lie it looks like something I'd find in Blockland and that ain't an insult
ooh lovely
im gonna find some cute lil seamless textures
hopefully the UV isnt a pain in my ass when i change the shape
since its still technically a cube
Did you change the sledgehammer sprite?
Order of the hotbar
Ooooh.
back is always first by default
Main challenge right now is ensuring compatibility with Weapon Condition Indicators. Ties my hands a bit in what I can do.
Is there a function of the context menu options that allows you to add a function to the "back" command sent from a gamepad upon choosing to back out of the context menu? he asked, fully expecting crickets but hoping to be wrong...
Looks like there is a fairly clean point to add custom code
function ISContextMenu:onJoypadDown(button)
if button == Joypad.AButton then
if self.mouseOver > 0 and self:getIsVisible() then
--print("calling option : " .. self.options[self.mouseOver].name);
-- we call the function if we have one
local option = self.options[self.mouseOver]
if option ~= nil and option.onSelect == nil and option.subOption ~= nil then
local subMenu = self:getSubMenu(option.subOption)
subMenu.mouseOver = 1;
if self:isOptionSingleMenu() then
subMenu.mouseOver = subMenu.mouseOver + subMenu:getDefaultOptionCount()
self:displaySubMenu(subMenu, option)
else
setJoypadFocus(self.player, subMenu)
end
elseif option ~= nil and option.onSelect ~= nil and not option.notAvailable then
ISContextMenu.globalPlayerContext = self.player;
self:closeAll();
option.onSelect(option.target, option.param1, option.param2, option.param3, option.param4, option.param5, option.param6, option.param7, option.param8, option.param9, option.param10);
end
end
end
-- HERE VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
if button == Joypad.BButton then
--[[
if self:isOptionSingleMenu() then
if self.parent then
self:displayAncestor(self.parent)
return
end
end
--]]
self:closeAll()
end
end
You could instantiate your context menu instance then override this bit
it freezes for ~20 seconds when you try to use the recipe to load every item in the game for this preview ๐
wrap present > all is also a funny button to have
maybe i won't use a recipe after all ๐
Very interesting idea... I will consider it. Thanks a bunch for finding that. I had actually resolved to add a "close" button to the context menu when I was that many levels deep
thems a lot of big type words, and i'm gonna take them as offense.
Doesn't seem to close the target menu...
Trying
Jumper.onContextMenuJoypadDown = ISContextMenu.onJoypadDown
function ISContextMenu:onJoypadDown(button)
Jumper.onContextMenuJoypadDown(self, button)
if button == Joypad.BButton then
if self.parent then
self.parent:setVisible(false)
end
self:setVisible(false)
end
end
So right after it does its original stuff I try to setVisible(false) on the parent and itself
Yet the deepest context menu survives ๐ญ
For some reason this bug does not exist for KBM users
I need to look into what happens differently when clicking off context menu vs. hitting B-button.
Something is missing for gamepad users (as usual ๐ญ)
wowo
(Also tried right before original function, no dice)
Bahahaha @wet sandal
Super hacky fix
But I got it workin on that breadcrumb
For laughs:
-- Context Menu Fix
Jumper.onContextMenuJoypadDown = ISContextMenu.onJoypadDown
function ISContextMenu:onJoypadDown(button)
Jumper.onContextMenuJoypadDown(self, button)
if button == Joypad.BButton then
for index = 1, #Jumper.categoryMenus do
if Jumper.categoryMenus[index]:isVisible() then
Jumper.categoryMenus[index]:setVisible(false)
end
Jumper.categoryMenus[index] = nil
end
end
end
-- Category Menu Fix From Hell
Jumper.categoryMenus = {}
-- World Context Menu Options
Jumper.bringingBuddies = false
Jumper.addCategoryLocation = function(player, menu, category)
local categoryMenu = menu:getNew(menu)
Jumper.categoryMenus[#Jumper.categoryMenus + 1] = categoryMenu
. . .
end
Tysm for spotting that function.
โค๏ธ
Nice!
Almost done my mod, just gotta add proper support for blank slots in the middle (they get shoved to the right side no matter what right now)
that is a great mod, i always want my main weapon to be 1
Is there a way to load additional recipe files, only if a sandbox bool is checked/true? I know how to create the options, and read the values, however I don't know how to make the Lua function add the file(s) containing the additional models, recipes, items, etc if said value is true.
Rubber Ducky solved it, feel free to skip these messages.
DEPRECATED: Okay, y'all, I'm increasingly suspicious the problem is, as usual, me. So the deal here is that all these menu functions and submenu functions work just swimmingly as long as you navigate straight to them and activate them...
Jumper.addCategoryLocation = function(player, menu, category)
local categoryMenu = menu:getNew(menu)
Jumper.categoryMenus[#Jumper.categoryMenus + 1] = categoryMenu
menu:addSubMenu(menu:addOption(category), categoryMenu)
for index, location in ipairs(Jumper.connections[category]) do
local locationMenu = menu:getNew(menu)
menu:addSubMenu(categoryMenu:addOption(location.name), locationMenu)
local jumpText = "Jump"
if SandboxVars.Jumper.canBringBuddies then jumpText = "Solo Jump" end
locationMenu:addOption(jumpText, player,
function()
Jumper.bringingBuddies = false
Jumper.jump(player, location.name, location.category)
categoryMenu:setVisible(false)
end
)
if SandboxVars.Jumper.canBringBuddies then
locationMenu:addOption("Group Jump", player,
function()
Jumper.bringingBuddies = true
Jumper.jump(player, location.name, location.category)
categoryMenu:setVisible(false)
end
)
end
locationMenu:addOption("Rename", player,
function()
Jumper.RenameLocationPanel:setCategory(category)
Jumper.RenameLocationPanel:setLocation(location.name)
Jumper.RenameLocationPanel:open()
if Jumper.joypad(player:getPlayerNum()) then
JumperKeyboard.show(
player:getPlayerNum(),
Jumper.RenameLocationPanel.textEntry,
Jumper.joypad(player:getPlayerNum()),
"Location", true --> renameMode
)
else
Jumper.RenameLocationPanel.textEntry.javaObject:focus()
end
categoryMenu:setVisible(false)
end
)
locationMenu:addOption("Forget", player,
function()
Jumper.forgetLocation(player, location.name, location.category)
categoryMenu:setVisible(false)
end
)
end
categoryMenu:addOption("Remember Current Location", player,
function()
Jumper.LocationPanel:setCategory(category)
Jumper.LocationPanel:open()
if Jumper.joypad(player:getPlayerNum()) then
JumperKeyboard.show(
player:getPlayerNum(),
Jumper.LocationPanel.textEntry,
Jumper.joypad(player:getPlayerNum()),
"Location"
)
else
Jumper.LocationPanel.textEntry.javaObject:focus()
end
end
)
categoryMenu:addOption("Rename Current Category", player,
function()
Jumper.RenameCategoryPanel:setCategory(category)
Jumper.RenameCategoryPanel:open()
if Jumper.joypad(player:getPlayerNum()) then
JumperKeyboard.show(
player:getPlayerNum(),
Jumper.RenameCategoryPanel.textEntry,
Jumper.joypad(player:getPlayerNum()),
"Category", true --> renameMode
)
else
Jumper.RenameCategoryPanel.textEntry.javaObject:focus()
end
end
)
categoryMenu:addOption("Forget Entire Category", player,
function()
Jumper.forgetCategory(player, category)
end
)
end
However, if I navigate to the 3rd level deep menu items, (Category > Location > Jump, e.g.), and then I press Left on the D-Pad, it skips from Jump-level to Category-level focus. The problem is that (A) this is not proper vanilla behavior for D-Pad left from 3rd to 2nd level of the world context menu, and (B) this leaves a misleading highlight on the 2nd level context option until you press D-Pad Right followed by D-Pad Left to trip the 2nd to 1st level transition, which is working correctly (which of course many people would never think to do, given the misleading visual cue about what is actually selected).
I feel like I must be doing something subtly wrong going from menu (the main level where I add a Category Name) to the first submenu (a Location in my code) to the second submenu (options to Jump, forget a Location, etc.).
I must not be linking them the way vanilla needs them to be linked but I just can't see why not.
Wait... could it be this?
local locationMenu = menu:getNew(menu)
Should it be this?
local locationMenu = categoryMenu:getNew(categoryMenu)
Omg that was it?
Thank you, Sir Ducky.
๐ฆ the duck method always works >.>
The duck always prevails.
Have created item with OnEat = 123ABC , but no context menu appears for using item, any help
Whacha building?
@viral karma @bronze yoke @astral dune @thick karma
Thank you for the support. Got the radar working ๐
Is it a food? Should be a food i think for. That to work. But i could be wrong
RADAR RADAR RADAR RADAR
i can't wait to see it be used wanna see some tickets MUHAHHA
christmas presents!
Got it thanks, was trying to do the noob way to make meds but didn't have HungerChange = X so it didnt think it was food
Hey ya'll whats the best way to automate server restarts to update mods? sorry if this gets asked allot.
A mod like one of these:
https://steamcommunity.com/sharedfiles/filedetails/?id=2844315442
https://steamcommunity.com/sharedfiles/filedetails/?id=2779169728
Plus a batch file that auto-restarts the server when it's closed. The mod will gracefully crash the server when the specified conditions are met (personally our community server uses the first one), such as updated mods were detected, and, noone is logged onto the server. The batch file will restart the server binary once it closes.
this is getting too deep ๐ฆ
@true vault Thank you, been trying to find a way without using RCON, just something simple.
As an example, the .bat file would look something like:
:start
@echo off
echo Starting Server
@setlocal enableextensions
@cd /d "%~dp0"
SET PZ_CLASSPATH=java/istack-commons-runtime.jar;java/jassimp.jar;java/javacord-2.0.17-shaded.jar;java/javax.activation-api.jar;java/jaxb-api.jar;java/jaxb-runtime.jar;java/lwjgl.jar;java/lwjgl-natives-windows.jar;java/lwjgl-glfw.jar;java/lwjgl-glfw-natives-windows.jar;java/lwjgl-jemalloc.jar;java/lwjgl-jemalloc-natives-windows.jar;java/lwjgl-opengl.jar;java/lwjgl-opengl-natives-windows.jar;java/lwjgl_util.jar;java/sqlite-jdbc-3.27.2.1.jar;java/trove-3.0.3.jar;java/uncommons-maths-1.2.3.jar;java/commons-compress-1.18.jar;java/
".\jre64\bin\java.exe" -Djava.awt.headless=true -Dzomboid.steam=1 -Dzomboid.znetlog=1 -XX:+UseZGC -XX:-CreateCoredumpOnCrash -XX:-OmitStackTraceInFastThrow -Xms16g -Xmx16g -Djava.library.path=natives/;natives/win64/;. -cp %PZ_CLASSPATH% zombie.network.GameServer -statistic 0 %1 %2
cls
timeout /t 30 /nobreak
goto start
Change the -Xms16g and -Xmx16g to whatever is appropriate for your own server.
@faint jewel how will people get the truck driver role?
ahh well what if some one want's to change professions ๐ฆ
itll limit the server a bit don't you think?
well we need a mod for that then.
Can you add "start /wait C:\steamcmd\steamcmd.exe +login anonymous +app_update 380870 +quit" so it also will check for game updates?
a profession board. where they can rechoose their profession.
lmao i think we should just let anyone be able to do it. if they buy it and don't have a truck then boom they are sol LOL
jk the profession board would be cool
That's what the mods I mentioned are for >.>
Oh wait, you said game updates there... I have no idea if that would work TBH, though, you might be able to append it to the end, before it loops back to the start..
I'll give it a go, the batch I was playing with would open the steamCMD updater then launch
The startserver.bat
Alright, so still looking if anyone can answer this:
Is there a way to load additional recipe files, only if a sandbox bool is checked/true? I know how to create the options, and read the values, however I don't know how to make the Lua function add the file(s) containing the additional models, recipes, items, etc if said value is true.
However, I also now need to know how to pull a sandbox option from the server, so the client can see if something is enabled or not.
Coincidentally, they're actually for two different things/options >.>
i aint put it in yet, could make it a server option... "only truckers can truck" XD
sandbox options should be synchronised anyway
as for conditional recipes, you can either create the recipe entirely through lua if it's enabled, or create it in the script and use some lua to yeet the recipe if it's disabled
What's the motivation for only loading the recipes based on sandbox vars? Couldn't you just control whether players know the recipe using Lua?
if the recipe is meant to be learned, this becomes very complicated, but yeah that is my preference
a mod of mine has a conditional recipe and i just set it to need to be learned when it's disabled
but i helped a server with removing an recipe from vanilla in a way that should be compatible with that too
Seems to work nicely ๐
(That's an AutoTsar bear bus bullbar installed on the front of a Filibuster Rhymes' RV)
i'm glad that worked for you!
Frankensteining different vehicle mods together isn't what I was planning on doing, but now that I can... ๐
questions, can you change a vehicles whole script while driving it?
just for... reasons.
Yeah, some way to refresh a vehicle's script during play would make debugging much faster, too. Like, I can modify the script object using Albion's technique, but it doesn't appear to update on the vehicle.
Actually, I seem to recall seeing a BaseVehicle method which applies the script to itself, need to go fishing...
it was before my time helping them, but stfr used to swap vehicle scripts instead of using skins and it caused a whole bunch of issues
i want to change a vehicle to ANOTHER vehicle.
it wasn't the right way of doing things in the first place so i never investigated if those issues could be mitigated
but there will at the very least be complications
I HAVE A GIMMICK VEHICLE THAT SOUNDS FUN. leave me alone lol.
No
Is it possible to set vehicle to not colide and not visible in any way?
What about changing wheels animation?
what are you trying to do?
I might mess with the idea of house on legs.
https://steamcommunity.com/sharedfiles/filedetails/?id=2560478285 ooooooh if only omeone would turn this into a general "point to a location" library, that would rock.
maybe some better art lol
Oh please continue down this avenue. This would be so rad.
I'm certainly having a good look at what's possible ๐ I'm rather attached to my Franklin Trip RV in my SP game, so being able to armor it up rather than switching to a Bear Bus is very appealing.
Hell yeah! Even if it is just the RV, sharing the code might make it possible for others to extend it to more vehicles and create a proper Mad Max style Zomboid experience ๐
I'm not sure how the AutoTsar author would feel about it though. The ATA Bear Bus mod and TsarLib mods would need to be dependencies of any mod this experimentation might grow into, but given that the armoring up is kind of the schtick of the ATA mods, they might not be happy about it being applied to other vehicles.
But first things first, seeing if it's even possible is fun ๐
Absolutely. They have their own Discord channel if you wish to ask them directly about permission to post your mod publicly ๐
That is pretty damn neat.
Would it be possible to add a Mod Options toggle to 'lock' the bar so you don't accidentally drag n' drop anything? ๐
The same request I got for the inventory containers version
Why did i not see this coming
Hahah ๐
Good call
I haven't played online in a tick, is the inventory containers one compatible with MP? I remember an earlier version of the same thing that didn't play well.
should be, i do store the mod data in the items, but i key off the playername/username
so should work as expected online
I only did theory for the MP support
But im yett to get a bug report relating to MP
Awesome. Slowly preparing a modlist for our group to return to online play when build 42 drops next year. I saw your mod yesterday and genuinely thought it wasn't possible for it to work in MP (due to that other mod in the past).
We'll have a lot of new players, and features like this are just great QoL we saw other new players last 'season' ask about.
I'll make sure to report it if we find something ๐
Haha thanks!
Nothing annoys me more than someone commenting:
"It doesn't work"
Refuses to elaborate
Leaves
Yeaaahh, I get that. Modding is rough sometimes. I just discovered that I managed to get 1000+ subs on my bait tooltips mod in the past 4 months, but 0 comments. Do people like it? Hate it? There's people who favourited it, but does that mean it is in a good state?
People never say a word ๐
i cant seem to figure out how to give a custom profession a free custom trait using profession framework
do i need the profession file to require the trait file in order to pull from it?
I've been calling vehicle:setScript("script name") multiple times (when reloading my script) and it seems to work fine. Mind you, I'm setting the same script each time, which has been tweaked just beforehand by the same reload. No idea how it would work with a totally different script name.
setScript only seems to add or replace parts though, not remove them.
So if you setScript to a script without some parts that were in the previous script those parts would probably stay around
I'm sitting in the car when I hit F11 and reload my script, so that much seems to work fine.
(In the driver seat)
Yeah, it can't remove parts.
Or rather, setScript doesn't. There might be some other way to remove parts.
quick question
when making a custom hoodie that has the Hood up or down option
do I need to add a second line in the fileGuidTable.xml?
cause there are 2 new models
the model with the hood up
and one with the hood down
Ibet not all players know that mods are made by players too. And not by devs . ๐
is it possible to add an outline to a vehicle?
Isnt this the functions for boats? Idk but i read from the mod chat i think... a while back. . Forgot who said it
Never looked at the codes yet. But u might want to check just to be sure
Revamp the profession first before doing the board.... Pls....
huh?
Ow this is mod chat thought i was reading servers chat lol
lol
thanks I'll check it out
That could be a spicy mod idea, the first time you join a server it shows a little pre-credits scene during the opening fade from black "this is how you died" blurb.
"Project Zomboid by The Indie Stone"
"Featuring mods by:"
<big scrolling mass of modder names>
laughing to myself at how they spelled Appetite in the game's code
it's probably so deeply ingrained in there that they have to keep it at this point
No is going to dowload that mod that takes credit using the intro tho
It'd make sense for servers and collections, I think, which seems to constitute a modest amount of mod subscriptions in general ๐
You can probably do a lua code that does that if conditions arent met
And it will say this server is using an illegal modpack .
Then when they come online players will die horribly
Perhaps a mod util that does that if you are not using the real id . And other modders would require that if they eant their code to be safe against ilegal modpackers
Or perhaps a function that disables auto updates from mods
Besides the reason for people doing modpacks is cuz the update thing
If our mods has feature to not recieve updates when sandbox turned off then that might reduce the number of theft
Ye ?
What about unhappyness? Hehe
can i make a trait using profession framework and redefine it with the basic code to add things the framework doesnt have?
@fast galleon i tagged u on a tech support thread. Check it out its your mod
Huh - so unrecognised fields in an item's script definition get put into the item's modData, eh? I'm not sure if that's neat or ugly...
Thats useful . I know some nods that used that. I tried it too with booleans its something veryuseful.
Why would u think its ugly to have more control over script items?
This is how xyberviri made carwannas pinkslip be able to send multiple args too
Well, I said I wasn't sure ๐ I guess it's just that if you make a typo on a real field, your misspelled field name will end up in modData.
I mean its iseful in temrs of having that extra container of data
Yeah, I guess.
Aswell as enabling flexibility between lua and the txt
it prints every time you add an unknown an argument, for each item
Down side eould be confusion to modders ehos only begining to learn the script items
True. Those messages in the console.txt are what led me to "discover" the behaviour
iirc, this works fine, but in mp this sort of messes up the vehicle
Question, if multiple mods have lua file named the same, only 1 will be ran, right? For example, Mod Options https://steamcommunity.com/sharedfiles/filedetails/?id=2169435993 , right. Most people create ModOptions.lua so if multiple mods do that only 1 will be ran? Or will they all be ran regardless?
hi all i am trying to write a simple mod to listen to some game events, but I can't find a guide on how to actually create a Lua script for them. Like for example if I want to listen to the EveryOneMinute function, what do I have to name the file in media/lua?
is there some FAQ or something for lua scripting & event listening? the docs are pretty sporadic from what i can find (which i understand way)
You mean you want something to be executed every minute?
yes, exactly
can i just call the lua file anything and just listen to EveryTenMinutes?
or does it have to have a specific name
lua file preferably something specific to your mod so other mod don't repeat it
and inside lua just put this
https://pzwiki.net/wiki/Modding:Lua_Events/EveryOneMinute
(example there)
where does it get logged?
so anything print() should appear in the in-game console in dev mode yeah?
yes, aside from when the console isn't visible (main menu, loading)
this console seems pretty jank
im trying to scroll up and down it slides around like its on ice or something
only 1 is used, in logs you will find message x overwrites y
so i have my script media/lua/client/CartoLog.lua, with this inside:
local function CartozoidEveryOneMinute()
print("CartozoidEveryOneMinute executing!");
end
Events.EveryOneMinute.Add(CartozoidEveryOneMinute)
but i dont see anying in the in-game dev console
am i missing something really obvious?
in-between, i hit the "reload lua" button on he main menu as well
are you sure that event exists? I cant find anything about it on pz api site
Reloads will not add function to events
reloads should just reload the file, right?
for some reason it appears as "unnamed mod", even though i filled out mod.info, but yes
but you wrote everyoneminute?
sorry, wrong link: https://pzwiki.net/wiki/Modding:Lua_Events/EveryOneMinute
EveryOneMinute is a valid event, it has a triggerEvent
huh, there aint one on the api site
thats the one i mean btw
https://zomboid-javadoc.com/41.65/index.html
Javadoc Project Zomboid Modding API package index
oh haha im dumb
VS code was working in a different folder than i thought
it is working now
the api doesn't show events, they're registered at runtime
and this is an outdated javadoc anyway
Well it worked for me for some time but guess im gonna have to decompile stuff myself
Thanks for notifying though
Question about errors. So let's say my lua file throws error in a function. Will the function be interrupted? Or will it keep running after? For example
if SandboxVars.MoreTraitsDynamic.GraverobberDynamic == true and not player:HasTrait("graverobber") and player:getPerkLevel(Perks.Scavenging) >= SandboxVars.MoreTraitsDynamic.GraverobberDynamicSkill and player:getZombieKills() >= SandboxVars.MoreTraitsDynamic.GraverobberDynamicKill then
player:getTraits():add("graverobber");
MTDapplyXPBoost(player, Perks.Scavenging, 1);
HaloTextHelper.addTextWithArrow(player, getText("UI_trait_graverobber"), true, HaloTextHelper.getColorGreen());
end
-- Antique Collector
if SandboxVars.MoreTraitsDynamic.AntiqueCollectorDynamic == true and not player:HasTrait("antique") and player:getPerkLevel(Perks.Scavenging) >= SandboxVars.MoreTraitsDynamic.AntiqueCollectorDynamicSkill then
player:getTraits():add("antique");
MTDapplyXPBoost(player, Perks.Scavenging, 1);
HaloTextHelper.addTextWithArrow(player, getText("UI_trait_antique"), true, HaloTextHelper.getColorGreen());
end
if there's error in 1st if, will it stop executing this function or will it keep going after?
it will be interrupted
well it depends where the error is
iirc it interrupts your current scope, so if it's inside an if it'll continue with the others, but if it's in the if statement itself the file will stop executing
shiet
The "OnGameStart" takes no parameters. How can I get the player and their save information at that moment?
getPlayer()
just that? no namespace or anything?
and wdym by save information
it's likely better to use OnCreatePlayer in your situation
that passes a player object
๐
ah wait but does that only execute when the player is first created? or does the player also get "created" when a game is loaded?
yeah it's every time the object is created
so "created" in the context of the game session
if you need to avoid this, generally you just set a moddata on the player
I am making a mod that let's you predict the weather.
(Once you learn how an have the equipment tho its not always 100% correct)
Tho ik some servers use commands to modify the weather for events and stuff so it breaks what I did.
Is there a way to remove the edit weather commands?
It breaks what I do if you manually change the weather lol
are you not just predicting the weather?
I can get the player object (https://zomboid-javadoc.com/41.65/zombie/characters/IsoPlayer.html) now, but when I try to access its SaveFileName property, it is nil. Is there some other way to get its save folder?
Javadoc Project Zomboid Modding API declaration: package: zombie.characters, class: IsoPlayer
It pretty much lines up weather events. So for the month it will trigger snow on the 13th, rain on 22nd etc etc (random weather examples)
And it does it for each 3 months it regenerates a cycle.
That's where it pulls the prediction from.
But say I go in and say "boom tropical storm command" it fucks with the weather all ready que up for the months.
Basicly makes all predictions wrong till next time it regenerates
why are you you trying to get the save anyway?
i want to add a file to it which will track certain events over time
in between saves as well
so if you quit, then come back the next day, it will continue adding
inbetween saves?
you can probably just write cross-save data like that to the lua cache directory
^
and if it's save specific you should just use global mod data
what do you mean by global mod data
if you only want to know the weather then you can refresh your data on that command
global mod data is basically a bunch of tables that saves with the save file
you can put anything you want in there, except objects and functions
is there a general guide on that?
or does it mean to just save the data in the mod folder on the filesystem
off the top of my head, local modData = ModData.getOrCreate('String Key, probably use the name of your mod')
this will give you a regular lua table, either empty or including anything you added to it before
you don't need to do anything special to save it so long as the table comes from here
OnCreatePlayer's PlayerIndex param is null?
that shouldn't ever happen
i tried appending it to a string and java complains that it is trying to append a null value
So im learning about homing,markers,arrows and all that kinds of highlighting stuff
But my problem is i have to delete them within the same function
What if iwant to delete it on a diffrent function?
If anyone has tried playing with em
can you print it? i can't see why it would be null
oh wait shit, it's failing down in the EveryTenMinutes, for which there is no parameters haha
all you need to do is pass the table to the other function
Can it be moddata?
It can(temporarily?), but I think they don't save so I would use something else
How exactly do i put it on a table
Like
table.insert(tablevar, markervar)
Or
tablevar['marker']=markervar
Are the function in same lua file?
Yeee they dont
Idk why.. if only theres a way to getPlayer():getMarker() em
https://github.com/Poltergeistzx/Project-Zomboid/blob/main/lua/zxMarkChunk.lua
here I add square markers and remove them, they appear again if I go far and come back but they don't persist between saves.
Betweent saves u mean like restarts?
So i should re trigger them incase they didapear
Like player dc or something
Java array with markers doesn't save, if you want them to appear after restart you need to set them again.
if they're meant to persist you should save some data about them in global mod data
like their x,y or something, whatever you need to reconstruct them
I wanted to stay between reloads, yeah
Well all i need is if the player comes incontact with the sq it deletes the markers
And if a certain period of time the player didnt make it i have a manual delete function
This is for skizots mod
The delivery thing
Im helping em with the arrows thats all
I have written the code but it failed
Does the job save somewhere? You can add a savedMarker to it and check if it exists or need to add one
Cuz its a delivery thing and when time is expired its mission failed or something
So i need to be able to remove it.
I have done this before but i used delayed timer
so i cannot use playerIndex in OnCreatePlayer because I believe that PlayerIndex is relative to the session, i.e. it will always be 0. But when I call player:getName(), I just get nil. Is there some special trick to accessing the Java object's getters that im not aware of?
playerindex is always 0-3, it's clientsided
getOnlinePlayers()
yeah i need something persistent
getName() isn't really a character thing so it doesn't really do anything on them, even though they technically have the method
do you need it to differentiate different characters played by the same player after they died or is just the actual player enough?
has to differentiate between different characters
there's no vanilla way to differentiate them, but it's pretty simple
this is single player only
if not modData.StarlitUUID then
modData.StarlitUUID = getRandomUUID()
end
```from one of my mods
i put this on OnCreatePlayer, it creates a character unique identifier
modData is from IsoPlayer:getModData()
is getRandomUUID() built-in somewhere or does it have to be defined?
so this should work, right?
local function CartozoidOnCreatePlayer(playerIndex, player)
print("CartoZoidOnCreatePlayer executing");
playerModData = IsoPlayer:getModData();
if not playerModData.CartozoidUUID then
playerModData.CartozoidUUID = getRandomUUID()
end
print("CartozoidUUID:");
print(playerModData.CartozoidUUID);
BTW i dont know how to format as code
```lua
-- code
```
it should be player:getModData()
yea
i wrote IsoPlayer since i don't know what your variable is going to be called
of course ^^
is there any way to add UI elements to the home screen somehow?
if I have following ModData structure
function ETInitialize()
player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
player:getModData().ExplorerTrait.OldCell = player:getModData().ExplorerTrait.OldCell or {};
player:getModData().ExplorerTrait.OldCell.X = player:getModData().ExplorerTrait.OldCell.X or 0;
player:getModData().ExplorerTrait.OldCell.Y = player:getModData().ExplorerTrait.OldCell.Y or 0;
player:getModData().ExplorerTrait.OldCell.ExploredTiles = player:getModData().ExplorerTrait.OldCell.ExploredTiles or {};
player:getModData().ExplorerTrait.CurrentCell = player:getModData().ExplorerTrait.CurrentCell or {};
player:getModData().ExplorerTrait.CurrentCell.X = player:getModData().ExplorerTrait.CurrentCell.X or 0;
player:getModData().ExplorerTrait.CurrentCell.Y = player:getModData().ExplorerTrait.CurrentCell.Y or 0;
player:getModData().ExplorerTrait.CurrentCell.ExploredTiles = player:getModData().ExplorerTrait.CurrentCell.ExploredTiles or {};
end```
and I wanna dump old cell and replace it with new cell
Do i need to do this
function dumpOldCell()
player = getPlayer();
player:getModData().ExplorerTrait.OldCell = player:getModData().ExplorerTrait.CurrentCell;
player:getModData().ExplorerTrait.OldCell.X = player:getModData().ExplorerTrait.CurrentCell.X;
player:getModData().ExplorerTrait.OldCell.Y = player:getModData().ExplorerTrait.CurrentCell.Y;
player:getModData().ExplorerTrait.OldCell.ExploredTiles = player:getModData().ExplorerTrait.CurrentCell.ExploredTiles;
end```
or this is enough
```lua
function dumpOldCell()
player = getPlayer();
player:getModData().ExplorerTrait.OldCell = player:getModData().ExplorerTrait.CurrentCell;
end
Aka
the shorter one is enough
ty
how do you get the player's current position? i have tried like 5 different ways and all of them return nil
print("Player is at: ")
player = getPlayer();
current = player.current;
print(current);
as well as
funny that u asked
player = getPlayer();
print(player.x);
print(player.y);
Im doing exactly that right now
playerX = math.floor(player:getX());
playerY = math.floor(player:getY());
print("Player pos: x"..playerX ..", y: "..playerY)
ahhh of course
because .current is protected
its been so long since i wrote in a language that makes you actually think about access lmao
ive become such a python monke
you can't really grab fields most of the time
there's some weird reflection stuff you can sometimes do but you usually don't need to bother with it anyway
theyre being all proper with their getters & setters
so i actually want to ultimately dump a lot of this data to a file, does anyone know what is the working directory that lua is executing in?
i tried some stuff off stackoverflow that is supposed to tell you the working dir but it didnt seem to work
anyone have any knowledge around scripting in meds that can give some points, having a nightmare of a time with making a painkiller that actually works
i'd recommend checking big trait mods. there are few negative perks out there that add pain to character
i'm fairly sure you can remove same way
don't know myself though, haven't dug in pain stuff
Updating my bait trap mod to also show what you can catch with each trap type.
I wanted to ask if people could think of any neat / useful additions I could make to this simple tooltip mod?
maybe subtree showing what kind of bait you can use to catch each?
I think that could get a bit spammy, but I do show the tooltip for baits.
oh thats cool
maybe remove the word "dead"
i guess you are probably using the entity name itself
but it is a bit odd
Would it only be shown when you have both a valid bait and a trap in your inventory?
(It's Mutie's Bait Tooltips on the workshop)
I am using the item name, because that's what we have access to in the code. This means it is localised depending on what language you have selected.
It is currently always shown, but I am working on:
- Using Mod Options to add a modifier key (e.g. hold Shift for extended tooltips)
- Using SandboxVars to limit it to certain skill level (e.g. Trapping 6+), a specific trait/occupation, or to requiring a magazine.
So unfortunately, removing the "Dead" part would mess up some localisations, and while perfectly reasonable for English, I can't guarantee that it's a good solution for, e.g. Hungarian.
yes thats a good point#
I'm curious about this idea. Is this something you'd personally want? I did a lot of trapping last I played and I always had my traps on the ground already, having prepared large trapping grounds or forest clearings for it.
I'm unsure if needing to 'pick up' a trap to remember baits is a good gameplay feature ๐
I haven't done any trapping yet, mainly due to the lack of bait...
I can recommend foraging for insects. Crickets, grasshoppers, and cockroaches can be used in stick traps to catch birds.
You can also find Worms through farming, or by furrowing soil with a trowel.
does anyone have any idea why i cannot write to a file in the lua function here?
fileDescriptor = io.open("carto.txt", "a");
shit
ok well i thought that might be the case, i guess it makes sense, too easy to do nefarious stuff
then does anyone have an idea of how i might be able to dump accumulated data on a character via its modData to a file some other way?
like is it possible to access the modData from outside of PZ?
If this is just for debugging you could write it to the console and check your logs?
anyone with bigrain here? Don't wanna spend next 10 min being pepega. If I want to grab 20x20 square around player, is this correct?
playerX = math.floor(player:getX());
playerY = math.floor(player:getY());
playerCellX = math.floor(playerX / 300);
playerCellY = math.floor(playerY / 300);
scoutedAreaMinX = math.max(playerX - 10, playerCellX * 300);
scoutedAreaMaxX = math.min(playerX + 10, (playerCellX + 1) * 300);
scoutedAreaMinY = math.max(playerX - 10, playerCellY * 300);
scoutedAreaMaxY = math.min(playerX + 10, (playerCellY + 1) * 300);
or did I mess up signs in last 4 lines?
no its meant to be a core feature
i want to allow the player to export data about their character that has been accumulated over the course of their run
@modern dune
Maybe you can find something here
I know chuck and burryaga also write to files
local fileWriter = getFileWriter(filename, createIfNull, append)
filenames are relative to Zomboid/Lua/
declaration: package: zombie.Lua, class: LuaManager, class: GlobalObject, class: LuaFileWriter
yeah, you can also search vanilla for filewriter filereader calls
i think my mod may not be possible then
i wanted to continuously grow a list of player positions & various significant events so that it could be visualized on a canvas of the world map afterwards
but if i cannot actually dump the data then...
you can dump the data with what i just mentioned
oh wait sorry i had not scrolled apparently
i wrote a little thing that collects statistics for a server and writes them to a json file, that's pretty similar to what you're trying to do
so it's definitely possible
yes indeed, ok that brings my motivation back haha
the tricky bit will be setting up a canvas viewer, that will probably have to be its own website, i will probably cannibalize this thing: https://map.projectzomboid.com/#7811x10385x9
the dev from that seems to have open sourced everything related to its development
yeah, i've seen a couple servers that actually run their own server maps
Oh heavens.
there's also a getModFileWriter if you'd prefer to write into a mod folder, wonder if that works
stupid question but how do you call a method on this now? I tried .close() and :close() and they both fail
should be like
local fileWriter = getFileWriter('test.txt', true, false)
fileWriter:write('whatever')
fileWriter:close()
thought i tried that, maybe i buggered it up somehow
ah it doesnt like relative paths
thats a bit annoying
ok well i guess its going in ./Lua then
you can use subdirectories, but you can't escape the lua folder
Any lua professionals?
size = 3;
scoutedAreaMinX = math.max(playerX - size, playerCellX * 300);
scoutedAreaMinY = math.max(playerX - size, playerCellY * 300);
scoutedAreaMaxX = math.min(playerX + size, (playerCellX + 1) * 300);
scoutedAreaMaxY = math.min(playerX + size, (playerCellY + 1) * 300);
print("Allowed area in this cell. From x="..scoutedAreaMinX..", y="..scoutedAreaMinY.." to x="..scoutedAreaMaxX..", y="..scoutedAreaMaxY);
for x = scoutedAreaMinX, scoutedAreaMaxX do
print("Working on x="..x);
for y = scoutedAreaMinY, scoutedAreaMaxY do
print("Working on y="..y);
cantor = (x + y) * (x + y + 1) / 2 + x;
print ("Got Cantor: "..cantor);
--table.bininsert(player:getModData().ExplorerTrait.CurrentCell.ExploredTiles, cantor);
end
end
Why doesn't it reach "working on y"?
well yeah if you use a different filewriter you can get yourself sandboxed to a different folder
there's also a sandbox file writer, which writes to Zomboid/Sandbox Presets/ but there isn't a reader for it lol
lol
usually mods that write into mod folder are weird, I uninstall them and when I decide to check them out again the data is gone, lol
bro does lua nested for loop only allows 1 line in it?
no
then why

ok, well thank you very, very much @bronze yoke, my proof of concept is complete
and also to others like @fast galleon and @dull moss
I mean all I did is told you how to get player X and Y, but yw ๐
well you showed me the one way i didnt try then lol
so on a more theoretical level, what do you guys think would be interested events that should be logged during a playthrough that a player might like to see on the map postgame?
obviously movements every 10m, zombie kills
player movement heatmap would be nice
i was thinking like "first time aquisition" of various special items, like sledgehammer, antique oven, generator, etc.
yeah i was thinking a movement and also a kill heatmap would be cool
can you verify these values are correct? scoutedAreaMinY, scoutedAreaMaxY
make sure it isn't a negative size
hm
bruh I'm r-word
LOG : General , 1671394323433> Allowed area in this cell. From x=11128, y=11128 to x=11134, y=6900

you use playerX in areaY
ty
as you can see I'm very keen on details

how would one get size of an array?
player:getModData().ExplorerTrait.CurrentCell = player:getModData().ExplorerTrait.CurrentCell or {};
player:getModData().ExplorerTrait.CurrentCell.X = player:getModData().ExplorerTrait.CurrentCell.X or 0;
player:getModData().ExplorerTrait.CurrentCell.Y = player:getModData().ExplorerTrait.CurrentCell.Y or 0;
player:getModData().ExplorerTrait.CurrentCell.ExploredTiles = player:getModData().ExplorerTrait.CurrentCell.ExploredTiles or {};
/some code here/
print("Size of Explored Tiles array: "..table.getn(player:getModData().ExplorerTrait.CurrentCell.ExploredTiles));
doesn't work
#player:getModData().ExplorerTrait.CurrentCell.ExploredTiles
you should bring moddata into the local space, and maybe some of these other tables too
hm
calling the java for every one of these operations is going to be pretty inefficient
is there an event for pickup up an item?
the latter would mostly just make things a bit prettier though
elaborate what you meanpls
this is how things are rn
I only access mod data few times
exception is writing stuff into it
hmm might be a waste if that's the whole function
oh no i meant my optimisation would be kind of unnecessary
i'd still recommend bringing the moddata into the local space but the full thing is not needed
but i call it like once
I initialize it once game load
so there are no nils
why would i bring it afterwards into function that runs every minute
local modData = player:getModData()
modData.ExplorerTrait = modData.ExplorerTrait or {}
modData.ExplorerTrait.OldCell = modData.ExplorerTrait.OldCell or {}
local OldCell = modData.ExplorerTrait.OldCell
OldCell.X = OldCell.X or 0
OldCell.Y = OldCell.Y or 0
OldCell.ExploredTiles = OldCell.ExploredTiles or {}
modData.ExplorerTrait.CurrentCell = modData.ExplorerTrait.CurrentCell or {}
local CurrentCell = modData.ExplorerTrait.CurrentCell
CurrentCell.X = CurrentCell.X or 0
CurrentCell.Y = CurrentCell.Y or 0
CurrentCell.ExploredTiles = CurrentCell.ExploredTiles or {}
```this is what i was thinking of, but i didn't know that was the entire usage of those tables in that function
I'm probably not getting something (barely any lua experience) but that seems generally unnecessary
it's just prettier
yea but if i want to edit the data
storing it in a local variable behaves exactly the same
lua tables are passed by reference not by value
also please make variables like this local, the names are kind of generic so this could easily cause problems with other mods, and global variables are just slower anyway
"all my mods" he says, while having 3 mods contribution 
wait
arent variables local by default
no... :(
if you want to keep your mods accessible to patching, you can keep everything in your mod that would be in the global namespace in a local table and return that table at the end of the file
that sounds like effort
like this
local Mod = {}
Mod.GlobalVariable = value
function Mod.Function(parameters)
local variablesInsideOfFunctionsDontNeedToUseTheTable
end
return Mod
```it's not too necessary though
so If I have something like this
player:getModData().KillCount = player:getModData().KillCount or {};
local categoryKills = 0;
if player:getModData().KillCount ~= nil and player:getModData().KillCount.WeaponCategory ~= nil then
I can make it like this
player:getModData().KillCount = player:getModData().KillCount or {};
local KillCount = player:getModData().KillCount;
local categoryKills = 0;
if KillCount ~= nil and KillCount.WeaponCategory ~= nil then
?
yeah
cool, gotta refracture 800 lines of code 
Could someone save me a few minutes of looking around. When I'm using client-side code is there a quick way to get data about the current character? Specifically, I want to check a skill level.
getPlayer():getPerkLevel(Perks.PerkName)
Thank you โฅ
to erase array i just = {} ?
depends, for lua tables usually you do myTable = nil
new fun envelope-pushing question: os is apparently also not implemented in kahlua, right? so is there an equivalent that i can get the actual unix timestamp with?
or some other way measure "real-world" time?
timestamp is implemented
be careful when doing this when bringing tables into the local space
when you do that to a table, you erase that specific reference, the table isn't removed unless every reference to it is removed
this? https://projectzomboid.com/modding/zombie/Lua/LuaManager.GlobalObject.html#getGametimeTimestamp()
declaration: package: zombie.Lua, class: LuaManager, class: GlobalObject
you can use that, but i've seen people using some os function for timestamps too
i use that one myself
so for example
t1 = {}
t1.t2 = {}
local t2 = t1.t2
t2 = nil
```t1.t2 will still have the table
the opposite is also true, but for moddata what's important is that you do modData.table = nil, not just a local reference to it
ye got it this way, thx
player:getModData().ExplorerTrait.CurrentCell.ExploredTiles = {};```
Just to clarify one more time, this is the same, right?
(and yes i made player local. noticed it after posting
)
but If i want to reset array like this
I need to use actual getModData, right?
so I can't replace
function dumpOldCell(playerCellX, playerCellY)
local player = getPlayer();
player:getModData().ExplorerTrait.OldCell = player:getModData().ExplorerTrait.CurrentCell;
player:getModData().ExplorerTrait.CurrentCell.X = playerCellX;
player:getModData().ExplorerTrait.CurrentCell.Y = playerCellY;
player:getModData().ExplorerTrait.CurrentCell.ExploredTiles = nil;
player:getModData().ExplorerTrait.CurrentCell.ExploredTiles = {};
end```
with
```lua
function dumpOldCell(playerCellX, playerCellY)
local player = getPlayer();
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.OldCell = ExplorerTraitData.CurrentCell;
ExplorerTraitData.CurrentCell.X = playerCellX;
ExplorerTraitData.CurrentCell.Y = playerCellY;
ExplorerTraitData.CurrentCell.ExploredTiles = nil;
ExplorerTraitData.CurrentCell.ExploredTiles = {};
end
Or is it fine?
looks like its fine so gonna leave it at that
ye it looks 10 times better
if I wanted to grab like, a refrigerator model for size reference in blender, anyone know where that particular file would be? I see the media folder with other models but like oven, stove etc seem to be evading me atm ^_^
they aren't models, they are sprites
that explains a lot, thanks ^_^
am i right in saying you can have multiple 'item' files rather than 1 huge file
track in which cell player is and what was the previous cell
successfully write function that dumps old cell and shifts current cell into slot of old cell in modData when player enters new cell
try to add a function that swaps current cell and old cell around if player enters previous cell
it starts swapping them every time main function is ran

My head actually starts to hurt at this point 
What's the function look like
at this point I should scratch everything and start all cells shenanigans' over
Yes
Is the previous cell relevant?
Wdym
Why is the previous cell tracked
oh
And why only two, previous and current
Cuz I want to track if player explored at least x% of a cell (I grab 20x20 tiles around player every minute) and add them to list of tiles explored in cell. Full cell is 90k so if I make it like 30% I hope it should be fine-ish performance-wise. And I track only 2 to not jam every single visited cell in there.
if i hit my 30% explored I mark cell as explored
Ah
and dont count shit in it anymore
So you can only trigger explored if you stay in the cell for the 30%
yes, and i wanna save info about prev cell if player is wondering around cell edge
and jumps between them
ideally i would save last 4
in case player is on intersection
but idk
i think 2 should be fine
hm
maybe i should switch to 4
would make stuff easier
probably
i dont have to bother with swapping shit around then
I don't see why tracking any number of cells would be that much of an issue tbh
Especially if you have a cut off %
Are you listing every square?
Wdym?
How are you tracking how much of a cell is explored?
You said add tiles
Like isosquares?
X,Y of all the squares?
nah im using cantor pairing function
to turn x and y into 1 number
local size = 3;
local scoutedAreaMinX = math.max(playerX - size, playerCellX * 300);
local scoutedAreaMinY = math.max(playerY - size, playerCellY * 300);
local scoutedAreaMaxX = math.min(playerX + size, (playerCellX + 1) * 300);
local scoutedAreaMaxY = math.min(playerY + size, (playerCellY + 1) * 300);
print("Allowed area in this cell. From x="..scoutedAreaMinX..", y="..scoutedAreaMinY.." to x="..scoutedAreaMaxX..", y="..scoutedAreaMaxY);
for x = scoutedAreaMinX, scoutedAreaMaxX do
for y = scoutedAreaMinY, scoutedAreaMaxY do
local cantor = (x + y) * (x + y + 1) / 2 + x;
--print ("Got Cantor: "..cantor);
table.bininsert(ExplorerTraitData.CurrentCell.ExploredTiles, cantor);
end
end
print("Size of Explored Tiles array: "..#ExplorerTraitData.CurrentCell.ExploredTiles);
my reason is that then i can have sorted array
and checking if cell is already there would be fast
cuz i dont have to check each cell that is scattered
in my array
I have a list of sorted numbers that I can insert into
much faster
Allowed area = area in this cell
so it doesnt grab tiles from other cells
i think it's pretty smart way of approaching this problem
It is
cuz of fast insert
Ok I just need to figure out how to store all cells visited then
didnt really do a lot of moddata and tables stuff in lua
so that's why initially i wanted just to do 2 cells
Cells have a world x/y afaik
You could store them as keys to a table with their explorer info
how can one create a table with any kind of identifier? Let's say I have modData().Data = {}. Is there any way I can add sub-tables into that table with identifier generated mid-code execution. For example, I want to add a table into it that I can later find by identifier 19823854
keying by x % 300, y % 300 should work
table with keys? lemme google that
As long as it's not references to objects modData can be used exactly like a Lua table and saved
A = {a={}}
A.a = {}
For concated keys -- A = {[x.."|"..y]} the bar is to clarify between the xy
so something like this?
local data = getPlayer():getModData().MyMod or {};
local key = --<some math function that creates a unique key>--
data.key = {};
I was going to use cantor for cell keys ๐
that shit is so good
data[key] = {}
cool, will try
The brackets let you use strings with spaces too
will know for future
I'll use cantor to get unique number so my cell list can be sorted
even more speed

So something like this?
function ETInitialize()
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.Cell = ExplorerTraitData.Cell or {};
end
function addNewCellToList(x, y)
local player = getPlayer();
local ExplorerTraitData = player:getModData().ExplorerTrait;
local cantor = (x + y) * (x + y + 1) / 2 + x;
ExplorerTraitData.Cell[cantor] = {};
ExplorerTraitData.Cell[cantor].ExploredTiles = {};
ExplorerTraitData.Cell[cantor].IsExplored = false;
end
strings with full stops too, useful for keying by item types and stuff
Seems reasonable to me, assuming your modData is initialised as expected.
yea it is, on game load
elaborate please, if possible?
Rather than repeating the Cantor calculation in multiple places, I'd create a function your code uses, something like getKeyForCoordinates(x, y) which does it there, and then use it throughout. DRY and all that.
this is more of a lua-specific question but does anyone know why this crashes, complaining that "Object tried to call nil in OnZombieDead"?
if next(cartozoidDeadZombies) == nil then
-- Lua is 1-indexed
local deadZombieIdx = 1;
cartozoidDeadZombies is defined as a global variable in the OnCreatePlayer function as such:
cartozoidDeadZombies = {}
i meant if you use []s you can have keys like t['Base.Item'], whereas t.Base.Item would need Base to be a table
Yeah, keyed tables don't need to be for'd through
I faintly recall next() not being a thing in Lua?
๐คทโโ๏ธ
Hmm, might be an old Lua thing maybe?
Is your table keyed?
If there aren't defined keys it defaults to numeric order, and you can use #
PZ uses Kahlua, which is a Java implementation of Lua which doesn't implement everything. I think it's somewhere around Lua version 5.1?
Hmm, although https://code.google.com/archive/p/kahlua/wikis/KahluaManual.wiki lists next under the section "Functions that behave the same as in Lua"
i explicitly key it to use incrementing ints
although i guess maybe i dont need to
why not just table.insert?
i thought you had to explicitly define the key in lua
can i just say like "myTable.insert("foo")" and it becomes {1: "foo"}?
I don't know the answer, but I learned the disappointing way that Lua added goto in 5.2 and we do NOT have that basic feature, so I would suspect our Kahlua is <5.2
If no keys are provided it's numeric
hmm maybe i dont need to be so pedantic about the keys then
if i say this: cartozoidDeadZombies = {zombie}
no keys means numeric
does this mean that it will now be a table with a single element mapping 1 -> zombie?
@modern dune Maybe just print(next) in debug console and quickly test whether Chuck is right.
If you get nil that was the issue
I think it's an associative array either way; you can either use explicit keys, or use implicit incrementing integer keys.
Yes
You can do list[1] to return that value and #list == 1
You can leave the list[n]=zombie
From what I read insert is stupidly costly
But then you'd have to be more mindful when you're adding values
indeed, nil
Yep, gotta implement that if you want it. ๐ญ Imagine how I feel using i.e. breaking repeat until true instead of goto.
Don't think I can implement goto very easily haha.
Only sadness awaits me
this is my first time using lua in any amount of depth
ive dicked around with it for very minor stuff at work but nothing substantial
same bro
You used while() and break?
That would be more code right?
repeat until true happens once with no further input... A while would need a control variable and usually another line for editing it, plus the word end in Lua I assume
Not sure I try to stay away from while lol
while(control) ... control = false end vs. repeat until true
I believe those would have the same result
But yeah Fenris_Wolf taught me that trick... You can break one iteration of a for loop if you go
for ... do repeat ... possible break ... until true end
The break breaks the repeat instead of the for loop so you can skip code made for certain players in a player loop with less nesting
Using stuff like if shitty(player) then break end
If I wrote the defecation mod, that would be a function.
function ETInitialize()
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.Cell = ExplorerTraitData.Cell or {};
end
function addNewCellToList(cellKey)
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.Cell[cellKey] = {};
ExplorerTraitData.Cell[cellKey].ExploredTiles = {};
ExplorerTraitData.Cell[cellKey].IsExplored = false;
print("Successfully added cell with key "..cellKey);
print("Current total cell count: "..#ExplorerTraitData.Cell);
end
why it doesn't show proper cell count?
LOG : General , 1671404799934> Successfully added cell with key 2246
LOG : General , 1671404799934> Current total cell count: 0
wdym?
Did you just add one value to test?
ah
To index 0? Or what
it's every minute. there should be at least 1 cell.
function ETInitialize()
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.Cell = ExplorerTraitData.Cell or {};
end
function addNewCellToList(cellKey)
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
ExplorerTraitData.Cell[cellKey] = {};
ExplorerTraitData.Cell[cellKey].ExploredTiles = {};
ExplorerTraitData.Cell[cellKey].IsExplored = false;
print("Successfully added cell with key "..cellKey);
print("Current total cell count: "..#ExplorerTraitData.Cell);
end
function ETLocationUpdate()
local player = getPlayer();
local playerX = math.floor(player:getX());
local playerY = math.floor(player:getY());
local ExplorerTraitData = player:getModData().ExplorerTrait;
local size = 1;
local scoutedAreaMinX = playerX - size;
local scoutedAreaMinY = playerY - size;
local scoutedAreaMaxX = playerX + size;
local scoutedAreaMaxY = playerY + size;
for x = scoutedAreaMinX, scoutedAreaMaxX do
for y = scoutedAreaMinY, scoutedAreaMaxY do
local cellX = math.floor(x / 300);
local cellY = math.floor(y / 300);
local cellKey = cantorKeyGenerator(cellX, cellY);
if ExplorerTraitData.Cell[cellKey] == nil then
addNewCellToList(cellKey);
end
local tileKey = cantorKeyGenerator(x, y);
print ("Got tileKey: "..tileKey);
table.bininsert(ExplorerTraitData.Cell[cellKey].ExploredTiles, cellKey);
end
end
end
Events.OnGameStart.Add(ETInitialize);
Events.EveryOneMinute.Add(ETLocationUpdate);
in my test it should've been 2
cuz 1 you start in
and then i wondered into a new one
What's add cell to list?
In the first chunk he posted
non-numeric meaning?
You can set up a sister table with numeric keys to cellkeys for values of order matters - but it shouldnt
1, 2, 3, etc
Has to be in order starting with 1 afaik
You don't need to iterate through the cells
It's faster if you just tug on the list with the key
Set the key if nothing returns
If order does matter you have to set another table
huh?
I actually wanted to have my Cell table sorted
idk if its possible
I don't think sorting would provide any value in this case?
But if you need it you have to use another list as a reference
well worlds is 50x50 cells
so i guess if its unsorted it wouldnt matter much
wait it doesnt matter at all
cuz im inserting value via the key
yea
also it's gonna be like 100 cells max anyway
by that point character has to earn trait 100%

I will take a closer look in a little bit but hard on my phone. Generally make sure your tables are actually indexing from 1 onward for # to work properly... I sometimes think I've done this right but accidentally revert to every other language's mindset... In Lua, I like adding to existing table of stuff like this:
stuff = {}
stuff[#stuff + 1] = nextStuff```
hm, ok, how do i then check if my data is in order 
This ensures that a new table begins indexing at 1 in a repeatable pattern
i know i'll do everytenminute event that will dump all cells and tiles in for loop in console 
indeed i was overcomplicating my code a lot
because i was actively refusing to bother to learn how tables work in lua
List1 = {a,b,c,d}
List2 = {a=apple, b=banana, c=carrot, d=durian}
You venndiagram the tables to so speak, and use one for order and the other for values
๐
so its like a python list and a dictionary at the same time
somebody looked at python and thought "you know what would make this better? MORE AMBIGUITY"
Or they're accessing it using pairs, which apparently doesn't guarantee order
Yes pairs doesn't get order and ipairs loses keys
But I don't think it maintains order either
Oof
is there a way to iterate through list of my cells stored in modddata? ones with keys?
ExplorerTraitData.Cell[cellKey] this stuff
I wanna go through all cells
that are there
For I=0 in pairs(list) do
cheers
You can add to a counter in each iteration - but the order isn't guaranteed
for index in pairs(list) do ... end should be fine right? @sour island

how can I grab cell key?
For k,v in pairs(list) do
For value, for key, value in pairs(list)
Also I think I mistyped, I don't think you can do i=0 and pairs lol
Haha I didn't know
K,V in pairs() is right
so something like this?
function ETDataDump()
local player = getPlayer();
player:getModData().ExplorerTrait = player:getModData().ExplorerTrait or {};
local ExplorerTraitData = player:getModData().ExplorerTrait;
for value, key in pairs(ExplorerTraitData.Cell) do
print("Cell #"..key);
print(" has "..#ExplorerTraitData.Cell[key].ExploredTiles.." explored tiles");
end
end
I hadn't seen it like that
For k in pairs will work though
I've used it
,v optional
I'm almost positive but feel free to run a quick debug console test and check
When indexing from 1
I saw it in someone else's code before I adopted it
And immediately preferred
That looks right but I'm on my phone
Because for me , _ makes me vomit
hello i was wondering if anyone could help me figure out how to run a dedicated server with mods or let me know if its something that is possible for pz friends and i cant seem to wrap our head around the cmd part of it due to lack of guides just looking for a point in the right direction. Also is this the right subchat for this question?
key throws error in print
print("Cell #"..key)
Afaik this is the most step-by-step guide on this https://pzwiki.net/wiki/Dedicated_Server
I used it to get a dedicated server running but I have not yet connected any friends to it... I've only ever used one for testing in mod development.
I doubt it covers every conceivable nuance of opening and forwarding your ports correctly, so that step will inherently take some personal troubleshooting based on your network setup
I connected to my own server using localhost (127.etc.)
Wouldn't work for online so at that step good luck haha

ok ill go through this guide thoroughly if i have any follow up question that do you mind me @ you and seeing if its something you can still help with? if its not a hassle lol
This works in lua online console in my phone... i would compare with yours for which major difference is failing you.
stuff = {}
stuff[1] = "Hello"
stuff[2] = "World"
for key in pairs(stuff) do
print(key)
end
Ohhh wait I see @dull moss
You wrote value, key
It's key, value
Reordering that will not change the order in which you receive variables
I'll test
This is where I saw your error
P sure Chuck and I said key, value lol
Don't know who told you value, key
But order is crucial there
Note that will only work if ExplorerTraitData.Cell is a table, and only so stuff if it's nonempty. If it's nil, pairs may throw an exception. Pretty sure it will
Lol yes right there I said "for key, value"
yea its just to test if it puts data in and stuff
for value for key
i thought it means first is value

But I see the confusion... i began by saying "For value," to indicate the format used if you WANT the value.
ah
yes but you miss the fact that im a 
I admit that was not the clearest I could have said that
... However if you HAD copy-pasted what I said, a very different error would have occurred
Haha
Just saying
Nw though glad you have it now
very cool
LOG : General , 1671407781934> Successfully added cell with key 2381
LOG : General , 1671407781934> Successfully added cell with key 2451
LOG : General , 1671407784417> Successfully added cell with key 2382
LOG : General , 1671407789401> Cell #2314 has 1 explored tiles
LOG : General , 1671407789402> Cell #2246 has 263 explored tiles
LOG : General , 1671407789402> Cell #2313 has 119 explored tiles
LOG : General , 1671407789402> Cell #2381 has 6 explored tiles
LOG : General , 1671407789402> Cell #2451 has 3 explored tiles
LOG : General , 1671407789403> Cell #2382 has 9 explored tiles```
๐
now setting explore range to something real, like 10 (instead of 1 like it was before)
this is looking nice
LOG : General , 1671407886885> Cell #2246 has 263 explored tiles
LOG : General , 1671407886885> Cell #2313 has 509 explored tiles
LOG : General , 1671407886886> Cell #2381 has 1064 explored tiles
LOG : General , 1671407886886> Cell #2451 has 255 explored tiles
LOG : General , 1671407886886> Cell #2382 has 278 explored tiles```
I'm still not sure how performance-hungry this is, any recommendations on how to test it?
Many people here seem to use os.clock()
the long number preceding the print is a timestamp afaik
Interesting, seems entirely possible it's in seconds.
this is where I saw it mentioned, but blair didn't say what unit it's in. Could conceivably by ms, I have no idea how slow the print function is
apologies for pinging you blair, I forgot to hit the button
nClock = os.clock(); throws error 
so I'm trying to add cells that explored with currently grabbed cells into an array
local size = 10;
local scoutedAreaMinX = playerX - size;
local scoutedAreaMinY = playerY - size;
local scoutedAreaMaxX = playerX + size;
local scoutedAreaMaxY = playerY + size;
local lastUsedCellKeys = {};
for x = scoutedAreaMinX, scoutedAreaMaxX do
for y = scoutedAreaMinY, scoutedAreaMaxY do
local cellX = math.floor(x / 300);
local cellY = math.floor(y / 300);
local cellKey = cantorKeyGenerator(cellX, cellY);
table.bininsert(lastUsedCellKeys, cellKey)
if ExplorerTraitData.Cell[cellKey] == nil then
addNewCellToList(cellKey);
end
local tileKey = cantorKeyGenerator(x, y);
table.bininsert(ExplorerTraitData.Cell[cellKey].ExploredTiles, tileKey);
end
end
for i in lastUsedCellKeys do
if #ExplorerTraitData.Cell[lastUsedCellKeys[i]].ExploredTiles >= 10000 then
ExplorerTraitData.Cell[lastUsedCellKeys[i]].IsExplored = true;
HaloTextHelper.addTextWithArrow(player, "Cell explored", true, HaloTextHelper.getColorGreen());
end
end```
but
I obviously fail
did I use last for loop correctly?
oh I need to use i,v
and then use v instead of i
I think
you need to use pairs ipairs or your own iterator to run that for loop
also, table.bininsert doesn't exist
it is, it's my own function
ok, fixed
ty for pairs help
for i, v in pairs(lastUsedCellKeys) do
if #ExplorerTraitData.Cell[lastUsedCellKeys[i]].ExploredTiles >= 10000 then
ExplorerTraitData.Cell[lastUsedCellKeys[i]].IsExplored = true;
HaloTextHelper.addTextWithArrow(player, "Cell #"..lastUsedCellKeys[i].." explored", true, HaloTextHelper.getColorGreen());
end
end
np
If I have following line in function, local lastUsedCellKeys = {};, every time function is called it's gonna make fresh empty array, right? I don't need to manually empty it, ye?
yes
cheers
How are item distribution chances calculated?
I had thought it was [ItemChance]/[Summation of the chances of all items in the list] = [% Chance per item roll]
But that really doesn't seem to be the case.
I added an item to the GunStoreDisplayCase list which has a summation of 178 before anything is added by mods.
So I set my item to 31 which should give it around a ~15% chance per roll if it worked like I thought it did.
With 4 rolls, I'd expect LootZed to show at most 40%.
Yet my item had a 99.9% chance in LootZed.
Each chance is roughly out of 100
There's alot of math but it kind of comes out to /100
Each roll is just multiple runs of the same %
It's not a weighted list if that's what you were wondering
Alright.
So can a list roll "nothing" then? Like if say everything was set to 0.001? Or does some item have to win the roll?
It's all independent afaik
also there's lower limit on %
fun goofy question time!
Yeah, I recall that -- the less loot mods actually trim off rolls
it is possible to change the players model at run time?
so i could change them from a player model to a zombie model to a custom model etc?
You can give an hidden item to be worn
I think that's how peach does his unique models
well i want it to be on the players themselves.
i want to make variants of the men and women models to be fat for instance. and just edit the bone structure to do so.
Thanks, Chuck and MusicManiac.
I don't know if thats doable unfortunately -- otherwise I think Peach would have done it.
His fat zombies are special costumes with clothes
i think outside the box lol... i'll figure something out lol.
It would be a lot of work I imagine for devs to implement
I'm not familiar with bone rigging and stuff
With being able to wear any clothes?
yeah, if i edit the skeletons on the base model, it will use the normal animations and will scale the clothes to match the new body
that's why i wanna know if it's possible to change them dynamically
so if you get to a certain weight it changes them to a new base model.
I'm still waiting for dynamically applied model for items
Anyone know the name of the item that can be wear like a fanny pack but has a capacity of 4. I donโt know the mod from which that item comes from.
https://steamcommunity.com/sharedfiles/filedetails/?id=2903713263 This is why I asked. It was really easy to make this actually ๐
They're unionizing
Yep, they just wanna go home.
I see poor them
LoadGridsquare event get crash?
Hi, just wanna ask about where I can find vanilla loot/item respawn script?
Dpends on the load you are running
ProceduralDistributions.lua in media/lua/server/items has a lot of em.
The scripts defining individual items are in a few places, but that's how they spawn
anything in media/scripts with items in the name probably has some item definitions afaik.
Anyone know the function for toggling model visibility? Can it even be done in Lua?
I believe the option's default key is F3 and called Toggle Models Enabled if that helps.
Okay I think it's done via ModelManager.instance.bDebugEnableModels = !ModelManager.instance.bDebugEnableModels; ... wonder if this is exposed.
Mmmm seems not but maybe I'm reading it wrong... will check in game to be sure.
Booo, nil.
When you Faction.getPlayerFaction(player) on two players with the same faction, will factionA == factionB, or do I need to get their names or something to make the equivalence work?
SNIPPET: load Lua file and get _ENV
---Load a lua file.
---@param p1 string
---@param p2 string
self.loadLuaFile = function (p1, p2)
local file = getModFileReader(p1, p2, false)
if file then
local script, err = loadstream(file, "@".. p1 .."/".. p2);
local _ENV = {};
if not script then
print(err);
return;
end
for k, v in pairs(_G) do
_ENV[k] = v;
end
setfenv(script, _ENV);
script();
return _ENV;
end
end
--config.lua
Config = {};
Config.MAX = 10;
---example.lua
local Config = Utils.loadLuaFile('Dogs', 'media/lua/config.lua')['Config'];
print(Config.MAX);
Is there any way I can add some ModData into the items that spawn by ProceduralDistributions?
if you want to add moddata to all of an item, add it as a parameter on the item
if it's a custom item just add it to the script, else
local item = ScriptManager.instance:getItem('Module.ItemName')
if item then
item:DoParam('ModDataName = value')
end
```which makes that item default with getModData().ModDataName = value
i need a script that i can run once that will place a bunch of tiles in specific places and SAVE THE DAMNED THINGS. so they dont keep getting deleted.
add your objects on loadgridsquare
function checkTileSpawns(sq)
local x, y, z = sq:getX(), sq:getY(), sq:getZ();
if #JobBoardTileSpawns.toSpawn > 0 then
for i = #JobBoardTileSpawns.toSpawn, 1, - 1 do
local tileSpawn = JobBoardTileSpawns.toSpawn[i];
if x == tileSpawn.x and y == tileSpawn.y and z == tileSpawn.z then
local sname = tileSpawn.Tile
local object = IsoObject.new(sq,sname)
sq:AddTileObject(object);
object:getSprite():setName(sname);
tileSpawn.spawned = true;
local signData = object:getModData();
signData.loc = tileSpawn.loc;
--object:getModData() = signData;
object:transmitCompleteItemToServer()
object:transmitModData()
--table.remove(JobBoardTileSpawns.toSpawn, i);
end
end
else
Events.LoadGridsquare.Remove(checkTileSpawns);
end
end```
Listen to albion, I think she's a wizard.
Is this only add modData on new spawn item, or all items that have spawn before too?
Yeah I think so, I can feel the magic around me now xD
i can't quite recall, but i think it was previously spawned items, so long as ModDataName hasn't been set already
guys how to spawn a magazine with all it's bullet's inside
Would it be possible to make a mod for zombies to spawn without limbs
Anyone know the cleanest way off the top to expand this for multiple sound variations, given jump1-8.ogg in the appropriate folder?
module Jumper {
imports {
Base
}
sound Rifting
{
category = Player,
clip
{
file = media/sound/jump.ogg,
}
}
}
Do I really just need to make 8 separate sounds?
Guessing maybe so... ew...
is tyhere a way to make something run when you open a ui?
You could make an ISPanelJoypad UI with an :open function @faint jewel
And do anything you want when you open it
you can add multiple clips for same sound, vanilla does it too in scripts
Key to proper open is to setVisible(true) and addToUIManager while you're in there, then
Point of that is that UI toggles will not find your UI in the active UIs and thus turn them on at inappropriate times if your UI is not in the UI manager when it's closed.
So just
file = ...,
file = ...,
or how is that written?
I couldn't find an example in vanilla
or is it
file = {
...,
...,
...
}
sound MaleZombieCombined
{
category = Zombie,
clip
{
event = Zombie/Voice/MaleA,
}
clip
{
event = Zombie/Voice/MaleB,
}
clip
{
event = Zombie/Voice/MaleC,
}
}
Ahhh
And it randomly chooses a clip or what?
Automatically based on any number of clips?
I imagine so
Well I'll give it a shot, seems interesting.
@fast galleon Nailed it
Ty
Code looks a lot neater this way lmao
Look at that fancy colour coding based on how strong this bait is!
possible to mod a rotating png images ?
i cant think of any vanilla thing that rotates an image
maybe ISUIElement:DrawTextureAngle(tex, centerX, centerY, angle)?
How visible to the Lua side of things are meta events? I'm wondering with RV Interior if we could do some sort of slight-of-hand to mitigate the fact that the player inside a vehicle interior is way outside of the map. Like, if we detected that a meta event has occurred targeting a player that's inside, manually trigger the same event in the outside world (if in MP and that part of the world is loaded) or generally stir up the zombies outside the vehicle when the player inside next exits/that part of the world is loaded up again.
i willtry
WEEEEEEEEEEEEEEEE
u got it working? you still need the function?
i guess not
gj
i did!
how did u do it
i screamed a lot.
you always do but aside from that
did u use math.atan2()?
function DistanceToTarget(x,y)
local player = getPlayer()
local distancetoplayer = IsoUtils.DistanceTo(player:getX(),player:getY(),x,y);
return math.floor(distancetoplayer);
end
function AngleToTarget(x,y)
local player = getPlayer()
local AngleFromPlayer = setAngleFromPoint(x,y)
return math.floor(AngleFromPlayer);
end
function setAngleFromPoint(x,y)
local player = getPlayer()
if(x and y) then
local radians = math.atan2(y - player:getY(), x - player:getX()) + math.pi
local degrees = ((radians * 180 / math.pi + 270) + 45) % 360 -- add 45 deg because of the isometric view? or idk for some reason i need to
return degrees;
end
end
Already spawned items arent edited



