diff --git a/media/lua/client/TOC/Controllers/DataController.lua b/media/lua/client/TOC/Controllers/DataController.lua index 892ac33..9a5a8a8 100644 --- a/media/lua/client/TOC/Controllers/DataController.lua +++ b/media/lua/client/TOC/Controllers/DataController.lua @@ -25,24 +25,18 @@ function DataController:new(username, isResetForced) self.__index = self o.username = username - local key = CommandsData.GetKey(username) + o.isResetForced = isResetForced + o.isDataReady = false - -- We don't want to request ModData if we're in SP, or if we're forcing a reset - if isClient() and not isResetForced then - ModData.request(key) - o.isResetForced = isResetForced - o.isDataReady = false - elseif isResetForced then - self:setup(key) - o.isResetForced = false - o.isDataReady = true - end + local key = CommandsData.GetKey(username) + ModData.request(key) DataController.instances[username] = o return o end + ---Setup a new toc mod data data class ---@param key string function DataController:setup(key) @@ -87,19 +81,34 @@ end ---In case of desync between the table on ModData and the table here ---@param tocData tocModDataType -function DataController:reapplyTocData(tocData) +function DataController:applyOnlineData(tocData) local key = CommandsData.GetKey(self.username) ModData.add(key, tocData) self.tocData = ModData.get(key) end +---@param key string +function DataController:loadLocalData(key) + self.tocData = ModData.get(key) + if self.tocData ~= nil and self.tocData ~= {} then + TOC_DEBUG.print("Found and loaded local data") + else + error("Local data failed to load!") + end +end ----------------- --* Setters *-- +---@param isDataReady boolean function DataController:setIsDataReady(isDataReady) self.isDataReady = isDataReady end +---@param isResetForced boolean +function DataController:setIsResetForced(isResetForced) + self.isResetForced = isResetForced +end + ---Set a generic boolean that toggles varies function of the mod ---@param isAnyLimbCut boolean function DataController:setIsAnyLimbCut(isAnyLimbCut) @@ -320,9 +329,6 @@ function DataController:apply() end function DataController.ReceiveData(key, data) - if not isClient() then - TOC_DEBUG.print("SP, skipping DataController.ReceiveData") - end -- During startup the game can return Bob as the player username, adding a useless ModData table if key == "TOC_Bob" then return end @@ -335,31 +341,30 @@ function DataController.ReceiveData(key, data) -- Get DataController instance if there was none for that user and reapply the correct ModData table as a reference local username = key:sub(5) local handler = DataController.GetInstance(username) - if handler.isResetForced or data == nil or data == {} or data == false then - TOC_DEBUG.print("Setup") - handler:setup(key) - handler.isResetForced = false + + -- Bit of a workaround, but in a perfect world, I'd use the server to get the data and that would be it. + -- but Zomboid Mod Data handling is too finnicky at best to be that reliable, in case of an unwanted disconnection and what not, + -- so for now, I'm gonna assume that the local data (for the local client) is the + -- most recent (and correct) one instead of trying to fetch it from the server every single time + if isClient() then + if handler.isResetForced or data == nil or data == {} or data == false then + handler:setup(key) + elseif username == getPlayer():getUsername() then + handler:loadLocalData(key) + else + handler:applyOnlineData(data) + end else - TOC_DEBUG.print("Reapply") - handler:reapplyTocData(data) + handler:loadLocalData(key) end - - -- if handler.isResetForced or handler.tocData == nil or handler.tocData.limbs == nil or handler.tocData.limbs.Hand_L == nil or handler.tocData.limbs.Hand_L.isCut == nil then - -- TOC_DEBUG.print("tocData in DataController for " .. handler.username .. " is nil, creating it now") - -- handler:setup(key) - -- handler.isResetForced = false - -- elseif table then - -- TOC_DEBUG.print("Reapply toc data for " .. handler.username) - -- handler:reapplyTocData(table) - -- end - + handler.isResetForced = false -- TODO Add a setter handler:setIsDataReady(true) -- Event triggerEvent("OnReceivedTocData", handler.username) - -- Transmit it to the server + -- Transmit it back to the server ModData.transmit(key) TOC_DEBUG.print("Transmitting data after receiving it for: " .. handler.username) diff --git a/media/lua/client/TOC/Controllers/LimitActionsController.lua b/media/lua/client/TOC/Controllers/LimitActionsController.lua index b14e3e5..f5a6034 100644 --- a/media/lua/client/TOC/Controllers/LimitActionsController.lua +++ b/media/lua/client/TOC/Controllers/LimitActionsController.lua @@ -1,20 +1,26 @@ +local LocalPlayerController = require("TOC/Controllers/LocalPlayerController") local DataController = require("TOC/Controllers/DataController") + local CachedDataHandler = require("TOC/Handlers/CachedDataHandler") local CommonMethods = require("TOC/CommonMethods") local StaticData = require("TOC/StaticData") ----------------- + +--* TIMED ACTIONS *-- +-- We want to be able to modify how long actions are gonna take, +-- depending on amputation status and kind of action. Also, when the +-- player has not completely cicatrized their own wounds, and try to do any action with +-- a prosthesis on, that can trigger random bleeds. + local function CheckHandFeasibility(limbName) local dcInst = DataController.GetInstance() - return not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(StaticData.LIMBS_TO_PROST_GROUP_MATCH_IND_STR[limbName]) end - --* Time to perform actions overrides *-- - local og_ISBaseTimedAction_adjustMaxTime = ISBaseTimedAction.adjustMaxTime --- Adjust time ---@diagnostic disable-next-line: duplicate-set-field @@ -71,12 +77,17 @@ function ISBaseTimedAction:perform() end end ---* Equipping items overrides *-- +--* EQUIPPING ITEMS *-- +-- Check wheter the player can equip items or not, for example dual wielding when you only have one +-- hand (and no prosthesis) should be disabled. Same thing for some werable items, like watches. + +---@class ISEquipWeaponAction +---@field character IsoPlayer local primaryHand = StaticData.PARTS_IND_STR.Hand .. "_" .. StaticData.SIDES_IND_STR.R local secondaryHand = StaticData.PARTS_IND_STR.Hand .. "_" .. StaticData.SIDES_IND_STR.L - +--* Equipping items overrides *-- local og_ISEquipWeaponAction_isValid = ISEquipWeaponAction.isValid ---Add a condition to check the feasibility of having 2 handed weapons or if both arms are cut off ---@return boolean @@ -95,9 +106,6 @@ function ISEquipWeaponAction:isValid() return isValid end ----@class ISEquipWeaponAction ----@field character IsoPlayer - ---A recreation of the original method, but with amputations in mind ---@param dcInst DataController function ISEquipWeaponAction:performWithAmputation(dcInst) @@ -173,7 +181,6 @@ function ISEquipWeaponAction:performWithAmputation(dcInst) end end - local og_ISEquipWeaponAction_perform = ISEquipWeaponAction.perform ---@diagnostic disable-next-line: duplicate-set-field function ISEquipWeaponAction:perform() @@ -188,7 +195,6 @@ function ISEquipWeaponAction:perform() end end - function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon, items, player) -- check if hands if not heavy damaged if (not playerObj:isPrimaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getSplintFactor() > 0) then diff --git a/media/lua/client/TOC/Controllers/LocalPlayerController.lua b/media/lua/client/TOC/Controllers/LocalPlayerController.lua index 8e67a13..add35da 100644 --- a/media/lua/client/TOC/Controllers/LocalPlayerController.lua +++ b/media/lua/client/TOC/Controllers/LocalPlayerController.lua @@ -5,15 +5,8 @@ local StaticData = require("TOC/StaticData") require("TOC/Events") ----------- --- TODO Separate this in more classes, it's getting too big - --- THIS SHOULD BE LOCAL ONLY! WE'RE MANAGING EVENTS AND INITIALIZATION STUFF! - --- LIST OF STUFF THAT THIS CLASS NEEDS TO DO --- Keep track of cut limbs so that we don't have to loop through all of them all the time --- Update current player status (infection checks) --- handle stats increase\decrease +-- Handle ONLY stuff for the local client ---@class LocalPlayerController ---@field playerObj IsoPlayer @@ -21,6 +14,9 @@ require("TOC/Events") ---@field hasBeenDamaged boolean local LocalPlayerController = {} + +--* Initialization + ---Setup the Player Handler and modData, only for local client ---@param isForced boolean? function LocalPlayerController.InitializePlayer(isForced) @@ -33,10 +29,6 @@ function LocalPlayerController.InitializePlayer(isForced) LocalPlayerController.playerObj = playerObj LocalPlayerController.username = username - -- Calculate amputated limbs and highest point of amputations at startup - --CachedDataHandler.CalculateAmputatedLimbs(username) - --CachedDataHandler.CalculateHighestAmputatedLimbs(username) - --Setup the CicatrizationUpdate event and triggers it once Events.OnAmputatedLimb.Add(LocalPlayerController.ToggleUpdateAmputations) LocalPlayerController.ToggleUpdateAmputations() @@ -68,7 +60,9 @@ function LocalPlayerController.ManageTraits(playerObj) end end ---* Health management *-- +---------------------------------------------------------- + +--* Health *-- ---Used to heal an area that has been cut previously. There's an exception for bites, those are managed differently ---@param bodyPart BodyPart @@ -96,7 +90,6 @@ function LocalPlayerController.HealArea(bodyPart) bodyPart:setSplint(false, 0) end ----comment ---@param bodyDamage BodyDamage ---@param bodyPart BodyPart ---@param limbName string @@ -114,7 +107,6 @@ function LocalPlayerController.HealZombieInfection(bodyDamage, bodyPart, limbNam dcInst:apply() end ----comment ---@param character IsoPlayer ---@param limbName string function LocalPlayerController.TryRandomBleed(character, limbName) @@ -135,6 +127,8 @@ function LocalPlayerController.TryRandomBleed(character, limbName) character:getBodyDamage():getBodyPart(adjacentBodyPartType):setBleedingTime(20) end end + + ------------------------- --* Damage handling *-- --- Locks OnPlayerGetDamage event, to prevent it from getting spammed constantly @@ -291,8 +285,6 @@ function LocalPlayerController.ToggleUpdateAmputations() CommonMethods.SafeStartEvent("EveryHours", LocalPlayerController.UpdateAmputations) end - - --* Tourniquet handling function LocalPlayerController.HandleTourniquet() print("test") @@ -301,5 +293,4 @@ end Events.OnPuttingTourniquet.Add(LocalPlayerController.HandleTourniquet) - return LocalPlayerController \ No newline at end of file diff --git a/media/lua/client/TOC/Main.lua b/media/lua/client/TOC/Main.lua index c938005..09cab0e 100644 --- a/media/lua/client/TOC/Main.lua +++ b/media/lua/client/TOC/Main.lua @@ -74,7 +74,7 @@ end --* Events *-- -Events.OnGameBoot.Add(Main.Start) +Events.OnGameBoot.Add(Main.Start) -- TODO Does this apply after death? if not isClient() and not isServer() then Events.OnPlayerDeath.Add(Main.WipeSinglePlayerData)