Bump to mod version and changed folder for specific game version

This commit is contained in:
ZioPao
2025-03-31 02:17:40 +02:00
parent b6b61b872f
commit e919c8c01b
64 changed files with 2 additions and 10 deletions

View File

@@ -1,211 +0,0 @@
local DataController = require("TOC/Controllers/DataController")
local ItemsController = require("TOC/Controllers/ItemsController")
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
local StaticData = require("TOC/StaticData")
local TourniquetController = require("TOC/Controllers/TourniquetController")
---------------------------
--- Manages an amputation. Will be run on the patient client
---@class AmputationHandler
---@field patientPl IsoPlayer
---@field limbName string
---@field bodyPartType BodyPartType
---@field surgeonPl IsoPlayer?
local AmputationHandler = {}
---@param limbName string
---@param surgeonPl IsoPlayer?
---@return AmputationHandler
function AmputationHandler:new(limbName, surgeonPl)
local o = {}
setmetatable(o, self)
self.__index = self
o.patientPl = getPlayer()
o.limbName = limbName
o.bodyPartType = BodyPartType[limbName]
-- TOC_DEBUG.print("limbName = " .. o.limbName)
-- TOC_DEBUG.print("bodyPartType = " .. tostring(o.bodyPartType))
if surgeonPl then
o.surgeonPl = surgeonPl
else
o.surgeonPl = o.patientPl
end
AmputationHandler.instance = o
return o
end
--* Static methods *--
---@param player IsoPlayer
---@param limbName string
function AmputationHandler.ApplyDamageDuringAmputation(player, limbName)
local ampGroup = StaticData.LIMBS_TO_AMP_GROUPS_MATCH_IND_STR[limbName]
local isTourniquetEquipped = false
-- Check if tourniquet is applied on the zone
for bl, tournAmpGroup in pairs(StaticData.TOURNIQUET_BODYLOCS_TO_GROUPS_IND_STR) do
local item = player:getWornItem(bl)
-- LimbName -> Group -> BodyLoc
if item and tournAmpGroup == ampGroup then
TOC_DEBUG.print("tourniquet is equipped")
isTourniquetEquipped = true
break
end
end
local bodyDamage = player:getBodyDamage()
local bodyPartType = BodyPartType[limbName]
local bodyDamagePart = bodyDamage:getBodyPart(bodyPartType)
TOC_DEBUG.print("damage patient - " .. tostring(bodyPartType))
bodyDamagePart:setBleeding(true)
bodyDamagePart:setCut(true)
local bleedingTime
if isTourniquetEquipped then
bleedingTime = ZombRand(1,5)
else
bleedingTime = ZombRand(10, 20)
end
bodyDamagePart:setBleedingTime(bleedingTime)
end
---@param prevAction ISBaseTimedAction
---@param limbName string
---@param surgeonPl IsoPlayer
---@param patientPl IsoPlayer
---@param stitchesItem InventoryItem
---@return ISStitch
function AmputationHandler.PrepareStitchesAction(prevAction, limbName, surgeonPl, patientPl, stitchesItem)
local bd = patientPl:getBodyDamage()
-- we need the adjacent one, not the actual one
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[limbName]
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
local stitchesAction = ISStitch:new(surgeonPl, patientPl, stitchesItem, bodyPart, true)
ISTimedActionQueue.addAfter(prevAction, stitchesAction)
return stitchesAction
end
---Setup the ISApplyBandage action that will trigger after the amputation
---@param prevAction ISBaseTimedAction
---@param limbName string
---@param surgeonPl IsoPlayer
---@param patientPl IsoPlayer
---@param bandageItem InventoryItem
---@return ISApplyBandage
function AmputationHandler.PrepareBandagesAction(prevAction, limbName, surgeonPl, patientPl, bandageItem)
local bd = patientPl:getBodyDamage()
-- we need the adjacent one, not the actual one
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[limbName]
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
local bandageAction = ISApplyBandage:new(surgeonPl, patientPl, bandageItem, bodyPart, true)
ISTimedActionQueue.addAfter(prevAction, bandageAction)
return bandageAction
end
--* Main methods *--
---Set the damage to the adjacent part of the cut area
---@param surgeonFactor number
function AmputationHandler:damageAfterAmputation(surgeonFactor)
TOC_DEBUG.print("Applying damage after amputation")
local patientStats = self.patientPl:getStats()
local bd = self.patientPl:getBodyDamage()
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[self.limbName]
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
local baseDamage = StaticData.LIMBS_BASE_DAMAGE_IND_NUM[self.limbName]
-- Check if player has tourniquet equipped on the limb
-- TODO Suboptimal checks, but they should work for now.
local hasTourniquet = TourniquetController.CheckTourniquetOnLimb(self.patientPl, self.limbName)
if hasTourniquet then
TOC_DEBUG.print("Do something different for the damage calculation because tourniquet is applied")
baseDamage = baseDamage * 0.5 -- 50% less damage due to tourniquet
end
bodyPart:AddDamage(baseDamage - surgeonFactor)
bodyPart:setAdditionalPain(baseDamage - surgeonFactor)
bodyPart:setBleeding(true)
bodyPart:setBleedingTime(baseDamage - surgeonFactor)
bodyPart:setDeepWounded(true)
bodyPart:setDeepWoundTime(baseDamage - surgeonFactor)
patientStats:setEndurance(surgeonFactor)
patientStats:setStress(baseDamage - surgeonFactor)
end
---Execute the amputation. This method doesn't check if the upper limb has been amputated or not, so if
--- somehow the method gets triggered and we're trying to cut off a part that doesn't really exist anymore,
--- it will still be executed. This is by design, additional checks must be made BEFORE running the AmputationHandler
---@param damagePlayer boolean
function AmputationHandler:execute(damagePlayer)
local surgeonFactor = self.surgeonPl:getPerkLevel(Perks.Doctor) * SandboxVars.TOC.SurgeonAbilityImportance
-- Set the data in modData
local dcInst = DataController.GetInstance()
dcInst:setCutLimb(self.limbName, false, false, false, surgeonFactor)
dcInst:apply() -- This will force rechecking the cached amputated limbs on the other client
-- Heal the area, we're gonna re-set the damage after (if it's enabled)
local bd = self.patientPl:getBodyDamage()
local bodyPart = bd:getBodyPart(self.bodyPartType)
LocalPlayerController.HealArea(bodyPart)
-- Give the player the correct amputation item
ItemsController.Player.DeleteOldAmputationItem(self.patientPl, self.limbName)
ItemsController.Player.SpawnAmputationItem(self.patientPl, self.limbName)
-- Add it to the list of cut limbs on this local client
local username = self.patientPl:getUsername()
CachedDataHandler.AddAmputatedLimb(username, self.limbName)
-- TODO Not optimal, we're already cycling through this when using setCutLimb
for i=1, #StaticData.LIMBS_DEPENDENCIES_IND_STR[self.limbName] do
local dependedLimbName = StaticData.LIMBS_DEPENDENCIES_IND_STR[self.limbName][i]
CachedDataHandler.AddAmputatedLimb(username, dependedLimbName)
end
-- Cache highest amputation and hand feasibility
CachedDataHandler.CalculateCacheableValues(username)
-- If the part was actually infected, heal the player, if they were in time (infectionLevel < 20)
if bd:getInfectionLevel() < 20 and bodyPart:IsInfected() and not dcInst:getIsIgnoredPartInfected() then
LocalPlayerController.HealZombieInfection(bd, bodyPart, self.limbName, dcInst)
end
-- The last part is to handle the damage that the player will receive after the amputation
if not damagePlayer then return end
self:damageAfterAmputation(surgeonFactor)
-- Trigger this event
triggerEvent("OnAmputatedLimb", self.limbName)
end
---Deletes the instance
function AmputationHandler:close()
AmputationHandler.instance = nil
end
return AmputationHandler

View File

@@ -1,167 +0,0 @@
local DataController = require("TOC/Controllers/DataController")
local StaticData = require("TOC/StaticData")
local CommonMethods = require("TOC/CommonMethods")
---------------------------
---@class CachedDataHandler
local CachedDataHandler = {}
---Reset everything cache related for that specific user
---@param username string
function CachedDataHandler.Setup(username)
CachedDataHandler.amputatedLimbs[username] = {}
-- username -> side
CachedDataHandler.highestAmputatedLimbs[username] = {}
-- Local only, doesn't matter for Health Panel
CachedDataHandler.handFeasibility = {}
end
---Will calculate all the values that we need
function CachedDataHandler.CalculateCacheableValues(username)
CachedDataHandler.CalculateHighestAmputatedLimbs(username)
if getPlayer():getUsername() == username then
CachedDataHandler.CalculateBothHandsFeasibility()
end
end
--* Amputated Limbs caching *--
CachedDataHandler.amputatedLimbs = {}
---Calculate the currently amputated limbs for a certain player
---@param username string
function CachedDataHandler.CalculateAmputatedLimbs(username)
TOC_DEBUG.print("Calculating amputated limbs for " .. username)
CachedDataHandler.amputatedLimbs[username] = {}
local dcInst = DataController.GetInstance(username)
for i=1, #StaticData.LIMBS_STR do
local limbName = StaticData.LIMBS_STR[i]
if dcInst:getIsCut(limbName) then
CachedDataHandler.AddAmputatedLimb(username, limbName)
end
end
end
---Add an amputated limb to the cached list for that user
---@param username string
---@param limbName string
function CachedDataHandler.AddAmputatedLimb(username, limbName)
TOC_DEBUG.print("Added " .. limbName .. " to known amputated limbs for " .. username)
-- Add it to the generic list
if CachedDataHandler.amputatedLimbs[username] == nil then
CachedDataHandler.amputatedLimbs[username] = {}
end
CachedDataHandler.amputatedLimbs[username][limbName] = limbName
end
---Returns a table containing the cached amputated limbs
---@param username string
---@return table
function CachedDataHandler.GetAmputatedLimbs(username)
return CachedDataHandler.amputatedLimbs[username]
end
--* Highest amputated limb per side caching *--
CachedDataHandler.highestAmputatedLimbs = {}
---Calcualate the highest point of amputations achieved by the player
---@param username string
function CachedDataHandler.CalculateHighestAmputatedLimbs(username)
TOC_DEBUG.print("Triggered CalculateHighestAmputatedLimbs")
local dcInst = DataController.GetInstance(username)
if dcInst == nil then
TOC_DEBUG.print("DataController not found for " .. username)
return
end
CachedDataHandler.CalculateAmputatedLimbs(username)
local amputatedLimbs = CachedDataHandler.amputatedLimbs[username]
CachedDataHandler.highestAmputatedLimbs[username] = {}
--TOC_DEBUG.print("Searching highest amputations for " .. username)
for k, _ in pairs(amputatedLimbs) do
local limbName = k
local side = CommonMethods.GetSide(limbName)
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
TOC_DEBUG.print("Added Highest Amputation: " .. limbName)
CachedDataHandler.highestAmputatedLimbs[username][side] = limbName
end
end
end
---Get the cached highest point of amputation for each side
---@param username string
---@return table<string, string>
function CachedDataHandler.GetHighestAmputatedLimbs(username)
return CachedDataHandler.highestAmputatedLimbs[username]
end
--* Hand feasibility caching *--
CachedDataHandler.handFeasibility = {}
---@param limbName string
function CachedDataHandler.CalculateHandFeasibility(limbName)
local dcInst = DataController.GetInstance()
local side = CommonMethods.GetSide(limbName)
-- TODO if we re run this too early, it might break everything after a forced re-init
CachedDataHandler.handFeasibility[side] = not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(limbName)
TOC_DEBUG.print("Calculated hand feasibility: " .. tostring(side))
end
---@param side string Either "L" or "R"
---@return boolean
function CachedDataHandler.GetHandFeasibility(side)
-- FIX horrendous workaround, but with a forced init we run the caching too early and it breaks this, setting it to nil.
if CachedDataHandler.handFeasibility[side] == nil then
CachedDataHandler.CalculateBothHandsFeasibility()
end
return CachedDataHandler.handFeasibility[side]
end
function CachedDataHandler.CalculateBothHandsFeasibility()
CachedDataHandler.CalculateHandFeasibility("Hand_L")
CachedDataHandler.CalculateHandFeasibility("Hand_R")
local interactStr = "Interact"
if CachedDataHandler.interactKey == nil or CachedDataHandler.interactKey == 0 then
CachedDataHandler.interactKey = getCore():getKey(interactStr)
end
if not CachedDataHandler.GetBothHandsFeasibility() then
TOC_DEBUG.print("Disabling interact key")
TOC_DEBUG.print("Cached current key for interact: " .. tostring(CachedDataHandler.interactKey))
getCore():addKeyBinding(interactStr, Keyboard.KEY_NONE)
else
TOC_DEBUG.print("Re-enabling interact key")
TOC_DEBUG.print("Cached current key for interact: " .. tostring(CachedDataHandler.interactKey))
getCore():addKeyBinding(interactStr, CachedDataHandler.interactKey)
end
end
function CachedDataHandler.GetBothHandsFeasibility()
return CachedDataHandler.handFeasibility["L"] or CachedDataHandler.handFeasibility["R"]
end
return CachedDataHandler

View File

@@ -1,180 +0,0 @@
local CommonMethods = require("TOC/CommonMethods")
local StaticData = require("TOC/StaticData")
local DataController = require("TOC/Controllers/DataController")
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
-------------------------
---@class ProsthesisHandler
local ProsthesisHandler = {}
local bodyLocArmProst = StaticData.MOD_BODYLOCS_BASE_IND_STR.TOC_ArmProst
local bodyLocLegProst = StaticData.MOD_BODYLOCS_BASE_IND_STR.TOC_LegProst
---Check if the following item is a prosthesis or not
---@param item InventoryItem?
---@return boolean
function ProsthesisHandler.CheckIfProst(item)
-- TODO Won't be correct when prost for legs are gonna be in
--TOC_DEBUG.print("Checking if item is prost")
if item == nil then
--TOC_DEBUG.print("Not prost")
return false
end
return item:getBodyLocation():contains(bodyLocArmProst)
end
---Get the grouping for the prosthesis
---@param item InventoryItem
---@return string
function ProsthesisHandler.GetGroup(item)
local fullType = item:getFullType()
local side = CommonMethods.GetSide(fullType)
local bodyLocation = item:getBodyLocation()
local position
if bodyLocation == bodyLocArmProst then
position = "Top_"
elseif bodyLocation == bodyLocLegProst then
position = "Bottom_"
else
TOC_DEBUG.print("Something is wrong, no position in this item")
position = nil
end
local index = position .. side
local group = StaticData.AMP_GROUPS_IND_STR[index]
return group
end
---Check if a prosthesis is equippable. It depends whether the player has a cut limb or not on that specific side. There's an exception for Upper arm, obviously
---@param fullType string
---@return boolean
function ProsthesisHandler.CheckIfEquippable(fullType)
--TOC_DEBUG.print("Current item is a prosthesis")
local side = CommonMethods.GetSide(fullType)
--TOC_DEBUG.print("Checking side: " .. tostring(side))
local highestAmputatedLimbs = CachedDataHandler.GetHighestAmputatedLimbs(getPlayer():getUsername())
if highestAmputatedLimbs then
local hal = highestAmputatedLimbs[side]
if hal and not string.contains(hal, "UpperArm") then
--TOC_DEBUG.print("Found acceptable limb to use prosthesis => " .. tostring(hal))
return true
end
end
-- No acceptable cut limbs
return false
end
---Handle equipping or unequipping prosthetics
---@param item InventoryItem
---@param isEquipping boolean
---@return boolean
function ProsthesisHandler.SearchAndSetupProsthesis(item, isEquipping)
if not ProsthesisHandler.CheckIfProst(item) then return false end
local group = ProsthesisHandler.GetGroup(item)
TOC_DEBUG.print("Setup Prosthesis => " .. group .. " - is equipping? " .. tostring(isEquipping))
local dcInst = DataController.GetInstance()
dcInst:setIsProstEquipped(group, isEquipping)
dcInst:apply()
-- Calculates hands feasibility once again
CachedDataHandler.CalculateBothHandsFeasibility()
return true
end
-------------------------
--* Overrides *--
---@param item InventoryItem
---@param isEquippable boolean
---@return unknown
local function HandleProsthesisValidation(item, isEquippable)
local isProst = ProsthesisHandler.CheckIfProst(item)
if not isProst then return isEquippable end
local fullType = item:getFullType() -- use fulltype for side
if isEquippable then
isEquippable = ProsthesisHandler.CheckIfEquippable(fullType)
else
getPlayer():Say(getText("UI_Say_CantEquip"))
end
return isEquippable
end
---@diagnostic disable-next-line: duplicate-set-field
local og_ISWearClothing_isValid = ISWearClothing.isValid
function ISWearClothing:isValid()
local isEquippable = og_ISWearClothing_isValid(self)
return HandleProsthesisValidation(self.item, isEquippable)
end
local og_ISWearClothing_perform = ISWearClothing.perform
function ISWearClothing:perform()
ProsthesisHandler.SearchAndSetupProsthesis(self.item, true)
og_ISWearClothing_perform(self)
end
local og_ISClothingExtraAction_isValid = ISClothingExtraAction.isValid
---@diagnostic disable-next-line: duplicate-set-field
function ISClothingExtraAction:isValid()
local isEquippable = og_ISClothingExtraAction_isValid(self)
-- self.extra is a string, not the item
local testItem = instanceItem(self.extra)
return HandleProsthesisValidation(testItem, isEquippable)
end
local og_ISClothingExtraAction_perform = ISClothingExtraAction.perform
function ISClothingExtraAction:perform()
local extraItem = instanceItem(self.extra)
ProsthesisHandler.SearchAndSetupProsthesis(extraItem, true)
og_ISClothingExtraAction_perform(self)
end
local og_ISUnequipAction_perform = ISUnequipAction.perform
function ISUnequipAction:perform()
--[[
Horrendous workaround
To unequp items, the java side uses WornItems.setItem, which has
a check for multiItem. Basically, if it's active, it won't actually remove the item,
fucking things up. So, to be 100% sure that we're removing the items, we're gonna
disable and re-enable the multi-item bool for the Unequip Action.
]]
local isProst = ProsthesisHandler.SearchAndSetupProsthesis(self.item, false)
local group
if isProst then
group = BodyLocations.getGroup("Human")
group:setMultiItem("TOC_ArmProst", false)
end
og_ISUnequipAction_perform(self)
if isProst then
group:setMultiItem("TOC_ArmProst", true)
-- we need to fetch the limbname associated to the prosthesis
local side = CommonMethods.GetSide(self.item:getFullType())
local highestAmputatedLimbs = CachedDataHandler.GetHighestAmputatedLimbs(getPlayer():getUsername())
if highestAmputatedLimbs then
local hal = highestAmputatedLimbs[side]
if hal then
-- This could break if amputated limbs aren't cached for some reason
triggerEvent("OnProsthesisUnequipped", hal)
end
end
end
end
return ProsthesisHandler