Jump to content

Search the Community

Showing results for tags 'Lua'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • 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

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Twitter


Interests

  1. The function EveryOneMinute() sometimes occurs twice at the same time.
  2. I mean animation + stopping running for a bit. --e.g. player:Fall() --would be helpful There are some unknown functions but they don't work: player:setFallOnFront() player:fallenOnKnees() -- adds blood player:setbFalling() player:setFallTime()
  3. Let's say there is a critical game function "render": function SomeClass:render() --Game code (safe) end And you want to inject into it. As you know, replacing the whole function is bad practice. Therefore, the injection in your mod will look something like this: local old_fn = SomeClass.render SomeClass.render = function(self, ...) --Your code (unsafe) return old_fn(self, ...) end The main difficulty is that your code may contain errors with a high chance. And if something goes wrong, the user will receive a ton of red errors or the game will freeze because the function is critical and is called roughly every tick. So you want at least stop spam of errors if something went wrong. There is a solution! local in_progress = false local old_fn = SomeClass.render SomeClass.render = function(self, ...) if in_progress then return old_fn(self, ...) end in_progress = true --Your code (unsafe) in_progress = false return old_fn(self, ...) end Actually, this code was created in order to avoid recursion. But as a side effect, it allows to bypass the storm of errors. If something breaks the mod, then the mod just stops working, and the game continues without further errors.
  4. Actually it's not a real bug but a kind of mistake in the code. Even so there is no any text in "Category" column in inventory whlie you are washing your clothes. P.S. It caused game freeze in my mod, because the game tries to draw nil in ISInventoryPane.lua:1885, and I injected in that code, that's why I decided to report it.
  5. Small optimization in ISAddItemInRecipe.lua https://pastebin.com/TRmSNVnZ
  6. Hey, so I was wondering if it would be possible to add an interaction button to zeds, nothing fancy, more like a proof-of-concept. If you press your right mouse button on an zed an small interaction button should pop up (like on anything else interactable), if i click it some function or so should be triggered. Im pretty new to modding Project Zomboid, im not quite sure where to start but I found some example LUA scripts from the devs located in: \media\luaexamples\ui But I dont know if its the right to look at, any tips or help would be appreciated.
  7. -- when you or a npc try to hit something xpUpdate.onWeaponHitXp = function(owner, weapon, hitObject, damage) local isShove = false if hitObject:isOnFloor() == false and weapon:getName() == "Bare Hands" then The function getName() returns translated name! It may be not English. So it should be: weapon:getType() == "BareHands"
  8. Hi, i encountered this bug, when i wanted to add another mod to my already running game. When you click on the "choose mods" button when loading the game, you get an empty screen (only the background picure of the game still exists). Now, this bug doesnt happen, if you clicked atleast once on the "Mods" button in the main menu before attempting to do this (once per game start is enough). As i found out, the reason for this is, that the game tries to display a box with text, using a function that does not exist. In the file "ISModsNagPanel.lua" in the location Steam\steamapps\common\ProjectZomboid\media\lua\client\OptionScreens in line 32: self.richText:setText(getText("UI_ModsNagPanel_Text")) The function "setText" doesnt exist. Replacing it with: self.richText.text=(getText("UI_ModsNagPanel_Text")) fixes the problem.
  9. 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.
  10. Hello Guys! Recently I'm playing PZ extensively with my Girlfriend and because I have 3 monitor's I always have the map (http://map.projectzomboid.com/) 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: https://www.youtube.com/watch?v=sJEKmZ5Nrh0 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: https://github.com/BigJk/PZTracker/releases Setup Video: https://www.youtube.com/watch?v=a4ycQgryxzw 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('http://127.0.0.1:9090/js');) 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
  11. I can create a class like this local noise = InventoryItemFactory.CreateItem("Peace.SoundBeacon"); local noiseTrap = IsoTrap.new(noise, cell, square); noiseTrap:addToWorld(); but I cant create some classes, i get an is nil error local radioLinePre = RadioLine.new("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.
  12. 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.
  13. setTeachedRecipes(java.util.List<java.lang.String> teachedRecipes) For example, how to use this function? setTeachedRecipes({"Recipe 1", "Recipe 2"}) ?
  14. 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?
  15. 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
  16. 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 label.name == "Equip/Unequip Pistol" then label:setTranslation("Equip/Unequip Pistol") label:setX(label.x) label:setWidth(label.width) elseif label.name == "Equip/Unequip Rifle" then label:setTranslation("Equip/Unequip Rifle") label:setX(label.x) label:setWidth(label.width) elseif label.name == "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.
  17. 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.
  18. 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':
  19. 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), } t.id = ZombRand(100000) .."-".. t.trigger Timers.ActiveTimers[t.id] = 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 timer.id then return end timer = timer.id 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
  20. 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
  21. 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
  22. 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
  23. 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!
  24. 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.
×
×
  • Create New...