diff --git a/media/lua/client/TOC_Debug.lua b/media/lua/client/TOC_Debug.lua new file mode 100644 index 0000000..e69de29 diff --git a/media/lua/client/TOC_HealthPanelBaseHandler.lua b/media/lua/client/TOC_HealthPanelBaseHandler.lua new file mode 100644 index 0000000..0ff724a --- /dev/null +++ b/media/lua/client/TOC_HealthPanelBaseHandler.lua @@ -0,0 +1,128 @@ +-- Had to cop and paste this stuff from the base game since this is a local only class. Kinda shit, but eh + +local BaseHandler = ISBaseObject:derive("BaseHandler") + +function BaseHandler:new(panel, bodyPart) + local o = {} + setmetatable(o, self) + self.__index = self + o.panel = panel + o.bodyPart = bodyPart + o.items = {} + return o +end + +function BaseHandler:isInjured() + local bodyPart = self.bodyPart + return (bodyPart:HasInjury() or bodyPart:stitched() or bodyPart:getSplintFactor() > 0) and not bodyPart:bandaged() +end + +function BaseHandler:checkItems() + for k,v in pairs(self.items) do + table.wipe(v) + end + + local containers = ISInventoryPaneContextMenu.getContainers(self:getDoctor()) + local done = {} + local childContainers = {} + for i=1,containers:size() do + local container = containers:get(i-1) + done[container] = true + table.wipe(childContainers) + self:checkContainerItems(container, childContainers) + for _,container2 in ipairs(childContainers) do + if not done[container2] then + done[container2] = true + self:checkContainerItems(container2, nil) + end + end + end +end + +function BaseHandler:checkContainerItems(container, childContainers) + local containerItems = container:getItems() + for i=1,containerItems:size() do + local item = containerItems:get(i-1) + if item:IsInventoryContainer() then + if childContainers then + table.insert(childContainers, item:getInventory()) + end + else + self:checkItem(item) + end + end +end + +function BaseHandler:dropItems(items) + return false +end + +function BaseHandler:addItem(items, item) + table.insert(items, item) +end + +function BaseHandler:getAllItemTypes(items) + local done = {} + local types = {} + for _,item in ipairs(items) do + if not done[item:getFullType()] then + table.insert(types, item:getFullType()) + done[item:getFullType()] = true + end + end + return types +end + +function BaseHandler:getItemOfType(items, type) + for _,item in ipairs(items) do + if item:getFullType() == type then + return item + end + end + return nil +end + +function BaseHandler:getItemOfTag(items, type) + for _,item in ipairs(items) do + if item:hasTag(type) then + return item + end + end + return nil +end + +function BaseHandler:getAllItemsOfType(items, type) + local items = {} + for _,item in ipairs(items) do + if item:getFullType() == type then + table.insert(items, item) + end + end + return items +end + +function BaseHandler:onMenuOptionSelected(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + ISTimedActionQueue.add(HealthPanelAction:new(self:getDoctor(), self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)) +end + +function BaseHandler:toPlayerInventory(item, previousAction) + if item:getContainer() ~= self:getDoctor():getInventory() then + local action = ISInventoryTransferAction:new(self:getDoctor(), item, item:getContainer(), self:getDoctor():getInventory()) + ISTimedActionQueue.addAfter(previousAction, action) + -- FIXME: ISHealthPanel.actions never gets cleared + self.panel.actions = self.panel.actions or {} + self.panel.actions[action] = self.bodyPart + return action + end + return previousAction +end + +function BaseHandler:getDoctor() + return self.panel.otherPlayer or self.panel.character +end + +function BaseHandler:getPatient() + return self.panel.character +end + +return BaseHandler \ No newline at end of file diff --git a/media/lua/client/TOC_Main.lua b/media/lua/client/TOC_Main.lua index 37c4d02..5ae6fdf 100644 --- a/media/lua/client/TOC_Main.lua +++ b/media/lua/client/TOC_Main.lua @@ -22,6 +22,7 @@ function Main.SetupTraits() for i=1, #traitsTable do local t = traitsTable[i] + ---@diagnostic disable-next-line: undefined-field t:addXPBoost(Perks.Left_Hand, 4) t:addXPBoost(Perks.Fitness, -1) t:addXPBoost(Perks.Strength, -1) diff --git a/media/lua/client/TOC_ModDataHandler.lua b/media/lua/client/TOC_ModDataHandler.lua index 6511ba5..e9b5351 100644 --- a/media/lua/client/TOC_ModDataHandler.lua +++ b/media/lua/client/TOC_ModDataHandler.lua @@ -18,6 +18,7 @@ function ModDataHandler:new(playerObj) self.__index = self o.playerObj = playerObj + ModDataHandler.instance = o return o @@ -25,7 +26,8 @@ end ---Setup a newly instanced ModDataHandler function ModDataHandler:setup() - if self.modData == nil then self:createData() end + local modData = self.playerObj:getModData()[StaticData.MOD_NAME] + if modData == nil then self:createData() end -- TODO Check compatibility or do we just skip it at this point? end @@ -35,27 +37,62 @@ function ModDataHandler:createData() self.playerObj:getModData()[StaticData.MOD_NAME] = {} + ---@type amputationTable + local defaultParams = {isCut = false, isInfected = false, isOperated = false, isCicatrized = false, isCauterized = false, isDependant = false} + -- Initialize limbs for i=1, #StaticData.LIMBS_STRINGS do - self:setLimbParams(StaticData.LIMBS_STRINGS[i], false, false, false, false, false, false) + self:setLimbParams(StaticData.LIMBS_STRINGS[i], defaultParams, 0) end end +----------------- +--* Setters *-- + +---Set isCut +---@param limbName string +---@param isCut boolean +function ModDataHandler:setIsCut(limbName, isCut) + self.playerObj:getModData()[StaticData.MOD_NAME][limbName].isCut = isCut +end + +---Set isInfected +---@param limbName string +---@param isInfected boolean +function ModDataHandler:setIsInfected(limbName, isInfected) + self.playerObj:getModData()[StaticData.MOD_NAME][limbName].isInfected = isInfected +end + +----------------- +--* Getters *-- +---Get isCut +---@param limbName string +---@return boolean +function ModDataHandler:getIsCut(limbName) + return self.playerObj:getModData()[StaticData.MOD_NAME][limbName].isCut +end + + + + + --* Limbs data handling *-- ---Set a limb and its dependend limbs as cut ---@param limbName string ----@param ampStatus amputationTable {isOperated, isCicatrized, isCauterized} ----@param surgeonFactor number -function ModDataHandler:setCutLimb(limbName, ampStatus, surgeonFactor) - local cicatrizationTime = -1 - if ampStatus.isCicatrized == false or ampStatus.isCauterized == false then +---@param isOperated boolean +---@param isCicatrized boolean +---@param isCauterized boolean +---@param surgeonFactor number? +function ModDataHandler:setCutLimb(limbName, isOperated, isCicatrized, isCauterized, surgeonFactor) + local cicatrizationTime = 0 + if isCicatrized == false or isCauterized == false then cicatrizationTime = StaticData.LIMBS_CICATRIZATION_TIME[limbName] - surgeonFactor end ---@type amputationTable - local params = {isCut = true, isInfected = false, isOperated = ampStatus.isOperated, isCicatrized = ampStatus.isCicatrized, isCauterized = ampStatus.isCauterized, isDependant = false} + local params = {isCut = true, isInfected = false, isOperated = isOperated, isCicatrized = isCicatrized, isCauterized = isCauterized, isDependant = false} self:setLimbParams(limbName, params, cicatrizationTime) diff --git a/media/lua/client/TOC_PlayerHandler.lua b/media/lua/client/TOC_PlayerHandler.lua index 8c5ecc3..8f4966a 100644 --- a/media/lua/client/TOC_PlayerHandler.lua +++ b/media/lua/client/TOC_PlayerHandler.lua @@ -41,6 +41,7 @@ function PlayerHandler.CutLimb(patient, surgeon, limbName, surgeryHelpItems) -- TODO Get surgeon ability from his aid skill local surgeonSkill = 50 + local surgeonFactor = surgeonSkill - 1 -- TODO Should be decided by surgeryHelpItems local bd = patient:getBodyDamage() local bodyPart = bd:getBodyPart(BodyPartType[limbName]) @@ -56,9 +57,7 @@ function PlayerHandler.CutLimb(patient, surgeon, limbName, surgeryHelpItems) patientStats:setEndurance(surgeonSkill) patientStats:setStress(baseDamage - surgeonSkill) - ---@type amputationTable - local amputationValues = {isOperated = false, isCicatrized = false, isCauterized = false} - PlayerHandler.modDataHandler:setCutLimb(limbName, amputationValues) + PlayerHandler.modDataHandler:setCutLimb(limbName, false, false, false, surgeonFactor) end @@ -70,4 +69,36 @@ function PlayerHandler.ForceCutLimb(limbName) -- TODO Spawn amputation item end -return PlayerHandler + + +--* Events *-- + +---Check if the player has an infected (as in, zombie infection) body part +---@param character IsoGameCharacter +---@param damageType string +---@param damage number +function PlayerHandler.CheckInfection(character, damageType, damage) + + -- This fucking event barely works. Bleeding seems to be the only thing that triggers it + -- TODO Check other body parts that are not included in the mod, if there's a bite there then the player is fucked + local bd = character:getBodyDamage() + + for i=1, #StaticData.LIMBS_STRINGS do + local limbName = StaticData.LIMBS_STRINGS[i] + local bptEnum = StaticData.BODYPARTSTYPES_ENUM[limbName] + local bodyPart = bd:getBodyPart(bptEnum) + + if bodyPart:bitten() then + if PlayerHandler.modDataHandler:getIsCut(limbName) then + bodyPart:SetBitten(false) + else + PlayerHandler.modDataHandler:setIsInfected(limbName, true) + end + end + end + +end + +Events.OnPlayerGetDamage.Add(PlayerHandler.CheckInfection) + +return PlayerHandler \ No newline at end of file diff --git a/media/lua/client/TOC_StaticData.lua b/media/lua/client/TOC_StaticData.lua index 3cb64e7..f3988d2 100644 --- a/media/lua/client/TOC_StaticData.lua +++ b/media/lua/client/TOC_StaticData.lua @@ -16,6 +16,7 @@ StaticData.SIDES_STRINGS = { -- Assembled BodyParts string ---@enum StaticData.LIMBS_STRINGS = {} +StaticData.BODYPARTSTYPES_ENUM = {} StaticData.LIMBS_DEPENDENCIES = {} StaticData.LIMBS_CICATRIZATION_TIME = {} @@ -27,6 +28,7 @@ for i = 1, #StaticData.SIDES_STRINGS do -- Assembled strings StaticData.LIMBS_STRINGS[assembledName] = assembledName + StaticData.BODYPARTSTYPES_ENUM[assembledName] = BodyPartType[assembledName] -- Dependencies and cicatrization time if part == StaticData.PARTS_STRINGS.Hand then diff --git a/media/lua/client/TOC_UI.lua b/media/lua/client/TOC_UI.lua new file mode 100644 index 0000000..aac64f4 --- /dev/null +++ b/media/lua/client/TOC_UI.lua @@ -0,0 +1,56 @@ +local CutLimbHandler = require("TOC_UIHandler") + +-- TODO Use this to replace the sprites once a limb is cut +ISHealthBodyPartPanel = ISBodyPartPanel:derive("ISHealthBodyPartPanel") + +function ISHealthBodyPartPanel:onMouseUp(x, y) + if self.selectedBp then + local dragging = ISInventoryPane.getActualItems(ISMouseDrag.dragging) + self.parent:dropItemsOnBodyPart(self.selectedBp.bodyPart, dragging) + end +end + +function ISHealthBodyPartPanel:prerender() + self.nodeAlpha = 0.0 + self.selectedAlpha = 0.1 + if self.selectedBp then + for index,item in ipairs(self.parent.listbox.items) do + if item.item.bodyPart == self.selectedBp.bodyPart then + self.nodeAlpha = 1.0 + self.selectedAlpha = 0.5 + break + end + end + end + ISBodyPartPanel.prerender(self) +end + +function ISHealthBodyPartPanel:cbSetSelected(bp) + if bp == nil then + self.parent.listbox.selected = 0 + return + end + for index,item in ipairs(self.parent.listbox.items) do + if item.item.bodyPart == bp.bodyPart then + self.parent.listbox.selected = index + break + end + end +end + + +local og_ISHealthPanel_dropItemsOnBodyPart = ISHealthPanel.dropItemsOnBodyPart + +function ISHealthPanel:dropItemsOnBodyPart(bodyPart, items) + og_ISHealthPanel_dropItemsOnBodyPart(self, bodyPart, items) + local cutLimbHandler = CutLimbHandler:new(self, bodyPart) + + for _,item in ipairs(items) do + cutLimbHandler:checkItem(item) + end + + if cutLimbHandler:dropItems(items) then + return + end + +end \ No newline at end of file diff --git a/media/lua/client/TOC_UIHandler.lua b/media/lua/client/TOC_UIHandler.lua new file mode 100644 index 0000000..2612e9a --- /dev/null +++ b/media/lua/client/TOC_UIHandler.lua @@ -0,0 +1,62 @@ +local BaseHandler = require("TOC_HealthPanelBaseHandler") +local CutLimbAction = require("TOC_CutLimbAction") + +---@class CutLimbHandler +local CutLimbHandler = BaseHandler:derive("CutLimbHandler") + + +local contextMenuCutLimb = "Cut" + +---Creates new CutLimbHandler +---@param panel any +---@param bodyPart any +---@return CutLimbHandler +function CutLimbHandler:new(panel, bodyPart) + local o = BaseHandler.new(self, panel, bodyPart) + o.items.ITEMS = {} + return o +end + +function CutLimbHandler:checkItem(item) + local itemType = item:getType() + if itemType == "Saw" or itemType == "GardenSaw" or itemType == "Chainsaw" then + self:addItem(self.items.ITEMS, item) + end + +end + +function CutLimbHandler:addToMenu(context) + local types = self:getAllItemTypes(self.items.ITEMS) + if #types > 0 then + local option = context:addOption(contextMenuCutLimb, nil) + local subMenu = context:getNew(context) + context:addSubMenu(option, subMenu) + for i=1,#types do + local item = self:getItemOfType(self.items.ITEMS, types[i]) + subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, item:getFullType()) + end + end +end + +function CutLimbHandler:dropItems(items) + local types = self:getAllItemTypes(items) + if #self.items.ITEMS > 0 and #types == 1 then + self:onMenuOptionSelected(types[1]) + return true + end + return false +end + +function CutLimbHandler:isValid(itemType) + return self:isInjured() and self:getItemOfType(self.items.ITEMS, itemType) +end + +function CutLimbHandler:perform(previousAction, itemType) + local item = self:getItemOfType(self.items.ITEMS, itemType) + previousAction = self:toPlayerInventory(item, previousAction) + + local action = CutLimbAction:new(self:getPatient(), self:getDoctor(), self.bodyPart) + ISTimedActionQueue.addAfter(previousAction, action) +end + +return CutLimbHandler \ No newline at end of file diff --git a/media/lua/client/TimedActions/TOC_CutLimbAction.lua b/media/lua/client/TimedActions/TOC_CutLimbAction.lua index e69de29..3c1840c 100644 --- a/media/lua/client/TimedActions/TOC_CutLimbAction.lua +++ b/media/lua/client/TimedActions/TOC_CutLimbAction.lua @@ -0,0 +1,8 @@ +require "TimedActions/ISBaseTimedAction" + +local CutLimbAction = ISBaseTimedAction:derive("CutLimbAction") + +function CutLimbAction:new(patient, surgeon, partName) + +end +return CutLimbAction \ No newline at end of file