Search the Community

Showing results for tags 'lua'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • News & Announcements
    • News
  • Project Zomboid
    • PZ Updates
    • General Discussions
    • Bug Reports
    • PZ Support
    • PZ Multiplayer
    • PZ Community & Creativity
    • PZ Suggestions
  • PZ Modding
    • Tutorials & Resources
    • Mods
    • Items
    • Mapping
    • Mod Ideas and Requests
  • General Games Development
    • Indie Scene
  • Other Discussions
    • General Discussion
    • Forum Games & Activities
    • Pen & Paper / Community RPGs

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start





Website URL







Found 64 results

  1. Peace

    Creating new java classes in lua

    I can create a class like this local noise = InventoryItemFactory.CreateItem("Peace.SoundBeacon"); local noiseTrap =, cell, square); noiseTrap:addToWorld(); but I cant create some classes, i get an is nil error local radioLinePre ="Test Message", 1, 1, 1); Is it just that some of the classes arent accessible in lua, or am i missing a namespace or something? I dont have much experience with lua.
  2. For example: local bd; local function fnEveryTenMinutes() if not bd then bd = getPlayer():getBodyDamage(); end ..... end Events.EveryTenMinutes.Add(fnEveryTenMinutes); I think it should reduce overhead on api calls.
  3. RoboMat

    Lua requests

    Like on the old forums people can post their requests for lua additions in this thread. Please just post requests here and don't debate about the ones made. The devs are perfectly capable of deciding what to add and what not to add Anyway, here we go: New / Changed Events: EveryMinute: Self explanatory.EveryHour: Self explanatory.OnUnequip: When Item is unequipped from the primary or secondary slot.OnItemUse: When item is used in the inventory. (E.g. "Eat Food" or "Bandage Wound")OnContainerUpdate: When the item containers are updated (parameters: table of contained items, getType() of the updated container) New / Changed Functions: IsoFloorBloodSplats(): in the Chunk class (or whatever is necessary to retrieve blood on walls and floors and remove it)FIX ItemContainer:isInCharacterInventory()getFps() in GameWindow.Getter / Setter for amount of splattered blood. Finished (already in the game) setPermaLocked(boolean) in IsoWindow -- RM : Done for in IsoWindow -- RM: Done for -- RJ : Done for -- RJ : Done for Fires when an item is equipped as primary weapon.-- RJ : Done for, param : player, itemOnEquipSecondary: Fires when an item is equipped as secondary weapon.-- RJ : Done for, param : player, itemOnItemEquipAny -- RJ : Use the OnPrimaryItem/OnSecondaryItem instead OnAmbientSound: Fires when ambient sounds is played (helicopters, gunshots ... etc.) - RJ : Done for, param : name of the ambient sound (like "chopper1", "pistolgun2",..)getClosedSprite() -- RJ : use getSprite()setClosedSprite()-- RJ : use setSprite(IsoSprite)getOpenSprite(...)-- RJ : Done for RJ : Done for RJ : Done for, use isDestroyed() to know if it's already smashed or notgetSmashedSprite()-- RJ : Done for
  4. RoboMat's Modding Tutorials - An introduction to modding for Project Zomboid - I - Introduction I1 - Where to start I2 - What is needed I3 - Lua Tutorials I4 - Other Resources II - The first steps II1 - Getting the connection II2 - The entry point: Events III - The first mod III1 - Preparations III1a - Folders III1b - Our mod's identification card III1c - The actual lua script III2 - Adding items to the inventory III3 - Handling keys III4 - Detecting the correct key IV - Custom professions IV1 - Creating a custom profession IV1a - The foundation IV1b - Creating the profession IV1c - Creating a new trait IV1d - Custom Spawnpoints IV1e - Custom Profession Clothing IV1f - Putting it all together IV2 - Linking Professions / Traits to game mechanics I. Introduction Hello there, this is my attempt to write a few modding tutorials for the community. I will try to update this whenever I have some spare time. 1. Where to start First things first. When I started looking into the code of Project Zomboid and the different mods I was a bit confused. There was the source code in Java, the additional code in Lua and the scripting language and I didn't really know which one to look into. To spare you this confusion I'll explain their purpose shortly: Java: Most of the source code of Project Zomboid is written in Java. While you can modify the java files it is not recommended. According to the developers changing the java source code won’t be necessary in future versions of Project Zomboid, so we won’t look into that. Eggplanticus has made a nice post about how to spelunk in the Java source if you want to try it nonetheless. Lua: There already are parts of the source of PZ that have been ported to lua. If you really want to get into modding, you won't get around learning its syntax. Scripting: At the moment it is only used for easily adding items to the game. While we will cover some of the basics of the scripting language we will mostly work with lua coding. 2. What is needed Basically to edit a lua file you can use any standard text editor that is capable of saving simple (unformatted) text files. So Wordpad (Windows) or TextEdit (Mac OS) will do. While it is possible to create a script with those programs they miss many features a specific IDE will give you (syntax-highlighting, auto-formatting, etc...). I prefered working with Eclipse IDE with an extra lua plugin installed for quite some time, but recently switched to IntelliJIdea - haven't been looking back ever since. There are other free alternatives like gedit, Notepad++, ZeroBraneStudio or XCode for example. Find one that works for you and stick with it. Remember: It's not the program that does the work. None of them will turn you into a RobertJohnson over night, they only make your life easier. 3. Lua Tutorials If you have some experience with programming already Lua will probably be fairly easy to pick up for you. I mainly used the official manual to learn the language, but of course there are many other great tutorials out there. From time to time I check the lua wiki and of course stack overflow. Just to be as clear about this as possible: This won't be a tutorial about lua. It will be a tutorial about modding Project Zomboid. If you don't understand parts of my code, you probably should learn some basic lua syntax first. If there is one thing I don't like then it's people who don't even take the time to read through the tutorial notes, then copy&paste the code and finally spam the thread with questions about "why it doesn't work". Don't be that person (unless you are Rathlord). 4. Other Resources For more tutorials you should visit and the tutorial section on the indiestone forums. If you have further questions you can post them in the modding help section of the the indiestone forums and one of the many coders will help you for sure. TOC Last updated: 12.11.2013 II. The first steps Okay now that we got that out of the way let's move on to the actual modding part. 1. Getting the connection To mod the game we somehow have to interact it. Lua's main purpose lies on extending existing programs written in other programming languages. As mentioned in the previous chapter the main base of Project Zomboid was written in Java. That's where the connection between lua and the java source code happens. With lua we can access all the public functions written in the Java source code. -- lua function function doStuffInLua(_player) -- getSpecificPlayer() is a public method defined in the java source code -- that returns the player. We can access it through lua. getSpecificPlayer(_player); end But how do we know which methods there are!? Well, we can look at the javadoc. It's basically a complete list of all methods in the Java source code and it has even been updated to recently. If you want to be on the save side I suggest that you open the source code and look through it yourself. I use a small programm called JD-GUI for that purpose. It has a useful search function that can search through the whole source code. In the course of this tutorial I will mark methods we call from java so you don't have to worry too much about that at the moment. Eggplanticus also released a good tutorial on how to decompile the java source over here. 2. The entry point: Events So now we know that we can call Java methods from our lua code, but we still don't know how we actually execute our lua code. We need something that runs our code, when Project Zomboid runs. This will be done with Events. You can think of events as entry points to the source code of the Project Zomboid source code. Once Project Zomboid encounters an Event from a mod it calls the associated function. -- the function we want to execute function sayStuff() -- Java: we get the first player local player = getSpecificPlayer(0); -- Java: let the player speak player:Say("I like turtles."); end -- this event will be fired every ten ingame minutes. -- In this case sayStuff() is the associated method and -- thus will be executed every ten minutes. Events.EveryTenMinutes.Add(sayStuff); This short "mod" lets the player talk about his love for testudines every ten minutes in the game. Nothing great but it gets the point across. There are already many different events added to the game which we can use for our mods and the developers are constantly adding new ones. For a somewhat complete list check out the Event Reference on Don't worry though, we will use some of them throughout this tutorial so you will slowly get the hang of it. TOC Last updated: 01.10.2013 III. The first mod Let's continue with a little more complex example. We will create a small cheat script that adds some items to the player's inventory when a certain key is pressed. 1. Preparations At first we're going to set up a proper folder structure and all the files we'll need to get the mod to work with Project Zomboid. Please note that this tutorial has Version and later in mind and thus is going to use the structure needed to work with the modloader. If everything is done right our mod will later on appear in the game like this: The almighty RobertJohnson has released a more in-depth tutorial about the modloader and functions. Once that version is released I'm going to update this post too! a.) Folders Please note, that the folder structure might slightly variate depending on what IDE you are using. I'm going to show you the end-structure which I use when I release my mods: I named the topmost folder (we are going to call this the base folder from now on) after our mod: CheatMod. This base folder is going to contain ALL of our mod files. The "media/lua" folder is basically the location of the vanilla lua files. When we drop our mod into the modloader it is going to copy the files in our base folder to their specified location in the PZ source files. This way our mods don't overwrite any base files and the mod can be removed from the game at any time without breaking it. Yay for the nifty modloader! b.) Our mod's identification card The modloader needs some way of identifying the mods given to it. This is done by the so called file. It is a simple (unformatted!) text file which contains some important information about our mod. It must be put into the base folder: To make it work we will have to fill it with information of course. Copy this to your file: name=Cheat Mod (1.0.0) poster=poster.png description=This mod is used to explain modding for Project Zomboid. It is going to show several aspects of modding from start to finish. -by RoboMat id=CheatMod name: The name of the mod. poster: The image file that is displayed in the mod menu in PZ. description: A short description of your mod. I am not sure how many characters this supports. id: The id of our mod. This is used to identify our mod. The id must have the same name as the base folder of our mod (in this case: CheatMod). If you drop you folders into your Project Zomboid "mods" folder now it would already display it as a mod in the game: Of course this isn't really a mod yet. We still need to give it some functionality c.) The actual lua script The last file we need to create is the lua script file. We are going to call it "AddItems.lua" and put it into "media/lua/Mods/CheatMod". Make sure that you really are using the correct suffix of ".lua". Now we are set and ready to begin working on our first mod! 2. Adding items to the inventory We are going to start with a simple script that allows us to add a few items to the player inventory as soon as a certain key is pressed. Adding items is a fairly easy task as you will see. Open your AddItems.lua and enter the following code. local function addItems() local player = getSpecificPlayer(0); -- Java: get player one local inv = player:getInventory(); -- Java: access player inv -- Java: add the actual items to the inventory inv:AddItem("Base.Axe"); inv:AddItem("Base.RippedSheets"); inv:AddItem("camping.TentPeg"); end As with the previous examples our starting point is the player. We need to "get" him first with getSpecificPlayer(0). We then can access his inventory with the getInventory() call. "getInventory()" returns an ItemContainer which happens to be the player's main inventory. This means we now can use all the java functions defined for the ItemContainer.class and one of them happens to be the nifty AddItem(...) function. If you look at the javadoc of this function you will notice that it expects a String as a parameter. What it doesn't tell you is, that it actually needs the module of the item you want to add and the name of the item itself. You can read our example above as "add item Axe from module Base". The code above would give the player an axe, some bandages and a tent peg from the camping module. How do you find out the modules and names of the items? Of course by looking through the source files. All items are currently located in "/media/scripts/items.txt", "/media/scripts/newitems.txt", "/media/scripts/camping.txt" and "/media/scripts/farming.txt". Just take a look at these files - the rest should be self explanatory. 3. Handling keys As we haven't defined an event yet, the function is pretty useless right now. We want the items to be added whenever the player presses a key and luckily the devs have given us the great OnKeyPressed event for that purpose. Let's add it to our mod: local function addItems() local player = getSpecificPlayer(0); -- Java: get player one local inv = player:getInventory(); -- Java: access player inv -- Java: add the actual items to the inventory inv:AddItem("Base.Axe"); inv:AddItem("Base.RippedSheets"); inv:AddItem("camping.TentPeg"); end -- Will be fired whenever we press a key. Events.OnKeyPressed.Add(addItems); This event will be called whenever a key is pressed in the game. The only problem is, that the event doesn't care which key that is. If we would leave our mod like this, the player would get spammed with countless items. We need to fix that! 4. Detecting the correct key One of the great things about events is, that some of them pass useful parameters to the function which is called through the event. The OnKeyPressed event for example passes the number of the pressed key to the function. The called function in this case is of course "addItems()". To use the parameter we have to slightly modify our code another time: -- We added the parameter to the function which -- will be passed to the function as soon as the -- event fires. local function addItems(_keyPressed) local key = _keyPressed; -- Store the parameter in a local variable. print(key); -- Prints the pressed key to the console. -- We test if the correct key is pressed. if key == 25 then local player = getSpecificPlayer(0); -- Java: get player one local inv = player:getInventory(); -- Java: access player inv -- Java: add the actual items to the inventory inv:AddItem("Base.Axe"); inv:AddItem("Base.RippedSheets"); inv:AddItem("camping.TentPeg"); end end -- This will be fired whenever a key is pressed. Events.OnKeyPressed.Add(addItems); Notice the _keyPressed parameter that was added to our function. You might wonder about the leading undaerscore. It is just a thing of coding style that I like to do, to be able to distinguish parameters from local variables in the function's body. The same goes for storing the parameter in the local variable "key". It might seem superfluous at first, but if you want to change the content of this variable later on, you can easily do that by changing its declaration at the top of the functions instead of having to track down every single occurence. Anyway, they _keyPressed parameter will receive a number corresponding to the pressed key and pass it into our function. Unfortunately I'm not to sure which numbering method is used in Project Zomboid, but I think it might be the one from LWJGL. You can use the print(key) call in the function to easily find out all numbers you need to know anyway. Basically we just have finished our first real mod. Save the AddItems.lua and copy your base folder into the Project Zomboid-mods folder. Now you can go into the game and enable your mod (restart the game afterwards!). Once you are in the game now, you should be able to cheat items into your character's inventory by pressing the 'P' key on your keyboard. TOC Last updated: 12.11.2013 IV. Custom professions Admittedly our first mod isn't very impressive so we are going to expand it a bit. The biggest problem at the moment is, that the player can cheat weapons into his or her inventory every playthrough, which might ruin legit savegames. 1. Creating a custom profession That's why we are going to create a custom "Cheater" Profession and link the cheat code to it. a.) The foundation Of course we need to create a new lua script. I'm gonna call it "CheaterProfession.lua" and save it in its own folder (Note: Basically it doesn't matter where you save your lua files, but good structuring will make it easier for you and others to organize and understand your project). After creating the file open it and add the following lines: -- CheaterProfession.luarequire'NPCs/MainCreationMethods';require'NPCs/ProfessionClothing'; This basically makes sure that the file is loaded after those two files which enables us to use their functions. (If someone has a more technical explanation feel free to PM me or comment below!). b.) Creating the profession Now we can start with actually creating the new profession. Add these lines to your CheaterProfession.lua -- CheaterProfession.lua require'NPCs/MainCreationMethods'; require'NPCs/ProfessionClothing'; local function initProfessions() -- Java: Create a new profession. local cheater = ProfessionFactory.addProfession("cheater", "Cheater", "Prof_rm_Cheater"); -- Java: Add a custom trait called Undesireable (no one likes cheaters ). cheater:addFreeTrait("rm_undesireable"); -- Java: Add the vanilla trait Nightowl. cheater:addFreeTrait("NightOwl"); end Lets go through the code. The part of it which actually creates / registers the new profession is: local cheater = ProfessionFactory.addProfession("cheater", "Cheater", "Prof_rm_Cheater"); It calls the addProfession(String type, String name, String IconPath) function of the ProfessionFactory. The parameters are used like this: type: Used to identify the profession internally in the game's code. name: Human readable name which appears in the game's menus etc. iconPath: Name of the custom icon to be displayed in the game. If we would leave the code here it would create a fine new profession without any traits though. That's where the remaining two lines come into play: cheater:addFreeTrait("rm_undesireable"); This adds a (you probably guessed it) trait to the profession we just created. "rm_Undesireable" is the trait we are going to create in a few seconds whereas "NightOwl" is one of the vanilla traits. Of course PZ doesn't know "rm_undesireable" yet, so we still have to actually create it. Lets do it. c.) Creating a new trait We add a new function above the one we created above to initialise the traits. local function initTraits() TraitFactory.addTrait("rm_undesireable", "Undesireable", 0, "Allows you to cheat.\nShame on you!", true); end Quite similar to the ProfessionFactory we used above, the TraitFactory class allows us to add a new trait by calling addTrait(String type, String name, int cost, String desc, boolean profession). Let me explain those parameters: type: This is the internal name used in the games code. It's also the name of the custom icon to be displayed in the game. ! Has to be lower case ! name: The human readable name displayed in menus etc. cost: Determines how many trait points it will cost to select this trait. desc: The description which appears when you hover over the trait. profession: If set to true the trait won't appear as a selectable trait but instead stays a "profession-only" trait. It really is as easy as that Now you actually already have a fully functional profession which you could play with. But it still is lacking two important parts of the profession system: Spawn points and custom clothing colours. d.) Custom Spawnpoints Spawnpoints determine where in the Gameworld the player will appear when the game starts. Before we can add a new spawnpoint though we of course need to find out its coordinates in the game. For this purpose I have created the "Coordinate Viewer", which displays the player's coordinates as a small overlay in the game. So if our cheater profession should start in the large warehouse (where else!?) the game will show us a player position of X: 3110 and Y: 1809. Unfortunately we can't use those "absolute" coordinates for the spawning code. We have to calculate the "relative" coordinates instead. Don't worry though - it is pretty easy. Basically you just need to divide the absolute coordinates by 300 to get the cells, but more importantly you have to ignore the remainder. Our coordinates for the big warehouse would be X: 10 and Y: 6 then. Now we have the cell in which the player should spawn. Relative to that position we need the exact coordinates and this is where the remainder comes into play. Still using the above coordinates the remainders of the division would be for X: 110 and for Y: 9. This probably sounds more complicated than it is. I suggest that you read through this post by The_Real_AI who maybe explains it a bit better. Now that we have calculated the coordinates, we need to tell the game to use them. -- Set custom spawn points for this profession. -- Modelled after spawn code by RegularX. Thanks to -- The_Real_Ai for his explanation on how to calculate -- them. local function initSpawnPoints() local spawn; -- Create a Spawnpoint in the large Warehouse. spawn = { { worldX = 10, worldY = 6, posX = 110, posY = 8, }, } -- Add our profession to the list of spawnpoints for Muldraugh. BaseGameCharacterDetails.spawnPoint.MuldraughKY.cheater = spawn; spawn = { { worldX = 39, worldY = 23, posX = 138, posY = 100, }, } -- Add our profession to the list of spawnpoints for West Point. BaseGameCharacterDetails.spawnPoint.WestPointKY.cheater = spawn; end Basically we have created a local table which holds our calculated coordinates and added it to the global table BaseGameCharacterDetails.spawnPoint. Take a look at the last line of the function: BaseGameCharacterDetails.spawnPoint.WestPointKY.cheater = spawn; We create a new index cheater and give it the value of our spawnpoint. It is essential that this index uses the type (check the parameters above) of your profession or else it won't work. It is probably self evident but MuldraughKY holds all spawns for Muldraugh, whereas WestPointKY creates spawns in West Point. e.) Custom Profession Clothing Finally we are going to add some custom colors for the profession clothing. The System is quite similar to the spawn points above: Basically we are going to create a table which holds all values for male and female "cheaters". ----- Set custom clothing and clothing colors for this -- profession. local function initClothing() local clothes = {} ProfessionClothing.rm_Burglar = clothes; end We create a table called clothes which will hold all of the necessary values. Then we have to make two nested tables to separate the "male" and "female" clothes (this means the guy can have blue and the lady pink colors for example - yay ). local function initClothing() local clothes = { male = { }, female = { }, } end Now we will add all the values need to create the clothes. First we declare which type of clothing item the character should wear. The male character is going to wear a Shirt and Trousers and the female character gets a Blouse and Skirt. ----- Set custom clothing and clothing colors for this -- profession. local function initClothing() local clothes = { male = { topPal = "Shirt_White", top = "Shirt", bottomPal = "Trousers_White", bottom = "Trousers", }, }, female = { topPal = "Blouse_White", top = "Blouse", bottomPal = "Skirt_White", bottom = "Skirt", }, } end You probably are wondering why there are two variables (top and topPal) for each item for example. As far as I understand the system the "pal" stuff just sets the color palette for the specific item. Why we have to do that ... I don't know It is something we gotta have to ask the devs. Last but not least we are going to give some colours to those clothes. Those values will be stored in two seperat tables called topCol and bottomCol. As you probably figured the first determines the colours of the top the character wears, whereas the latter determines the clothes for pants, skirts, etc. PZ uses the three values Red, Green and Blue (RGB) to calculate the final colour. Those values have a floating point range from 0 to 1 which was a bit strange for me at first considering that most programs and games I've used use values from 0 to 255 I will leave it to you to figure out which values return which colour. In my example here all clothes will be black: ----- Set custom clothing and clothing colors for this -- profession. local function initClothing() local clothes = { male = { topPal = "Shirt_White", top = "Shirt", bottomPal = "Trousers_White", bottom = "Trousers", topCol = { r = 0.1, g = 0.1, b = 0.1, }, bottomCol = { r = 0.1, g = 0.1, b = 0.1, }, }, female = { topPal = "Shirt_White", top = "Shirt", bottomPal = "Trousers_White", bottom = "Trousers", topCol = { r = 0.1, g = 0.1, b = 0.1, }, bottomCol = { r = 0.1, g = 0.1, b = 0.1, }, }, } ProfessionClothing.cheater = clothes end Just like the spawnpoints we add the table of our cheater profession to the global table called ProfessionClothing with the last line of the function. f.) Putting it all together We still need to tell PZ to call our functions once the game boots so that our custom values are initialised. We wlll use our beloved Events for that. Add these lines to the end of your CheaterProfession.lua file: Events.OnGameBoot.Add(initTraits); Events.OnGameBoot.Add(initProfessions); Events.OnGameBoot.Add(initSpawnPoints); Events.OnGameBoot.Add(initClothing); We are done here. Congratulations you have created your first custom Profession The complete file should look like this: TOC Last updated: 12.11.2013 2. Linking Professions / Traits to game mechanics What we want to do now is link a special game mechanic to the trait of the profession we just created. Of course this isn't a must, but it doesn't make much sense to implement a trait that doesn't have any effect in the game, does it? You will see that it is actually pretty easy. Let's get to it. Coming soon™... TOC Last updated: 08.11.2013
  5. setTeachedRecipes(java.util.List<java.lang.String> teachedRecipes) For example, how to use this function? setTeachedRecipes({"Recipe 1", "Recipe 2"}) ?
  6. Updated to 34.28 Sorry for taking so long guys, I switched jobs and I spend most of my free time trying to figure out this being a father thing lol. My son is only 8 months old and I spend all of my free time with him. He and his mother went on "vacation" to visit family out of town so I finally got time to complete the mod. Sorry, and I hope everyone hasn't lost interest. When you choose one of the custom hairstyles at the character creation menu the character preview will show the player bald. Don't freak out, that is completely normal and as of right now there is no way to change it. There are 2 different versions, both included in the download. One is for players that use Jab's ModelLoader and the other is for players that don't. Either way the install instructions are included. Have fun!!! Download Alternate Download If you enjoy this content feel free to Donate. FYI, the mod is still currently beta, though it works perfectly fine. It's only beta because I'm not finished adding hairstyles for men and I haven't even started adding beards or hairstyles for the women. I have actually created my own tools to make it easier, once production is finished I will release the tools also, that way everyone can add their own hairstyles to the game easily. ALSO...Do not add my mod to any modpacks.
  7. How to change the amount of starting perk points? I have a company that does my hosting but I have to tell them what to edit ect...anyone know? and will it affect future players?
  8. Good afternoon. I attempted to search through the Vanilla rendition of PZ's files to find the script that represents the White Microwave, to no avail. Much to my chagrin, it does not exist in the SCRIPTS file and is only referenced in the Translation file. The Microwave sound effect is there, but for the likes of me, I can't see where the Microwave itself is located. The reason I want to know the answer to this is because the "Hydro Craft" Mod has several items that can spawn in cabinets that are exact, but non-functioning, duplicates of placable Furniture. For example, you can find a microwave (HCMicrowave), a mini-fridge (HCMinifridge), and a washing machine (HCWashingmachine). All three of those items have equivalents in the Vanilla rendition. None of the HC versions really do anything outside of being disassembled. I know that it is completely possible to disassemble a placable Furniture piece (e.g. a television or radio), but what about the opposite? What I want to write is a Crafting Recipe that takes the non-functioning HC versions of furniture and converts them to the Vanilla rendition furniture. With this ability in place, likewise, I also want to create a Recipe for the opposite, so that the special parts HC adds to those things can be gathered more fairly. I know or a fact that Vanilla rendition Furniture has a reference as an Item, because you can pick them up and interact with them. Where are the files for the Vanilla rendition, placeable Furniture located? What can I do with them, and how? Thank you. -TURTLESHROOM
  9. So... you want hotkeys the player can press that does something for your mod. The problem: The player should be able to reconfigure these keys, so they don't conflict with the players existing setup or other mods they have loaded. Sure you can have these keys setup in a 'settings.lua' file the player can edit, but that leads to its own problems... If a user edits this file, and the mod is designed for multiplayer, then they'll have issues connecting to servers since the checksums won't match. Maybe you're feeling clever, and decided to write these settings into a settings.ini file instead, and just read the ini on loading (thus not having to worry about checksums), but that's a problem too....users rarely read the documentation, and hate manually editing files in notepad! So...the only real answer is to have a proper GUI where they can edit these settings, and what better GUI to use then PZ's own options screen! For this tutorial I'll explain using some work I've been doing on the ORGM mod today. I needed 3 new hotkeys: for equipping the best pistol, best rifle, and one for the best shotgun. Nice and clean there, no need to manually edit file, or screw up the luachecksums, or need to explain to users how to do it other then: 'it will be in your pz options screen' Here's our script in full: All the key bindings listed on the options screen are stored in the global table called keyBinding First we need to find the index of the option we want to insert after: local index = nil for i,b in ipairs(keyBinding) do if b.value == "Equip/Unequip Stab weapon" then index = i break end end The next chunks of code are wrapping in a 'if index then .... end' block, but I'll omit that here just so I can break this 'if statement' into smaller pieces (you can see it in the full script in the spoiler above) Since we got our index and know our insertion point, lets insert the new options: table.insert(keyBinding, index+1, {value = "Equip/Unequip Pistol", key = 5}) table.insert(keyBinding, index+2, {value = "Equip/Unequip Rifle", key = 6}) table.insert(keyBinding, index+3, {value = "Equip/Unequip Shotgun", key = 7}) Note these keys actually correspond to 4, 5 and 6 respectively (esc is key=1, swinging weapon is key=2, firearm is key=3, and stabbing weapon is key=4) You can also use constant values for these, if you look in shared/keyBinding.lua, you'll see rack firearm is key = Keyboard.KEY_X Now we need to overwrite the MainOptions:create() method, so we can fix some translation issues: local oldCreate = MainOptions.create function MainOptions:create() oldCreate(self) for _, keyTextElement in pairs(MainOptions.keyText) do repeat if not keyTextElement or not keyTextElement.txt then break end local label = keyTextElement.txt if == "Equip/Unequip Pistol" then label:setTranslation("Equip/Unequip Pistol") label:setX(label.x) label:setWidth(label.width) elseif == "Equip/Unequip Rifle" then label:setTranslation("Equip/Unequip Rifle") label:setX(label.x) label:setWidth(label.width) elseif == "Equip/Unequip Shotgun" then label:setTranslation("Equip/Unequip Shotgun") label:setX(label.x) label:setWidth(label.width) end until true end end Notice the first thing in that block is we store the original MainOptions:create() method in a variable, and call it first thing in our overwrite. By doing this we're just basically appending our new code to the end of the original function. The problem is if we don't do this, our options will appear as "UI_optionscreen_binding_Equip/Unequip Pistol" on the screen, unless you have a proper translation entry. Since we dont, we need to change the label translations so we don't have that "UI_optionscreen_binding_" prefix. As well as changing the text that gets shown, we need to reset the x position, and the width of the label or they'll still be positioned too far off. By calling label:setTranslation() it fixes the label.x and label.width variables, but doesn't actually adjust the positions so we need to call label:setX() and label:setWidth() manually. And thats it for the options screen...all you need to do to have the custom keys show up and be configurable. This is where our 'if index then .... end' block actually ends. Note you'll still have the translation problem when the user clicks to change the key to something else, the popup will need fixing.... you have to overwrite MainOptions:render() for that, I won't be covering that here since its a minor issue, and doing that might be incompatible if 2 mods use this same technique. The code above can be used by multiple mods at the same time without issue, even with our overwrite: If your mod overwrites MainOptions:create(), and another mod loads after and uses the same technique, then their overwrite ends up calling yours, and yours then calls the original function. Now for the final piece, the event hook when the player presses a key: Events.OnKeyPressed.Add(function(key) local player = getSpecificPlayer(0) if key == getCore():getKey("Equip/Unequip Pistol") then player:Say("Key pressed: Equip/Unequip Pistol") elseif key == getCore():getKey("Equip/Unequip Rifle") then player:Say("Key pressed: Equip/Unequip Rifle") elseif key == getCore():getKey("Equip/Unequip Shotgun") then player:Say("Key pressed: Equip/Unequip Shotgun") end end) Our key presses here don't actually do much, the player just says which of the keys options got triggered. But that's all there is to it, custom user configurable keys that don't force players to manually edit files, and bypass server lua checksum comparisons.
  10. Hello. In collaboration with the admins of the Redboid community server, we have discovered a bug that prevents Linux clients from joining Windows-based servers. It seems that there is a mismatch between the contents of the "media/lua" folder between the clients. Specifically, the Linux client has the following file, which is not present in the Windows client: lua/client/OptionScreens/WorldScreen.lua This causes Linux clients attempting to connect to show the following error message: "You have been kicked because your game files do not match the server's.". This is also reflected in the attached screenshot. Removing the above mentioned file on the Linux client, seems to completely resolve the issue. A few system details: OS: Kubuntu 18.04 Kernel: Linux {redacted} 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux PZ version: 39.67.5 (Steam) Please let me know if you have any further questions.
  11. So I was working on some code for our server mod, and it turned out pretty cool. Since I haven't written a tutorial in a while, I thought I'd share. The problem: I wanted to create special upgraded items, and unique(ish) ones, without having to define the objects in the media/scripts/*.txt files, or having to mess around with distribution tables and all that nonsense. The items also had to be able to inherit properties from the base items they were copying. But, that being said...this tutorial isn't so much about the end goal, but the methods used to accomplish it. Warning: some of the tricks used are semi-advanced and not normally done for sanity purposes. It's useful to be familiar with the InventoryItem class API, and the HandWeapon subclass for this tutorial particularly the various 'get' and 'set' methods, since thats what we'll be using (in a very backwards and dynamic way!) The full code (well, partially edited) for the script is here, but I'll break it down into smaller pieces below: Now the first bit kinda speaks for itself: local UPGRADE_CHANCE = 10 -- 1 in # chance item is upgraded local SPECIAL_CHANCE = 100000 -- 1 in # chance item is special The chances that a spawned item will be a 'upgraded version' or a 'special version'. So first we need to create some tables holding the new stats for our upgraded items. For this example, all the items are weapons but any item will work: local UpgradedItems = { ["Base.KitchenKnife"] = { { absolute = { Name = "Fancy Kitchen Knife", }, multiplier = { ConditionLowerChance = 2, } } }, ["Base.Axe"] = { { absolute = { Name = "Hatchet", TwoHandWeapon = false, OtherHandUse = false, }, multiplier = { MinDamage = 0.7, MaxDamage = 0.7, MaxRange = 0.7, MinimumSwingTime = 0.7, SwingTime = 0.7, Weight = 0.7, ActualWeight = 0.7, }, } } } local SpecialItems = { ["Base.KitchenKnife"] = { { absolute = { Name = "Lorena Bobbitt's Knife", CriticalChance = 100, }, multiplier = { ConditionLowerChance = 10, } }, { absolute = { Name = "Jack the Ripper's Knife", }, multiplier = { ConditionLowerChance = 10, MaxDamage = 1.5, }, }, }, ["Base.Axe"] = { { absolute = { Name = "Lizzy Borden's Axe", CriticalChance = 100, }, multiplier = { ConditionLowerChance = 4, }, }, { absolute = { Name = "Paul Bunyan's Axe", }, multiplier = { ConditionLowerChance = 4, TreeDamage = 4, }, relative = { MaxDamage = 1, MinDamage = 1, }, }, }, ["ORGM.ColtSAA"] = { { absolute = { Name = "Billy the Kidd's Colt SAA", HitChance = 75, AimingTime = 5, }, }, } } For those UpgradedItems and SpecialItems tables, the key/value pairs are 'the full name of the item', and the value is another table. That table contains a second layer of tables: each possible upgrade. Take a look at the SpecialItem one for "Paul Bunyan's Axe" { absolute = { Name = "Paul Bunyan's Axe", }, multiplier = { ConditionLowerChance = 4, TreeDamage = 4, }, relative = { MaxDamage = 1, MinDamage = 1, }, }, It contains all 3 sections (the other items only contain 2 sections each), 'absolute', 'multiplier', and 'relative'. Absolute sets a value to a specific value. Multiplier takes a items current value, and multiplies it. Relative takes a items current value, and adds onto it. Now, the function that does the actual item upgrade: local upgradeItem = function(item, upgrade) if not item or not upgrade then return end if upgrade.absolute then for key, value in pairs(upgrade.absolute) do item["set" .. key](item, value) end end if upgrade.multiplier then for key, value in pairs(upgrade.multiplier) do item["set" ..key](item, item["get" ..key](item) * value) end end if upgrade.relative then for key, value in pairs(upgrade.relative) do item["set" ..key](item, item["get" ..key](item) + value) end end end This function takes 2 arguments, the item to be upgraded, and the upgrade data. This is the part that calls the InventoryItem and HandWeapon methods, but you'll notice there's no actual method calls hardcoded in there such as item:setName(value) or item:setConditionLowerChance(value)! Instead, we're treating these items as actual lua tables, and building the method names dynamically from strings: item["set" .. key](item, value) so when the key is "Name" and the value is "Paul Bunyan's Axe", its checking the 'item' table for 'setName', and treating the returned value as a function, passing it 2 arguments: the item itself, and "Paul Bunyan's Axe". This is identical to: item:setName("Paul Bunyan's Axe") If the key is "ConditionLowerChance" and the multiplier value is 4, then this: item["set" ..key](item, item["get" ..key](item) * value) becomes this: item:setConditionLowerChance(item:getConditionLowerChance() * 4) I should mention at this point: this is a completely backwards way of doing it and generally not advisable. You can drive yourself nuts calling methods dynamically this way when you need to debug a error. BUT it is completely valid way of dynamically deciding on method calls using strings, instead of having a massive pile of if/elseif conditions. So now we have a function that can create our upgraded/special items from normal ones, and tables holding our upgrade data, now for the final part: deciding on when to upgrade: Events.OnFillContainer.Add(function(roomName, containerType, container) -- see if any of our items that spawned have possible upgrades for itemName, upgrades in pairs(UpgradedItems) do repeat local items = container:FindAll(itemName) if not items then break end for i=1,items:size() do repeat if ZombRand(UPGRADE_CHANCE) +1 > 1 then break end upgradeItem(items:get(i-1), upgrades[ZombRand(#upgrades) + 1]) until true end until true end -- see if any of our items that spawned have possible special versions for itemName, upgrades in pairs(SpecialItems) do repeat local items = container:FindAll(itemName) if not items then break end for i=1,items:size() do repeat if ZombRand(SPECIAL_CHANCE) +1 > 1 then break end local item = items:get(i-1) if not item then break end upgradeItem(item, upgrades[ZombRand(#upgrades) + 1]) -- set condition to max since this is a special item:setCondition(item:getConditionMax()) until true end until true end end) We simply hook the OnFillContainer event. This event is triggered AFTER the base files have filled out items in a container, allowing us to see what spawned. You'll notice I use a funky way of looping through the upgrade tables here: for itemName, upgrades in pairs(UpgradedItems) do repeat local items = container:FindAll(itemName) if not items then break end ... until true end That snippit above is technically a double loop, the 'for .. end', and the 'repeat ... until true' part. Why would I do such a thing? While lua doesn't have a keyword 'continue' for skipping the rest of the code and jumping to the next repeat of the loop. All you can do is 'break' out of a loop. By using this funny loop syntax, we can use 'break' as a skip: it breaks out of the 'repeat .. until ..' part, and goes straight to the part of the 'for ... end' loop. Doing this cuts down on a pile of nested 'if' statements. For example if I wrote the first 'for' loop normally: -- for .. do repeat .... until .. end for itemName, upgrades in pairs(UpgradedItems) do repeat local items = container:FindAll(itemName) if not items then break end for i=1,items:size() do repeat if ZombRand(UPGRADE_CHANCE) +1 > 1 then break end upgradeItem(items:get(i-1), upgrades[ZombRand(#upgrades) + 1]) until true end until true end -- for .. do .... end for itemName, upgrades in pairs(UpgradedItems) do local items = container:FindAll(itemName) if items then for i=1,items:size() do if ZombRand(UPGRADE_CHANCE) +1 == 1 then upgradeItem(items:get(i-1), upgrades[ZombRand(#upgrades) + 1]) end end end end These are small loops without too many nests, so its not overly a big deal here, but its a handy trick to know that many people probably aren't aware of. But there we go, dynamically created special items that spawn without editing the script files or distribution tables, and inherit values from the base items. Hopefully if actually read all of that you learned a trick or two. Plus, how can you go wrong when you see this as a characters 'favorite weapon':
  12. Hi all, Has anyone got all the explanations of the Sandboxvars file? I have the below for my server with the explanations I know, Please can someone fill in the blanks?; SandboxVars = { VERSION = 3, Zombies = 4, (How many zombies when the server starts, 1 is insane amount, 5 is none) Distribution = 1, (Where the zombies gravitate to, 1 is urban (in cities), 2 is uniform (everywhere)) DayLength = 3, (1 is 15 minutes, 2 is 30 minutes, 3 is 1 hour, 4 is 2 hours, 5 is 3 hours, 6 is 4 hours, 7 is 5 hours, 8 is 12 hours, 9 is real-time) StartYear = 1, (1 is the 1st year etc) StartMonth = 4, (1 is Jan, 12 is Dec) StartDay = 1, (1 is the 1st of the month etc) StartTime = 2, (1 is 7AM, 2 is 9AM, 3 is 12PM, 4 is 2PM, 5 is 5PM, 6 is 9PM, 7 is 12AM, 8 is 2AM, 9 is 5AM) WaterShut = 7, (1=instant, 2=0-30days, 3=0-2month, 4=0-6month, 5=0-1years, 6=0-5years, 7=2-6month, 7=6-12month) ElecShut = 7, (1=instant, 2=0-30days, 3=0-2month, 4=0-6month, 5=0-1years, 6=0-5years, 7=2-6month, 7=6-12month) WaterShutModifier = 500, (the number of days before water is shut off -1 mean instant) ElecShutModifier = 480, (the number of days before electricity is shut off -1 mean instant) FoodLoot = 4, (1 is extremely rare, 5 is abundant) WeaponLoot = 2, (1 is extremely rare, 5 is abundant) OtherLoot = 3, (1 is extremely rare, 5 is abundant) Temperature = 3, (1 is very cold, 5 is very hot) Rain = 3, (How often it rains, 1 is very dry, 5 is is very rainy) ErosionSpeed = 5, (How fast erosion occurs, 1 is very fast (20 days), 5 is very slow (500 days)) XpMultiplier = 15.0, (Obvious) Farming = 1, (How fast crops grow, 1 is very fast, 5 is very slow) CompostTime = 1 Determines how long it will take for food to decay in a composter. (1Week=1 2Weeks=2 3Weeks=3 4Weeks=4 6Weeks=5 8Weeks=6 10Weeks=7 12Weeks=8) StatsDecrease = 4, (How fast Stats Decrease when not being used, 1 is very fast, 5 is very slow) NatureAbundance = 3, (1 is very poor, 5 is very abundant) Alarm = 6, (How often houses are alarmed, 1 is never, 6 is very often) LockedHouses = 6, (How often houses are locked, 1 is never, 6 is very often) StarterKit = false, (To start with some basic essentials) Nutrition = false, (To enable the Nutrition system, calorie intake etc) FoodRotSpeed = 5, (How fast food rots, 1 is very fast, 5 is very slow) FridgeFactor = 5, (How effective refrigeration is, 1 is very low, 5 is very high) LootRespawn = 3, (How often loot respawns, 1 is none, 2 is every day, 3 is every week, 4 is every month, 5 is every two months) SeenHoursPreventLootRespawn = 0 This value is an integer defining the number of hours. When >0, loot will not respawn in zones that have been visited within this number of hours. [Default=0] TimeSinceApo = 1, (How many days since the start of the Apocalypse) PlantResilience = 3, (Plants resilience against disease/weather. 1 is very low, 5 is very high) PlantAbundance = 3, (How much farm plants produce. 1 is very poor, 5 is very abundant) EndRegen = 3, (Endurance regeneration (how fast you regain endurance). 1 is very fast, 5 is very slow) Helicopter = 3, (how regularly helicopters pass over the event zone. 1=never, 2 =once, 3=sometimes, 4=often) MetaEvent = 2, (how often zombie attacking meta-game events like distant gunshots will occur. 1=never, 2=sometimes, 3=often) SleepingEvent = 2, (governs night-time meta-game events during the player's sleep. 1=never, 2=sometimes, 3=often) GeneratorSpawning = 3, (increase/decrease the chance of electrical generators spawning on the map. 1=very low, 2=low, 3=normal, 4=high, 5=very high) GeneratorFuelConsumption = 1.0, (impacts how much fuel is consumed by generators. No fuel required= 0 . Minimum = 0, Maximum=100) SurvivorHouseChance = 3, (increase/decrease probability of discovering randomized safe houses on the map: either burnt out, containing loot stashes, dead survivor bodies etc. 1=never, 2=extremly rare, 3=rare, 4=sometimes, 5=often, 6=very often) AnnotatedMapChance = 4, (impacts on how often a looted map will have annotations marked on it by deceased survivors. 1=never, 2=extremely rare, 3=rare, 4=sometimes, 5=often, 6=very often) CharacterFreePoints = 10, (adds free traits points during character creation) ConstructionBonusPoints = 3, (Player-built construction strength. 1=very low, 2=low, 3=normal, 4=high, 5=very high) NightDarkness = 2, (Darkness during night. 1=pitch black, 2=dark, 3=normal, 4=bright) InjurySeverity = 2, (increases and decreases the impact injuries on your body, and their healing time. 1=low, 2=normal, 3=high) BoneFracture = true, (False=no fractures, true=bones can break) HoursForCorpseRemoval = 72, (number of in-game hours before zombies corpses are automatically removed from the map) DecayingCorpseHealthImpact = 3, (governs impact that nearby decaying bodies has on the player's health and emotions. 1=none 2=low, 3=normal, 4=high) BloodLevel = 4, (how much blood spatter when getting injured or killing zombies. will 1=none 2=low, 3=normal, 4=high, 5=ultra gore) ClothingDegradation = 2, (governs how quickly clothing degrades, becomes dirty and bloodied. 1=disabled, 2=slow, 3=normal, 4=fast) FireSpread = false, (fire can spread or not. false=off, true=on) DaysForRottenFoodRemoval = 4, (number of in game days before rotten food is removed from the map. -1 means that rotten food is never removed.) AllowExteriorGenerator = true This allows generators to power exterior tiles, and for example can get gas pumps working after the electricity has turned off. (True or False) ZombieAttractionMultiplier = 1 Use this to multiply or reduce engine general loudness. [Minimum=0] [Maximum=100] [Default=1] CarSpawnRate = 2 (Low=1 Normal=2 High=3) ChanceHasGas = 1 Governs the chances of finding vehicles with gas in the tank. (Low=1 Normal=2 High=3) InitialGas = 2 Governs how full gas tanks will be in discovered cars. (VeryLow=1 Low=2 Normal=3 High=4 VeryHigh=5 Full=6) CarGasConsumption = 1.0 The rate in which vehicles will consume fuel. [Minimum=0.0] [Maximum=100] [Default=1.0]. LockedCar = 4 How frequent the doors of a vehicle will be locked. (Never=1 ExtremelyRare=2 Rare=3 Sometimes=4 Often=5 VeryOften=6) CarGeneralCondition = 2 In what condition new cars will spawn. (VeryLow=1 Low=2 Normal=3 High=4 VeryHigh=5) CarDamageOnImpact = 3 Governs how much damage a vehicle will take after collisions. (VeryLow=1 Low=2 Normal=3 High=4 VeryHigh=5) TrafficJam = true Enable or disable traffic jams that spawn on the main roads of the map. (True or False) CarAlarm = 4 The frequency in which a car alarm will be triggered when opening a door. This will attract zombies to the vehicle's position. (Never=1 ExtremelyRare=2 Rare=3 Sometimes=4 Often=5 VeryOften=6) PlayerDamageFromCrash = true Enable or disable player getting damage from being in a car accident. (True or False) SirenShutoffHours = 1 Number of hours before the siren sound of a car alarm will stop playing. 0.0 means it will play until the car battery is dead. [Minimum=0] [Maximum=168] [Default=0] RecentlySurvivorVehicles = 1 Governs whether the player can discover a car that has been maintained and cared for after the infection struck, i.e. is still in working order. (Low=1 Normal=2 High=3) EnableVehicles = true Enable or disable vehicles from spawning into the game. (True or False) VehicleEasyUse = false If true, cars will all be unlocked with a full gas tank and low engine loudness. (True or False) ZombieLore = { Speed = 3, (1 is sprinters (fastest), 2 is fast shamblers, 3 is shamblers (slowest)) Strength = 3, (1 is superhuman, 2 is normal, 3 is weak) Toughness = 3, (1 is tough, 2 is normal, 3 is fragile) Transmission = 1, (1 is blood/saliva, 2 is everyone is infected, 3 is no transmission) Mortality = 6, (This governs how deadly infection is. 1 is instant, 6 is 1 to 2 weeks) Reanimate = 1, (How fast zombies come back to life...again. 1 is instant, 6 is 1 to 2 weeks) Cognition = 3, (How smart zombies are. 1 is Navigate/Use Doors, 3 is basic navigation only) Memory = 2, (How much zombies will remember. 1 is long, 4 is none) Decomp = 1, (1 is slows/weakens them, 4 is no effect) Sight = 2, (How well zombies can see. 1 is eagle-eyed, 3 is poor) Hearing = 2, (How well zombies can hear. 1 is pinpoint, 3 is poor) Smell = 2, (How well zombies can smell. 1 is bloodhound, 3 is poor) ThumpNoChasing = false, (environmental attacks. zombies that have not seen/heard a player can attack doors and constructions while roaming. true=on, false=off) ThumpOnConstruction = true, (damage construction. governs whether or not zombies can destroy player constructions and defences. true=on, false=off) ActiveOnly = 1, (governs whether zombies are more active during the day, or whether they act more nocturnally. Inactive zombies will be slower and tend not to give a chase. 1=both, 2=night, 3=day) TriggerHouseAlarm = true Allows zombies to trigger house alarms when breaking through windows and doors. Enabling this option will cause zombies to constantly be movie around populated areas, making the early game much more difficult. (True or False) }, ZombieConfig = { PopulationMultiplier = 0.5, (Depends on "Zombies" in the SandboxVars. population multiplier: (old var. "zombie intensity") set how many zombies you want to begin with) Minimum=0,Maximum=4,Default=1) PopulationStartMultiplier = 1.0, (Adjusts the desired population at the start of the game. it's a start multiplier: how much of the "population multiplier" you want at game start (it will slowly increase) Minimum=0,Maximum=4,Default=1) PopulationPeakMultiplier = 2.0, (Adjusts the desired population on the peak day. Set how many zombies you want at X days (and forever after) Minimum=0,Maximum=4,Default=1) PopulationPeakDay = 100, (The day when the population reaches it's peak. Minimum=1, Maximum=365, Default=28) RespawnHours = 96, (The number of in-game hours that must pass before zombies may respawn in a cell. If zero spawning is disabled. Minimum=0, Maximum=8760, Default=72) RespawnUnseenHours = 10, (The number of in-game hours that a chunk must be unseen before zombies may re-spawn in it. Minimum=0, Maximum=8760, Default=16) RespawnMultiplier = 0.1, (The fraction of a cells desired population that may re-spawn every RespawnHours. Minimum=0, Maximum=1, Default=0.1) RedistributeHours = 12.0, (The number of in-game hours that must pass before zombies migrate to empty parts of the same cell. If zero, migration is disabled. Minimum=0, Maximum=8760, Default=12) FollowSoundDistance = 200, (The distance a virtual zombie will try to walk towards the last sound it heard. Minimum=10, Maximum=1000, Default=100) RallyGroupSize = 20, (The size of groups real zombies form when idle. Zero means zombies don't form groups. Groups don't form inside buildings or forest zones. Minimum=5, Maximum=1000, Default=20) RallyTravelDistance = 30, (The distance real zombies travel to from groups when idle. Minimum=5, Maximum=50, Default=20) RallyGroupSeparation = 15, (The distance between zombie groups. Minimum=5, Maximum=25, Default=15) RallyGroupRadius = 4, (How close members of a group stay to the group's leader. Minimum=1, Maximum=10, Default=3) }, } This I am sure will help a lot of people out too. I also have the settings for the servertest.ini file with the explinations that I know... nightlengthmodifier=1.0 (Length of the night, 0.5 would make the night go twice as fast) PVP=false (False is PvE, True is PvP) PauseEmpty=true (time in game pauses when the server is empty) GlobalChat=true (Enables in game chat) Open=true (Allows anyone to join) ServerWelcomeMessage= <RGB:0,0,0> To chat locally press 't', to global chat press 'y' or add '/all' before chatting <LINE> Type '/help' to have a list of available commands <LINE> <RGB:0,0,0> (Message that is displayed when joining the server) LogLocalChat=true (Logs all local chat for server admins to view) AutoCreateUserInWhiteList=true (Adds user to Whitelist when they join the server) DisplayUserName=true (Displays player’s usernames in game) SpawnPoint=0,0,0 (Use this to define a custom spawn point instead of the random one from character creation) SafetySystem=true (Allow the user to change their safety (if false and if PVP=true, then the safety will always be off) ShowSafety=true (Allow the players to see if someone have his safety off with the skull icon) SafetyToggleTimer=100 (When the player disable safety it take some times before HE enable it (tho the other players see it instantly), define it here) SafetyCooldownTimer=120 (Every time you hit someone in safety off, add this timer to the cool down before you can actually toggle safety off) SpawnItems= (Define specific items for everyone to spawn with) DefaultPort=16261 (Your server game port) ResetID= (Leave alone) Mods=Hydrocraft (Mods added to server) Map=Muldraugh, KY (Maps added to server) DoLuaChecksum=true (Do the lua checksum. Players with modified Lua files that differ from the server files will not be able to connect. true=Lua check, false=no lua check) Public=true (Everyone can see the server in the server list) PublicName= (Name of the server) PublicDescription= (Description of the server that is displayed in the server list) MaxPlayers=64 (Max number of players for the server) PingFrequency=10 (How often to ping clients in seconds) PingLimit=400 (Max ping in ms, if client exceeds this amount they will be kicked) HoursForLootRespawn=2 (How many in-game hours for loot to re-spawn) MaxItemsForLootRespawn=6 (Max items to spawn in each container) ConstructionPreventsLootRespawn=true (If you start building on a house for example, loot will stop respawning in that house) DropOffWhiteListAfterDeath=false (Takes you off the Whitelist if you die) NoFireSpread=true (Fire doesn’t spread) NoFire=true (No Fire) AnnounceDeath=true (Death is announced to all players) MinutesPerPage=1.0 (How long books take to read. Lower number faster, higher number slower) HoursForCorpseRemoval=2.0 (How many in-game hours before corpses disappear) SaveWorldEveryMinutes=10 (How often to save the server in minutes) PlayerSafehouse=true (Allows players and Admins to claim houses etc as safehouses) AdminSafehouse=false (Allows only Admins to claim safehouses) SafehouseAllowTrepass=false (Allow players to trespass through other players safehouses) SafehouseAllowFire=false (Allow fire in safehouses) SafehouseAllowLoot=false (Allow players to loot other players safehouses) SafehouseAllowRespawn=true (Allow owner of safehouse to respawn in their safehouse) SafehouseDaySurvivedToClaim=1 (How many days you need to survive before you can claim a safehouse) SafeHouseRemovalTime=144 (If you do not visit your safehouse in this many game days it will be released) AllowDestructionBySledgehammer=true (Allow walls to be knocked down with the Sledgehammer) KickFastPlayers=false (Kick players that appear to be moving faster than is possible. May be buggy -- use with caution) ServerPlayerID= (Leave alone) RCONPort=27015 (Port for RCON) RCONPassword= (Password for RCON) Password= (Password for server. Leave blank if you want anyone to join your server) MaxAccountsPerUser=0 (Limits the number of different accounts a single Steam unser may create on this server. Ignored when using the hosts button) SleepAllowed=false (Enable sleep) SleepNeeded=false (If true you will need to sleep when exhausted) SteamPort1=8766 (Leave alone) SteamPort2=8767 (Leave alone) WorkshopItems= (MOD IDs - When you run the server with these ID's in the Mods will auto update) SteamScoreboard=true (show steam usernames and avatars in the player list. true=visible to everyone, false=visible to no one, admin=visible to admins) SteamVAC=true (Steam anti cheat) UPnP=true (attempt to configure a UPnP-enabled internet gateway to automatically setup port forwarding rules. The server will fall back to default ports if this fails) UPnPLeaseTime=86400 (port lease time in seconds (86400 == 24 hours). This should not be changed) UPnPZeroLeaseTimeFallback=true (retry with zero lease time if port-mapping fails (helps with some routers). This should not be changed.) UPnPForce=true (remove existing port mappings. This should not be changed) CoopServerLaunchTimeout=20 CoopMasterPingTimeout=60 VoiceEnable=true (In game Voip) VoiceComplexity=5 VoicePeriod=20 VoiceSampleRate=24000 VoiceBuffering=8000 VoiceMinDistance=1.0 VoiceMaxDistance=50.0 Voice3D=true server_browser_announced_ip= UseTCPForMapDownloads=false PlayerRespawnWithSelf=false PlayerRespawnWithOther=false FastForwardMultiplier=40.0 PlayerSaveOnDamage=true SaveTransactionID=false DisableSafehouseWhenPlayerConnected=false Faction=true (enable Factions) FactionDaySurvivedToCreate=2 (How many days you must survive to create a Faction) FactionPlayersRequiredForTag=1 AllowTradeUI=true (Allows you to trade among players) HoursForWorldItemRemoval=0.0 WorldItemRemovalList=Base.Vest,Base.Shirt,Base.Blouse,Base.Skirt,Base.Shoes ItemRemovalListBlacklistToggle=false DisableRadioStaff=false DisableRadioAdmin=true DisableRadioGM=true DisableRadioOverseer=false DisableRadioModerator=false DisableRadioInvisible=true ClientCommandFilter=-vehicle.*;+vehicle.damageWindow;+vehicle.fixPart;+vehicle.installPart;+vehicle.uninstallPart ItemNumbersLimitPerContainer=0 If anyone can fill in the gaps, I and i'm sure the whole community would be very thankful. Cheers all, M700N
  13. As you (probably) already know, PZ allows us to define timed events using OnEveryTenMinutes, EveryHours, and EveryDays. As handy as they are, sometimes we want a more refined system. Maybe we want a event to trigger in 15 minutes, and possibly repeat itself a few times then stop. Maybe we want something to happen every 60 seconds in game. Well I got bored this morning and cooked up such a system... (this would go in the lua/shared folder) First we create our Timers table: Timers = { ActiveTimers = {}, } This will hold our functions, and the sub-table ActiveTimers will hold our actual timer queue. Now we need a handy function to add timers to our table: Timers.add = function(delay, repeats, callback, args) local hours = getGameTime():getWorldAgeHours() local t = { delay = delay, callback = callback, args = args, repeats = repeats, trigger = hours + (delay/60), } = ZombRand(100000) .."-".. t.trigger Timers.ActiveTimers[] = t return t end This function takes 4 arguments: delay = the number of minutes to wait before triggering our timer. This should be a integer value greater then 0. repeats = the number of times to repeat the timer, after the first triggering. If repeats is 0, nil or false, it will only fire once. If true then it will endlessly fire. A value of 2 will trigger a total of 3 times (the initial trigger, then 2 repeats) callback = the function to call when this timer is triggered. It should accept 2 arguments: the timer itself, and whatever value is in the 'args' variable args = passed to your callback function. This can be anything, although you should be careful not to pass variables that may have expired (ie: a IsoPlayer object on a server, in case that player disconnects before the timer is triggered) Its going to be up to you to make sure your callback function properly verifies anything you pass to it as args. Notice we use getGameTime():getWorldAgeHours() to help define when this timer should trigger (see the t.trigger variable in the above function). This will return a float value such as 125.25, which would mean 125 hours and 15 minutes into the game (125.50 is 125h and 30min). Since our 'minutes' are a percent value of 1 (15 minutes = .25) we use delay/60 Now we need a function to remove our timers just in case we need to cancel early: Timers.remove = function(timer) if type(timer) == "table" then -- not a proper timer table if not then return end timer = end Timers.ActiveTimers[timer] = nil end The timer argument can be one of 2 things: the actual timer table returned by Timers.add(), or the timer id. Now those 2 important functions are out of the way, time for our function that actually checks if a timer should be triggered: Timers.check = function() local current = getGameTime():getWorldAgeHours() for id, timer in pairs(Timers.ActiveTimers) do if timer.trigger <= current then if not timer.repeats or timer.repeats == 0 then Timers.ActiveTimers[id] = nil elseif type(timer.repeats) == "number" then timer.repeats = timer.repeats - 1 end timer.trigger = current + (timer.delay/60) timer.callback(timer, timer.args) end end end basically we loop through our Timers.ActiveTimers table, and if the timer.trigger is less then the current world age hours, its time to call the callback function! Notice if the timer.repeats is a number (and not 0) it lowers the repeat by 1. It also sets up the next timer.trigger value. Pretty easy stuff. Now we need to be able to call the Timers.check() function on a interval, using PZ's events system. There's 2 events we can use, each with benefits and drawbacks: Events.OnTick.Add(Timers.check) This method using OnTick will give you the most accurate timers and allows you to setup timers with a delay of 1 minute. Its drawback is that its called ALOT (multiple times per 1 second of game time), so if your planning on having alot of active timers at once, performance may suffer and you should probably use this instead: Events.EveryTenMinutes.Add(Timers.check) The drawback here is timers are effectively only triggered every ten minutes. So now for a example of a timer added client side (they can be added server side as well) local callback = function(timer, args) if not timer.repeats or timer.repeats == 0 then args:Say("Last Call!") else args:Say("Timer Triggered!") end end Events.OnGameStart.Add(function() Timers.add(15, 3, callback, getSpecificPlayer(0)) end) On logging into the game, this will make our player say "Timer Triggered!" every 15 minutes, 3 times, then 15 minutes later say "Last Call!" Please note these timers are NOT saved on exiting (or server shutdown), I'll leave that part to you creative people to figure out a method of doing so. This is after all, a tutorial on timers, not saving data
  14. M700N

    SandboxVars.lua file explanation

    Hi all, I have the below for my server with the explanations I know, Please can someone fill in the blanks?; SandboxVars = { Zombies = 4, (1 is insane amount, 5 is none) Distribution = 1, (1 is urban, 2 is uniform) DayLength = 3, (1 is 15 minutes, 2 is 30 minutes, 3 is 1 hour, 4 is 2 hours, 5 is 3 hours, 6 is 4 hours, 7 is 5 hours, 8 is 12 hours, 9 is real-time) StartYear = 1, (1 is the 1st year etc) StartMonth = 4, (1 is Jan, 12 is Dec) StartDay = 1, (1 is the 1st of the month etc) StartTime = 2, (1 is 7AM, 2 is 9AM, 3 is 12PM, 4 is 2PM, 5 is 5PM, 6 is 9PM, 7 is 12AM, 8 is 2AM, 9 is 5AM) WaterShut = 2, ElecShut = 2, WaterShutModifier = 500, (the number of days before water is shut off -1 mean instant) ElecShutModifier = 480, (the number of days before electricity is shut off -1 mean instant) FoodLoot = 4, (1 is extremely rare, 5 is abundant) WeaponLoot = 2, (1 is extremely rare, 5 is abundant) OtherLoot = 3, (1 is extremely rare, 5 is abundant) Temperature = 3, (1 is very cold, 5 is very hot) Rain = 3, (1 is very dry, 5 is is very rainy) ErosionSpeed = 5, (1 is very fast (20 days), 5 is very slow (500 days)) XpMultiplier = 15.0, (Obvious) Farming = 1, (1 is vey fast, 5 is very slow) StatsDecrease = 4, (1 is very fast, 5 is very slow) NatureAbundance = 3, (1 is very poor, 5 is very abundant) Alarm = 6, (1 is never, 6 is very often) LockedHouses = 6, (1 is never, 6 is very often) StarterKit = false, Nutrition = false, FoodRotSpeed = 5, (1 is very fast, 5 is very slow) FridgeFactor = 5, (1 is very low, 5 is very high) LootRespawn = 2, (1 is none, 2 is every day, 3 is every week, 4 is every month, 5 is every two months) TimeSinceApo = 1, PlantResilience = 3, (Plants resilience against disease/weather. 1 is very low, 5 is very high) PlantAbundance = 3, (How much farm plants produce. 1 is very poor, 5 is very abundant) EndRegen = 3, (Endurance regeneration (how fast you regain endurance). 1 is very fast, 5 is very slow) ZombieLore = { Speed = 3, (1 is sprinters (fastest), 2 is fast shamblers, 3 is shamblers (slowest)) Strength = 3, (1 is superhuman, 2 is normal, 3 is weak) Toughness = 3, (1 is tough, 2 is normal, 3 is fragile) Transmission = 1, (1 is blood/saliva, 2 is everyone is infected, 3 is no transmission) Mortality = 6, (This governs how deadly infection is. 1 is instant, 6 is 1 to 2 weeks) Reanimate = 1, (How fast zombies come back to life...again. 1 is instant, 6 is 1 to 2 weeks) Cognition = 3, (How smart zombies are. 1 is Navigate/Use Doors, 3 is basic navigation only) Memory = 2, (How much zombies will remember. 1 is long, 4 is none) Decomp = 1, (1 is slows/weakens them, 4 is no effect) Sight = 2, (How well zombies can see. 1 is eagle-eyed, 3 is poor) Hearing = 2, (How well zombies can hear. 1 is pinpoint, 3 is poor) Smell = 2, (How well zombies can smell. 1 is bloodhound, 3 is poor) ThumpNoChasing = true, }, ZombieConfig = { PopulationMultiplier = 0.5, PopulationStartMultiplier = 1.0, PopulationPeakMultiplier = 2.0, PopulationPeakDay = 100, RespawnHours = 50.0, RespawnUnseenHours = 15.0, RespawnMultiplier = 0.1, RedistributeHours = 12.0, FollowSoundDistance = 200, RallyGroupSize = 20, RallyTravelDistance = 30, RallyGroupSeparation = 15, RallyGroupRadius = 3, }, } This I am sure will help a lot of people out who are starting to run their own servers. Cheers all, M700N
  15. lemmy101

    Lua Debugger

    Just a few bullet points for now, will expand on it later: Will fill this out as I go, we're uploading an SI test release btw Must be in debug mode (either hold left shift while booting the game, or for more permanently run game with -debug / -Ddebug params (depends, try both))* - alternatively try holding left shift while booting the game.There is an edit box above the filename browser that you can use to search for files containing case insensitive strings F11 breaks into the debugger at the next available Lua entry point. Key is bindable.F5 steps into code, F6 steps over code.Left double click lua line to place / remove breakpoint.Local variables panel is something that required a lot of guesswork and fiddling this end, and was by far the most complicated thing, and there may be times where it doesn't show something it should. Will get to all these in time.Still some issues with java objects in object viewer etcJust occured to me I didn't update the main dev branch with the new map debugging stuff (showing characters / collision, will get that in another release)Right click object viewer for menu to put a breakpoint on the data on read / write, or to add to the watch window.Left double click stuff to open info in a window is the general rule for object viewers, stacks etc.Line numbers may occasionally be a line off in errors / stack. Will look to improve this if possible, but its tricky. Even ProDG the official Sony Playstation debugger suffered this problem the entire time I used it.If UI breakpoints aren't enough, call the function breakpoint() in lua this will always break every time it runs. Expect bugs and slightly unfinished things. It's all very experimental, but is already MASSIVELY useful for any lua modder, so get used to using it if you do lua and you're not using it, then you are MAD. *Mac Users need to follow these steps to use the debugger: Open your and look for a file called "Info.plist" then search for this line: <string>-noverify -XX:+UseNUMA -XX:+AggressiveOpts -XX:+TieredCompilation -XX:Tier2CompileThreshold=70000 -XX:CompileThreshold=1500 -Xms64m -Xmx512m -XX:+UseAdaptiveSizePolicy -XX:GCTimeRatio=50 -XX:MaxGCPauseMillis=20</string>add "-Ddebug" to it (of course before the last </string> tag).
  16. I suggest adding a method that will allow us to load skinned mesh in game! I replaced the original models of clothes, and it looks good. But unfortunately adding them without replacing the original is impossible, since there is no skinned model load method. :(( Class LuaManager.GlobalObject has a method that allows loading a static model, but it does not allow upload skinned model, because it sends boolean true to ModelLoader.instance.Load
  17. I have made a program that extracts the global lua functions, like getPlayer() and the this is the result. Please let me know what you think! Many thanks, HOWZ1T
  18. Hi there, i'm not really sure where to post this but i'm looking for someone who is experienced in lua that could help me fix this mod and make it usable again. Let me know if you can, or know someone that can help!
  19. The idea is to mod the base campfire so that it cannot be walked over. I want to have a campfire down in use with the survivors mod but without them walking into it and burning to death. Ideally, when the campfire itself is placed on the ground, you can toggle the protection on or off. I can do graphics, just not the coding. I was thinking the base campfire and a tall campfire; like in the walking dead when they build it up with stones to hide the light. Same effect, but it protects the survivors from burning down my camp / safehouse / map. Some advice on where to look maybe or how to make it happen, I can do the graphics.
  20. This tutorial assumes you know the very basics of Lua: what a variable is, and how to assign one. what a function is, and how to call one and pass variables to it. what a table is, and how to declare one. It is dedicated to modders new to Lua, and is a general tutorial on Lua... not specific to modding PZ. Variables and function scope: This seems to be one of the more overlooked aspect I've noticed in mods, and is EXTREMELY important for efficient and fast code. There are 2 scopes: global and local. * Global variables can be accessed by any part of the code, from any function, in any file, and are declared like: * Local variables can only be accessed from the file (or function) that they are declared in. The more variables declared, the longer its going to take to find any specific one. Think of it like a phonebook... if you need to look up a number and that book has 1000 different numbers in it, it will take longer to find the one you want. Ideally you only want the book to contain numbers your actually planning on calling. One of the reasons Lua is used as a language for a lot of games is due to its speed. One of the reasons its fast is because by default it doesn't pollute the global space with unneeded stuff. The most important thing to remember: ALL VARIABLES ARE GLOBAL BY DEFAULT UNLESS DECLARED LOCAL. This is often overlooked. If we wanted to make sure a variable can not be accessed outside the file or function (thus not polluting the global namespace), we declare it like this: local modName = "My new mod" If we wanted a to declare this in a function printModInfo instead: function printModInfo() local modName = "My new mod" print(modName) end Had we left out the 'local' key word there, modName reverts to global, and can now be accessed anywhere. Not only is it bad for performance, it also runs the risk of accidentally over writing another variable...if someone else's mod used the same variable name in the global namespace. Lets assume we actually want modName to be global, as well as modInfo, modAuthor and modVersion, so we can access them from other files in the mod. We could declare them all global but why pollute the global space more then we have to? We're better off sticking them in a global table: MyModData = { modName = "My new mod", modInfo = "My description", modAuthor = "Me!", modVersion = 1.0 } print(MyModData.modName) It may not seem like we've saved much, only adding 1 item into the global space instead of 4, but it adds up. Tables are important for organizing and separating data. This same concept applies to functions, they can exist in the global or local space, and are assumed global unless declared with the local keyword. They can also be declared in 2 styles: -- global function printModInfo() ... end printModInfo = function() ... end -- local local function printModInfo() ... end local printModInfo = function() ... end You may have noticed the second style there actually creates a function but assigns it to a variable name, this is perfectly valid and can be a handy trick: function printModInfoStyle1() ... end function printModInfoStyle2() ... end printModInfo = printModInfoStyle1 we can reassign printModInfo to Style1 or Style2, depending on some condition and call it later simply as printModInfo() Lets say you want to add a Event that triggers on keypress: local function someFunction(key) ... end Events.OnKeyPressed.Add(someFunction) Remember to declare that function local, its not getting called from anywhere else. Actually, since its only getting passed to Events.OnKeyPressed.Add, and not even getting called locally, you can shortcut and skip polluting the local space as well: Events.OnKeyPressed.Add(function(key) ... end) Some coders may disagree with that last example, but remember the trick to writing efficient Lua is to keep the scope as small as possible, since we'll never need that function again, there is no point assigning it a name. If you create a number of functions, and the only code that calls those functions exists within the same file, be sure to make them local. The same thing I said above about sticking global variables into a table to avoid namespace pollution also applies to functions. If all those functions you declared you need to access elsewhere, put them in a table: MyModFunc = { functionNo1 = function() ... end, functionNo2 = function() ... end, functionNo3 = function() ... end, } MyModFunc.functionNo4 = function() ... end -- this works too This isn't related to global/local scope, but is often the most confusing (and annoying) part for new Lua coders so worth mentioning. Functions inside tables can actually be declared and accessed 2 ways: MyModFunc = { } function MyModFunc.functionNo1() ... end function MyModFunc:functionNo2() ... end and calling them as: MyModFunc.functionNo1() MyModFunc:functionNo2() Notice the use of : in functionNo2 instead of the . The first style is a normal function, and behaves exactly like you'd expect. The second style is technically called a 'method', it will pass a variable named 'self' to the function. In this case 'self' is the table MyModFunc. The functionNo2 method is basically doing this: function MyModFunc.functionNo2(self) ... end MyModFunc.functionNo2(MyModFunc) Now that all that is sorted out, here's a additional scoping trick... functions can be created inside other functions: local functionNo1() local myVariable = "some text" local functionNo2 = function() print(myVariable) end return functionNo2 end local result = functionNo1() result() -- prints "some text" this calls the first function, which returns the second, the second (now in the variable 'result') is called, and prints "some text" While the above bit of code itself not overly useful, it demonstrates a few points: functions inside functions, and variables are inherited from the above scope (even locals) and can be used after their scope has ended.
  21. Hello Guys! Recently I'm playing PZ extensively with my Girlfriend and because I have 3 monitor's I always have the map ( open on one of the other monitor's. One thing that annoyed me was that even in borderless window mode I had to click out of PZ to move the map to see everything I wanted. Finding the position of your player was also a bit annoying, so one night I sat down and started programming and PZTracker was the result. PZTracker connects the online map to the game. The map will follow your player position if you like and you can move around (arrow keys) or zoom in and out (num+ and num-) on the map by pressing the keys WITHIN PZ. No need to tab out of PZ. You really just need to press buttons ingame. Little Preview: I was faced with the problem of connecting two separated systems that had no connection whatsoever. PZ and an Website. I had to get information out of PZ and into the map website. At first I thought about memory reading, but I dropped that idea when modding PZ came to my mind. And so PZTracker currently consists of 3 "components". Component 1: The PZTrackerMod I had to get the information out of the game. I realized this by writing a simple mod. So the PZTrackerMod is just a typical mod written in lua (never worked with lua before, but was easy enough to get everything working in a few minutes) that prints out important information, like player position and keypress events to the PZ cmd. Currently the PZTrackerMod has the following Shortcuts: F - Enables or Disables follow mode. If disabled the map won't follow the position of your player. Arrow Keys - Move the map up, down, left, right for easy navigation. Num + - Zooms into the map. Num - - Zooms out of the map. Component 2: pz_tracker.exe Now I had to get the data that gets printed by the PZTrackerMod out of the cmd, so I wrote a program in golang that starts PZ as a child process and reads and parses the stdout (the text stuff you see in the cmd). Now the program is able to get the data out of the game. To forward this data it also opens a websocket in wich all the data get's send if somebody is connected to it. Component 3: inject.js Now we come to the last part. We got the data that we can get through the websocket from the pz_tracker.exe. Now we have to get the data into the map. Currently I solved the Problem with a small javascript code that I lode into the running map website via the "Chrome Development Console". It,s just pasting the code into the console and hit enter, so even somebody without coding experience should be able to do this. What the code does is to connect to the websocket and read the data that get sent to him. It then uses the data to move the map to the player location or respond to key press events and move or zoom the map. Just download the ZIP File of the latest release: Setup Video: Step 1: Download the current Version and extract it somewhere. Step 2: Copy the "PZTrackerMod" to your "Mods" Folder (C:\Users\YOUR USERNAME\Zomboid\mods) Copy the "PZTracker.exe" and "inject-min.js" to your "ProjectZomboid" Folder (With steam: C:\...\Steam\SteamApps\common\ProjectZomboid) Step 3: Start the "PZTracker.exe" and open the PZMap Step 4: Activate the "PZTrackerMod" in your running Project Zomboid. Step 5: Open the Developer Console in your PZMap browser window (Chrome: Ctrl - Shift - I). Paste the code that is displayed in PZTracker after "Insert into development console:" into the development console and hit enter. (Should be something like: $.getScript('');) Step 6: Load a Singleplayer Game or join a Server that has "PZTrackerMod" enabled and hit F when you see your character. Now you should see the map moving. Use the shortcuts mentioned above. Advanced Stuff If you start PZTracker for the first time it will generate a config filed called "pztracker_config.json". Open this file with a texteditor and you will find the settings for PZTracker. You should understand them just by the name, but in case an explanation of them will be added shortly. Github Repository: BigJk/PZTracker First of all I would really like to hear the opinion on this from you guys. Maybe you don't like the idea and it will just be a little tool for me to use when I play with my girlfriend, but in case you like it I will get it ready to release in a short while and think about possible future features. Any ideas? Maybe I can simplify the process of getting the data into the map and get away from this "hacky" way of doing it, even though I must admit that it works way better than I have ever expected xD Thank you for taking your time and reading this and huge thanks to blindcoder for creating this awesome map website! I hope you don't mind my playing around xP
  22. ToastedFishSandwich

    How to Spawn a Zombie

    Hi all. I know this probably quite a simple problem and I have tried to find a solution on but haven't had any luck just yet. Quite a while ago I could do it like this: z = getVirtualZombieManager():createRealZombieNow(X, Y, Z); But sometime in the past few years that stopped working. What's the new method (and what's the best way to find out for myself in the future)? Edit: Okay I may have found it already myself (I could have found it sooner if Google hadn't decided to hide the majority of my search results on the topic for some reason). Testing now. For anybody trying to solve the same problem in future new code is z = createZombie(dupeX, dupeY, dupeZ, nil, 0, IsoDirections.E);
  23. RandomFace

    Changing zombie lore during a game

    Hi all, First time posting. I was wondering if there was a way to change zombie lore during a game? Is there a lua table for this? As an example lets say I wanted to change zombies from fast shamblers to shamblers depending on an event in game, is that possible or is it something that can only be set at the beginning of the game? If there's no global table that effects all zombies in real time then does each zombie have it's own settings table I can potentially loop through and change? Hope that made sense. Thanks for any responses.
  24. Leond

    Zed Bag Patch

    Zed Bag Patch With the state this is in right now I am not posting a download link. However if you would like a workaround for your mod list let me know. I can make a custom workaround patch for you. This is a patch to allow multiple mods to create Quick Access Containers in the players inventory! I like to use both Quickbags, and US Military Gear but found out that it would only allow the mod that loaded last to have the quick access bags. This 'patch' is just a modified ISQuickAccessContainers.lua with the bags from both mods. Once I have had a chance to test it and make sure it doesn't cause any weird issues with the mods conflicting then I will look at posting a download link. Todo: Known Bugs Currently supported mods Under the hood (code snippet) Let me know what you think and if you know any other mods you would like added to this patch. NOTE: This is just a patch to get these mods working together. All credit for these mods goes to their respective creators and contributors. This is kind of my first dive into PZ modding so I would really like feedback so I can learn more.
  25. Berdryn

    [SOLVED] RemoveOnRotten lua script

    RemoveOnRotten = {}; function RemoveOnRotten.removeItems() local player = getSpecificPlayer(0); local inv = player:getInventory(); if inv:contains("Matter - Spiritual (Rotten)") == true then inv:Remove("Matter - Spiritual (Rotten)"); end end end Event.OnPlayerUpdate.Add(RemoveOnRotten.removeItems); I'm not sure if this is even set up, kinda writing in the dark as still new to lua. I'm trying to get it so that as soon as the item rots, the script detects it and removes it from the player inventory. Thanks in advance!