1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"todo-tree.tree.scanMode": "workspace",
|
||||
"mod_id": "3236152598",
|
||||
"zomboid_user_folder": "C:/Users/picch/Zomboid",
|
||||
"zomboid_folder": "E:\\Steam\\steamapps\\common\\ProjectZomboid",
|
||||
"zomboid_server_folder": "E:\\Steam\\steamapps\\common\\Project Zomboid Dedicated Server",
|
||||
|
||||
15
.vscode/tasks.json
vendored
15
.vscode/tasks.json
vendored
@@ -9,6 +9,12 @@
|
||||
"options": {"statusbar": {"label": "$(combine) Assemble Mod"}},
|
||||
"command": "python ${config:zomboid_user_folder}/PaosCrap/make_workshop_pack.py picch ${workspaceFolderBasename}",
|
||||
},
|
||||
{
|
||||
"label": "Upload mod",
|
||||
"type": "shell",
|
||||
"options": {"statusbar": {"label": "$(arrow-up) Upload Mod"}},
|
||||
"command": "python ${config:zomboid_user_folder}/PaosCrap/upload_mod_to_steam/main.py ${config:mod_id} ${config:zomboid_user_folder}/Workshop/${workspaceFolderBasename}",
|
||||
},
|
||||
{
|
||||
"label": "Run Zomboid Debug No Steam",
|
||||
"type": "shell",
|
||||
@@ -59,6 +65,15 @@
|
||||
"problemMatcher": [
|
||||
"$eslint-stylish"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Run Zomboid Test Server 3",
|
||||
"options": {"statusbar": {"label": "$(run) Zomboid Server (TOC+FH+BH+iMedsFixed)"}},
|
||||
"type": "shell",
|
||||
"command":"\"${config:zomboid_server_folder}\\StartServer64_nosteam_custom.bat\" TOC_FH_BH_imeds",
|
||||
"problemMatcher": [
|
||||
"$eslint-stylish"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,39 +1,75 @@
|
||||
|
||||
---@class Compat
|
||||
---@field handlers table<string, {fun : function, isActive : boolean}>
|
||||
local Compat = {
|
||||
handlers = {}
|
||||
}
|
||||
|
||||
local function HandleModCompatibility()
|
||||
--- Brutal hands has a TOC_COMPAT but its check is wrong and uses an old API.
|
||||
function Compat.BrutalHandwork()
|
||||
BrutalHands = BrutalHands or {}
|
||||
BrutalHands.TOC = require("TOC/API")
|
||||
|
||||
end
|
||||
|
||||
|
||||
local activatedMods = getActivatedMods()
|
||||
TOC_DEBUG.print("Checking for mods compatibility")
|
||||
|
||||
--[[
|
||||
Brutal hands has a TOC_COMPAT but its check is wrong and uses an old API.
|
||||
]]
|
||||
if activatedMods:contains('BrutalHandwork') then
|
||||
TOC_DEBUG.print("found BrutalHandwork, activating compat module")
|
||||
BrutalHands = BrutalHands or {}
|
||||
BrutalHands.TOC = require("TOC/API")
|
||||
end
|
||||
|
||||
--[[
|
||||
Was handled inside old TOC
|
||||
]]
|
||||
if activatedMods:contains('FancyHandwork') then
|
||||
TOC_DEBUG.print("found FancyHandwork, activating compat module")
|
||||
|
||||
require("TimedActions/FHSwapHandsAction")
|
||||
local og_FHSwapHandsAction_isValid = FHSwapHandsAction.isValid
|
||||
function FHSwapHandsAction:isValid()
|
||||
local tocApi = require("TOC/API")
|
||||
if tocApi.hasBothHands(self.character) then
|
||||
return og_FHSwapHandsAction_isValid(self)
|
||||
else
|
||||
return false
|
||||
end
|
||||
--- Was handled inside old TOC
|
||||
function Compat.FancyHandwork()
|
||||
require("TimedActions/FHSwapHandsAction")
|
||||
local og_FHSwapHandsAction_isValid = FHSwapHandsAction.isValid
|
||||
function FHSwapHandsAction:isValid()
|
||||
local tocApi = require("TOC/API")
|
||||
if tocApi.hasBothHands(self.character) then
|
||||
return og_FHSwapHandsAction_isValid(self)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnGameStart.Add(HandleModCompatibility)
|
||||
|
||||
function Compat.iMeds()
|
||||
require("Component/Interface/Service/ContextMenu/Menu/HealthPanel/HealthPanelMenuInitializer")
|
||||
-- placeholder, in case we need to do something more drastic with it.
|
||||
end
|
||||
|
||||
|
||||
------------------------------
|
||||
|
||||
Compat.handlers = {
|
||||
["BrutalHandwork"] = {
|
||||
fun = Compat.BrutalHandwork,
|
||||
isActive = false},
|
||||
["FancyHandwork"] = {
|
||||
fun = Compat.FancyHandwork,
|
||||
isActive = false},
|
||||
|
||||
-- either or
|
||||
['iMeds'] = {
|
||||
fun = Compat.iMeds,
|
||||
isActive = false},
|
||||
['iMedsFixed'] = {
|
||||
fun = Compat.iMeds,
|
||||
isActive = false}
|
||||
}
|
||||
|
||||
|
||||
function Compat.RunModCompatibility()
|
||||
local activatedMods = getActivatedMods()
|
||||
TOC_DEBUG.print("Checking for mods compatibility")
|
||||
|
||||
for k, modCompatHandler in pairs(Compat.handlers) do
|
||||
if activatedMods:contains(k) then
|
||||
TOC_DEBUG.print("Found " .. k .. ", running compatibility handler")
|
||||
modCompatHandler.fun()
|
||||
modCompatHandler.isActive = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
Events.OnGameStart.Add(Compat.RunModCompatibility)
|
||||
|
||||
return Compat
|
||||
@@ -6,7 +6,7 @@ require("TOC/Events")
|
||||
|
||||
---@class Main
|
||||
local Main = {
|
||||
_version = "2.0.15"
|
||||
_version = "2.1"
|
||||
}
|
||||
|
||||
function Main.Start()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
local Compat = require("TOC/Compat")
|
||||
|
||||
local CutLimbInteractionHandler = require("TOC/UI/Interactions/CutLimbInteractionHandler")
|
||||
local WoundCleaningInteractionHandler = require("TOC/UI/Interactions/WoundCleaningInteractionHandler")
|
||||
@@ -11,6 +11,9 @@ local WoundCleaningInteractionHandler = require("TOC/UI/Interactions/WoundCleani
|
||||
local isReady = false
|
||||
|
||||
function SetHealthPanelTOC()
|
||||
|
||||
-- depending on compatibility
|
||||
|
||||
isReady = true
|
||||
end
|
||||
|
||||
@@ -128,23 +131,23 @@ function ISHealthPanel:render()
|
||||
end
|
||||
|
||||
|
||||
local og_ISHealthPanel_update = ISHealthPanel.update
|
||||
function ISHealthPanel:update()
|
||||
og_ISHealthPanel_update(self)
|
||||
-- TODO Listen for changes on other player side instead of looping this
|
||||
-- local og_ISHealthPanel_update = ISHealthPanel.update
|
||||
-- function ISHealthPanel:update()
|
||||
-- og_ISHealthPanel_update(self)
|
||||
-- -- TODO Listen for changes on other player side instead of looping this
|
||||
|
||||
|
||||
-- FIX Re-enable it, just for test
|
||||
if self.character then
|
||||
local locPlUsername = getPlayer():getUsername()
|
||||
local remPlUsername = self.character:getUsername()
|
||||
if locPlUsername ~= remPlUsername and self:isReallyVisible() then
|
||||
-- Request update for TOC DATA
|
||||
local key = CommandsData.GetKey(remPlUsername)
|
||||
--ModData.request(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- -- FIX Re-enable it, just for test
|
||||
-- if self.character then
|
||||
-- local locPlUsername = getPlayer():getUsername()
|
||||
-- local remPlUsername = self.character:getUsername()
|
||||
-- if locPlUsername ~= remPlUsername and self:isReallyVisible() then
|
||||
-- -- Request update for TOC DATA
|
||||
-- local key = CommandsData.GetKey(remPlUsername)
|
||||
-- --ModData.request(key)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
|
||||
|
||||
@@ -252,10 +255,10 @@ end
|
||||
|
||||
local og_ISHealthPanel_getDamagedParts = ISHealthPanel.getDamagedParts
|
||||
function ISHealthPanel:getDamagedParts()
|
||||
-- TODO Overriding it is a lot easier, but ew
|
||||
|
||||
if isReady then
|
||||
|
||||
-- check for imeds or if TOC is ready to display its stuff on the health panel
|
||||
if isReady == false or Compat.handlers['iMeds'].isActive or Compat.handlers['iMedsFixed'].isActive then
|
||||
return og_ISHealthPanel_getDamagedParts(self)
|
||||
elseif isReady then
|
||||
local result = {}
|
||||
local bodyParts = self:getPatient():getBodyDamage():getBodyParts()
|
||||
if isClient() and not self:getPatient():isLocalPlayer() then
|
||||
@@ -274,8 +277,5 @@ function ISHealthPanel:getDamagedParts()
|
||||
end
|
||||
end
|
||||
return result
|
||||
|
||||
else
|
||||
return og_ISHealthPanel_getDamagedParts(self)
|
||||
end
|
||||
end
|
||||
@@ -1,151 +1,148 @@
|
||||
-- todo activate after some more testing
|
||||
|
||||
if not SandboxVars.TOC.EnableZombieAmputations then return end
|
||||
|
||||
require "lua_timers"
|
||||
|
||||
local ItemsController = require("TOC/Controllers/ItemsController")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
-------------------------------
|
||||
|
||||
---@param zombie IsoZombie|IsoGameCharacter|IsoMovingObject|IsoObject
|
||||
---@return integer trueID
|
||||
local function GetZombieID(zombie)
|
||||
-- Big love to Chuck and Sir Doggy Jvla for this code
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local pID = zombie:getPersistentOutfitID()
|
||||
local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "")
|
||||
while #bits < 16 do bits[#bits + 1] = 0 end
|
||||
|
||||
-- trueID
|
||||
bits[16] = 0
|
||||
local trueID = Long.parseUnsignedLong(string.reverse(table.concat(bits, "")), 2)
|
||||
|
||||
return trueID
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
|
||||
|
||||
-- local ItemsController = require("TOC/Controllers/ItemsController")
|
||||
-- local StaticData = require("TOC/StaticData")
|
||||
-- local CommandsData = require("TOC/CommandsData")
|
||||
-- -------------------------------
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItems(item)
|
||||
return item:getType():contains("Amputation_")
|
||||
end
|
||||
|
||||
-- ---@param item InventoryItem
|
||||
-- local function PredicateAmputationItems(item)
|
||||
-- return item:getType():contains("Amputation_")
|
||||
-- end
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItemLeft(item)
|
||||
return item:getType():contains("Amputation_") and item:getType():contains("_L")
|
||||
end
|
||||
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItemRight(item)
|
||||
return item:getType():contains("Amputation_") and item:getType():contains("_R")
|
||||
end
|
||||
|
||||
---@param zombie IsoZombie
|
||||
local function SpawnAmputation(zombie, side)
|
||||
local index = ZombRand(1, #StaticData.PARTS_STR)
|
||||
local limb = StaticData.PARTS_STR[index] .. "_" .. side
|
||||
local amputationFullType = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limb
|
||||
|
||||
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
|
||||
|
||||
|
||||
-- Add reference and transmit it to server
|
||||
local pID = GetZombieID(zombie)
|
||||
local zombieKey = CommandsData.GetZombieKey()
|
||||
local zombiesMD = ModData.getOrCreate(zombieKey)
|
||||
if zombiesMD[pID] == nil then zombiesMD[pID] = {} end
|
||||
zombiesMD[pID][side] = amputationFullType
|
||||
ModData.add(zombieKey, zombiesMD)
|
||||
ModData.transmit(zombieKey)
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
|
||||
|
||||
|
||||
-- local function PredicateAmputationItemLeft(item)
|
||||
-- return item:getType():contains("Amputation_") and item:getType():contains("_L")
|
||||
-- end
|
||||
|
||||
-- local function PredicateAmputationItemRight(item)
|
||||
-- return item:getType():contains("Amputation_") and item:getType():contains("_R")
|
||||
-- end
|
||||
|
||||
-- ---@param zombie IsoZombie|IsoGameCharacter|IsoMovingObject|IsoObject
|
||||
-- ---@return integer trueID
|
||||
-- local function GetZombieID(zombie)
|
||||
|
||||
-- -- Big love to Chuck and Sir Doggy Jvla for this code
|
||||
-- ---@diagnostic disable-next-line: param-type-mismatch
|
||||
-- local pID = zombie:getPersistentOutfitID()
|
||||
-- local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "")
|
||||
-- while #bits < 16 do bits[#bits+1] = 0 end
|
||||
|
||||
-- -- trueID
|
||||
-- bits[16] = 0
|
||||
-- local trueID = Long.parseUnsignedLong(string.reverse(table.concat(bits, "")), 2)
|
||||
|
||||
-- return trueID
|
||||
-- end
|
||||
local bloodAmount = 10
|
||||
|
||||
|
||||
-- ---@param zombie IsoZombie
|
||||
-- local function SpawnAmputation(zombie, side)
|
||||
-- local index = ZombRand(1, #StaticData.PARTS_STR)
|
||||
-- local limb = StaticData.PARTS_STR[index] .. "_" .. side
|
||||
-- local amputationFullType = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limb
|
||||
---@param player IsoGameCharacter
|
||||
---@param zombie IsoZombie
|
||||
---@param handWeapon HandWeapon
|
||||
local function HandleZombiesAmputations(player, zombie, handWeapon, damage)
|
||||
if not instanceof(zombie, "IsoZombie") or not instanceof(player, "IsoPlayer") then return end
|
||||
if player ~= getPlayer() then return end
|
||||
|
||||
-- Check type of weapon. No hands, only knifes or such
|
||||
local weaponCategories = handWeapon:getScriptItem():getCategories()
|
||||
if not (weaponCategories:contains("Axe") or weaponCategories:contains("LongBlade")) then return end
|
||||
|
||||
local isCrit = player:isCriticalHit()
|
||||
local randomChance = ZombRand(0, 100) > (100 - SandboxVars.TOC.ZombieAmputationDamageChance)
|
||||
if (damage > SandboxVars.TOC.ZombieAmputationDamageThreshold and randomChance) or isCrit then
|
||||
TOC_DEBUG.print("Amputating zombie limbs - damage: " .. tostring(damage))
|
||||
local zombieInv = zombie:getInventory()
|
||||
-- Check left or right
|
||||
if not zombieInv:containsEval(PredicateAmputationItemLeft) then
|
||||
SpawnAmputation(zombie, "L")
|
||||
elseif not zombieInv:containsEval(PredicateAmputationItemRight) then
|
||||
SpawnAmputation(zombie, "R")
|
||||
end
|
||||
|
||||
|
||||
-- ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
|
||||
-- add blood splat every couple of seconds for a while
|
||||
addBloodSplat(getCell():getGridSquare(zombie:getX(), zombie:getY(), zombie:getZ()), bloodAmount)
|
||||
local timerName = tostring(GetZombieID(zombie)) .. "_timer"
|
||||
timer:Create(timerName, 1, 10, function()
|
||||
addBloodSplat(getCell():getGridSquare(zombie:getX(), zombie:getY(), zombie:getZ()), bloodAmount)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnWeaponHitCharacter.Add(HandleZombiesAmputations)
|
||||
|
||||
-----------------------------
|
||||
|
||||
local localOnlyZombiesMD
|
||||
|
||||
local function SetupZombiesModData()
|
||||
local zombieKey = CommandsData.GetZombieKey()
|
||||
localOnlyZombiesMD = ModData.getOrCreate(zombieKey)
|
||||
end
|
||||
|
||||
Events.OnInitGlobalModData.Add(SetupZombiesModData)
|
||||
|
||||
|
||||
-- -- Add reference and transmit it to server
|
||||
-- local pID = GetZombieID(zombie)
|
||||
-- local zombieKey = CommandsData.GetZombieKey()
|
||||
-- local zombiesMD = ModData.getOrCreate(zombieKey)
|
||||
-- if zombiesMD[pID] == nil then zombiesMD[pID] = {} end
|
||||
-- zombiesMD[pID][side] = amputationFullType
|
||||
-- ModData.add(zombieKey, zombiesMD)
|
||||
-- ModData.transmit(zombieKey)
|
||||
-- end
|
||||
|
||||
-- -------------------------------
|
||||
|
||||
-- ---@param player IsoGameCharacter
|
||||
-- ---@param zombie IsoZombie
|
||||
-- ---@param handWeapon HandWeapon
|
||||
-- function HandleZombiesAmputations(player, zombie, handWeapon, damage)
|
||||
-- if not instanceof(zombie, "IsoZombie") or not instanceof(player, "IsoPlayer") then return end
|
||||
-- if player ~= getPlayer() then return end
|
||||
|
||||
-- -- TODO Check type of weapon. No hands, only knifes or such
|
||||
|
||||
|
||||
|
||||
-- if damage < 3 or ZombRand(0,100) < 25 then return end
|
||||
|
||||
-- TOC_DEBUG.print(handWeapon:getName())
|
||||
|
||||
|
||||
-- local zombieInv = zombie:getInventory()
|
||||
|
||||
|
||||
-- -- Check left or right
|
||||
-- local leftItem = zombieInv:containsEval(PredicateAmputationItemLeft)
|
||||
|
||||
-- if not leftItem then
|
||||
-- SpawnAmputation(zombie, "L")
|
||||
-- return
|
||||
-- end
|
||||
|
||||
|
||||
-- local rightItem = zombieInv:containsEval(PredicateAmputationItemRight)
|
||||
-- if not rightItem then
|
||||
-- SpawnAmputation(zombie, "R")
|
||||
-- return
|
||||
-- end
|
||||
-- end
|
||||
|
||||
|
||||
-- Events.OnWeaponHitCharacter.Add(HandleZombiesAmputations)
|
||||
|
||||
-- -----------------------------
|
||||
|
||||
-- local localOnlyZombiesMD
|
||||
|
||||
-- local function SetupZombiesModData()
|
||||
-- local zombieKey = CommandsData.GetZombieKey()
|
||||
-- localOnlyZombiesMD = ModData.getOrCreate(zombieKey)
|
||||
|
||||
-- end
|
||||
|
||||
-- Events.OnInitGlobalModData.Add(SetupZombiesModData)
|
||||
|
||||
|
||||
|
||||
|
||||
-- ---@param zombie IsoZombie
|
||||
-- local function ReapplyAmputation(zombie)
|
||||
-- local pID = GetZombieID(zombie)
|
||||
|
||||
-- if localOnlyZombiesMD[pID] ~= nil then
|
||||
-- -- check if zombie has amputation
|
||||
-- local zombiesAmpData = localOnlyZombiesMD[pID]
|
||||
-- local zombieInv = zombie:getInventory()
|
||||
-- local foundItem = zombieInv:containsEvalRecurse(PredicateAmputationItems)
|
||||
|
||||
-- if foundItem then
|
||||
-- return
|
||||
-- else
|
||||
-- local leftAmp = zombiesAmpData['L']
|
||||
-- if leftAmp then
|
||||
-- ItemsController.Zombie.SpawnAmputationItem(zombie, leftAmp)
|
||||
-- end
|
||||
|
||||
-- local rightAmp = zombiesAmpData['R']
|
||||
-- if rightAmp then
|
||||
-- ItemsController.Zombie.SpawnAmputationItem(zombie, rightAmp)
|
||||
-- end
|
||||
|
||||
-- -- Removes reference, local only
|
||||
-- localOnlyZombiesMD[pID] = nil
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- Events.OnZombieUpdate.Add(ReapplyAmputation)
|
||||
---@param zombie IsoZombie
|
||||
local function ReapplyAmputation(zombie)
|
||||
local pID = GetZombieID(zombie)
|
||||
|
||||
if localOnlyZombiesMD[pID] ~= nil then
|
||||
-- check if zombie has amputation
|
||||
local zombiesAmpData = localOnlyZombiesMD[pID]
|
||||
local zombieInv = zombie:getInventory()
|
||||
local foundItem = zombieInv:containsEvalRecurse(PredicateAmputationItems)
|
||||
|
||||
if foundItem then
|
||||
return
|
||||
else
|
||||
local leftAmp = zombiesAmpData['L']
|
||||
if leftAmp then
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, leftAmp)
|
||||
end
|
||||
|
||||
local rightAmp = zombiesAmpData['R']
|
||||
if rightAmp then
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, rightAmp)
|
||||
end
|
||||
|
||||
-- Removes reference, local only
|
||||
localOnlyZombiesMD[pID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnZombieUpdate.Add(ReapplyAmputation)
|
||||
|
||||
216
media/lua/client/lua_timers.lua
Normal file
216
media/lua/client/lua_timers.lua
Normal file
@@ -0,0 +1,216 @@
|
||||
-- Made by Vyshnia
|
||||
-- Workshop ID: 2875394066
|
||||
-- Mod ID: LuaTimers
|
||||
|
||||
local os_time = os.time
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
local assert = assert
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
|
||||
timer = {
|
||||
Timers = {},
|
||||
SimpleTimers = {}
|
||||
}
|
||||
|
||||
function timer:Simple(delay, func)
|
||||
|
||||
assert(type(delay) == "number", "Delay of timer should be a number type")
|
||||
assert(type(func) == "function", "Func of timer should be a function type (lol)")
|
||||
|
||||
table_insert(self.SimpleTimers, {
|
||||
EndTime = os_time() + delay,
|
||||
Func = func
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
function timer:Create(name, delay, repetitions, func)
|
||||
|
||||
assert(type(name) == "string", "ID of timer should be a string type")
|
||||
assert(type(delay) == "number", "Delay of timer should be a number type")
|
||||
assert(type(repetitions) == "number", "Repetitions of timer should be a number type")
|
||||
assert(type(func) == "function", "Func of timer should be a function type (lol)")
|
||||
|
||||
self.Timers[name] = {
|
||||
Delay = delay,
|
||||
StartRepetitions = repetitions,
|
||||
Repetitions = repetitions,
|
||||
Infinity = repetitions == 0,
|
||||
LastFuncTime = os_time(),
|
||||
Func = func,
|
||||
Paused = false,
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
local function timerUpdate()
|
||||
|
||||
local cur_time = os_time()
|
||||
|
||||
for k,v in pairs(timer.Timers) do
|
||||
|
||||
if not v.Paused then
|
||||
|
||||
if cur_time >= v.LastFuncTime + v.Delay then
|
||||
|
||||
v.Func()
|
||||
|
||||
v.LastFuncTime = cur_time
|
||||
|
||||
if not v.Infinity then
|
||||
|
||||
v.Repetitions = v.Repetitions - 1
|
||||
|
||||
if v.Repetitions <= 0 then
|
||||
|
||||
timer.Timers[k] = nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local simple_timers = timer.SimpleTimers
|
||||
|
||||
for i = #simple_timers, 1, -1 do
|
||||
|
||||
local t = simple_timers[i]
|
||||
|
||||
if t.EndTime <= cur_time then
|
||||
|
||||
t.Func()
|
||||
|
||||
table_remove(simple_timers, i)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
Events.OnTickEvenPaused.Add(timerUpdate)
|
||||
|
||||
function timer:Remove(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
self.Timers[name] = nil
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function timer:Exists(name)
|
||||
|
||||
return self.Timers[name] and true or false
|
||||
|
||||
end
|
||||
|
||||
function timer:Start(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
t.Repetitions = t.StartRepetitions
|
||||
t.LastFuncTime = os_time()
|
||||
t.Paused = false
|
||||
t.PausedTime = nil
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function timer:Pause(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
if t.Paused then return false end
|
||||
|
||||
t.Paused = true
|
||||
t.PausedTime = os_time()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function timer:UnPause(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
if not t.Paused then return false end
|
||||
|
||||
t.Paused = false
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
timer.Resume = timer.UnPause
|
||||
|
||||
function timer:Toggle(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
t.Paused = not t.Paused
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function timer:TimeLeft(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return end
|
||||
|
||||
if t.Paused then
|
||||
|
||||
return (t.Repetitions - 1) * t.Delay + (t.LastFuncTime + t.Delay - t.PausedTime)
|
||||
|
||||
else
|
||||
|
||||
return (t.Repetitions - 1) * t.Delay + (t.LastFuncTime + t.Delay - os_time())
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function timer:NextTimeLeft(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return end
|
||||
|
||||
if t.Paused then
|
||||
|
||||
return t.LastFuncTime + t.Delay - t.PausedTime
|
||||
|
||||
else
|
||||
|
||||
return t.LastFuncTime + t.Delay - os_time()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function timer:RepsLeft(name)
|
||||
|
||||
local t = self.Timers[name]
|
||||
|
||||
return t and t.Repetitions
|
||||
|
||||
end
|
||||
@@ -3,14 +3,9 @@ local StaticData = require("TOC/StaticData")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local ServerDataHandler = {}
|
||||
ServerDataHandler.modData = {}
|
||||
|
||||
|
||||
---Get the server mod data table containing that player TOC data
|
||||
---@param key string
|
||||
---@return tocModDataType
|
||||
|
||||
@@ -3,5 +3,8 @@ Sandbox_EN = {
|
||||
Sandbox_TOC_CicatrizationSpeed = "Cicatrization Speed",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Wound Dirtyness Multiplier",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Relevance of surgeon doctor ability",
|
||||
Sandbox_TOC_EnableZombieAmputations = "Enable Zombie amputations",
|
||||
Sandbox_TOC_ZombieAmputationDamageThreshold = "Zombie amputations damage treshold",
|
||||
Sandbox_TOC_ZombieAmputationDamageChance = "Zombie amputations damage chance",
|
||||
|
||||
}
|
||||
@@ -28,3 +28,31 @@ option TOC.SurgeonAbilityImportance
|
||||
translation = TOC_SurgeonAbilityImportance,
|
||||
}
|
||||
|
||||
option TOC.EnableZombieAmputations
|
||||
{
|
||||
type = boolean,
|
||||
default = false,
|
||||
page = TOC,
|
||||
translation= TOC_EnableZombieAmputations,
|
||||
}
|
||||
|
||||
|
||||
option TOC.ZombieAmputationDamageThreshold
|
||||
{
|
||||
type = integer,
|
||||
min = 0,
|
||||
max = 10,
|
||||
default = 4,
|
||||
page = TOC,
|
||||
translation = TOC_ZombieAmputationDamageThreshold,
|
||||
}
|
||||
|
||||
option TOC.ZombieAmputationDamageChance
|
||||
{
|
||||
type = integer,
|
||||
min = 0,
|
||||
max = 100,
|
||||
default = 25,
|
||||
page = TOC,
|
||||
translation = TOC_ZombieAmputationDamageChance,
|
||||
}
|
||||
2
mod.info
2
mod.info
@@ -4,5 +4,5 @@ description=You've been bitten. You have only two choices.
|
||||
id=TheOnlyCure
|
||||
icon=icon.png
|
||||
url=https://github.com/ZioPao/The-Only-Cure
|
||||
modversion=2.0.15
|
||||
modversion=2.1
|
||||
pzversion=41.65
|
||||
|
||||
147
workshop.txt
147
workshop.txt
@@ -1,147 +0,0 @@
|
||||
version=1
|
||||
id=3236152598
|
||||
title=The Only Cure - Rebuilt
|
||||
description=[img]https://raw.githubusercontent.com/ZioPao/The-Only-Cure/551125bb50cb65608ad89ca81ef0daccb3b02c4c/dev_stuff/logos/title.png[/img]
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]You're bitten. You have two choices.[/h1]
|
||||
|
||||
description=Wait until you succumb to the virus or take matters into your hands.
|
||||
|
||||
description=
|
||||
|
||||
description=This version of [b]The Only Cure[/b] has been rebuilt from scratch to support future additions.
|
||||
|
||||
description=
|
||||
|
||||
description=Supports [b]Single Player[/b] and [b]Multiplayer[/b]!
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]Setup[/h1]
|
||||
|
||||
description=Use it with the following mods for the intended experience:
|
||||
|
||||
description=[list]
|
||||
|
||||
description=[*] [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2904920097]Fancy Handwork[/url]
|
||||
|
||||
description=[*] [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2934621024]Brutal Handwork[/url]
|
||||
|
||||
description=[/list]
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]Quick guide[/h1]
|
||||
|
||||
description=[h2]Amputation[/h2]
|
||||
|
||||
description=Get a [i]Saw[/i] or a [i]Garden Saw[/i], right click on it, and choose which limb to amputate. You can also drag n' drop your Saw item directly into the afflicted area to start cutting it off.
|
||||
|
||||
description=
|
||||
|
||||
description=If you have a tourniquet, place it on the correct side to dampen the amount of damage you will take after you're done amputating the limb.
|
||||
|
||||
description=
|
||||
|
||||
description=Keep in mind that if you amputate your upper arm, you won't be able to equip any prosthesis.
|
||||
|
||||
description=
|
||||
|
||||
description=[h2]Cicatrization[/h2]
|
||||
|
||||
description=You can check the cicatrization status of an amputated limb from your [b]Health Panel[/b]
|
||||
|
||||
description=From time to time, you should clean your wounds with a bandage to help the cicatrization process.
|
||||
|
||||
description=If your limb isn't completely cicatrized, you can still equip prosthetic limbs, but that can trigger random bleedings from that area.
|
||||
|
||||
description=
|
||||
|
||||
description=[h2]Prosthesis[/h2]
|
||||
|
||||
description=If you're missing a hand, you won't be able to do a lot of things, such as equipping two-handed weapons. With prosthetics limbs, you can fix that.
|
||||
|
||||
description=There are two prosthesis type that can be crafted\found in medical areas:
|
||||
|
||||
description=[list]
|
||||
|
||||
description=[*] Hook Prosthesis
|
||||
|
||||
description=[*] Arm Prosthesis
|
||||
|
||||
description=[/list]
|
||||
|
||||
description=
|
||||
|
||||
description=The main difference between the twos is that your actions will take longer with the Hook Prosthesis.
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]Issues[/h1]
|
||||
|
||||
description=Got any issues? Report them on GitHub!
|
||||
|
||||
description=[url=https://github.com/ZioPao/The-Only-Cure][img]https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white[/img][/url]
|
||||
|
||||
description=
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]Credits[/h1]
|
||||
|
||||
description=
|
||||
|
||||
description=[table]
|
||||
|
||||
description= [tr]
|
||||
|
||||
description= [th]Pao[/th]
|
||||
|
||||
description= [th]Developer[/th]
|
||||
|
||||
description= [/tr]
|
||||
|
||||
description= [tr]
|
||||
|
||||
description= [th]Mr. Bounty[/th]
|
||||
|
||||
description= [th]Original Developer[/th]
|
||||
|
||||
description= [/tr]
|
||||
|
||||
description= [tr]
|
||||
|
||||
description= [th]Chuckleberry Finn[/th]
|
||||
|
||||
description= [th]Logo and Icon[/th]
|
||||
|
||||
description= [/tr]
|
||||
|
||||
description= [tr]
|
||||
|
||||
description= [th]dhert[/th]
|
||||
|
||||
description= [th]Compatibility API[/th]
|
||||
|
||||
description= [/tr]
|
||||
|
||||
description=[/table]
|
||||
|
||||
description=
|
||||
|
||||
description=[hr]
|
||||
|
||||
description=
|
||||
|
||||
description=[h1]Want to support me?[/h1]
|
||||
|
||||
description=[url=https://ko-fi.com/M4M7IERNW][img]https://storage.ko-fi.com/cdn/kofi3.png[/img][/url]
|
||||
|
||||
description=
|
||||
|
||||
description=[hr]
|
||||
|
||||
tags=Build 41;Balance;Interface;Items;Misc;Multiplayer;Realistic;Textures
|
||||
visibility=private
|
||||
@@ -159,7 +159,7 @@ description= [/tr]
|
||||
|
||||
description= [tr]
|
||||
|
||||
description= [th]JCloudJalix, Rinary1[/th]
|
||||
description= [th]JCloudJalix, Rinary1, pllq, ttaeo[/th]
|
||||
|
||||
description= [th]Translations[/th]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user