Reorganizing
This commit is contained in:
69
media/lua/client/TOC/API.lua
Normal file
69
media/lua/client/TOC/API.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
------------------------------------------
|
||||
-- Compatibility Handler by Dhert
|
||||
------------------------------------------
|
||||
|
||||
-- TODO Connect this with TOC logic instead of hardcoding it here
|
||||
local parts = {
|
||||
"Right_Hand",
|
||||
"Left_Hand",
|
||||
"Right_LowerArm",
|
||||
"Left_LowerArm"
|
||||
}
|
||||
-- TODO Connect this with TOC logic instead of hardcoding it here
|
||||
local vars = {
|
||||
"isCut",
|
||||
"isProsthesisEquipped"
|
||||
}
|
||||
|
||||
|
||||
local TOC_Compat = {}
|
||||
|
||||
-- Raw access, must pass valid part
|
||||
--- @param player IsoPlayer
|
||||
--- @param part string
|
||||
--- @return boolean
|
||||
TOC_Compat.hasArmPart = function(player, part)
|
||||
if not player or not part then return false end
|
||||
local data = (player:getModData().TOC and player:getModData().TOC.Limbs) or nil
|
||||
return not data or not data[part] or (data[part][vars[1]] and data[part][vars[2]]) or not data[part][vars[1]]
|
||||
end
|
||||
|
||||
-- Raw access, must pass valid parts. Will check for 2 parts (arm and hand)
|
||||
--- @param player IsoPlayer
|
||||
--- @param part string
|
||||
--- @param part2 string
|
||||
--- @return boolean
|
||||
TOC_Compat.hasArm = function(player, part, part2)
|
||||
if not player or not part then return false end
|
||||
local data = (player:getModData().TOC and player:getModData().TOC.Limbs) or nil
|
||||
return not data or (not data[part] or (data[part][vars[1]] and data[part][vars[2]]) or not data[part][vars[1]]) or (not data[part] or (data[part2][vars[1]] and data[part2][vars[2]]) or not data[part2][vars[1]])
|
||||
end
|
||||
|
||||
-- Check if hand is available
|
||||
--- @param player IsoPlayer
|
||||
--- @param left boolean?
|
||||
--- @return boolean
|
||||
TOC_Compat.hasHand = function(player, left)
|
||||
return TOC_Compat.hasArm(player, ((left and parts[2]) or parts[1]), ((left and parts[4]) or parts[3]))
|
||||
end
|
||||
|
||||
-- Check if both hands are available
|
||||
--- @param player IsoPlayer
|
||||
--- @return boolean
|
||||
TOC_Compat.hasBothHands = function(player)
|
||||
return TOC_Compat.hasArm(player, parts[1], parts[3]) and TOC_Compat.hasArm(player, parts[2], parts[4])
|
||||
end
|
||||
|
||||
-- This returns a number for the hands that you have
|
||||
----- 11 == both hands
|
||||
----- 10 == left hand
|
||||
----- 01 (1) == right hand
|
||||
----- 00 (0) == no hands
|
||||
--- @param player IsoPlayer
|
||||
--- @return integer
|
||||
TOC_Compat.getHands = function(player)
|
||||
return ((TOC_Compat.hasArm(player, parts[1], parts[3]) and 1) or 0) + ((TOC_Compat.hasArm(player, parts[2], parts[4]) and 10) or 0)
|
||||
end
|
||||
|
||||
|
||||
return TOC_Compat
|
||||
10
media/lua/client/TOC/CommonMethods.lua
Normal file
10
media/lua/client/TOC/CommonMethods.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local CommonMethods = {}
|
||||
|
||||
---Returns the side for a certain limb or prosthesis
|
||||
---@param name string
|
||||
---@return string "L" or "R"
|
||||
function CommonMethods.GetSide(name)
|
||||
if string.find(name, "_L") then return "L" else return "R" end
|
||||
end
|
||||
|
||||
return CommonMethods
|
||||
7
media/lua/client/TOC/Debug.lua
Normal file
7
media/lua/client/TOC/Debug.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
TOC_DEBUG = {}
|
||||
TOC_DEBUG.disablePaneMod = false
|
||||
|
||||
|
||||
function TOC_DEBUG.togglePaneMod()
|
||||
TOC_DEBUG.disablePaneMod = not TOC_DEBUG.disablePaneMod
|
||||
end
|
||||
104
media/lua/client/TOC/Handlers/AmputationHandler.lua
Normal file
104
media/lua/client/TOC/Handlers/AmputationHandler.lua
Normal file
@@ -0,0 +1,104 @@
|
||||
local ModDataHandler = require("TOC/Handlers/ModDataHandler")
|
||||
local ItemsHandler = require("TOC/Handlers/ItemsHandler")
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
---------------------------
|
||||
|
||||
-- TODO Add Bandages, Torniquet, etc.
|
||||
--- This will be run EXCLUSIVELY on the client which is getting the amputation
|
||||
---@class AmputationHandler
|
||||
---@field patient 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.patient = getPlayer()
|
||||
o.limbName = limbName
|
||||
o.bodyPartType = BodyPartType[self.limbName]
|
||||
if surgeonPl then
|
||||
o.surgeonPl = surgeonPl
|
||||
else
|
||||
o.surgeonPl = o.patient
|
||||
end
|
||||
|
||||
AmputationHandler.instance = o
|
||||
return o
|
||||
end
|
||||
|
||||
|
||||
--* Main methods *--
|
||||
|
||||
---Starts bleeding from the point where the saw is being used
|
||||
function AmputationHandler:damageDuringAmputation()
|
||||
print("TOC: Damage patient")
|
||||
local bodyDamage = self.patient:getBodyDamage()
|
||||
local bodyDamagePart = bodyDamage:getBodyPart(self.bodyPartType)
|
||||
|
||||
bodyDamagePart:setBleeding(true)
|
||||
bodyDamagePart:setCut(true)
|
||||
bodyDamagePart:setBleedingTime(ZombRand(10, 20))
|
||||
end
|
||||
|
||||
---Execute the amputation
|
||||
---@param damagePlayer boolean?
|
||||
function AmputationHandler:execute(damagePlayer)
|
||||
|
||||
-- TODO Calculate surgeonStats
|
||||
-- TODO Cap it to a certain amount, it shouldn't be more than ...?
|
||||
local surgeonFactor = 1
|
||||
if damagePlayer == nil then damagePlayer = true end -- Default at true
|
||||
if damagePlayer then
|
||||
local patientStats = self.patient:getStats()
|
||||
local bd = self.patient:getBodyDamage()
|
||||
local bodyPart = bd:getBodyPart(self.bodyPartType)
|
||||
local baseDamage = StaticData.LIMBS_BASE_DAMAGE[self.limbName]
|
||||
|
||||
-- Set the bleeding and all the damage stuff in that part
|
||||
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
|
||||
|
||||
|
||||
-- Set the data in modData
|
||||
ModDataHandler.GetInstance():setCutLimb(self.limbName, false, false, false, surgeonFactor)
|
||||
|
||||
-- Give the player the correct amputation item
|
||||
ItemsHandler.DeleteOldAmputationItem(self.patient, self.limbName)
|
||||
ItemsHandler.SpawnAmputationItem(self.patient, self.limbName)
|
||||
|
||||
-- Add it to the list of cut limbs
|
||||
PlayerHandler.AddLocalAmputatedLimb(self.limbName)
|
||||
|
||||
-- Set the highest amputation and caches them.
|
||||
ISHealthPanel.GetHighestAmputation()
|
||||
end
|
||||
|
||||
---Deletes the instance
|
||||
function AmputationHandler:close()
|
||||
AmputationHandler.instance = nil
|
||||
end
|
||||
|
||||
--* Events *--
|
||||
function AmputationHandler.UpdateCicatrization()
|
||||
if ModDataHandler.GetInstance():getIsAnyLimbCut() == false then return end
|
||||
|
||||
|
||||
end
|
||||
|
||||
return AmputationHandler
|
||||
117
media/lua/client/TOC/Handlers/ItemsHandler.lua
Normal file
117
media/lua/client/TOC/Handlers/ItemsHandler.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
|
||||
---------------------------
|
||||
|
||||
--- Submodule to handle spawning the correct items after certain actions (ie: cutting a hand)
|
||||
---@class ItemsHandler
|
||||
local ItemsHandler = {}
|
||||
|
||||
---Returns the correct index for the textures of the amputation
|
||||
---@param isCicatrized boolean
|
||||
---@return number
|
||||
---@private
|
||||
function ItemsHandler.GetAmputationTexturesIndex(playerObj, isCicatrized)
|
||||
local textureString = playerObj:getHumanVisual():getSkinTexture()
|
||||
local isHairy = string.find(textureString, "a$")
|
||||
-- Hairy bodies
|
||||
if isHairy then
|
||||
textureString = textureString:sub(1, -2) -- Removes b at the end to make it compatible
|
||||
end
|
||||
|
||||
local matchedIndex = string.match(textureString, "%d$")
|
||||
|
||||
-- TODO Rework this
|
||||
if isHairy then
|
||||
matchedIndex = matchedIndex + 5
|
||||
end
|
||||
|
||||
if isCicatrized then
|
||||
if isHairy then
|
||||
matchedIndex = matchedIndex + 5 -- to use the cicatrized texture on hairy bodies
|
||||
else
|
||||
matchedIndex = matchedIndex + 10 -- cicatrized texture only, no hairs
|
||||
end
|
||||
end
|
||||
|
||||
return matchedIndex - 1
|
||||
end
|
||||
|
||||
---Main function to delete a clothing item
|
||||
---@param playerObj IsoPlayer
|
||||
---@param clothingItem InventoryItem?
|
||||
---@return boolean
|
||||
---@private
|
||||
function ItemsHandler.RemoveClothingItem(playerObj, clothingItem)
|
||||
if clothingItem and instanceof(clothingItem, "InventoryItem") then
|
||||
playerObj:removeWornItem(clothingItem)
|
||||
|
||||
playerObj:getInventory():Remove(clothingItem) -- Can be a InventoryItem too.. I guess? todo check it
|
||||
print("TOC: found and deleted " .. tostring(clothingItem))
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Search and deletes an old amputation clothing item on the same side
|
||||
---@param playerObj IsoPlayer
|
||||
---@param limbName string
|
||||
function ItemsHandler.DeleteOldAmputationItem(playerObj, limbName)
|
||||
local side = CommonMethods.GetSide(limbName)
|
||||
for partName, _ in pairs(StaticData.PARTS_STRINGS) do
|
||||
local othLimbName = partName .. "_" .. side
|
||||
local othClothingItemName = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. othLimbName
|
||||
|
||||
-- TODO FindAndReturn could return an ArrayList. We need to check for that
|
||||
local othClothingItem = playerObj:getInventory():FindAndReturn(othClothingItemName)
|
||||
|
||||
|
||||
-- If we manage to find and remove an item, then we should stop this function.
|
||||
---@cast othClothingItem InventoryItem
|
||||
if ItemsHandler.RemoveClothingItem(playerObj, othClothingItem) then return end
|
||||
end
|
||||
end
|
||||
|
||||
---Deletes all the old amputation items, used for resets
|
||||
---@param playerObj IsoPlayer
|
||||
function ItemsHandler.DeleteAllOldAmputationItems(playerObj)
|
||||
|
||||
for i=1, #StaticData.LIMBS_STRINGS do
|
||||
local limbName = StaticData.LIMBS_STRINGS[i]
|
||||
local clothItemName = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName
|
||||
local clothItem = playerObj:getInventory():FindAndReturn(clothItemName)
|
||||
---@cast clothItem InventoryItem
|
||||
ItemsHandler.RemoveClothingItem(playerObj, clothItem)
|
||||
end
|
||||
end
|
||||
|
||||
---Spawns and equips the correct amputation item to the player.
|
||||
function ItemsHandler.SpawnAmputationItem(playerObj, limbName)
|
||||
print("Clothing name " .. StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||
local clothingItem = playerObj:getInventory():AddItem(StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||
local texId = ItemsHandler.GetAmputationTexturesIndex(playerObj, false)
|
||||
|
||||
---@cast clothingItem InventoryItem
|
||||
clothingItem:getVisual():setTextureChoice(texId) -- it counts from 0, so we have to subtract 1
|
||||
playerObj:setWornItem(clothingItem:getBodyLocation(), clothingItem)
|
||||
end
|
||||
|
||||
--------------------------
|
||||
--* Overrides *--
|
||||
|
||||
local og_ISInventoryPane_refreshContainer = ISInventoryPane.refreshContainer
|
||||
|
||||
---Get the list of items for the container and remove the reference to the amputation items
|
||||
function ISInventoryPane:refreshContainer()
|
||||
og_ISInventoryPane_refreshContainer(self)
|
||||
if TOC_DEBUG.disablePaneMod then return end
|
||||
for i=1, #self.itemslist do
|
||||
local cItem = self.itemslist[i]
|
||||
if cItem and cItem.cat == "Amputation" then
|
||||
--print("TOC: current item is an amputation, removing it from the list")
|
||||
table.remove(self.itemslist, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ItemsHandler
|
||||
179
media/lua/client/TOC/Handlers/ModDataHandler.lua
Normal file
179
media/lua/client/TOC/Handlers/ModDataHandler.lua
Normal file
@@ -0,0 +1,179 @@
|
||||
local StaticData = require("TOC/StaticData")
|
||||
|
||||
----------------
|
||||
---@alias partData { isCut : boolean?, isInfected : boolean?, isOperated : boolean?, isCicatrized : boolean?, isCauterized : boolean?, isVisible : boolean?, cicatrizationTime : number }
|
||||
---@alias tocModData {Hand_L : partData, ForeArm_L : partData, UpperArm_L : partData, Hand_R : partData, ForeArm_R : partData, UpperArm_R : partData, isIgnoredPartInfected : boolean, isAnyLimbCut : boolean}
|
||||
----------------
|
||||
-- TODO This class should handle all the stuff related to the mod data
|
||||
|
||||
---@class ModDataHandler
|
||||
---@field playerObj IsoPlayer
|
||||
---@field tocData tocModData
|
||||
local ModDataHandler = {}
|
||||
|
||||
---@param playerObj IsoPlayer
|
||||
---@return ModDataHandler
|
||||
function ModDataHandler:new(playerObj)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
o.playerObj = playerObj
|
||||
o.tocData = playerObj:getModData()[StaticData.MOD_NAME]
|
||||
|
||||
ModDataHandler.instance = o
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Setup a newly instanced ModDataHandler
|
||||
---@param force boolean?
|
||||
function ModDataHandler:setup(force)
|
||||
local tocData = self.playerObj:getModData()[StaticData.MOD_NAME]
|
||||
if force or tocData == nil or tocData.Hand_L == nil or tocData.Hand_L.isCut == nil then
|
||||
self:createData()
|
||||
end
|
||||
-- TODO Check compatibility or do we just skip it at this point?
|
||||
end
|
||||
|
||||
function ModDataHandler:createData()
|
||||
print("TOC: createData")
|
||||
|
||||
local modData = self.playerObj:getModData()
|
||||
modData[StaticData.MOD_NAME] = {
|
||||
|
||||
-- Generic stuff that does not belong anywhere else
|
||||
isIgnoredPartInfected = false,
|
||||
isAnyLimbCut = false
|
||||
}
|
||||
|
||||
-- Set a reference to TOC data in ModData
|
||||
self.tocData = self.playerObj:getModData()[StaticData.MOD_NAME]
|
||||
|
||||
---@type partData
|
||||
local defaultParams = {isCut = false, isInfected = false, isOperated = false, isCicatrized = false, isCauterized = false, isVisible = false}
|
||||
|
||||
|
||||
-- Initialize limbs
|
||||
for i=1, #StaticData.LIMBS_STRINGS do
|
||||
local limbName = StaticData.LIMBS_STRINGS[i]
|
||||
modData[StaticData.MOD_NAME][limbName] = {}
|
||||
self:setLimbParams(StaticData.LIMBS_STRINGS[i], defaultParams, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------
|
||||
--* Setters *--
|
||||
|
||||
---Set a generic boolean that toggles varies function of the mod
|
||||
---@param isAnyLimbCut boolean
|
||||
function ModDataHandler:setIsAnyLimbCut(isAnyLimbCut)
|
||||
self.tocData.isAnyLimbCut = true
|
||||
end
|
||||
|
||||
---Set isCut
|
||||
---@param limbName string
|
||||
---@param isCut boolean
|
||||
function ModDataHandler:setIsCut(limbName, isCut)
|
||||
self.tocData[limbName].isCut = isCut
|
||||
end
|
||||
|
||||
---Set isInfected
|
||||
---@param limbName string
|
||||
---@param isInfected boolean
|
||||
function ModDataHandler:setIsInfected(limbName, isInfected)
|
||||
self.tocData[limbName].isInfected = isInfected
|
||||
end
|
||||
|
||||
---Set isIgnoredPartInfected
|
||||
---@param isIgnoredPartInfected boolean
|
||||
function ModDataHandler:setIsIgnoredPartInfected(isIgnoredPartInfected)
|
||||
self.tocData.isIgnoredPartInfected = isIgnoredPartInfected
|
||||
end
|
||||
|
||||
-----------------
|
||||
--* Getters *--
|
||||
|
||||
---Set a generic boolean that toggles varies function of the mod
|
||||
---@return boolean
|
||||
function ModDataHandler:getIsAnyLimbCut()
|
||||
return self.tocData.isAnyLimbCut
|
||||
end
|
||||
|
||||
---Get isCut
|
||||
---@param limbName string
|
||||
---@return boolean
|
||||
function ModDataHandler:getIsCut(limbName)
|
||||
return self.tocData[limbName].isCut
|
||||
end
|
||||
|
||||
---Get isIgnoredPartInfected
|
||||
---@return boolean
|
||||
function ModDataHandler:getIsIgnoredPartInfected()
|
||||
return self.tocData.isIgnoredPartInfected
|
||||
end
|
||||
|
||||
---Get isVisible
|
||||
---@return boolean
|
||||
function ModDataHandler:getIsVisible(limbName)
|
||||
return self.tocData[limbName].isVisible
|
||||
end
|
||||
|
||||
--* Limbs data handling *--
|
||||
|
||||
---Set a limb and its dependend limbs as cut
|
||||
---@param limbName string
|
||||
---@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 partData
|
||||
local params = {isCut = true, isInfected = false, isOperated = isOperated, isCicatrized = isCicatrized, isCauterized = isCauterized, isVisible = true}
|
||||
self:setLimbParams(limbName, params, cicatrizationTime)
|
||||
|
||||
for i=1, #StaticData.LIMBS_DEPENDENCIES[limbName] do
|
||||
local dependedLimbName = StaticData.LIMBS_DEPENDENCIES[limbName][i]
|
||||
|
||||
-- We don't care about isOperated, isCicatrized, isCauterized since this is depending on another limb
|
||||
-- Same story for cicatrizationTime, which will be 0
|
||||
self:setLimbParams(dependedLimbName, {isCut = true, isInfected = false, isVisible = false}, 0)
|
||||
end
|
||||
|
||||
-- Set that a limb has been cut, to activate some functions without having to loop through the parts
|
||||
self:setIsAnyLimbCut(true)
|
||||
|
||||
end
|
||||
|
||||
---Internal use only, set a limb data
|
||||
---@param limbName string
|
||||
---@param ampStatus partData {isCut, isInfected, isOperated, isCicatrized, isCauterized, isVisible}
|
||||
---@param cicatrizationTime integer?
|
||||
---@private
|
||||
function ModDataHandler:setLimbParams(limbName, ampStatus, cicatrizationTime)
|
||||
local limbData = self.tocData[limbName]
|
||||
if ampStatus.isCut ~= nil then limbData.isCut = ampStatus.isCut end
|
||||
if ampStatus.isInfected ~= nil then limbData.isInfected = ampStatus.isInfected end
|
||||
if ampStatus.isOperated ~= nil then limbData.isOperated = ampStatus.isOperated end
|
||||
if ampStatus.isCicatrized ~= nil then limbData.isCicatrized = ampStatus.isCicatrized end
|
||||
if ampStatus.isCauterized ~= nil then limbData.isCauterized = ampStatus.isCauterized end
|
||||
if ampStatus.isVisible ~= nil then limbData.isVisible = ampStatus.isVisible end
|
||||
|
||||
if cicatrizationTime ~= nil then limbData.cicatrizationTime = cicatrizationTime end
|
||||
end
|
||||
|
||||
---@return ModDataHandler
|
||||
function ModDataHandler.GetInstance()
|
||||
if ModDataHandler.instance ~= nil then
|
||||
return ModDataHandler.instance
|
||||
else
|
||||
return ModDataHandler:new(getPlayer())
|
||||
end
|
||||
end
|
||||
|
||||
return ModDataHandler
|
||||
154
media/lua/client/TOC/Handlers/PlayerHandler.lua
Normal file
154
media/lua/client/TOC/Handlers/PlayerHandler.lua
Normal file
@@ -0,0 +1,154 @@
|
||||
local ModDataHandler = require("TOC/Handlers/ModDataHandler")
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
-----------
|
||||
|
||||
-- TODO We should instantiate this anyway if we want to keep track of cut limbs here. Doing so, we would be able to handle other players too
|
||||
|
||||
-- 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
|
||||
|
||||
---@class PlayerHandler
|
||||
---@field modDataHandler ModDataHandler
|
||||
---@field playerObj IsoPlayer
|
||||
local PlayerHandler = {}
|
||||
|
||||
---Setup player modData
|
||||
---@param _ nil
|
||||
---@param playerObj IsoPlayer
|
||||
---@param isForced boolean?
|
||||
function PlayerHandler.InitializePlayer(_, playerObj, isForced)
|
||||
PlayerHandler.modDataHandler = ModDataHandler:new(playerObj) -- TODO This isn't gonna work for MP purposes
|
||||
PlayerHandler.modDataHandler:setup(isForced)
|
||||
PlayerHandler.playerObj = playerObj
|
||||
|
||||
-- Calculate amputated limbs at startup
|
||||
PlayerHandler.amputatedLimbs = {}
|
||||
|
||||
for i=1, #StaticData.LIMBS_STRINGS do
|
||||
local limbName = StaticData.LIMBS_STRINGS[i]
|
||||
if PlayerHandler.modDataHandler:getIsCut(limbName) then
|
||||
PlayerHandler.AddLocalAmputatedLimb(limbName)
|
||||
end
|
||||
end
|
||||
|
||||
-- Since isForced is used to reset an existing player data, we're gonna clean their ISHealthPanel table too
|
||||
if isForced then
|
||||
ISHealthPanel.highestAmputations = {}
|
||||
local ItemsHandler = require("TOC/Handlers/ItemsHandler")
|
||||
ItemsHandler.DeleteAllOldAmputationItems(playerObj)
|
||||
end
|
||||
end
|
||||
|
||||
---Handles the traits
|
||||
---@param playerObj IsoPlayer
|
||||
function PlayerHandler.ManageTraits(playerObj)
|
||||
local AmputationHandler = require("Handlers/TOC_AmputationHandler")
|
||||
for k, v in pairs(StaticData.TRAITS_BP) do
|
||||
if playerObj:HasTrait(k) then
|
||||
-- Once we find one, we should be done.
|
||||
local tempHandler = AmputationHandler:new(v)
|
||||
tempHandler:execute(false) -- No damage
|
||||
tempHandler:close()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Cache the currently amputated limbs
|
||||
---@param limbName string
|
||||
function PlayerHandler.AddLocalAmputatedLimb(limbName)
|
||||
print("TOC: added " .. limbName .. " to known amputated limbs")
|
||||
table.insert(PlayerHandler.amputatedLimbs, limbName) -- TODO This should be player specific, not generic
|
||||
end
|
||||
|
||||
--* Getters *--
|
||||
|
||||
---Get a table with the strings of the cached amputated limbs
|
||||
---@return table
|
||||
function PlayerHandler.GetAmputatedLimbs()
|
||||
return PlayerHandler.amputatedLimbs or {}
|
||||
end
|
||||
|
||||
--* Events *--
|
||||
|
||||
---Check if the player has an infected (as in, zombie infection) body part
|
||||
---@param character IsoGameCharacter
|
||||
function PlayerHandler.CheckInfection(character)
|
||||
-- This fucking event barely works. Bleeding seems to be the only thing that triggers it
|
||||
if character ~= getPlayer() then return end
|
||||
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() or bodyPart:IsInfected() then
|
||||
if PlayerHandler.modDataHandler:getIsCut(limbName) then
|
||||
bodyPart:SetBitten(false)
|
||||
else
|
||||
PlayerHandler.modDataHandler:setIsInfected(limbName, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check other body parts that are not included in the mod, if there's a bite there then the player is fucked
|
||||
-- We can skip this loop if the player has been infected. The one before we kinda need it to handle correctly the bites in case the player wanna cut stuff off anyway
|
||||
if PlayerHandler.modDataHandler:getIsIgnoredPartInfected() then return end
|
||||
|
||||
for i=1, #StaticData.IGNORED_PARTS_STRINGS do
|
||||
local bodyPartType = BodyPartType[StaticData.IGNORED_PARTS_STRINGS[i]]
|
||||
local bodyPart = bd:getBodyPart(bodyPartType)
|
||||
if bodyPart and (bodyPart:bitten() or bodyPart:IsInfected()) then
|
||||
PlayerHandler.modDataHandler:setIsIgnoredPartInfected(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnPlayerGetDamage.Add(PlayerHandler.CheckInfection)
|
||||
|
||||
|
||||
--* Overrides *--
|
||||
|
||||
local og_ISBaseTimedAction_adjustMaxTime = ISBaseTimedAction.adjustMaxTime
|
||||
--- Adjust time
|
||||
function ISBaseTimedAction:adjustMaxTime(maxTime)
|
||||
local time = og_ISBaseTimedAction_adjustMaxTime(self, maxTime)
|
||||
local modDataHandler = ModDataHandler.GetInstance()
|
||||
if time ~= -1 and modDataHandler and modDataHandler:getIsAnyLimbCut() then
|
||||
local pl = getPlayer()
|
||||
|
||||
for i=1, #PlayerHandler.amputatedLimbs do
|
||||
local limbName = PlayerHandler.amputatedLimbs[i]
|
||||
if modDataHandler:getIsCut(limbName) then
|
||||
local perk = Perks["Side_" .. CommonMethods.GetSide(limbName)]
|
||||
local perkLevel = pl:getPerkLevel(perk)
|
||||
local perkLevelScaled
|
||||
if perkLevel ~= 0 then perkLevelScaled = perkLevel / 10 else perkLevelScaled = 0 end
|
||||
time = time * (StaticData.LIMBS_TIME_MULTIPLIER[limbName] - perkLevelScaled)
|
||||
end
|
||||
end
|
||||
end
|
||||
return time
|
||||
end
|
||||
|
||||
local og_ISBaseTimedAction_perform = ISBaseTimedAction.perform
|
||||
--- After each action, level up perks
|
||||
function ISBaseTimedAction:perform()
|
||||
og_ISBaseTimedAction_perform(self)
|
||||
|
||||
if PlayerHandler.modDataHandler:getIsAnyLimbCut() then
|
||||
for side, _ in pairs(StaticData.SIDES_STRINGS) do
|
||||
local limbName = "Hand_" .. side
|
||||
if ModDataHandler.GetInstance():getIsCut(limbName) then
|
||||
PlayerHandler.playerObj:getXp():AddXP(Perks["Side_" .. side], 2) -- TODO Make it dynamic
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return PlayerHandler
|
||||
58
media/lua/client/TOC/Handlers/ProsthesisHandler.lua
Normal file
58
media/lua/client/TOC/Handlers/ProsthesisHandler.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
|
||||
-------------------------
|
||||
|
||||
---@class ProsthesisHandler
|
||||
local ProsthesisHandler = {}
|
||||
|
||||
|
||||
---Cache the correct texture for the Health Panel for the currently equipped prosthesis
|
||||
function ProsthesisHandler.SetHealthPanelTexture()
|
||||
-- TODO do it
|
||||
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 bodyLocation string
|
||||
---@return boolean
|
||||
function ProsthesisHandler.CheckIfEquippable(bodyLocation)
|
||||
print("Current item is a prosthesis")
|
||||
local side = CommonMethods.GetSide(bodyLocation)
|
||||
|
||||
for i=1, #PlayerHandler.amputatedLimbs do
|
||||
local limbName = PlayerHandler.amputatedLimbs[i]
|
||||
if string.contains(limbName, side) and not string.contains(limbName, "UpperArm") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- No acceptable cut limbs
|
||||
getPlayer():Say("I can't equip this")
|
||||
return false
|
||||
end
|
||||
|
||||
--* Overrides *--
|
||||
|
||||
function ISWearClothing:isValid()
|
||||
local bodyLocation = self.item:getBodyLocation()
|
||||
if not string.contains(bodyLocation, "TOC_ArmProst") then
|
||||
return true
|
||||
else
|
||||
return ProsthesisHandler.CheckIfEquippable(bodyLocation)
|
||||
end
|
||||
end
|
||||
|
||||
local og_ISClothingExtraAction_isValid = ISClothingExtraAction.isValid
|
||||
function ISClothingExtraAction:isValid()
|
||||
local bodyLocation = self.item:getBodyLocation()
|
||||
|
||||
if og_ISClothingExtraAction_isValid(self) and not string.contains(bodyLocation, "TOC_ArmProst") then
|
||||
return true
|
||||
else
|
||||
return ProsthesisHandler.CheckIfEquippable(bodyLocation)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return ProsthesisHandler
|
||||
49
media/lua/client/TOC/Main.lua
Normal file
49
media/lua/client/TOC/Main.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
|
||||
|
||||
------------------
|
||||
---@class Main
|
||||
local Main = {}
|
||||
|
||||
|
||||
---Setups the custom traits
|
||||
function Main.SetupTraits()
|
||||
-- Perks.Left_Hand is defined in perks.txt
|
||||
|
||||
local traitsTable = {}
|
||||
local trait1 = TraitFactory.addTrait("Amputee_Hand", getText("UI_trait_Amputee_Hand"), -8, getText("UI_trait_Amputee_Hand_desc"), false, false)
|
||||
traitsTable[1] = trait1
|
||||
|
||||
local trait2 = TraitFactory.addTrait("Amputee_LowerArm", getText("UI_trait_Amputee_LowerArm"), -10, getText("UI_trait_Amputee_LowerArm_desc"), false, false)
|
||||
traitsTable[2] = trait2
|
||||
|
||||
local trait3 = TraitFactory.addTrait("Amputee_UpperArm", getText("UI_trait_Amputee_UpperArm"), -20, getText("UI_trait_Amputee_UpperArm_desc"), false, false)
|
||||
traitsTable[2] = trait3
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
TraitFactory.addTrait("Insensitive", getText("UI_trait_Insensitive"), 6, getText("UI_trait_Insensitive_desc"), false, false)
|
||||
|
||||
TraitFactory.setMutualExclusive("Amputee_Hand", "Amputee_LowerArm")
|
||||
TraitFactory.setMutualExclusive("Amputee_Hand", "Amputee_UpperArm")
|
||||
TraitFactory.setMutualExclusive("Amputee_LowerArm", "Amputee_UpperArm")
|
||||
end
|
||||
|
||||
|
||||
function Main.Start()
|
||||
Main.SetupTraits()
|
||||
|
||||
-- Starts initialization for local client
|
||||
Events.OnCreatePlayer.Add(PlayerHandler.InitializePlayer)
|
||||
|
||||
end
|
||||
|
||||
--* Events *--
|
||||
|
||||
Events.OnGameBoot.Add(Main.Start)
|
||||
84
media/lua/client/TOC/Test.lua
Normal file
84
media/lua/client/TOC/Test.lua
Normal file
@@ -0,0 +1,84 @@
|
||||
if not getActivatedMods():contains("TEST_FRAMEWORK") or not isDebugEnabled() then return end
|
||||
local TestFramework = require("TestFramework/TestFramework")
|
||||
local TestUtils = require("TestFramework/TestUtils")
|
||||
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
local AmputationHandler = require("Handlers/TOC_AmputationHandler")
|
||||
|
||||
|
||||
TestFramework.registerTestModule("Functionality", "PlayerHandler", function()
|
||||
local Tests = {}
|
||||
function Tests.InitializePlayer()
|
||||
local pl = getPlayer()
|
||||
PlayerHandler.InitializePlayer(_, pl, true)
|
||||
end
|
||||
|
||||
function Tests.SetMaxPerks()
|
||||
local pl = getPlayer()
|
||||
for _=0, 10 do
|
||||
pl:LevelPerk(Perks["Side_L"])
|
||||
pl:LevelPerk(Perks["Side_R"])
|
||||
pl:getXp():setXPToLevel(Perks["Side_L"], pl:getPerkLevel(Perks["Side_L"]))
|
||||
pl:getXp():setXPToLevel(Perks["Side_R"], pl:getPerkLevel(Perks["Side_R"]))
|
||||
end
|
||||
|
||||
SyncXp(pl)
|
||||
end
|
||||
|
||||
function Tests.ResetPerks()
|
||||
local pl = getPlayer()
|
||||
for _=0, 10 do
|
||||
pl:LoseLevel(Perks["Side_L"])
|
||||
pl:LoseLevel(Perks["Side_R"])
|
||||
pl:getXp():setXPToLevel(Perks["Side_L"], pl:getPerkLevel(Perks["Side_L"]))
|
||||
pl:getXp():setXPToLevel(Perks["Side_R"], pl:getPerkLevel(Perks["Side_R"]))
|
||||
end
|
||||
SyncXp(pl)
|
||||
end
|
||||
|
||||
return Tests
|
||||
end)
|
||||
|
||||
|
||||
TestFramework.registerTestModule("Functionality", "Amputation", function()
|
||||
local Tests = {}
|
||||
|
||||
function Tests.CutLeftHand()
|
||||
local handler = AmputationHandler:new("Hand_L")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("Hand_L"))
|
||||
end
|
||||
|
||||
function Tests.CutLeftForearm()
|
||||
local handler = AmputationHandler:new("ForeArm_L")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("ForeArm_L") and PlayerHandler.modDataHandler:getIsCut("Hand_L"))
|
||||
end
|
||||
|
||||
function Tests.CutLeftUpperarm()
|
||||
local handler = AmputationHandler:new("UpperArm_L")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("UpperArm_L") and PlayerHandler.modDataHandler:getIsCut("ForeArm_L") and PlayerHandler.modDataHandler:getIsCut("Hand_L"))
|
||||
end
|
||||
|
||||
function Tests.CutRightHand()
|
||||
local handler = AmputationHandler:new("Hand_R")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("Hand_R"))
|
||||
end
|
||||
|
||||
function Tests.CutRightForearm()
|
||||
local handler = AmputationHandler:new("ForeArm_R")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("ForeArm_R") and PlayerHandler.modDataHandler:getIsCut("Hand_R"))
|
||||
end
|
||||
|
||||
function Tests.CutRightUpperarm()
|
||||
local handler = AmputationHandler:new("UpperArm_R")
|
||||
handler:execute()
|
||||
TestUtils.assert(PlayerHandler.modDataHandler:getIsCut("UpperArm_R") and PlayerHandler.modDataHandler:getIsCut("ForeArm_R") and PlayerHandler.modDataHandler:getIsCut("Hand_R"))
|
||||
end
|
||||
|
||||
return Tests
|
||||
|
||||
end)
|
||||
58
media/lua/client/TOC/TimedActions/CutLimbAction.lua
Normal file
58
media/lua/client/TOC/TimedActions/CutLimbAction.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
require "TimedActions/ISBaseTimedAction"
|
||||
local AmputationHandler = require("Handlers/TOC_AmputationHandler")
|
||||
|
||||
|
||||
-----------------------------
|
||||
|
||||
---@class CutLimbAction : ISBaseTimedAction
|
||||
---@field patient IsoPlayer
|
||||
---@field character IsoPlayer
|
||||
---@field limbName string
|
||||
local CutLimbAction = ISBaseTimedAction:derive("CutLimbAction")
|
||||
|
||||
---Starts CutLimbAction
|
||||
---@param patient IsoPlayer
|
||||
---@param surgeon IsoPlayer
|
||||
---@param limbName string
|
||||
---@return CutLimbAction
|
||||
function CutLimbAction:new(surgeon, patient, limbName)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
-- We need to follow ISBaseTimedAction. self.character is gonna be the surgeon
|
||||
o.character = surgeon
|
||||
o.patient = patient
|
||||
o.limbName = limbName
|
||||
|
||||
o.stopOnWalk = true
|
||||
o.stopOnRun = true
|
||||
|
||||
o.maxTime = 100
|
||||
if o.character:isTimedActionInstant() then o.maxTime = 1 end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function CutLimbAction:isValid()
|
||||
-- TODO Surgeon should be close to patient
|
||||
return true
|
||||
end
|
||||
|
||||
function CutLimbAction:start()
|
||||
if self.patient == self.character then
|
||||
-- Self
|
||||
self.handler = AmputationHandler:new(self.limbName)
|
||||
self.handler:damageDuringAmputation()
|
||||
else
|
||||
-- Other player
|
||||
-- TODO Send Damage
|
||||
end
|
||||
end
|
||||
|
||||
function CutLimbAction:perform()
|
||||
self.handler:execute()
|
||||
ISBaseTimedAction.perform(self)
|
||||
end
|
||||
|
||||
return CutLimbAction
|
||||
115
media/lua/client/TOC/UI/CutLimbInteractions.lua
Normal file
115
media/lua/client/TOC/UI/CutLimbInteractions.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
local BaseHandler = require("UI/TOC_HealthPanelBaseHandler")
|
||||
local CutLimbAction = require("TimedActions/TOC_CutLimbAction")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local ModDataHandler = require("TOC/Handlers/ModDataHandler")
|
||||
|
||||
---------------------
|
||||
|
||||
|
||||
---Check if the item name corresponds to a compatible saw
|
||||
---@param itemName string
|
||||
local function CheckIfSaw(itemName)
|
||||
return itemName == "Saw" or itemName == "GardenSaw" or itemName == "Chainsaw"
|
||||
end
|
||||
|
||||
---Add the action to the queue
|
||||
---@param limbName string
|
||||
---@param surgeon IsoPlayer
|
||||
---@param patient IsoPlayer
|
||||
local function PerformAction(limbName, surgeon, patient)
|
||||
ISTimedActionQueue.add(CutLimbAction:new(surgeon, patient, limbName))
|
||||
end
|
||||
|
||||
---Adds the actions to the inventory context menu
|
||||
---@param surgeonNum number
|
||||
---@param context ISContextMenu
|
||||
local function AddInventoryAmputationOptions(surgeonNum, context)
|
||||
local surgeonObj = getSpecificPlayer(surgeonNum)
|
||||
local option = context:addOption(getText("ContextMenu_Amputate"), nil)
|
||||
local subMenu = context:getNew(context)
|
||||
context:addSubMenu(option, subMenu)
|
||||
for i=1, #StaticData.LIMBS_STRINGS do
|
||||
local limbName = StaticData.LIMBS_STRINGS[i]
|
||||
if not ModDataHandler.GetInstance():getIsCut(limbName) then
|
||||
local limbTranslatedName = getText("ContextMenu_Limb_" .. limbName)
|
||||
subMenu:addOption(limbTranslatedName, limbName, PerformAction, surgeonObj, surgeonObj) -- TODO Should be patient, not surgeon
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Handler for OnFillInventoryObjectContextMenu
|
||||
---@param player number
|
||||
---@param context ISUIElement
|
||||
---@param items table
|
||||
local function AddInventoryAmputationMenu(player, context, items)
|
||||
local item = items[1] -- Selected item
|
||||
if CheckIfSaw(item.name) then
|
||||
AddInventoryAmputationOptions(player, context)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Events.OnFillInventoryObjectContextMenu.Add(AddInventoryAmputationMenu)
|
||||
|
||||
-------------------------------------
|
||||
|
||||
---@class CutLimbHandler : BaseHandler
|
||||
local CutLimbHandler = BaseHandler:derive("CutLimbHandler")
|
||||
|
||||
|
||||
---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 CheckIfSaw(itemType) 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(getText("ContextMenu_Amputate"), nil)
|
||||
local subMenu = context:getNew(context)
|
||||
context:addSubMenu(option, subMenu)
|
||||
for i=1, #StaticData.LIMBS_STRINGS do
|
||||
local limbName = StaticData.LIMBS_STRINGS[i]
|
||||
if not ModDataHandler.GetInstance():getIsCut(limbName) then
|
||||
local limbTranslatedName = getText("ContextMenu_Limb_" .. limbName)
|
||||
subMenu:addOption(limbTranslatedName, self.onMenuOptionSelected, nil)
|
||||
end
|
||||
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:getItemOfType(self.items.ITEMS, itemType)
|
||||
end
|
||||
|
||||
function CutLimbHandler:perform(previousAction, itemType)
|
||||
print("perform cutlimbhandler")
|
||||
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
|
||||
96
media/lua/client/TOC/UI/HealthPanel.lua
Normal file
96
media/lua/client/TOC/UI/HealthPanel.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
|
||||
---@diagnostic disable: duplicate-set-field
|
||||
local CutLimbHandler = require("UI/TOC_CutLimbInteractions")
|
||||
|
||||
---------------------------------
|
||||
|
||||
-- We're overriding ISHealthPanel to add custom textures to the body panel.
|
||||
-- By doing so we can show the player which limbs have been cut without having to use another menu
|
||||
-- We can show prosthesis too this way
|
||||
-- We also manage the drag'n drop of items on the body to let the players use the saw this way too
|
||||
|
||||
ISHealthBodyPartPanel = ISBodyPartPanel:derive("ISHealthBodyPartPanel")
|
||||
|
||||
--* Handling drag n drop of the saw *--
|
||||
|
||||
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
|
||||
|
||||
local og_ISHealthPanel_doBodyPartContextMenu = ISHealthPanel.doBodyPartContextMenu
|
||||
function ISHealthPanel:doBodyPartContextMenu(bodyPart, x, y)
|
||||
og_ISHealthPanel_doBodyPartContextMenu(self, bodyPart, x, y)
|
||||
local playerNum = self.otherPlayer and self.otherPlayer:getPlayerNum() or self.character:getPlayerNum()
|
||||
|
||||
-- To not recreate it but reuse the one that has been created in the original method
|
||||
local context = getPlayerContextMenu(playerNum)
|
||||
local cutLimbHandler = CutLimbHandler:new(self, bodyPart)
|
||||
cutLimbHandler:addToMenu(context)
|
||||
end
|
||||
|
||||
|
||||
--* Modification to handle visible amputation on the health menu *--
|
||||
|
||||
function ISHealthPanel.GetHighestAmputation()
|
||||
ISHealthPanel.highestAmputations = {}
|
||||
for i=1, #PlayerHandler.amputatedLimbs do
|
||||
local limbName = PlayerHandler.amputatedLimbs[i]
|
||||
local index = CommonMethods.GetSide(limbName)
|
||||
if PlayerHandler.modDataHandler:getIsCut(limbName) and PlayerHandler.modDataHandler:getIsVisible(limbName) then
|
||||
ISHealthPanel.highestAmputations[index] = limbName
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local og_ISHealthPanel_initialise = ISHealthPanel.initialise
|
||||
function ISHealthPanel:initialise()
|
||||
if self.character:isFemale() then
|
||||
self.sexPl = "Female"
|
||||
else
|
||||
self.sexPl = "Male"
|
||||
end
|
||||
og_ISHealthPanel_initialise(self)
|
||||
end
|
||||
|
||||
local og_ISHealthPanel_render = ISHealthPanel.render
|
||||
function ISHealthPanel:render()
|
||||
og_ISHealthPanel_render(self)
|
||||
|
||||
-- TODO Handle another player health panel
|
||||
|
||||
if ISHealthPanel.highestAmputations then
|
||||
-- Left Texture
|
||||
if ISHealthPanel.highestAmputations["L"] then
|
||||
local textureL = StaticData.HEALTH_PANEL_TEXTURES[self.sexPl][ISHealthPanel.highestAmputations["L"]]
|
||||
self:drawTexture(textureL, self.healthPanel.x/2 - 2, self.healthPanel.y/2, 1, 1, 0, 0)
|
||||
end
|
||||
|
||||
-- Right Texture
|
||||
if ISHealthPanel.highestAmputations["R"] then
|
||||
local textureR = StaticData.HEALTH_PANEL_TEXTURES[self.sexPl][ISHealthPanel.highestAmputations["R"]]
|
||||
self:drawTexture(textureR, self.healthPanel.x/2 + 2, self.healthPanel.y/2, 1, 1, 0, 0)
|
||||
end
|
||||
else
|
||||
ISHealthPanel.GetHighestAmputation()
|
||||
end
|
||||
end
|
||||
|
||||
-- We need to override this to force the alpha to 1
|
||||
local og_ISCharacterInfoWindow_render = ISCharacterInfoWindow.prerender
|
||||
function ISCharacterInfoWindow:prerender()
|
||||
og_ISCharacterInfoWindow_render(self)
|
||||
self.backgroundColor.a = 1
|
||||
end
|
||||
132
media/lua/client/TOC/UI/HealthPanelBaseHandler.lua
Normal file
132
media/lua/client/TOC/UI/HealthPanelBaseHandler.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
-- Had to copy and paste this stuff from the base game since this is a local only class. Kinda shit, but eh
|
||||
|
||||
---@class BaseHandler : ISBaseObject
|
||||
---@field panel ISUIElement
|
||||
---@field bodyPart BodyPart
|
||||
---@field items table
|
||||
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
|
||||
1
media/lua/client/TOC/UI/ProsthesisBuilderUI.lua
Normal file
1
media/lua/client/TOC/UI/ProsthesisBuilderUI.lua
Normal file
@@ -0,0 +1 @@
|
||||
-- TODO Separate UI to craft prosthesis... No just use the crafting menu you mook
|
||||
67
media/lua/client/TOC/UI/SurgeryInteractions.lua
Normal file
67
media/lua/client/TOC/UI/SurgeryInteractions.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
local PlayerHandler = require("TOC/Handlers/PlayerHandler")
|
||||
local ModDataHandler = require("TOC/Handlers/ModDataHandler")
|
||||
|
||||
---------------
|
||||
|
||||
-- TODO Surgery Kits
|
||||
|
||||
local function AddInventorySurgeryMenu(playerNum, context, items)
|
||||
|
||||
end
|
||||
|
||||
Events.OnFillInventoryObjectContextMenu.Add(AddInventorySurgeryMenu)
|
||||
|
||||
|
||||
-- TODO Oven
|
||||
|
||||
-- TODO We need a class to handle operations, this is just a placeholder
|
||||
local function Cauterize(limbName)
|
||||
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param playerNum any
|
||||
---@param context ISContextMenu
|
||||
---@param worldObjects any
|
||||
---@param test any
|
||||
local function AddOvenContextMenu(playerNum, context, worldObjects, test)
|
||||
local pl = getSpecificPlayer(playerNum)
|
||||
|
||||
if not ModDataHandler.GetInstance():getIsAnyLimbCut() then return end
|
||||
local amputatedLimbs = PlayerHandler.GetAmputatedLimbs()
|
||||
|
||||
local stoveObj = nil
|
||||
for _, obj in pairs(worldObjects) do
|
||||
if instanceof(obj, "IsoStove") then
|
||||
stoveObj = obj
|
||||
break
|
||||
end
|
||||
end
|
||||
if stoveObj == nil then return end
|
||||
if pl:HasTrait("Brave") or pl:getPerkLevel(Perks.Strength) > 5 then
|
||||
local isTempLow = stoveObj:getCurrentTemperature() < 250
|
||||
local tempTooltip = ISToolTip:new()
|
||||
tempTooltip:initialise()
|
||||
tempTooltip:setName("ContextMenu_Cauterize_TempTooLow_tooltip")
|
||||
tempTooltip.description = getText("Tooltip_Surgery_TempTooLow")
|
||||
tempTooltip:setVisible(false)
|
||||
|
||||
local optionMain = context:addOption(getText("ContextMenu_Cauterize"), nil)
|
||||
local subMenu = context:getNew(context)
|
||||
context:addSubMenu(optionMain, subMenu)
|
||||
for i=1, #amputatedLimbs do
|
||||
local limbName = amputatedLimbs[i]
|
||||
local option = subMenu:addOption(getText("ContextMenu_Limb_" .. limbName), limbName, Cauterize)
|
||||
option.notAvailable = isTempLow
|
||||
if isTempLow then
|
||||
option.toolTip = tempTooltip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Events.OnFillWorldObjectContextMenu.Add(AddOvenContextMenu)
|
||||
|
||||
|
||||
-- TODO Other stuff?
|
||||
Reference in New Issue
Block a user