• Content count

  • Joined

  • Last visited


About Fenris_Wolf

Contact Methods

  • Website URL

Profile Information

  • Interests
    coding and gunning down the undead

Recent Profile Visitors

477 profile views
  1. Patch Regular Branch someday ?

    There's already lots of programs capable of generating diff files, so modders can isolate whats changed in important files to them without having to have a full list generated by the dev team. That being said, any important major API changes should be mentioned in release notes. Modders need to take care when developing and try and limit damage that can be done with a game update: Overwrite as little of the base game as possible, the more of the base you replace, the more likely it is to break later (and the less likely it will be compatible with other mods). Overwrite functions, not full files. Most importantly, document what you've overwritten, and why (especially for larger mods). If someone else needs to make it compatible with a future version after you've moved onto other things, this is a major help. It takes less then a minute for you to write, and can save them hours.
  2. Damn my luck!

    If only I had actually survived lol...the odds of finding that fully loaded gun with silencer in the starting house on rare loot settings were pretty damn slim...the odds of it actually jamming on the last round i tried to shoot...well that was just ironic. Started out so well, and went downhill so quickly
  3. I should actually post a 'somewhat' related but slightly different tutorial here (instead of making a new thread) How to edit the durability of all weapons, without having to redefine the items in the media/scripts/*.txt files This is really quite simple. local DurabilityFixTable = { "Base.Axe", "Base.BaseballBat", "Base.BaseballBatNails", "Base.ButterKnife", "Base.Hammer", "Base.KitchenKnife", "Base.Poolcue", "Base.Screwdriver", "Base.Sledgehammer", "Base.AxeStone", "Base.HuntingKnife", "Base.IcePick", "Base.LetterOpener", "Base.Crowbar", -- add more extra weapons as needed.... } for _, item in ipairs(DurabilityFixTable) do local scriptItem = getScriptManager():FindItem(item) if scriptItem then scriptItem:setConditionLowerChance(scriptItem:getConditionLowerChance() * 2) end end That's it! All weapons have less chance of lowering condition (effectively twice as strong), by directly manipulating the script items.
  4. sure, the HandWeapon class has a setWeaponSprite() method. One of the 'special items' for baseball bats (not in the tutorial above) is using it: { absolute = { Name = "Addy Carver's Z Whacker", WeaponSprite = "BaseballbatSpiked", }, multiplier = { CriticalChance = 4, MaxDamage = 1.5, MinDamage = 1.5, SwingTime = 0.8, MinimumSwingTime = 0.8, ConditionLowerChance = 10, Weight = 0.7, ActualWeight = 0.7, } }, Note the original item is a normal baseball bat, not a spiked version. This replaces the sprite to use the spiked variation.
  5. Display icon above player (like safetysystem skull)

    The button seems to call toggleSafetyServer Looking around in the LuaManager.GlobalObject class API, i can see a getRenderer() function. Possibly use getRenderer():render(Texture tex, float x, float y, float width, float height, float r, float g, float b, float a) or one of the variations of that method?
  6. Patch Regular Branch someday ?

    That's the hazard of developing mods for a unfinished in-development game (and why I rarely do it). Its defiantly not up to the game's devs to ensure mods work across versions. When a code change will better suit the game (performance or other usefulness), but break some mods that maybe relying on the code staying the same...well...screw the mods. If the original author is no longer willing to update the mod to ensure compatibility, and the mod is popular enough that it warrants a update, some interested party will probably be willing to pick up the torch.
  7. 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':
  8. .3f is characters after the dot .0f will give you a whole number, rounded up or down as needed Don't think PZ tracks the lunar phase at all
  9. oddly enough, lua doesn't have a simple rounding function. There might be a basic one available through PZ's java API but I'm unsure on that one. At any rate you can use: local x = 0.12345678 x = tonumber(string.format("%.3f", x)) print(x) -- prints 0.123
  10. Damn my luck!

    So here I am testing the new Profession Framework Mod and some tweaked professions..playing on Survival mode (also ORGM and the Silencers mod loaded). I decide to start as a burglar in westpoint. All loaded up with some fine trait choices (including lucky). So I'm looking through my starting house, and what do I find in my bedroom, a fully loaded Remington 870 with silencer attached! I've got a crowbar, a set of duffelbags and my new shotgun, feeling confident, time to go looting. Seems like there's a good number of Z's in the area so i thin the herd out a bit...house next door is all locked up but has a broken window, I see the zombie standing in the kitchen. So I decide to remove the broken glass and let the noise lure any Z's inside out. Go figure as I do it, a zombie jumps out of the trees next to me and gets in a scratch. So I fight them all off with my crowbar and shotgun, the last round jams and gets ejected to the ground as I rack the gun. So now I'm feeling queasy and anxious, probably infected. That bastard got me, went back to my house and picked up that jammed shotgun round from the ground on the way. I'm gonna die, and by stupid luck I still have that last round left I can use to keep myself from becoming one of them... On the upside, at least the rest of them wont hear the shot as I take my own life... Hours survived: 5, Zombies killed: 26
  11. Profession Framework Mod

    Agreed. Some of the current implementations in the base game are rather clunky. When it's a bit more refined, would you be interested in handling the steam upload? Given the nature of most of your current framework style mods, I can't really think of anyone better suited.
  12. Profession Framework Mod

    It should at some point if someone is willing to upload and maintain it there when updates come out (since I'm not a steam user). Not being on steam really limits the usefulness of such a framework. That being said, its still in a semi-testing phase, and I'd like to refine it more first, including adding error/sanity checking features and such.
  13. Profession Framework Mod

    This mod is designed to simply the process of adding new professions, or editing the default ones. As well as simplifying the addition/modification of a profession's skills, traits and known recipes, it also allows for the creation of custom profession starting kits: both items in inventory and on the ground in front of them, and running a custom OnNewGame event for each profession. The 'special effect traits' (ones that don't edit skill levels) such as brave, lucky, outdoorsman, etc can be properly used by new professions without bugs and extra coding on the modder's part. Please note this mod adds no new professions or changes itself, it is simply a framework for use by other modders. Example of a upgraded Park Ranger, starting with the outdoorsman trait, ORGM's Lee Enfield No4 (with scope and sling attached), spare ammo, a hiking bag, and a tent and campfire kit on the ground at their feet: Example of a new profession: The Military Sniper, starting with Inconspicuous, Graceful and Brave, ORGM's SR-25 (with scope and sling) and spare ammo: Example of a updated Chef, starting with a set of GOOD kitchen knives: List of all 'special effect traits' that can now be added to professions: For best use and compatibility with other profession mods that may use this framework, it is advised you don't actually include this mods lua files in your mod. Instead make it a requirement, and just call the ProfessionFramework.addProfession( ) function from your own mod. Downloads: Current Version (1.00-alpha): Direct download link coming soon Github Development Version: https://github.com/FWolfe/ProfessionsFramework
  14. it means the player variable is set to nil, not a IsoPlayer object, some line of code above your example is failing to set the variable. Within the scope (or condition in this case) function test() if true then local x = "OK" end print(tostring(x)) end x() -- prints 'nil' local is bound within any 'if' statement, as well as for/while/repeat loops, and 'do' blocks
  15. Negative Traits

    @Pann I just had a thought that's probably worth sharing... This problem can be by-passed! Taking "Lucky" as a example which we know is hardcoded in all the java and lua. Creating a second trait such as 'Lucky2' that's defined as a occupation trait, all those hardcoded checks of course won't know to look to see if the character has the new Lucky2 trait. The work around is really quite simple, I'm surprised I didn't think of it sooner. Events.OnNewGame.Add(function(player, square) if player:hasTrait("Lucky2") then player:getTraits():remove("Lucky2") player:getTraits():add("Lucky") end end)