#mod_development
1 messages ยท Page 38 of 1
look at teleport mod ๐
if he do this then he use his own util function using
Padd_Utils[3]()<
????
why are there separate perks for Maintenence, BladeMaintenence and BluntMaintenence?
Anyone knows how to get the item type of a placed world object? I don't have issue finding the objects with a cell:getObjects() just getting the string I need.
Specifically I'm trying to have Ham Radio placed in the world (like furniture) to return me "HamRadio1" or "Base.HamRadio1" whatever works. I've tried to do getName() or getType() with no luck so far.
I think I can store mysettings in the moddata of a zombie. and load from there if I restart the game. Where do I find " onload chunks" I didn't find any event or something like this.
ask TIS thats how they wanted do it. maybe theres a diffrence? perhaps cuz u use the blunt to build and the blades for food? idk
I'm considering the implications of playing with setHoursSurvived clientside. So far, I've heard that getHoursSurvived may play a role in certain rates, e.g., panic reduction, but I don't see that in the Lua. In the Lua, however, I do see getHoursSurvived being used to determine whether it's too soon to sleep. Does it get used all over the place on the Java side or something?
$ grep -r getHoursSurvived ProjectZomboid/zombie/
grep: ProjectZomboid/zombie/ai/sadisticAIDirector/SleepingEvent.class: binary file matches
grep: ProjectZomboid/zombie/ai/ZombieGroupManager.class: binary file matches
grep: ProjectZomboid/zombie/characters/BodyDamage/BodyDamage.class: binary file matches
grep: ProjectZomboid/zombie/characters/Faction.class: binary file matches
grep: ProjectZomboid/zombie/characters/ILuaGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoPlayer.class: binary file matches
grep: ProjectZomboid/zombie/GameTime.class: binary file matches
grep: ProjectZomboid/zombie/iso/areas/SafeHouse.class: binary file matches
grep: ProjectZomboid/zombie/network/GameClient.class: binary file matches
grep: ProjectZomboid/zombie/network/GameServer.class: binary file matches```
It's referenced in those classes
Hmmm yeah I'm not going to be able to counteract all that realistically. Hmmm...
if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
}
This chunk of Java in LevelPerk is proving to be the bane of my existence.
I wrote a sneaky way of making it not happen by playing with getHouseSurvived() (locking it to 0 and storing it elsewhere while the HUD is off).
But this unfortunately has gameplay side effects, and aside from the sleeping side-effects I do not know how to mitigate them... and mitigation of the sleeping side effects could have other side effects. (Also likely Agoraphobic and Claustrophobic panic-related side effects.)
I kinda wish I could just mod that Java class and rewrite that condition with an extra boolean variable, "burryagaWantsToSeeYou" ๐คช
Is the method with that conditional called from lua? If so, you could set hours survived before it is called and revert it immediately after
Unfortunately I don't know. Maybe? Possibly in ISPlayerStatsUI?
if button.internal == "LEVELPERK" then
self.char:LevelPerk(self.selectedPerk.perk, false);
self.char:getXp():setXPToLevel(self.selectedPerk.perk, self.char:getPerkLevel(self.selectedPerk.perk));
SyncXp(self.char)
self:loadPerks();
if self.selectedPerk.perk == Perks.Strength or self.selectedPerk.perk == Perks.Fitness then
self:loadTraits();
end
end
I don't know if LevelPerk above is the correct or only important place LevelPerk gets called
And also in tons of debug scenarios maybe?
Those shouldn't matter because when you're initializing those scenarios getHoursSurvived would be < .01666 [1 minute]
I see a lot of getPlayer():LevelPerk(...) in Steps.lua
Idk what Steps is for... just to track walking stuff?
XpUpdate.lua seems to have its own special levelPerk function, but it doesn't explicitly call LevelPerk anywhere, so that's confusing.
This chunk seems to call LevelPerk... not sure what the ISSkillProgressBar refers to.
function ISSkillProgressBar:onMouseUp(x, y)
-- our selected lvl
local lvlSelected = math.floor(self:getMouseX()/20);
-- if you have skill pts and the skill is ready to evolve and if you clicked on the right lvl
if self.xp >= self.xpForLvl and self.level == lvlSelected and not self.perk:isPassiv() then
self.char:LevelPerk(self.perk:getType());
...
...
...
end
Also
function ISChallenge2PlayerUpWindow:onOptionMouseDown(button, x, y)
local playerObj = self.char
-- manage the item
playerObj:getModData()["challenge2Xp"] = playerObj:getModData()["challenge2Xp"] - button.cost;
if button.internal == "skills" then
-- we add the xp for this skill, so the xp panel will be updated
playerObj:LevelPerk(button.perk);
...
...
...
All these different params are confusing me, too. Not clear if LevelPerk needs 1 or 2 or what. Not sure if they're even calling same function
Assuming it's a function with optional params but that's an assumption
Okay on the Java side it's these two functions:
That keep getting called mostly
afaik
I don't think I have a corresponding function I can decorate but idk I could be missing it
I mean I think I would still release the mod as is and just warn people that the No-XP mode is only for making movies, and causes issues for gameplay, but I would greatly prefer to find a workaround that hides XP harmlessly ๐ญ
But then again they can just turn off XP growth if they want to make movies...
sigh
So close
__classmetatables[zombie.characters.IsoPlayer.class].__index.LevelPerk
That's the lua function that calls into the java method, if that's what you were looking to decorate
Really??? I can just do
function __classmetatables[zombie.characters.IsoPlayer.class].__index.LevelPerk(...)
end```
?
--[[
Usage example:
BurryagaUtils.patchClassMethod(zombie.inventory.types.Moveable.class, "getDisplayName", function(original_fn)
return function(self, arg1, arg2, ...)
local modData = self:getModData()
if modData and modData.new_value then
return modData.new_value
end
local result = original_fn(self, arg1, arg2, ...)
result.someProperty = false
return result
end
end)
]]
BurryagaUtils.patchClassMethod = function(class, methodName, createPatch)
local metatable = __classmetatables[class]
if not metatable then
error("Unable to find metatable for class "..tostring(class))
end
local metatable__index = metatable.__index
if not metatable__index then
error("Unable to find __index in metatable for class "..tostring(class))
end
local originalMethod = metatable__index[methodName]
metatable__index[methodName] = createPatch(originalMethod)
end
Can use that to simply doing it in general
Stfu really that would work?
Where did you find this insanity? Where is __classmetatables anywhere?
Looks to be how kahlua exposes java objects to the lua side. @undone elbow mentioned it a few days back
Can I write [anything].[anything] is is [anything].patchClassMethod a key function that Lua has somewhere?
__classmetatables is in _G
You use it like in the usage example above it
So I just call it once and the method is patched?
And I can name the method patcher essentially anything?
BurryagaUtils.patchClassMethod(zombie.characters.IsoPlayer.class, "LevelPerk", function(original_fn)
return function(self, perk, b1)
-- pre stuff
local result = original_fn(self, perk, b1)
-- post stuff
return result
end
end)
yea
Whoa.
It patches the calls to that java method from the lua code. Doesn't affect java->java calls of that method
Whoa.
Where is _G? Is thee an online directory of these functions / classes?
it's a global table that is built in lua language
basically think of it as Lua lives inside _G
Anything that's not declared local goes into _G. Can think of it is as the table that implements the broadest scope.
function myGlobalFunction() end
myGlobalVariable = 5
print(_G.myGlobalFunction)
print(_G.myGlobalVariable)
Is there a way to see this info online anywhere? Are y'all just decompiling the Java? Where is this information discovered? How did anyone figure out __classmetatables was hiding in the global scope?
it's completely built into lua
every application that uses lua has it
even wow's addon system
it's how lua operates
Read the answer
If you mean the __classmetatables field in _G specifically, it's how kahlua implements exposing java methods to lua. See https://github.com/krka/kahlua2/blob/64ff71a8b213f3a4d7b0319f974a878771a6ab89/core/src/se/krka/kahlua/vm/KahluaUtil.java#L110
https://github.com/krka/kahlua2/blob/64ff71a8b213f3a4d7b0319f974a878771a6ab89/j2se/src/se/krka/kahlua/integration/expose/LuaJavaClassExposer.java#L67
I hear what you're really telling me
@visual abyss @hearty dew I'm gonna try this and if it works I'm reading both of these links until I cry
is there a list of modifiers that weapon part can improve/decrease
How do you add a mod option that is modifiable only in mp servers by server admins?
Wouldn't sandbox vars do the trick?
Do you mean modifiable while the server is running?
If this, can check that the client is admin or debug before setting the variable```lua
if isAdmin() or isDebugEnabled() then
Halp? @hearty dew
Seems to imply metatable__index is not a table?
Even though it does exist?
Can someone explain me why this works
FactionMapClass = {}
function FactionMapClass:new()
local o = {}
setmetatable(o, self)
self.__index = self
return o
end
function FactionMap()
FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
return FactionMapClass.instance
end
But this, does not work
FactionMapClass = {}
function FactionMapClass:new()
--
local o = FactionMapClass
setmetatable(o, self)
self.__index = self
return o
end
function FactionMap()
FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
return FactionMapClass.instance
end
@hearty dew If you can help, this is about what we talked yesterday about making classes, and singletons
When I use the second code vscode gives me auto complete and intellisense on FactionMap
While on the first one it does not
but how exactly do you add an option in the first place? I think I saw a framework on the workshop earlier, but would that be reliable for that kind of purpose oor..?
A file called sandbox-options.txt in \YourModNameHere\media\
VERSION = 1,
option YOURMODNAME.YOURMODOPTION
{
type = boolean, default = false,
page = A PAGE NAME HERE,
translation = SOME_TRANSLATION,
}
Ah, thanks!
Firearms B41, More Traits, Share Annotations and similiar mods all use the sandbox-options.txt
https://steamcommunity.com/sharedfiles/filedetails/?id=2256623447&searchtext=firearms
https://steamcommunity.com/sharedfiles/filedetails/?id=1299328280&searchtext=more+traits
https://steamcommunity.com/sharedfiles/filedetails/?id=2815560151&searchtext=annotations
Look at the mods code to see how they use it ๐
Idk what that is. Need the actual error message from the console.txt ๐
Error message on the left no?
Attempted index of non-table?
I tried scrolling to most recent
The debug ui breaks before printing the error message
so it will highlight the problem and not tell you what it is until you step forward
I did step forward
often easier to just look at console.txt imo
I took one step past the break
But I can open console.txt
That's in user/Zomboid right?
yea
Uhhhh lmao
Something about trying to patch this way is really making Zomboid mad
function: DawnOfTheZed.lua -- file: DawnOfTheZed.lua line # 156 | MOD: Dawn of the Zed (Hide XP Notifications)
LOG : General , 1666181454514> attempted index of non-table
LOG : General , 1666181454642> creating new sourcewindow: C:/Users/Zen/Zomboid/Workshop/Dawn of the Zed/Contents/mods/DawnOfTheZedHideXP/media/lua/client/DawnOfTheZed.lua
LOG : General , 1666181493592> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181493592> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181493753> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181493753> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181493909> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181493910> UNKNOWN GLFW KEY CODE: 283
LOG : General , 1666181531085> EXITDEBUG: RenderThread.isCloseRequested 1
Well, in the 2nd, the object that represents your instance of a class, is the global FactionMapClass. So every new instance would be the same instance. I presume that's not what you're going for if you're writing a new() function
As for this, I'd guess that intellisense isn't able to infer that you've set the metatable to self (i.e. FactionMapClass) (which is why you can call the functions in the FactionMapClass on the object returned by new()). In other words, intellisense isn't smart enough to understand the trickiness of the metatables you've set.
Okay, I launched without this, and then reloaded Lua with this, and got the errors above... so I think this is the fundamental issue, one way or another:
local metatable = __classmetatables[class]
if not metatable then
error("Unable to find metatable for class "..tostring(class))
end
local metatableIndex = metatable.__index
if not metatableIndex then
error("Unable to find __index in metatable for class "..tostring(class))
end
local originalMethod = metatableIndex[methodName]
metatableIndex[methodName] = createPatch(originalMethod)
end```
(Tried with metatable__index, too, I just renamed it. Neither works.)
Interesting, now I'm wondering if the intellisense is not smart enough, is i because it's limited and I need another Lua plug in or is it because I'm writing bad code? ๐ค
Can you paste the code you're running? I can't figure it out from that part of the error message
Well, metatables could change a runtime, so it's a risky assumption to use the metatable to infer autocompletion in some sense 
Maybe there is a way to annotate the code so that intellisense can do the autocompletion you want
@hearty dew
LOG : General , 1666182204624> 328,279,713> -----------------------------------------
STACK TRACE
-----------------------------------------
function: stuff -- file: objects.lua line # 221 | Vanilla
function: console -- file: objects.lua line # 1 | Vanilla
LOG : General , 1666182204629> 328,279,718> attempted index of non-table
ERROR: General , 1666182204634> 328,279,723> ExceptionLogger.logException> Exception thrown java.lang.RuntimeException: attempted index of non-table at KahluaUtil.fail line:82.
ERROR: General , 1666182204639> 328,279,728> DebugLogStream.printException> Stack trace:
java.lang.RuntimeException: attempted index of non-table
at se.krka.kahlua.vm.KahluaUtil.fail(KahluaUtil.java:82)
at se.krka.kahlua.vm.KahluaUtil.luaAssert(KahluaUtil.java:70)
at se.krka.kahlua.vm.KahluaThread.tableSet(KahluaThread.java:1726)
at se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:594)
at se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:163)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1980)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1782)
at se.krka.kahlua.integration.LuaCaller.pcall(LuaCaller.java:76)
at se.krka.kahlua.integration.LuaCaller.protectedCall(LuaCaller.java:117)
at zombie.ui.UIDebugConsole.ProcessCommand(UIDebugConsole.java:278)
at zombie.core.Core.updateKeyboardAux(Core.java:1991)
at zombie.core.Core.updateKeyboard(Core.java:2322)
at zombie.core.Core.DoFrameReady(Core.java:3083)
at zombie.GameWindow.frameStep(GameWindow.java:780)
at zombie.GameWindow.run_ez(GameWindow.java:680)
at zombie.GameWindow.mainThread(GameWindow.java:494)
at java.base/java.lang.Thread.run(Unknown Source)
LOG : General , 1666182204645> 328,279,734> -----------------------------------------
STACK TRACE
-----------------------------------------
function: stuff -- file: objects.lua line # 221 | Vanilla
function: console -- file: objects.lua line # 1 | Vanilla
That's the error I got when running that
line 221 is
BurryagaUtils.patchClassMethod = function(class, methodName, createPatch)```
Add ```lua
BurryagaUtils = BurryagaUtils or {}
above that line
Ohhhhhhhhhhhh
That explains why I didn't get stuck there the first time I ran your code
The first time I ran it I renamed that to a normal function and got all the way into the game
No issues, but it didn't work, so I reverted to your version verbatim and got that error
๐
Okay error is good now, relaunching to see if verbatim version works
Maybe your line numbers were off? Sometimes you have to click reload file in the debug ui's file viewer to get the correct lines
I don't know why that happened that way, but it identified the end of the function instead of the call to it as the issue. It seemed to know that function was an issue but didn't tell me why very well
the end caught the highlight in my debug even though it told me to check line 156
The debug ui is trying to be too helpful maybe, heh
line 156 was just the last line of the function that went bad though
I think that was why it got flagged
๐ญ no dice @hearty dew
Hmmm
let me see
Okay thank, I'll give another look at my code once I'm back from work
@hearty dew Okay, so I tried this... no errors, but it doesn't seem to 0 the HoursSurvived before the crucial moment, because I am still seeing the level-up notifications... Any brilliant suggestions?
local function zeroSurvivedTime()
for playerIndex = 0, getNumActivePlayers() - 1 do
local player = getSpecificPlayer(playerIndex)
if player and not ISUIHandler.allUIVisible then
player:Say("I'm patched mothafucka")
backupHoursSurvived = backupHoursSurvived + player:getHoursSurvived()
player:setHoursSurvived(0.0)
end
end
end
patchJavaMethodB = function(class, methodName, createPatch)
local metatable = __classmetatables[class]
if not metatable then
error("Unable to find metatable for class " .. tostring(class))
end
local metatableIndex = metatable.__index
if not metatableIndex then
error("Unable to find __index in metatable for class " .. tostring(class))
end
local originalMethod = metatableIndex[methodName]
metatableIndex[methodName] = createPatch(originalMethod)
end
patchJavaMethodB(zombie.characters.IsoPlayer.class, "LevelPerk",
function(metatableMethod)
return function(self, perk, booleanFlag)
zeroSurvivedTime()
local result = metatableMethod(self, perk, booleanFlag)
-- restoreSurvivedTime()
return result
end
end
)```
(Doesn't work when named Burryaga.etc either, tested that first.)
The call to zeroSurvivedTime should fire every time LevelPerk gets a call from Lua, right?
Wait.... idea
correct
There are 2 LevelPerk functions on Java side
Is it possible this only targets one?
Is there a way to target both? I seem to only ID the method by its name, but Java IDs by name and # of params
No, it will handle both. There is only one lua side
lua doesn't have function overriding like java
Hmmm well it does not seem to be patching... I can't even get it make the player talk
I tried including a player:Say() in my patched function and nothin came out
zeroSurvivedTime()
print("Hours survived after zeroing are: "..self:getHoursSurvived())
local result = metatableMethod(self, perk, booleanFlag)
would do something like that to verify the code does what I expect
On it
btw, you could pass in self as a param to zeroSurvivedTime to limit the change to that player
(self is a player object in that context)
is there no way to make it appear only as part of server settings if running in MP, and not appear in singleplayer sandbox settings?
No, don't believe so
Great, thanks. I was just using my known-to-be-working version and had made no efforts to improve zeroSurvivedTime in the new context... Appreciate the tip
zeroSurvivedTime WILL hide the xp notice if I run it OnTick
At least no without patching things lua-side
Try give a look at how the player sleep is option is handled, IIRC the option to toggle it on-off only appears in MP
i will give it a look, thanks!
No output
I'd try calling the method via the player object in the lua console
getSpecificPlayer(0):LevelPerk(foo, bar)
Hmmmmmmm that actually did get a reaction.
Also, an error I believe
Hmm I need a real perk ref
If in this scenario you are testing the method is being called java->java, that would explain it not firing because this approach only will patch the method when called from lua
$ grep -r LevelPerk ProjectZomboid/zombie/
grep: ProjectZomboid/zombie/characters/ILuaGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter$XP.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/Lua/LuaEventManager.class: binary file matches
Not that many classes call LevelPerk though
Is there something I could do to mod the calls Java->Java from those classes?
To zero the offending variable at the perfect times?
depends on how they are called
Wouldn't be able to intercept the call, but perhaps could patch the calling method
What tool do y'all recommend to decompile the Java?
I clearly need to read those files
And possibly others
I've just been using http://www.javadecompilers.com, but it's the worst option
Out of these, the only actual call is from the IsoGameCharacter$XP:AddXp method
This maybe :
Alrighty, looks promising enough
Thanks
Immaculate Biryani
(Creating a search flag for myself ๐คช )
I'm going to need these when I get this decompiled
Not sure if I'll have time to finish this morning
player:getXp():AddXP(Perks.MetalWelding, 15)
Looks like most of the ways vanilla lua-side adds xp is this way, not using LevelPerk
What exactly is the problem you are trying to solve by stopping xp additions?
My goal is to mute the popup that tells you when you've leveled up... If I could jump in before AddXP and jump out after the determination has been made regarding whether that XP levels you up, that would be perfect. I tried earlier to hook AddXP using Events.Add but it didn't work because my function would fire after the player was already done leveling.
I just do not want to see the green text above character's head
The sound is acceptable, though tbh I'd also love to get rid of that. (But only while the HUD is invisible.)
FYI, I do not want to stop any XP additions... I only want to intervene to 0 the HoursSurvived variable because afaik that's the easiest way to prevent that green text from appearing... it will not appear while your HoursSurvived are at 0.
Maybe patch the halonote altogether?
I presume you looked into patching IsoPlayer:Say already? That's a quick thing to try
I don't know how I would patch Say to prevent that... This seems to be crucial afaik, courtesy of albion:
public void LevelPerk(final PerkFactory.Perk perk, final boolean b) {
Objects.requireNonNull(perk, "perk is null");
if (perk == PerkFactory.Perks.MAX) {
throw new IllegalArgumentException("perk == Perks.MAX");
}
final IsoPlayer isoPlayer = (IsoPlayer)Type.tryCastTo((Object)this, (Class)IsoPlayer.class);
final IsoGameCharacter.PerkInfo perkInfo = this.getPerkInfo(perk);
if (perkInfo != null) {
final IsoGameCharacter.PerkInfo perkInfo2 = perkInfo;
++perkInfo2.level;
if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
}
if (perkInfo.level > 10) {
perkInfo.level = 10;
}
if (GameClient.bClient && isoPlayer != null) {
GameClient.instance.sendSyncXp(isoPlayer);
}
LuaEventManager.triggerEventGarbage("LevelPerk", (Object)this, (Object)perk, (Object)perkInfo.level, (Object)true);
if (GameClient.bClient && isoPlayer != null) {
GameClient.sendPerks(isoPlayer);
}
return;
}
final IsoGameCharacter.PerkInfo e = new IsoGameCharacter.PerkInfo(this);
e.perk = perk;
e.level = 1;
this.PerkList.add(e);
if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
}
if (GameClient.bClient && this instanceof IsoPlayer) {
GameClient.instance.sendSyncXp(isoPlayer);
}
LuaEventManager.triggerEvent("LevelPerk", (Object)this, (Object)perk, (Object)e.level, (Object)true);
}
Notice it only calls addTextWithArrow when your HoursSurvived is above a minute
Could I patch the addTextWithArrow function somehow to prevent those XP messages? I figured it's a Java file.
I do not know how I would determine whether to 0 the appropriate variable while character is talking
Doesn't look like this is called lua-side on xp updates, anyway
Fair.
idk, I'd figure out what's actually causing those messages overhead, and try to work from there how to prevent it from occurring for the cases you're interested in
Pretty sure this does it:
if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
}
That is the only thing I seek to prevent from happening by setting HoursSurvived to 0
Ah, okay. So either in that method call, addTextWithArrow, maybe there is some way to prevent it, or calls to LevelPerk or AddXp could be patched (which is the direction you were going)
And afaik the only ways to prevent it are for HoursSurvived being 0, or being in Tutorial, or not having a valid player object.
Correct, that is what I was hoping. I don't know how to fix addTextWithArrow at all
I need to see that function probably
Events on AddXp and LevelPerk were a bust because they always fire after I level
If only there were an Xp message duration variable somewhere
and I could just make that 0
Wouldn't that be nice
Didn't see a way to do it down the addTextWithArrow route. That seems to all be done java side as far as I checked.
That's the IsoPlayer:getXp() object. I'd try patching AddXP
That was first thing I tried actually but I kinda hit a dead end with it.
zombie.characters["IsoGameCharacter$XP"].class believe it would be
yea
Are the params the same as in the doc for adding to the AddXP event?
How the heck can Lua take such a range of inputs for various Java methods and send them where they belong? return function(self, perk, float, boolean1, boolean2, boolean3)?
What single super-return would apply to all three versions of AddXP ?
if they're so wildly different?
Is Handweapon even a Perk?
patchJavaMethodB(zombie.characters["IsoGameCharacter$XP"].class, "AddXp",
function(metatableMethod)
return function(self, perk, booleanFlag)
-- Hopefully before.
zeroSurvivedTime()
self:Say("Why, hello, there!")
print("Hours survived after zeroing are: "..self:getHoursSurvived())
local result = metatableMethod(self, perk, booleanFlag)
-- Hopefully before.
restoreSurvivedTime()
return result
end
end
)
```?
Would (self, perk, booleanFlag) become (self, perk, float, boolean1, boolean2, boolean3)?
btw why you're on it, can you tell me why most times I won't get the skill level up note above player
In the kahlua layer, I would presume they check the parameter types and match it to the appropriate java.lang.reflect.Method
If you don't care about the params, can just use ... to capture them all and pass them along unchanged
Really???!?
Like this?
patchJavaMethodB(zombie.characters["IsoGameCharacter$XP"].class, "AddXp",
function(metatableMethod)
return function(...)
zeroSurvivedTime()
self:Say("Why, hello, there!")
print("Hours survived after zeroing are: "..self:getHoursSurvived())
local result = metatableMethod(...)
restoreSurvivedTime()
return result
end
end
)
return function(self, ...)
metatableMethod(self, ...)
end
(I presume you want to use self?)
yeah good idea
you are referencing self in the print
Yeah I forgot but thank you
Wow
So AddXp is void so I can stop returning the void, yeah?
yea
Okay so,
1- How do you reference that mod option in the code?
2- does the translation field reference translation files?
3- What is the naming policy in translation files? Because translations only worked if I named them certain names like ContextMenu_XX or Tooltip_XX, but wouldn't work in other cases
also are there more fields that can be utilized apart from those 3?
The easiest way is to learn from a mod that already uses this. Like "Eggon's All Doors Are Yours" mod or "Working Treadmill" mod or many others. That's what I did anyway.
was struggling to find mods that used sandbox options, but thanks!
- I think just with file sandbox-options.txt in /media/
- Yes in media/lua/shared/Translate/EN/Sandbox_EN.txt
Omg I think I hooked AddXP (which apparently is the spelling in Java, WHYYYYYYY?)
I don't know if it's gonna work yet because I threw an error from it, but progress!
OMFG I THINK IT WORKED
@hearty dew You truly must let me send you coffee
is there an Event for pickup item / transfer item to inventory?
one last question, any idea if the page field has a defined list of pages to use or if I can just add my own page?
can u use lua to spawn an ATM in the game at a specific coordinate? (like if someone would have placed it in the game by hand)
You can make your own
It's a custom name. This will be the name of the section on the left when choosing the sandbow parameters
@hearty dew Omg it works perfectly
aaa okay thanks!
It's tracking HoursSurvived and acting like it's not
It's so beautiful, kill me now while I'm happy guys
so i'm wondering if it's possible to have a gun support different type of mags (like 5 round mag and 10 round mag)
or do i need to make new item gun for each mag supported?
i tried magtype=mag1;mag2,
Believe arsenal mod does that. I don't know offhand how though
or whatever it was
soo is it normal for it to look like this?
but it didnt really wor klolol
You'll need to use translate
If you are missing translations, yes
arsenal[26]?
yea
Translation files have a very specific naming pattern
var in file media/lua/shared/Translate/EN/Sandbox_EN.txt
Got it it to work, thanks so much!
@hollow current
media/sandbox-options.txt
VERSION = 1,
option nostartingbelts.blacklist
{
type = string,
default = Belt;Belt2,
page = nostartingbelts,
translation = nostartingbelts_blacklist,
}
media/lua/shared/Translate/EN/Sandbox_EN.txt
Sandbox_EN = {
Sandbox_nostartingbelts = "No Starting Belts",
Sandbox_nostartingbelts_blacklist = "Blacklisted items",
Sandbox_nostartingbelts_blacklist_tooltip = "Semicolon separated list of blacklisted item identifiers. Only these items will be removed on newly created characters. Any other items will allowed on newly created characters. Only use either the Blacklist or Whitelist. Do not use both. E.g. Belt2;Base.Belt;Glasses_Normal",
}
Some lua file
print(SandboxVars.nostartingbelts.blacklist)
interesting. i see it now. using moddata to add another mag
then basically editing the actual item's mag type
oh man this will do.
i need to learn moddata
i know of it but i'm not well informed with it. is there any info on it that i can read?
I want to get the same time for a time action, independent of sandbox.
120 * getGameTime():getMinutesPerDay()
This is some code I found ways back, will it work?
Is it possible to print to the console.txt from lua? print only appears in the debug console...
yourTime * (getGameTime():getMinutesPerDay() / defaultGameTime)
I think?
I'm confused now... I'll check again... Maybe I need a break...
if the time was left alone, it would be just 100% (normal speed)
i promise you it does write to console.txt at same time
Sorry, I just was blind...
no worries
Is default something constant or does it change
idk. i'm sure you can find it somewhere
i've never touched that sort of thing yet
just giving you the math
basically you want to get the % change from the default time
so if the gametime was 2x faster
that's 150%
60 * 1.50 = 90 which should be at same pace
as 60
quick question, so the sandbox option appears in SP options, but not when creating the world in say, Hosted server, any idea why?
I suggest doing what @hearty dew suggested
tail txt in terminal
here
if you need - i use powershell: Get-Content PATH_TO_CONSOLE_TXT -Tail 100 -Wait
it'll act like a live feed logger for you in the terminal
yeah makes sense, the number I use gets halved otherwise
you probably could try finding out what the default speed
and just set it as a constant in your lua scripts
Did you managed to solve the object problem?
nah
i dropped it for now
i'd like some actual progress so i'm working on other stuff lol
i'll circle back around later
beside it's not too important right now in term of required mechanism
ok... did my last suggestion with getting the object also fail or is the object not on the square itself? I did this to check if there is a fence on the square...
ok
oh i missed that. i apologize. I just copied the message into my notes
so if i understand how moddata() works, it's a table with extra entries that isnt supported by vanilla in txt script?
its already done automatically by their vanilla parsing so i don't need to do anything to parse it
I don't see a default minutes per day, but there is a getDeltaMinutesPerDay which returns MinutesPerDayStart / MinutesPerday
What is the most early event when sandbox vars are already loaded from save or received from server?
could try retrieving default on boot event
InitGlobalModData is the one that works for both I think
I didn't look for the specific event, but it seemed they aren't loaded when shared/ or when client/ scripts are loaded, I'm pretty sure. OnGameBoot comes after client/ and before server/ lua files are loaded. Perhaps at that point. Perhaps even later?
The tricky thing is that the sandbox variables can be created earlier (and populated with the default), but the configured values aren't loaded until later
sandbox are loaded after onInitWorld
does the event
Events.EveryOneMinute
happen every minute ingame time? or in real life time 1 minute?
in game time
global mod data? Or mod data on java objects?
They behave differently
i'm guessing the former
looking at arsenal
Gun:getMagazineType() ~= "Base.Fixed"
err
wrong one
local Ext = Gun:getModData().ExtMagType
ExtMagType is an entry in the item script
which is obviously not supported by vanilla
That's mod data on that object (gun inventory item, I presume)
global mod data is accessed through functions in the GlobalObject. I think it's modData()?
There's a nice writeup for global mod data. I'll try to find it
that would be appreciated
global mod data has to be manually synchronized
Mod data on objects, I understand, is synchronized automatically.
I haven't used it personally, so I'm not 100% certain
In general, moddata is not related to the script. That mod just happens to use some concepts from the script in naming identifiers in the mod data table
Think of (non-global) mod data as a table that pz will persist automatically for you on that object. In it you can put basic lua types, nested tables, strings, numbers, etc
The mod might not be activated
When you go through that UI to mess with server configurations, it doesn't automatically reload the lua files for the mods that should be activated as it does in singleplayer. So you run into situations where sandbox vars are missing
Quick question, is there a mod that disables military gear and zombies?
I need that
Not sure. Might try asking in #mod_support
I have two questions:
-
Is it possible to remove an item from being wieldable? (Wield as Primary, Wield as Secondary)
-
Is it possible to TURN OFF a drainable item when it enters the inventory? Best example would be for turning a flashlight off once it enters the inventory. I could probably adapt the vanilla code for attaching walkie-talkies to the belt would turn it off but cant find that code
- wouldn't that be determined by type?
hey does anyone know where the scripting is that starts spawning katanas in zombies after 60 days?
It's Type = Drainable as I need it to be used by batteries. Assumed I could somehow alter the contextmenu but idk
It's in the java side. It reads that number of days until the item can spawn from the loot table to determine if enough time has passed to spawn the item. The property, however, is in one of the loot tables in lua
believe it was the attachedWeapon loot table
.
What function of IsoPlayer returns the visible name in mp?
that's getDisplayName, I believe
they were separate in a previous build, but they were merged into maintenance
I played with the walktypes of the zombies. Personally I think there is a big gap between "5" and "sprint1". Is it possible to speed up walking a bit? I tried it with setSpeedMod (IsoGameCharacter) but I didn't notice a speedchange.
zombieData.WalkType = "5"
zombie:setSpeedMod(2)
print(player:getDisplayName()) -- "KathieRobb"
Should be just "Kathie" I guess
Maybe getForname?
I'm not sure which is displayed tbh. It might change in steam/nosteam. And I vaguely remember there an option to change whether the player name or username/steamid is shown.. I don't know ๐
getForname is wrong. It returns some hardcoded string, 'Bob'. getFullName returns the characters name
player:getForname() -- just "Bob", despite the full name is "Kathie Robb"
I have a gun with a custom entry
item gun
{
AmmoType1 = ammo1,
}
and when i try to do gun:getModData().AmmoType1 it just returns nil
am I missing something
Moddata doesn't read from custom entries like that as far as I know. I haven't seen that before, at least
@hearty dew Okay, nevermind and thanks. I guess it's too difficult to get quick workaround.
_obj:getModData().RadioItemID = worldItem:getID()
Is it not set via lua as well?
i know the param is successfully added LOG : General , 1666197757747> adding unknown item param "AmmoType1" = "newammo2""
in Item.java line 2623
in void DoParam()
I look in my code... I did this already...
key.copyModData(this.DefaultModData);
Hmm.. yea, it looks like it puts it into DefaultModData and, it should copy over the default when creating an item instance
this was it. thank you
i wonder if its because i still had the gun before i added these code
yeah
What type is gun?
yea, that would explain it
and spawned another one
o.TotalWorkUnits = itemModData.TotalWorkUnits or 200```
``` item UnfinishedBat
{
Weight = 2.0,
Type = Normal,
DisplayName = Unfinished Bat,
DisplayCategory = Tool,
WorldStaticModel = Log,
Icon = RawBat,
Tags = SoulMod_UnfinishedWoodItem,
ResultItem = BaseballBat,
RequiredSkill = Carpentry 1,
TotalWorkUnits = 10,
}```
awesome thanks
this works for me...
allo, is it possible to check if another mod is enabled using lua? google isn't helping much
if getActivatedMods():contains("modidnotworkshopid") then
Someone has an suggestion about my zombie speed problem?
Are you trying to adjust a zombie's speed beyond the sprint/shamble/fast-shamble discrete options?
I copied the text from my message above:
I played with the walktypes of the zombies. Personally I think there is a big gap between "5" and "sprint1". Is it possible to speed up walking a bit? I tried it with setSpeedMod (IsoGameCharacter) but I didn't notice a speedchange.
zombieData.WalkType = "5"
zombie:setSpeedMod(2)
and the answer to your question is yes ๐
Then I think you're in uncharted territory :)
Might need to dig into the java side to see what setSpeedMod does, and how that factors in or doesn't to the zombie speed
ok... then I'll look at this later. It's not the most importet.
Unfortunatly I have no clue what I'm doing. I just searched the docs for "speed" stuff.
inventory context menu is client right?
How do I get started?
The best way is to look at somebody else mod, and try to edit it to fit your needs
And then ask yourself "why is this working/not working"
does anyone have any idea how to add custom traits?
https://github.com/MrBounty/PZ-Mod---Doc/blob/main/How to make a custom trait.md this guide seems to be clientsided only
Most traits don't need server side stuff, what are you trying to do?
i would recommend using profession framework https://steamcommunity.com/sharedfiles/filedetails/?id=1343686691
it simplifies the process and ensures compatibility, and it has some documentation
to modify player stats and things doesn't need to be serversided?
and how do i tell what realm a function needs to run in then?
Nope, most stuff happens client side, unless the TIS Devs decide to add some anti cheat measure, but even then, the mod user can just disable the anti cheat
they've mentioned moving certain stuff to the server but you can worry about that when that actually happens
huh, how do other players get your stats and things?
are injuries server sided at the least?
and i don't even need to register traits serverside? huh.
How to remove something from context menu in inventory?
injuries are client side
there's actually some occasional weird behaviour if you don't, so i would register them in shared
gotcha
like what exactly? add a little more detail pls
is there a way to view the base game code?
is it possible to teleport them to add speed? like fast move. but lol teleporting zeds! haha
nvm
To make a horror movie mod where the light is flickering and the zombies randomly appear near you ๐
flickering lights would be cute actually
i want that after that light propagation update
I want to remove the option "Turn on" and "Turn off" from an item when it's in the inventory, but when it's in the world it should be default again
Soooo, I do not know why, or how, but this works as a singleton in lua 
FactionMapClass = {}
function FactionMapClass:new()
return self
end
-- This is a singleton
function FactionMap()
FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
print('FactionMapClass.instance'..tostring(FactionMapClass.instance))
return FactionMapClass.instance
end
And I can access it's instance from everywhere like as example, this
if FactionMap():isShowFactionMap() then
FactionMap():restoreFactionPlayerSymbols()
else
FactionMap():restoreVanillaPlayerSymbols()
end
And, the self works inside the functions, so, I know it works, nice.
But, whyyyyyyyyyyyyyyyyyyyyyyyyyyyy
Like, this confuses the hell out of me, zomboid classes are implemented in a complete different way
like this:
function ISUIElement:new (x, y, width, height)
local o = {}
setmetatable(o, self)
self.__index = self
local maxY = getCore():getScreenHeight();
local maxX = getCore():getScreenWidth();
o.x = math.max(0, math.min(x, maxX - width));
o.y = math.max(0, math.min(y, maxY - height));
o.width = width;
o.height = height;
o.anchorLeft = true;
o.anchorRight = false;
o.anchorTop = true;
o.anchorBottom = false;
o.dock = "none";
o.minimumWidth = 0;
o.minimumHeight = 0;
o.scrollwidth = 0;
o.removed = false;
return o
end
Why is my code working 
As far as I know the creation of the context menu is a horrible long lua function. It does more or less all the menuitems at once if I remember correctly... (someone correct me if I'm wrong).
But I found some functions in the file ISContextMenu.lua which you eventually can use. For example:
ISContextMenu:removeOptionByName(optName)
I think the context should offer you this...
I forgot to mention I think of the event: OnFillInventoryObjectContextMenu
lua 'objects' are just tables, there really isn't much you need to do special
Is it "good coding" if I put my function which I expect to execute in Solo and on the Server in a lua file in the server directory in my mod.
I still struggle a bit with the Server/Client/Shared and Solo concept...
Ah, ohhh that why I keep reading about many different ways of making classes in lua
So, I managed to make* instant sync maps between faction members in MP
||*atm it only works on my PC tho :(||
thank you โค๏ธ
hmm so.. I've add submenu to submenu
it works but the submenu of submenu doesnt go away after clicks
I have the object itself for WorldObject, what would it be for inventory object?
ISInventoryItemContextMenu? Just assuming since ISWorldObjectContextMenu
Thank you! Does it need to be placed somewhere specific folder wise? Saw someone do Lua/Client/Context/Inventory/file
afaik no
i just did lua/client/mod_inventorycontext.lua
as long as it in client folder i mean
And "require 'ISUI/ISInventoryItemContextMenu';" would be correct too?
Sorry for all the questions
Sorry was afk. Did it work? what was your solution?
I didn't get that far yet. Still unsure how to remove it tbh
I think I got the object now or w.e to remove it from
But unsure where I can find the names of the entires like if it's ContextMenu_Turn_On/ContextMenu_Turn_Of or something different
I never did it by myself but I used the function to add my element on top. I thought about the following steps:
local function addProceedWorkMenu(player, context, items)
--your conditions
context:removeOptionByName(optName)
end
Events.OnFillInventoryObjectContextMenu.Add(addProceedWorkMenu)
I don't know if you have to use the getText like
getText("ContextMenu_Unfavorite")
for the name. Look in the ISInventoryPOaneContextMenu.lua.
Where do I find the ISInventoryPaneContextMenu.lua?
client/isui/
in the first function createMenu they do a lot of tests... followed by the first triggerevent() and then based on the tests the menu entries are created...
With a search I found:
local txt = getText("ContextMenu_Turn_On");
if canBeActivated:isActivated() then
txt = getText("ContextMenu_Turn_Off");
end
conditions here would be if the player has the item I want to remove it from in the inventory correct?
so like a search through PlayerInv
the event triggers if your rightclick one or more items. so you should check if the items or the item is the one you want to remove the menuitem.
I assume I would need two instances right? Can't remove multiple options in one call?
context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
A codesnippet from a context menu I used:
local invItem = items[1];
if not instanceof(invItem, "InventoryItem") then
invItem = items[1].items[1];
end```
Note: I didn't do the same. I checked if its one or more items on the stack and used the first if their are multiple.
I think so.
Okay so something like this with pseudo code lol
require 'ISUI/ISInventoryItemContextMenu';
function removeContextMenuEntries(player, context, item)
local playerObj = getSpecificPlayer(player)
local playerInv = playerObj:getInventory()
if instanceof(playerInv, "ElectricHeater")
-- loop through the inventory and if it finds the ITEM we'll do below else return
context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
UPDATED
probably should go in shared/ if it is used in both client/ and server/
does anyone have a short explanation for suburbs distribution? I have read the dist files and I have no idea what they are. seems like distribution is covered comprehensively in the other dist files
you should define parameters like my function has:
(player, context, items)
the event gives you these...
Like described here:
https://pzwiki.net/wiki/Modding:Lua_Events/OnFillInventoryObjectContextMenu
@blissful salmon
We should make a statue of you, and pin this message
Yes I already read that. But in my case it's only for Server and Solo but not on the client. As far I understand Solo loads all but both isClient() and isServer() are false.
What you've implemented here is a very round about way to do this:```lua
function FactionMap()
return FactionMapClass
end
Okay so this should work? I mean as it's correctly formatted?
require 'ISUI/ISInventoryItemContextMenu';
function removeContextMenuEntries(player, context, item)
local playerObj = getSpecificPlayer(player)
local playerInv = playerObj:getInventory()
if instanceof(playerInv, "InventoryItem") then
local item = object:getItem()
if item:getType() == "ElectricHeater" then
context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
end
end
end
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
No more statues ๐ข
Singleplayer runs all 3 (just as a multiplayer client does)
Sorry, I was trying to explain why it works
No worries dude, I'm joking. 
The client runs the server part? So I should at some
if isClient() then return end
on the top of some files?
because new() returns self (which is a reference to FactionMapClass when called as FactionMapClass:new()), FactionMapClass.instance = FactionMapClass:new() sets instance to reference FactionMapClass. Then that reference is returned by FactionMap()
The client will load the lua files from server/, yes. I didn't understand the second question, sorry
So, I accidentally achieved a lua (Singleton) Rube Goldberg machine ๐ค
so you done with the debug UI and thi sis a difrent mod youo r working on?
The if in the middle shoud be (i think):
context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
end```
This works if you only have one item on the stack... else you shoud loop through items[1].
At least I understood it this way as I read through one of the luas...
Problem solved ๐ฏ

-- This is an overly complex singleton, but I kinda like it
function FactionMap()
FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
return FactionMapClass.instance
end
I want to belive I have a real class
When you call a function using : in lua, it takes whatever is to the left of the : and assigns that to the self variable inside the function being called. So
Foo = {stuff = "abc"}
function Foo:func()
print(self.stuff) -- prints "abc", because self == Foo
end
Foo:func()
I made a code segment in my message... I think I have to leave some files if it's the client... so far I didn't notice any issues but you never know...
Okay so just changing my code from item to item[1]?
Oooooooh, I have been using lua all this time and did not know about that
replace this whole part:
local item = object:getItem()
if item:getType() == "ElectricHeater" then
context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
end
end
ah sorry...
you still need this:
f item[1]:getType() == "ElectricHeater" then
But wouldn't it remove the context menu from all items? Looking to remove it from one specific
Okay thank โค๏ธโค๏ธ
thank if it works :-p
I will LMAO
It's simply a fancy way to do this exact same thing:```lua
Foo = {stuff = "abc"}
function Foo.func(self)
print(self.stuff) -- prints "abc", because self == Foo
end
Foo.func(Foo)
Note I changed the `:` to a `.`
This thing about : and . is really confusing but you made it clear, thank you tyrir
Is there a mod to make Zomboid set in the present day?
You can set the start date to 30 years forward maybe ๐
you will have to make a mod for this i think
yes world clock by konijima
wow how many modder do you manage to solve problems? @hearty dew i saw loads of thnx haha
your awsome man
i think they were hoping for more than changing a number
I vote for Tyrir as "the Saint of the church of Spiffo"
I meant more like a mod that adds cell phones and electric cars and stuff like that
you'd be able to find bits and pieces, but i don't think there's any kind of big overhaul mod like that
Heyo. Haven't done any modding with PZ yet, but I've been teasing around with an idea since I saw a few different mods on the Workshop... Would it be possible to enable weather damaging structures?
I STILL have no clue how to unfocus the gd debug console.
I am working on a couple mods adjacently.
not an easy mod to build but you can do it..
anyone know what kind of display cases are in the ary gallery? I want to add a spawn specific to those cases
*art gallery
u probably want to learn the how to be able to get ids of tiles then be able to input dmg to them like how players or zeds hit them
the be able to put that on a function that detects the weather.
and lastly be able to communicate the cahnges that happned to all clients so that everyone sees it.. i think? not sure..
My interest is in turning PZ into a survival game with a different opponent than zombies. I'm fine with zombies, but my wife is phobic. I've always enjoyed inclement weather as a challenge. Things like Toxic Fog and Anomalous Storm got me thinking about it.
u know where to start then ๐
Seems like it might be suited better for a custom map with only player-built structures, to limit the check intensity.
try asking mapping section they know all about tiles.
you can also find out the answer by yourself by using the tilepicker aka brushtool
would still be the same cuz you would have to use onloadgrid or something like that i think
ok so you can actually limit loot spawns to a tile in game? I saw in the distriubtions but I thought it was a texture not an actual coordinate
which is the most intensive event when it comes to ram usage i believe
as it loads every time a player moves and tiles within his radius loads so you load alot of tiles i believe
but im not really sure ihavent learned to use it yet
no.. not unless u have a custom container i guess
on a custom map
Hm, so perhaps better to have a fairly instantaneous effect than an ongoing one... So, instead of having weather that will slowly break down structures, have say, a heavy lightning strike that will check the grid, blast X tiles, and be done with it.
i guess
or maybe you can create custom tiles that after a certain period of time changes its sprite and its health?
Ooh, self-deteriorating tiles are possible eh?
not sure either. just throwing ideas. brain storm
Is there an event fired when the player updates their map?
Ah, so brains come down and beat down the players' structures?
(couldn't help myself lmao)
what do mean by update? like discover? i guess since thats when vehicle spawn right?
yeah name the mod brain storm lol
or if it hits u learn a random recipe each time
Causes all zombies in the area to start their "eating on the ground" animation, but also attracts a bunch of zombies to the area.
loool
barricaded world uses this
I forgot to mention, when the player updates their in-game map by writing a symbol or text on it
Yeah it does, I saw it in the logs
LOG : General , 1666210390524> reading D:\ZomboidDevCache\Saves\Sandbox\18-10-2022_06-57-22\InGameMap.ini
LOG : General , 1666210400465> writing D:\ZomboidDevCache\Saves\Sandbox\18-10-2022_06-57-22\InGameMap.ini
But I did not see any event fire by it
I see
I will post this again as I'm still having issues ๐ฆ Soul your solution didn't work either but thank you so much for trying โค๏ธ
I'm trying to remove the "Wield as Primary" and "Wield as Secondary" in the context menu of my item "ElectricHeater". Here's my attempt.
require 'ISUI/ISInventoryItemContextMenu';
function removeContextMenuEntries(player, context, item)
local playerObj = getSpecificPlayer(player)
local playerInv = playerObj:getInventory()
if instanceof(playerInv, "InventoryItem") then
local item = object:getItem()
if item:getType() == "ElectricHeater" then
context:removeOptionByName("ContextMenu_Equip_Primary");
context:removeOptionByName("ContextMenu_Equip_Secondary");
end
end
end
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
you still check the inventory if its an inventoryitem. you have to check the item[1]. maybe do some prints:
print(tostring(item[1]:getName()))
oh god dayzmod days intensifies
Do I even need the variables playerObj and playerInv?
no
just use player whats the problem?
require 'ISUI/ISInventoryItemContextMenu';
function removeContextMenuEntries(player, context, item)
print(tostring(item[1]:getName()))
if item:getType() == "ElectricHeater" then
context:removeOptionByName("ContextMenu_Equip_Primary");
context:removeOptionByName("ContextMenu_Equip_Secondary");
end
end
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
Like so?
the only time you need getspecificplayer is when you mess with stuff i think across send client/servercommand.
in the if you also should use item[1]
isnt that item:get(0)
and make a print if you get in.
yes
Getting errors when using it with the added [1] after IF statement
but I think I only used get() on arrays so far.
function: removeContextMenuEntries -- file: HeaterISInventoryItemContextMenu.lua line # 5 | MOD: Sapphire's Playground
Line 5 is the print
Object tried to call nil
off the top of my head lua doesnt use Array[#]
do you see the print in your console and the error?
no print in the console no
It says error on createMenu and onRightMouseUp, "Object tried to call nil in removeContextMenuEntries"
The lua file is located in lua/client/ISUI/FILE
yes, but I just do it when i get them from Java... both should work in this case I think. It depends on the index.
oh wait i guess you do yeah ignore me im still at work messing with powershell
can you post the error?
Sure pastebin?
yes
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.
hey sorry for spamming the question but im modding item spawning and i'm
It sounds like the object isn't indexed or w.e since it's getting nil? assuming nil = null
i'm in need of an answer about the point of suburbs.distribution
is line 5 the print or the if?
the print
Might need to translate those strings using getText
Same error if I remove the print
I have to check the item class.
(unrelated to your exception. Didn't look at that)
that's prob gonna be the next error lol, but yea I assume so.
context:removeOptionByName(getName("ContextMenu_Equip_Secondary")); should be fine?
oh ok
getText instead of getName
I really appreciate this. thank you for helping me โค๏ธ
Did you remove the old function from the event and add your new (fixed) one?
(If you reloaded the save game, it would have done this)
This is what I got right now:
require 'ISUI/ISInventoryItemContextMenu';
function removeContextMenuEntries(player, context, item)
if item[1]:getType() == "ElectricHeater" then
context:removeOptionByName(getText("ContextMenu_Equip_Primary"));
context:removeOptionByName(getText("ContextMenu_Equip_Secondary"));
end
end
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
Unsure if it answers your question
Is there an event for when this function is called? playSoundLocal
I keep logging in and out of the game yea, but always boot a new save ๐
can you put this at the start of the function? and comment the rest for now....
print(type(invItem))
if not instanceof(invItem, "InventoryItem") then
print("not instance of")
invItem = items[1].items[1];
else
print("is instance of")
end```
on it!
error again
sec
tried renaming my function variable from item to items and see if it works
since I saw the new code used items and not item
ah damn... you called the parameter item not items.
I get
table
not instance of
I also saw it right now...
so just rename to items?
SAPPHIREUtils = SAPPHIREUtils or {}
SAPPHIREUtils.InspectMetatables = SAPPHIREUtils.InspectMetatables or true
SAPPHIREUtils.InspectDefaultDepth = SAPPHIREUtils.InspectDefaultDepth or 3
SAPPHIREUtils.InspectTableIndentWidth = SAPPHIREUtils.InspectTableIndentWidth or 4
SAPPHIREUtils.inspect = function(t, depth, header)
depth = depth or SAPPHIREUtils.InspectDefaultDepth
header = header or string.format("---------- %s ----------", type(t))
local printOutput = {}
table.insert(printOutput, header)
local table_cache = {}
local function inspect_impl(t, depth, indent, prefix)
local indentLead = prefix and "." or " "
prefix = prefix or ""
depth = depth - 1
local tableIndent = indentLead..string.rep(" ", SAPPHIREUtils.InspectTableIndentWidth - 1)
local prefixIndent = string.rep(" ", string.len(prefix))
if type(t) == "table" then
if table_cache[t] then
table.insert(printOutput, indent..prefix..tostring(t).." ** PRUNED. Cycle/duplicate detected **")
return
end
if depth < 0 then
table.insert(printOutput, indent..prefix..tostring(t).." ** PRUNED. Max depth reached **")
return
end
table_cache[t] = true
table.insert(printOutput, indent..prefix..tostring(t).." {")
for k, v in pairs(t) do
inspect_impl(v, depth, indent..prefixIndent..tableIndent, "["..tostring(k).."] => ")
end
local metatable = getmetatable(t)
if SAPPHIREUtils.InspectMetatables and metatable ~= nil then
inspect_impl(metatable, depth, indent..prefixIndent..tableIndent, "<METATABLE> => ")
end
table.insert(printOutput, indent..prefixIndent.."}")
elseif type(t) == "userdata" then
local metatable = getmetatable(t)
if not SAPPHIREUtils.InspectMetatables or metatable == nil then
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t))
return
end
if depth < 0 then
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t).." ** PRUNED. Max depth reached **")
return
end
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t).." <")
inspect_impl(metatable, depth,
indent..prefixIndent..indentLead..string.rep(" ", string.len("("..type(t)..") ") - 1),
"<METATABLE> => ")
table.insert(printOutput, indent..prefixIndent..">")
elseif type(t) == "string" then
table.insert(printOutput, indent..prefix..'"'..t..'"')
else
table.insert(printOutput, indent..prefix..tostring(t))
end
end
inspect_impl(t, depth, "")
print(table.concat(printOutput, "\n"))
return t
end
function removeContextMenuEntries(player, context, item)
SAPPHIREUtils.inspect(item)
if item[1]:getType() == "ElectricHeater" then
context:removeOptionByName(getText("ContextMenu_Equip_Primary"));
context:removeOptionByName(getText("ContextMenu_Equip_Secondary"));
end
end
Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
It will print out what item is
gawdamn ๐
local invItem = items[1];
print(type(invItem))
if not instanceof(invItem, "InventoryItem") then
print("not instance of")
invItem = items[1].items[1];
if instanceof(invItem, "InventoryItem") then
print("now is instance of")
end
else
print("is instance of")
end```
on it
if this doesn't work try the print of Tyrir
ok... so the items[1].items[1] is your heater...
okay that's odd lol
For me this was only the case if I had a stack of items. So when you click the plus in inventory do you have more then one?
so you can remove the prints and work with invItem.
yes. if there are multiple items you have to loop through item[1].items instead of using the first one like i did.
Only one heater is still items[1].items[1]
It's like my initial code snippet on the post...
#mod_development message
Ohhh!!!!
no... i think if its one item then you should use items[1]
Yea that makes more sense to me now lol
my code check first if the items[1] is the instance and if not i selected the first one of items[1].items ...
Yup! It works, thx!!
And you should probably loop throught it.
I don't know if there is a function to check if all items are heater. Else maybe the turn on or off should not appear I thing.
Hi, ho we can tell how many units to use in a recipe ? Like BlowTorch units ?
recipes are in media/scripts/recipes
there you can see what items are required in a recipe. you can decide what amount of blowtorch units you want to use in a recipe based the amount of blowtorch units used in other recipes
Yes, actually the propane from blowtorch doesn't go down when i craft things
`recipe Craft Scrap Metal
{
Category : Welding,
UnusableMetal=2,
keep BlowTorch,
keep WeldingMask,
Result : ScrapMetal,
OnGiveXP : Recipe.OnGiveXP.MetalWelding25,
Sound : BlowTorch,
Time : 30,
AnimNode : Disassemble,
}`
So, what i need to add here ?
you need to add BlowTorch=x, with the unusable metal command to make the recipe consume fuel
Okay thanks you, i will add this
is it possible to force distribution for certain grids?
I want to add loot spawns to the art gallery displaycases specifically but they are generic shop locations. Would it be better to change the tile type??
If I have two items from a mod I want to have the exact same functions how would I use the item:getType == ?
I mean rn for one item it'd be item:getType == "ModdedItem"
Would I just do item:getType == "ModdedItem1" or item:getType == "ModdedItem2"?
seems correct... i already had something similar... give me a second...
I used:
Tags = SoulMod_UnfinishedWoodItem,
if invItem:hasTag("SoulMod_UnfinishedWoodItem") then
First line is defining a tag on your items... Second line is to check the tag on the item. So if you have a third and a fourth item you don't have to add them to the if statement. it's enought to tag the new items...
I'm off for today... hope this last lines help you ๐
Anyone know how to catch a signal the moment after your player spawns into the game and becomes physically controllable?
Or alternatively the moment the UI is drawn after spawning?
Maybe the first OnTick?
Hmmm interesting
Oh wait I have an idea that might work...
Hmmm
I think I know the show UI function that gets used, I can just decorate it
I had to ask to think of this, sorry.
Yo yo yo -- so I'm getting requests on making the Graffiti mod work better in MP. Right now, if you leave the chunk in MP the graffiti dissapears -- and it seems like it doesn't get added to the server side so other players also can't see it. Any help would be appreciated as I have no clue wtf i am doing XD
is OnCreatePlayer not suitable?
Didn't work for me, maybe I did it wrong?
I tried simply Saying something
But it didn't talk
maybe it gets called too early
I thought maybe player gets created shortly before it appears and become useable, moveable, can talk, etc
I guess I could have triggered it wrong
i had an issue where server commands sent after that event didn't actually get received
If anyone knows Say DOES work to talk when you spawn, I did it wrong, and I'd love to be corrected
That would be the absolute easiest way
so some weird stuff does happen with that event for sure
I think I may know a way. I am gonna give it a shot. A little wonky but it should work.
hey there! I tried your proposal but doesn't work for me. with such a recipe, the game allows me to use a single berry to realize the recipe instead of requiring 5 (and then may produce and error depending on whether I separate the lines with a comma or not). hmmm... strange because from a logical point of view, it would be reasonable that it works exactly as you suggested...
I figured it out. it was just one line of code
local function OnTick()
Events.OnTick.Remove(OnTick)
-- do your thing
end
Oh crap it seems so obvious in retrospect โค๏ธ
so, i know how to log data in the server's log folder, but how does one log data into the client's c users username zomboid logs folder?
print("text to log") will write to the active log file and then the log files are archived into the log folder when the process restarts
in a specific file, not just in the console.txt
with serverside logging, we can run
sendClientCommand(getPlayer(), 'ISLogSystem', 'writeLog', {loggerName = "foo", logText = "foo!"})
and this will create a file ending in _foo.txt in the server's ./Logs directory, with an entry that says after a timestamp foo!
what i'm wondering is, how doth one create a file in the client's ./Logs directory with a specific filename and content

That looks to call into this java method, ```java
@LuaMethod(name="writeLog", global=true)
public static void writeLog(String string, String string2) {
LoggerManager.getLogger((String)string).write(string2);
}
Might try calling `writeLog(string, string)` from the client and see what happens :p

Hadn't seen this before
i shall try this when i get a chance ty!!!!!!
Might check if LoggerManager is exposed to lua as well. If so, it might have have other interesting logging facilities on it
it appears to only log to the client!!! perfect!!!! thank you!!!!!!!!!!
so is it possible to wrap text in tooltip if it's too long?
Anyone know a good program to edit just strings ๐ค I want to edit all instances of strings in a file but keep the rest of the formatting
yeah?
Would I be able to edit just the strings and leave all the formatting and position of the text in tact?
ok i got visual studio code
How to play a sound on red popup?
yeah. use find and replace function
Hi, extremely simple modding question (lua distributions)
Why is it that an item with a weight of 0.001 seems to show up more frequently than it should?
Eg. For every 1k zeds killed, I seem to find it at least twice.
Or am I misinterpreting the scale of the weight?
how is that any different from notepad++ then
In what way does notepad++'s find and replace not meet this requirement? I'm a bit confused by what functionality you're looking for that notepad++'s or vsc's find and replace doesn't cover
@marble lynx It's proportional to whatever else could possibly drop.
Like if the list you are adding it to has
ItemA = 0.1
ItemB = 0.1
YourItem = 0.001
Your item will have a 0.5% chance or so of dropping.
And that's for each possible roll the container has.
Oh I see, that sure makes things more difficult and complicated
No wonder stuff like Brita's ammo and guns seem to spawn like crazy
okay so I essentially need to make sure I'm placing all the text back in the same spot
But only the strings
that's the problem
Like I'm not replacing all the text with just one bit of text
I'm running the text through a converter that changes it
i could use a regular expression to change all the text to be the same thing sure, but that would be boring
What is the converter?
Is this conversion being done while the game is running, or are you converting it while making the mod?
nah I'd just be doing it while making the mod
it'd be way more work to convert it while the game is running
I know the end result is cringe, but this is a weird problem to try and solve
XD
Then you could use the Translate files.
Have entries like
IGUI_Say_Something = [text]
IGUI_Saw_Something_UWU = [uwu text]
Then anywhere you need to add these strings, you can call getText(IGUI_Say_Something_UWU)
Well I was just aiming to quickly edit all the radio
awk might can do something like that if the lines are structured so the strings can be parsed out. If there's a lot to the converter, might be best off writing a perl or python script to parse each line, run it through uwuing and then insert the uwu'd text back
I should probably just go to the uwuifer github thing and download that package and just edit it to suit my needs
How do I make a recipe object where I can apply the methods listed here: https://zomboid-javadoc.com/41.65/zombie/scripting/objects/Recipe.html ?
Javadoc Project Zomboid Modding API declaration: package: zombie.scripting.objects, class: Recipe
without defining the recipe in a script?
i.e. entirely in lua?
getScriptManager():getRecipe('Recipe Name')
No. The recipe also has a script definition. I just need to make the corresponding recipe object out of it so that I can modify and access it's data via lua code.
Then you can get a Recipe object via the ScriptManager like albion illustrated
Thanks! That looks good!
hello I just got into modding and was wondering if anyone could help me
I have been looking at tutorials but they all seem to be dated
This is for a school project so if anyone is available please dm me and I will ask my questions.
Just ask here, maybe someone has the answers to your questions ||https://dontasktoask.com/||
does anyone have an event for sleeping/going to sleep i can use?
The part i'm at with mod making im just writting the starting scripts media and textures folders. for some reason my images (such as my poster for the mod) wont load. I dont know if my syntax is wrong because the video is dated or if I didnt follow the guide properly
does the name of the image for the poster have to be poster.png
I didn't find anything related event related with that, but you can use OnPlayerUpdate event and check if sleeping
no, it can be anything as long as it's a png and your mod.info points to it
yeahh, that's what i'm thinking. well. another question, how do you just, kill a player?
ok then man I ask. my png has a space in it. Do i need to add that space when i put it in the mod.info
yeah
IsoGameCharacter has setHealth(p1 float), I did never use that, but probably this will kill instantly the player
nice
or just dont use spaces
yeah i'd stay away from spaces
no idea if they're okay or not in this context but it's generally something you avoid with things like this
Yea i know i just kinda typed in the name fast
how do i send a message to chat? this documentation hurts to look at
or how do i see where print statements go?
did you enable debug mode?
yeah
just to be sure, you're asking how to see the variables print or..(?
yeah, you should see one on bottom left of the screen, this only shows if you enable debug mode
like that
havent checked the codes . sorry bout that if it was misleading
There is also Zomboid/console.txt in your user directory. Best to tail that file in a bigger console than use the one in game imo
let me see the scrip pls
woah!! pls share that one line!! ๐
so i've discovered at least one cause of the nonsense that is the game telling the client a file doesn't exist that does - for an unrelated mod - issue.
lol i gave it to them
it's transmitCompleteObjectToServer()
called on whatever the thing was u need to sync
if u create something purely clientside this is necessary
anyway back to this
if you have two folders with different capitalizations but the same name
which is possible on linux, but not windows
the lua system will throw a fit
remove the .png
the script system on the other hand doesn't care
media/lua/items/something.lua
and media/lua/Items/somethingElse.lua
and ur getting a random "file missing on client"
my in game icons arent working either
the game engine prefixes them with Item_
but u dont enter it in the text
so if u name ur icon Something.png
thank you! i can finally spawn tiles!
it won't work, u need Item_Something.png
gotcha. Thank you so much
tried to verify files?
thats what i did before and it fixed it
do i rename my pngs or my mod info
it was every member of the server, glytch3r
modinfo
caused by my mod
an update to it
and i know the lua subsystem is fucky because i put it in Items instead of items
and it still overrides the original file
so it clearly isn't case sensitive
yet linux lets it be
which makes it breakkkk
and mac is also case sensitive
so anyone who mods on mac or linux will run into this potentially
ouch .
so i guess they have to unsub and resub to a new version if thats the case? if i understood it correctly... else they will have misdirectory issues..
well no i just rolled back the change and will now roll out new version
that's not my point tho it's to document the problem for other modders
gonna go report to TIS on the forum now
hope it works ..
dont need to hope i tested it locally lol
same with the icon files
you have to put them on the texture folder
and theshould be named
Item_nameoficon.png
on the script that uses it
you have to remove
the Items_ and the .png
like so
Item=nameoficon,
How to make custom BloodLocation?
omg thats something new ..
may i send another screen shot. One of my mod info. Its still not working. Neither my poster or in game icons
Okay, I've found ๐
Example, i want to do metal socks that protect both feet and lower legs, i'll simply add a BloodLocation = Feet;LowerLegs, in the item script.
Full list of per-bodypart location: Bag (back), Hands, Head, Neck, UpperBody, LowerBody, LowerLegs, UpperLegs, LowerArms, UpperArms, Groin.
just use mod template
and how exactly do you create png? they have to have transparency info. if u save it as jpg and changed the extension it will not work
if your dimension is off it will not work
so i got the image off the internet
then went to gimp
made it transparent
resized to 35 by 35
and exported as png
Any way to give drainable uses to an item in the script file?
I want to use an item like 10 times
item:Use()
moose just answered this earlier if you scroll up #mod_development message
Anybody know what the onTabTornOff in some UI is for? Can you like pull a tab off the window?
or is it supposed to be TurnOff
Does someone know why I get "userdata" as datatype when I call the following code? I wanted to get a zombie by its ID:
print("gameClient: " .. type(gameClient))
local zombie = gameClient:getZombie(soundZombieId)```
The last line fails because gameClient isn't a table with this function.
^hey so I did some digging and found that "gallery" is actually a room type that is not included in the distribution files and therefore I am able to target the Art Gallery displaycases with forceForRooms. Just thought i'd drop that in case anyone else has the same question. You can also target specific containers by using forceForTile. You can find the tile info by using the debug chunk inspector. So location specific spawning is actually quite simple.
how does one skip the night
it's getting annoying when night hits while i'm trying to test shit
and fast forward takes forever
userdata means java object or array
Yea. I've seen some mods (e.g. STALKER armor) use media/lua/Client instead of media/lua/client, and suspected that played a part in some players issues because they had the client on windows and server on linux
If pz doesn't account for filesystem case differences, that's going to result in issues about files appearing in different paths or not found when the server and client have different case sensitivities when looking up files
If you tostring a userdata that is a java object exposed via kahlua, it will sometimes print the java type for you e.g. zombie.characters.IsoPlayer@0xaddress
local gameClient = getGameClient()
SoulUtils.inspectJava(gameClient, "getZombie")
But what exactly is the difference between calling getPlayer() and getGameClient()
When I get the player I can use its methods/function but when I get the gameclient then I can't...
I'll check this after lunch.... ๐
It shows you getZombie is a static method
So I can't call static object via the getGameClient() object? Can I call it using another way? I'm also not sure if it gives me what I want. But least I can test then...
You could call it if it were exposed. It appears to not be exposed to lua side.
Technically, you can call it in debug mode because java.lang.reflect.Method is exposed only in debug mode, but that's not going to help you except in making some debug tools
and no, if it were exposed, you'd call static methods in lua like this from the table containing the class functions```lua
GameClient.getZombie()
-- or
zombie.network.GameClient.getZombie()
Can also get static fields that way (but they have stale data)
How does one translate item? ItemName_EN.txt?
Ok, thx. How can I check if something is exposed or not? Is it in a specific java class?
Yea, you can decompile zombie.Lua.LuaManager$Exposer. You'll find IsoPlayer exposed in there but not GameClient
You can check quickly in code by seeing if the functions are there or not :)
or just print(GameClient)
If it is exposed, you'll get a table. If not, it will be nil
Thx I found it.
Yes
Then have entries 'ItemName_[module].[itemname] = "itemname but in EN",'
Ty!
My best solution... works perfectly, but I'm wondering if anyone can think of a faster way? It's awkward that I have to double-toggle the UI to get it to hide on respawn. It works, but I hate how it looks. โค๏ธ to anyone who can explain to me why the game takes the next toggle after respawn as a toggle ON event if the UI was OFF before death, yet clearly SHOWS the UI already after respawn. If the UI is showing (i.e., ON), why does toggle after respawn send yet another ON signal? Exhausted from trying to solve this, tbh.
-- Death Loop
-- This is the best way I can find to rapidly rebind sidebar
-- to the rest of the UI hiding process after respawn.
-- PLEASE send me a better way if you know one. Basically,
-- this says, "The tick after the sidebar becomes visible again,
-- hide it if it was hidden when you died."
-- isVisiblePreferred is established elsewhere in my code.
-- It is equivalent to the visibility of the HUD, unless you
-- (A) enter the Main Menu, or (B) die. In these two cases, it
-- retains its state as a way of reverting to your preferred
-- state when you (A) unpause or (B) respawn.
-- hideAgainOnRespawn(ticks) is not added to OnTick
-- unless you had hidden UI before death.
local function hideAgainOnRespawn(ticks)
for playerIndex = 0, getNumActivePlayers() - 1 do
local player = getSpecificPlayer(playerIndex)
if not player then return end
local isVisibleSidebar = UIManager.getUI():get(4):isVisible()
if isVisibleSidebar then
Events.OnTick.Remove(hideAgainOnRespawn)
ISUIHandler.toggleUI()
ISUIHandler.toggleUI()
end
end
end
local function OnPlayerDeath(player)
if not isVisiblePreferred then
Events.OnTick.Add(hideAgainOnRespawn)
end
end
Events.OnPlayerDeath.Add(OnPlayerDeath)
maybe because the first toggle created an instance or activated a variable which you can now toggle off?
you cant turn off something thats not on? if it hasnt been declared its nil??
not really sure tho but this is my best guess
I meant exactly. I understand abstractly that something in the code that determines whether the UI needs to be hidden or shown is determining that it needs to be shown while that side panel is visible after a no-HUD respawn. I just don't know exactly where that variable is or what it's called or how it's being used. I tried decorating ISUIHandler.setVisibleAllUI and I also tried patching UIManager.setVisibleAllUI, but to no avail in either case. It's not based on ISUIHandler.isVisibleAllUI or UIManager.VisibleAllUI either, as far as I can tell. The only way I can detect it and turn it back off is by listening for a change in the specific visibility value of that side panel. (But, even so, to get the toggle working again, I have to do it twice at that moment, because this doesn't tell me why the toggle isn't working, only when it can be fixed.)
what is side panel?
would anyone happen to know why the first recipe doesnt show up
the box recipe does
like wtf
and yes, the OnCreate function exists
good lord
i dont know how i missed that ending comment on 2nd line
and i was trying to figure out why the past hour
i need to make a syntax highlight for this
json syntax highlighting might do a good enough job on it
Did not seem to work for me on vscode
Ah :/
I was planning to make a vscode extension to help with formatting and hight lighing this scrip files
Also, Tyrir since you are online, do you know a simple way to broadcast globalmoddata from a client to all the other clients?
Afaik global mod data transmissions (as well as commands you can do via lua) all are between server and client. So probably would need to setup an event handler on the server for OnReceiveGlobalModData that transmits your moddata to clients when it receives the update from a client
or just have clients request it when needed if possible
๐ค
Interesting, thank you tyrir
All the buttons on the left side of the screen that can be clicked to open and close stuff
I'm not sure it has a name
I tried printing its name once and got nothing
But I call it side panel
the weird thing is it happened with linux client/linux server too
u'd think one OS or the other wouldnt care
but it broke both
at least the particular issue i reported
im aware of the STALKER mod's issues
i know the maker of that
@autumn stump
speaking of u
i found potential cause and Tyrir points out one
maybe u can check ur mod
Oh. Damn I will check if thatโs the issue. It makes sense. Thank you Evelyn and @hearty dew ! You think if I change that folder name and update the mod, it wonโt break anything? Iโm always a bit scared of changing folder names and updating in case it breaks it for people. Thanks a lot!
in the debug menu, you can increase the speed much much faster than the normal controls allows you
i also do this too. works on local hosted server (where i test mods)
tho there are times when it doesnt run the script via buttom so i end up using console instead
try adding the module on the jtem ZEEd, if its base then. Base.ZEEd,
also theres suppose to be require stuff on the top of the lua script double check if its the right one
the issue i had was having two folders with diff capitalization and same name
in the SAME mod
cuz it was a server override/tweak mod
and i was tweaking mods with diff capitalizations
that's how i got onto this
if this fixes it please post on the bug report thread to add info
more chance they fix the problem
On SP you can mess with weather controls, there are options for darkness and lighting though they don't seem to always work, could be my fault. Sometime setting the weather controls from cheat menu mod works better.
Iโll try this out, thanks!
missing ending comment was the issue
i removed the module cause i was just trying to experiment with solutions
when i shared the pic
Is there a way to make a function run every X seconds instead of every frame or very tick?
I think a function I'm using is running a little too often
is it possible to change an items attachment location via console? just for that 1x spawn instance.. and or its sprite?
if (ticks % 60 ~= 0) then return end
First line of the OnTick
There's the OnEveryTenMinutes event for in-game 10 mins. If you want a function run periodically in irl time, I think the only way is to utilize OnTick (or one of the other similar on tick events, some fire when the game is paused, some don't) and check if enough wall clock time has passed using the time functions in os.
there we go
that took forever to implement that syntax highlight
now i shouldnt miss any comments
You can count frames in OnTick too, but need to factor in that fps are not consistent
@gilded hawk My solution would be approximately close. Not sure if you need exact.
It sounded like you did not need precision
Like you just want to slow down how often you do a complicated thing
The solution is interesting, and what tyrir said it's also interesting, I'll think about it ๐
I think Tyrir is talking about what I did
In his own terms
"counting frames" = using the tick variable
I could be wrong
Pointing out the problem with what I offered
MxUtils = MxUtils or {}
MxUtils.IntervalTimers = MxUtils.IntervalTimers or {}
--[[
Usage example:
local intervalTimerID = MxUtils.createIntervalTimer(5000, function()
print("5 seconds have elapsed!")
end)
MxUtils.deleteIntervalTimer(intervalTimerID)
]]
MxUtils.createIntervalTimer = function(intervalInMilliseconds, intervalElapsedEventHandler, runOnce)
local id = #MxUtils.IntervalTimers + 1
local lastIntervalTime = math.floor(os.time() * 1000)
MxUtils.IntervalTimers[id] = function(tickCounter)
local time = math.floor(os.time() * 1000)
if os.difftime(time, lastIntervalTime + intervalInMilliseconds) >= 0 then
if runOnce then
MxUtils.deleteIntervalTimer(id)
end
lastIntervalTime = time
intervalElapsedEventHandler(id)
end
end
-- Other events to consider
-- Events.OnRenderTick.Add(MxUtils.IntervalTimers[id])
-- Events.OnTickEvenPaused.Add(MxUtils.IntervalTimers[id])
Events.OnTick.Add(MxUtils.IntervalTimers[id])
return id
end
MxUtils.deleteIntervalTimer = function(id)
if MxUtils.IntervalTimers[id] then
Events.OnTick.Remove(MxUtils.IntervalTimers[id])
MxUtils.IntervalTimers[id] = nil
else
print(string.format("WARNING: Unknown interval timer id %s", tostring(id)))
end
end
I don't even understand how to use this ๐
Is this using background tasks?
Or synchronous?
local intervalID = MxUtils.createIntervalTimer(5000, function() print("It's been 5 seconds!") end)
-- then later to stop it
MxUtils.deleteIntervalTimer(intervalID)
It's just an event handler on OnTick that calls the provided function when enough wall time has elapsed
so polling basically
Oh. So you call the function to add the listener and then you use the clock to count time passed when each tick lands?
lua doesn't have any ways to use OS timers to avoid the polling
yea
I see so the reason you have the array is to time different events?
And you can store their IDs separately?
Events that could begin at arbitrary times?
yea
It's a basic way to implement timers by polling if you don't have OS timers
yeah it'd have to be java exposed but alas
send a request to TIS
I wanted to extend it to run lua coroutines, so you could give it a thread to run periodically, something like this:```lua
function foo()
print("starting routine")
wait(seconds(5))
print("5 seconds later")
wait(minutes(1))
print("one min after that")
end
But I haven't yet found a good use case for doing it in pz
Good day! Me and a friend are big fans of the "Crossed" comic series and wanted to make some mods for Zomboid. If someone has time and wants to work on such a project, please write to me via Discord.
You don't have to know the comic series!
Got the idea from https://stackoverflow.com/a/5128495
-- a volcano erupts every 2 minutes
function level_with_volcano( interface )
while true do
wait(seconds(5))
start_eruption_volcano()
wait(frames(10))
s = play("rumble_sound")
wait( end_of(s) )
start_camera_shake()
-- more stuff
wait(minutes(2))
end
end
If someone can think of when something like that'd be useful, that'd be interesting to hear ๐
There already is a horny jail mod for pz
I did one #mod_development message
Oh cool
Do you have any use cases for it yet? I was thinking it might be good for scripting events, but that doesn't seem too common in pz mods that I've seen (at least the ones I play with)
Hmm I have this at the moment
---@deprecated
IsoDog.update = function(self, thread)
while true do
if self:getState() == "Wander" and #self:getActionQueue() == 0 then
local currentSquare = self.character:getCurrentSquare();
local squares = UTILS.getSquareAround(currentSquare, 5);
local squaresFiltred = UTILS.Table.filter(squares, function(element) return element and element ~= currentSquare end);
local goToSquare = squaresFiltred[ZombRand(1, #squaresFiltred)];
local action = ISWalkToTimedAction:new(self.character, goToSquare)
action.maxTime = 1000; -- BUILD 41.77 Broken something.
action.useProgressBar = false;
self:addAction(action);
print("Dog walking around");
--thread:Wait(ZombRand(1000, 5000));
end
if self:getState() == "Follow" then
local owner = self:getOwner();
if owner then
local ownerCoords = Vector3f.new(owner:getX(), owner:getY(), owner:getZ());
local distance = ownerCoords:distance(self.character:getX(), self.character:getY(), self.character:getZ());
if distance >= 3 then
self:clearActions();
local action = TASK_GO_TO_LOCATION_OFFSET:new(self.character, owner, 3.0);
action.maxTime = 1000; -- BUILD 41.77 Broken something.
action.useProgressBar = false;
self:addAction(action);
if distance >= 7 then
self.character:NPCSetRunning(true);
--self.character:setSprinting(true)
else
self.character:NPCSetRunning(false);
--animal:setSprinting(false)
end
end
print("Dog following owner")
end
thread:Wait(1000);
end
thread:Wait(20)
end
end
Like the ai thread for creatures. Nice :)
Event.OnTick.Add( Your scientists were so preoccupied with whether they could, they didn't stop to think if they should. )
man like literally every mod that uses this lags out every server
theres a couple of okay ones but more often than not ontick is laggy if it runs on the server once you get past a certain number doing anything more than basic checks to fire off some other event, that angry turrets mod was killing my server the other day.
What would be the best way to make sure a tile is placed indoors with a roof above it? I want to add a check for placing my heater down so it can't heat outside.
Would it be square:getRoof() and square:getRoom()? Not sure if it's the exact names but I know they exist
isnt there a IsIndoor or isInside() check for isosquare
oh it might be one yea
So I should be able to call if square:isOutside() == FALSE I'll allow it?
(not square:isOutside())
np mate
@thorn bane Got custom chat tabs working more or less. Still wip
are there any good references or source information for getting started to learn lua gui specifically for Project Zomboid?
there's some on the PZ Wiki but tbf I usually just look at other similiar projects and adapt
oh okay. I'd like to get started with making simple windows and buttons and go from there. Just thought maybe there was someplace I wasn't looking that would help more with it.
Windows and buttons? So primarily UI stuff?
yes
Sub to this mod: https://steamcommunity.com/sharedfiles/filedetails/?id=2760035814
And look through the LUA, it's more like a framework but could be good for starts
@thorn bane also patches ISChat to function in singleplayer, in case that was needed. Need to pass true as the last parameter to addChatTab for it to create the chat window in singleplayer
If you want to code completely from scratch-ish, I downloaded this mod and used it as a template: https://steamcommunity.com/sharedfiles/filedetails/?id=2793605206
You'll have to code the opening on of the modal (UI) to be onGameStart or use his example where he uses a button on the left panel
okay, awesome! I'll get started with these. Thank you.
No worries! I sadly can't help you with any code related questions as I'm just starting myself but those two projects had me get a easy head start!
all good. I really want to learn. I just couldn't find information on the ui stuff like I did with the coding so thought I would ask here.
You think the spaces in the mod main folder may also play an issue on this? As in, my armor pack has two spaces: "STALKER Armor Pack". Maybe the OS thinks of the spaces weird.
How does noise propagate? Like say you generate a noise that is 100 range and 100 loudness.
Does the noise attract zombies within 100 tiles of the source with 100 loudness through out then stop cold after that?
Does the noise's loudness decay from 100 at the source to 0 at 100 tiles away?
Or is the noise at full loudness up to 100 tiles then decays after that that until the loudness falls to 0?
