This tutorial I will show you
- how file load order works
- how to think and structure lua mods
- how to modify vanilla behaviour
- how to use
requirewith passion - and more...
Project Zomboid uses globals mostly everywhere, this make it easy for modders to use the objects anywhere but it also make it easy to break things by assiging an existing global with something that it shouldn't.
Other mods sometime uses globals too and when players runs 200+ mods at the same time, bet there is possibly conflicts, but also the global environment will be a real mess.
There is a solution to prevent using globals and this is exactly what we will be looking at here! But before that let's get to the most basic stuff.
Bear with me. π»
It may be confusing when we first start modding Project Zomboid so... Let's break this down once for all!
sharedfiles must be agnostic (Contains classes and/or functions that may be needed intoclientand/orserverfiles)
clientfiles cannot requireserverfiles- in multiplayer
clientfiles runs only on theclient machine
serverfile cannot requireclientfiles- in singleplayer
serverfiles runs only when booting a savegame - in multiplayer
serverfiles runs on both theclient machineandserver machine
- Is there objects, functions or classes that can help me creating my feature?
- Is my feature going to be networked in multiplayer, is it transmitted automatically under the hood or I will need to handle transmition myself?
- Do I need to store data on the player, in an object, in an item or globally in the world itself?
- Can I take advantage of existing functions or objects such as the 150+ available timed actions?
- Do I need to overwrite a base feature or can I hook into it and extend it's behaviour?
- Do I need something that is not exposed by the Java engine into lua?
I want to make it so the player cannot do a specific action for a some new reasons.
-
Do I need to think about networking?
No, timed action are client sided. -
Do I need to overwrite something?
Yes but more specifically, I need to Hook into a timed action. -
Can we just skip the talk and see code example?
Wait no more!
Let's create a client file into
C:/Zomboid/mods/examplemod/media/lua/client/MyScriptName.lua
Now let's choose a timed action to Hook into by browsing into
C:/Program Files (x86)/Steam/steamapps/common/ProjectZomboid/media/lua/client/TimedActions
I chose ISBuryCorpse.lua and I want to prevent the player from being able to bury a corpse if he is too hungry.
So let's open MyScriptName.lua and also ISBuryCorpse.lua into a code editor
By reading the timed action script we learned that isValid method return a boolean that define if the action can run or not.
ISBuryCorpse.lua
function ISBuryCorpse:isValid()
local playerInv = self.character:getInventory()
return playerInv:containsType("CorpseMale") or playerInv:containsType("CorpseFemale")
endLet's Hook into and add our new condition to the pile.
MyScriptName.lua
--- Save a reference to the original method
local ISBuryCorpse_isValid = ISBuryCorpse.isValid
--- Now overwrite the vanilla method
function ISBuryCorpse:isValid()
--- We return the original method result
--- But we also add our own condition
return ISBuryCorpse_isValid(self) and self.character:getStats():getHunger() < 0.75
endCrazy! We just modified the behaviour of an action in 10 seconds.
But this didn't require anything?
No the timed action is a global object from the vanilla game so we did not need anything.
To be continued...