From c19a586110099fd2e369d960f263e57477d00b22 Mon Sep 17 00:00:00 2001 From: Pao Date: Fri, 3 Feb 2023 14:19:36 +0100 Subject: [PATCH] Refactor --- media/lua/client/TOC_Checks.lua | 41 ++- media/lua/client/TOC_Client.lua | 10 +- media/lua/client/TOC_CommonFunctions.lua | 32 +-- media/lua/client/TOC_CutLimb.lua | 226 ++++++++++++++++ media/lua/client/TOC_Debug.lua | 32 ++- media/lua/client/TOC_HelperFunctions.lua | 197 +------------- media/lua/client/TOC_LocalActions.lua | 2 +- media/lua/client/TOC_OperateLimb.lua | 69 +++++ media/lua/client/TOC_ProsthesisMethods.lua | 68 +++++ media/lua/client/TOC_Update.lua | 10 + media/lua/client/TOC_main.lua | 247 ++---------------- media/lua/client/TimedActions/ISCutLimb.lua | 2 +- .../TimedActions/ISInstallProsthesis.lua | 2 +- .../TimedActions/ISUninstallProsthesis.lua | 59 +---- 14 files changed, 501 insertions(+), 496 deletions(-) create mode 100644 media/lua/client/TOC_CutLimb.lua create mode 100644 media/lua/client/TOC_OperateLimb.lua create mode 100644 media/lua/client/TOC_ProsthesisMethods.lua diff --git a/media/lua/client/TOC_Checks.lua b/media/lua/client/TOC_Checks.lua index d13a30c..187bf37 100644 --- a/media/lua/client/TOC_Checks.lua +++ b/media/lua/client/TOC_Checks.lua @@ -42,8 +42,47 @@ function CheckIfProsthesisCanBeUnequipped(part_name) return true end -------------------------------- +----------------------------------------- +function CheckIfItemIsAmputatedLimb(item) + -- TODO Benchmark if this is faster + local item_full_type = item:getFullType() + + + if string.find(item_full_type, "TOC.Amputation_") then + return true + else + return false + end + + +end + +function CheckIfItemIsProsthesis(item) + + -- TODO find a cleaner way + local item_full_type = item:getFullType() + local prosthesis_list = GetProsthesisList() + + for _, v in pairs(prosthesis_list) do + if v == item_full_type then + return true + end + end + + return false + +end + +function CheckIfItemIsInstalledProsthesis(item) + local item_full_type = item:getFullType() + if string.find(item_full_type, "TOC.Prost_") then + return true + else + return false + end + +end diff --git a/media/lua/client/TOC_Client.lua b/media/lua/client/TOC_Client.lua index 3c5539f..f65ea1c 100644 --- a/media/lua/client/TOC_Client.lua +++ b/media/lua/client/TOC_Client.lua @@ -44,12 +44,12 @@ function SendEquipProsthesis(player, part_name, prosthesis_base_name) sendClientCommand("TOC", "SendServer", arg) end -function SendUnequipProsthesis(player, part_name, equipped_prosthesis) +function SendUnequipProsthesis(player, part_name) local arg = {} arg["From"] = getPlayer():getOnlineID() arg["To"] = player:getOnlineID() arg["command"] = "UnequipProsthesis" - arg["toSend"] = { part_name, equipped_prosthesis} + arg["toSend"] = { player, part_name} sendClientCommand("TOC", "SendServer", arg) end @@ -100,7 +100,7 @@ end -- Patient (receive) Commands["CutLimb"] = function(arg) local arg = arg["toSend"] - TheOnlyCure.CutLimb(arg[1], arg[2], arg[3], arg[4]) + TocCutLimb(arg[1], arg[2], arg[3], arg[4]) end Commands["OperateLimb"] = function(arg) @@ -116,7 +116,7 @@ Commands["EquipProsthesis"] = function(arg) local arg = arg["toSend"] - TheOnlyCure.EquipProsthesis(arg[1], arg[2]) + TocEquipProsthesis(arg[1], arg[2]) end @@ -126,7 +126,7 @@ Commands["UnequipProsthesis"] = function(arg) local arg = arg["toSend"] - TheOnlyCure.UnequipProsthesis(arg[1]) + TheOnlyCure.UnequipProsthesis(arg[1], arg[2]) end diff --git a/media/lua/client/TOC_CommonFunctions.lua b/media/lua/client/TOC_CommonFunctions.lua index 97d5665..1a26e04 100644 --- a/media/lua/client/TOC_CommonFunctions.lua +++ b/media/lua/client/TOC_CommonFunctions.lua @@ -95,28 +95,18 @@ function TocFindCorrectClothingProsthesis(item_name, part_name) end -function TocFindAmputationInInventory(player, side, limb) +function TocGetAmputationItemInInventory(player, part_name) + local player_inventory = player:getInventory() - local item_name = "TOC.Amputation_" .. side .. "_" .. limb - local found_item = player_inventory:FindAndReturn(item_name) - if found_item then - return found_item:getFullType() - - end - + local amputation_item_name = TocFindAmputationOrProsthesisName(part_name, player, "Amputation") + local amputation_item = player_inventory:FindAndReturn(amputation_item_name) + return amputation_item end -function TocFindEquippedProsthesisInInventory(player, side, limb) - local player_inventory = player:getInventory() - for _, prost in ipairs(GetProsthesisList()) do - local item_name = TocFindCorrectClothingProsthesis(prost, side .."_" .. limb) - local found_item = player_inventory:FindAndReturn(item_name) +function TocGetSawInInventory(surgeon) - if found_item then - return found_item:getFullType() - - end - - end - -end \ No newline at end of file + local player_inv = surgeon:getInventory() + local item = player_inv:getItemFromType("Saw") or player_inv:getItemFromType("GardenSaw") or + player_inv:getItemFromType("Chainsaw") + return item +end diff --git a/media/lua/client/TOC_CutLimb.lua b/media/lua/client/TOC_CutLimb.lua new file mode 100644 index 0000000..b1f6d8c --- /dev/null +++ b/media/lua/client/TOC_CutLimb.lua @@ -0,0 +1,226 @@ +------------------------------------------ +-------- THE ONLY CURE BUT BETTER -------- +------------------------------------------ +----------- CUT LIMB FUNCTIONS ----------- + +local function TocCheckIfStillInfected(limbs_data) + if limbs_data == nil then + return + end + -- Check ALL body part types to check if the player is still gonna die + local check = false + + + for _, v in ipairs(GetBodyParts()) do + if limbs_data[v].is_infected then + check = true + end + end + + if limbs_data.is_other_bodypart_infected then + check = true + end + + return check +end + +local function TocCureInfection(body_damage, part_name) + + local body_part_type = body_damage:getBodyPart(TocGetBodyPartFromPartName(part_name)) + + body_damage:setInfected(false) + body_part_type:SetInfected(false) + body_damage:setInfectionMortalityDuration(-1) + body_damage:setInfectionTime(-1) + body_damage:setInfectionLevel(0) + local body_part_types = body_damage:getBodyParts() + + -- TODO I think this is enough... we should just cycle if with everything instead of that crap up there + for i = body_part_types:size() - 1, 0, -1 do + local bodyPart = body_part_types:get(i); + bodyPart:SetInfected(false); + end + + if body_part_type:scratched() then body_part_type:setScratched(false, false) end + if body_part_type:haveGlass() then body_part_type:setHaveGlass(false) end + if body_part_type:haveBullet() then body_part_type:setHaveBullet(false, 0) end + if body_part_type:isInfectedWound() then body_part_type:setInfectedWound(false) end + if body_part_type:isBurnt() then body_part_type:setBurnTime(0) end + if body_part_type:isCut() then body_part_type:setCut(false, false) end --Lacerations + if body_part_type:getFractureTime() > 0 then body_part_type:setFractureTime(0) end +end + +local function TocDeleteOtherAmputatedLimbs(side) + + -- if left hand is cut and we cut left lowerarm, then delete hand + + + for _, limb in pairs(TOC_limbs) do + local part_name = "TOC.Amputation_" .. side .. "_" .. limb + local amputated_limb = getPlayer():getInventory():FindAndReturn(part_name) + if amputated_limb then + getPlayer():getInventory():Remove(amputated_limb) + end + + end + +end + +---@param heal_bite boolean +local function TocSetParametersForMissingLimb(body_part, heal_bite) + body_part:setBleeding(false) + body_part:setBleedingTime(0) + body_part:setDeepWounded(false) + body_part:setDeepWoundTime(0) + body_part:setScratched(false, false) -- why the fuck are there 2 booleans TIS? + body_part:setScratchTime(0) + body_part:setCut(false) + body_part:setCutTime(0) + + if heal_bite then + body_part:SetBitten(false) + body_part:setBiteTime(0) + end + +end + +function TocDamagePlayerDuringAmputation(patient, part_name) + + -- Since we're cutting that specific part, it only makes sense that the bleeding starts from there. + -- Then, we just delete the bleeding somewhere else before applying the other damage to to upper part of the limb + local body_part_type = TocGetBodyPartFromPartName(part_name) + local body_damage = patient:getBodyDamage() + local body_damage_part = body_damage:getBodyPart(body_part_type) + + + body_damage_part:setBleeding(true) + body_damage_part:setCut(true) + body_damage_part:setBleedingTime(ZombRand(10, 20)) +end + +---------------------------------------------------------------------------------- + +--- Main function for cutting a limb +---@param part_name string the part name to amputate +---@param surgeon_factor any the surgeon factor, which will determine some stats for the inflicted wound +---@param bandage_table any bandages info +---@param painkiller_table any painkillers info, not used +function TocCutLimb(part_name, surgeon_factor, bandage_table, painkiller_table) + + -- TODO Separate Cut Limb in side and limb instead of single part_name + + -- Items get unequipped in ISCutLimb.Start + + local player = getPlayer() + local toc_data = player:getModData().TOC + local limbs_data = toc_data.Limbs + + + + -- TODO Stop for a bit, + + -- Cut Hand -> Damage in forearm + -- Cut Forearm -> Damage in Upperarm + -- Cut UpperArm -> Damage to torso + + local body_damage = player:getBodyDamage() + local body_part = body_damage:getBodyPart(TocGetBodyPartFromPartName(part_name)) + local adiacent_body_part = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(part_name)) + + local stats = player:getStats() + + + + -- Reset the status of the first body part, since we just cut it off it shouldn't be bleeding anymore + -- The bit will be checked later since we're not sure if the player is not infected from another wound + TocSetParametersForMissingLimb(body_part, false) + + -- Set damage, stress, and low endurance after amputation + adiacent_body_part:AddDamage(100 - surgeon_factor) + adiacent_body_part:setAdditionalPain(100 - surgeon_factor) + adiacent_body_part:setBleeding(true) + adiacent_body_part:setBleedingTime(100 - surgeon_factor) + adiacent_body_part:setDeepWounded(true) + adiacent_body_part:setDeepWoundTime(100 - surgeon_factor) + stats:setEndurance(surgeon_factor) + stats:setStress(100 - surgeon_factor) + + + -- Set malus for strength and fitness + player:LoseLevel(Perks.Fitness) + player:LoseLevel(Perks.Strength) + + + + -- If bandages are available, use them + adiacent_body_part:setBandaged(bandage_table.use_bandage, 10, bandage_table.is_bandage_sterilized, + bandage_table.bandage_type) + + + + -- If painkillers are available, use them + -- TODO add painkiller support + + -- Use a tourniquet if available + -- TODO add tourniquet + + if limbs_data[part_name].is_cut == false then + limbs_data[part_name].is_cut = true + limbs_data[part_name].is_amputation_shown = true + limbs_data[part_name].cicatrization_time = limbs_data[part_name].cicatrization_base_time - surgeon_factor * 50 + + for _, depended_v in pairs(limbs_data[part_name].depends_on) do + limbs_data[depended_v].is_cut = true + limbs_data[depended_v].is_amputation_shown = false + limbs_data[depended_v].cicatrization_time = limbs_data[part_name].cicatrization_base_time - + surgeon_factor * 50 + + local should_depended_v_be_healed_of_bite = limbs_data[depended_v].is_infected and + body_damage:getInfectionLevel() < 20 + local depended_body_part = body_damage:getBodyPart(TocGetBodyPartFromPartName(depended_v)) + TocSetParametersForMissingLimb(depended_body_part, should_depended_v_be_healed_of_bite) + + if should_depended_v_be_healed_of_bite then + limbs_data[depended_v].is_infected = false + end + + + + end + + + -- Heal the infection here + local body_damage = player:getBodyDamage() + if limbs_data[part_name].is_infected and body_damage:getInfectionLevel() < 20 then + limbs_data[part_name].is_infected = false + + -- NOT THE ADIACENT ONE!!! + body_part:SetBitten(false) + body_part:setBiteTime(0) + + -- Second check, let's see if there is any other infected limb. + if TocCheckIfStillInfected(limbs_data) == false then + TocCureInfection(body_damage, part_name) + getPlayer():Say("I'm gonna be fine...") -- TODO Make it visible to other players, check True Actions as reference + else + getPlayer():Say("I'm still gonna die...") + end + end + + + + -- Check for older amputation models and deletes them from player's inventory + local side = string.match(part_name, '(%w+)_') + TocDeleteOtherAmputatedLimbs(side) + + --Equip new model for amputation + local amputation_clothing_item = player:getInventory():AddItem(TocFindAmputatedClothingFromPartName(part_name)) + TocSetCorrectTextureForAmputation(amputation_clothing_item, player, false) + player:setWornItem(amputation_clothing_item:getBodyLocation(), amputation_clothing_item) + + + -- Set blood on the amputated limb + TocSetBloodOnAmputation(getPlayer(), adiacent_body_part) + end + +end diff --git a/media/lua/client/TOC_Debug.lua b/media/lua/client/TOC_Debug.lua index 67d729c..59c41af 100644 --- a/media/lua/client/TOC_Debug.lua +++ b/media/lua/client/TOC_Debug.lua @@ -1,3 +1,28 @@ + +-- Side functions +local function TocGetAmputationFullTypeFromInventory(player, side, limb) + local player_inventory = player:getInventory() + local item_name = "TOC.Amputation_" .. side .. "_" .. limb + local found_item = player_inventory:FindAndReturn(item_name) + if found_item then + return found_item:getFullType() + + end + +end + +local function TocGetEquippedProsthesisFullTypeFromInventory(player, side, limb) + local player_inventory = player:getInventory() + for _, prost in ipairs(GetProsthesisList()) do + local item_name = TocFindCorrectClothingProsthesis(prost, side .."_" .. limb) + local found_item = player_inventory:FindAndReturn(item_name) + if found_item then + return found_item:getFullType() + end + end +end + + function TocResetEverything() -- This has to be run on the local player to be sure that we're correctly reassigning everything local player = getPlayer() @@ -16,8 +41,7 @@ function TocResetEverything() -- Destroy the amputation or prosthesis item for _, v in ipairs(GetBodyParts()) do - --local amputated_clothing = player:getInventory():FindAndReturn(TocFindAmputatedClothingFromPartName(v)) - -- TODO make it better + -- TODO This is incredibly shitty local amputation_item_name = TocFindAmputationOrProsthesisName(v, player, "Amputation") local prosthesis_item_name = TocFindAmputationOrProsthesisName(v, player, "Prosthesis") @@ -49,8 +73,8 @@ end function TocResetClothingItemBodyLocation(player, side, limb) local player_inventory = player:getInventory() local limbs_data = player:getModData().TOC.Limbs - local amputation_item_name = TocFindAmputationInInventory(player, side, limb) - local equipped_prosthesis_item_name = TocFindEquippedProsthesisInInventory(player, side, limb) + local amputation_item_name = TocGetAmputationFullTypeFromInventory(player, side, limb) + local equipped_prosthesis_item_name = TocGetEquippedProsthesisFullTypeFromInventory(player, side, limb) print(amputation_item_name) print(equipped_prosthesis_item_name) diff --git a/media/lua/client/TOC_HelperFunctions.lua b/media/lua/client/TOC_HelperFunctions.lua index e0c05e4..2184a96 100644 --- a/media/lua/client/TOC_HelperFunctions.lua +++ b/media/lua/client/TOC_HelperFunctions.lua @@ -1,89 +1,11 @@ --- Init -function TocCutLimbForTrait(player, limbs_data, part_name) - local amputation_clothing_item = player:getInventory():AddItem("TOC.Amputation_" .. part_name) - TocSetCorrectTextureForAmputation(amputation_clothing_item, player, true) - - player:setWornItem(amputation_clothing_item:getBodyLocation(), amputation_clothing_item) - limbs_data[part_name].is_cut = true - limbs_data[part_name].is_operated = true - limbs_data[part_name].is_amputation_shown = true - limbs_data[part_name].is_cicatrized = true - - for _, v in pairs(limbs_data[part_name].depends_on) do - limbs_data[v].is_cut = true - limbs_data[v].is_operated = true - limbs_data[v].is_amputation_shown = false - limbs_data[v].is_cicatrized = true - end -end --- CutLimb -function TocCheckIfStillInfected(limbs_data) - if limbs_data == nil then - return - end - -- Check ALL body part types to check if the player is still gonna die - local check = false - for _, v in ipairs(GetBodyParts()) do - if limbs_data[v].is_infected then - check = true - end - end - if limbs_data.is_other_bodypart_infected then - check = true - end - - return check -end - -function TocCureInfection(body_damage, part_name) - - local body_part_type = body_damage:getBodyPart(TocGetBodyPartFromPartName(part_name)) - - body_damage:setInfected(false) - body_part_type:SetInfected(false) - body_damage:setInfectionMortalityDuration(-1) - body_damage:setInfectionTime(-1) - body_damage:setInfectionLevel(0) - local body_part_types = body_damage:getBodyParts() - - -- TODO I think this is enough... we should just cycle if with everything instead of that crap up there - for i = body_part_types:size() - 1, 0, -1 do - local bodyPart = body_part_types:get(i); - bodyPart:SetInfected(false); - end - - if body_part_type:scratched() then body_part_type:setScratched(false, false) end - if body_part_type:haveGlass() then body_part_type:setHaveGlass(false) end - if body_part_type:haveBullet() then body_part_type:setHaveBullet(false, 0) end - if body_part_type:isInfectedWound() then body_part_type:setInfectedWound(false) end - if body_part_type:isBurnt() then body_part_type:setBurnTime(0) end - if body_part_type:isCut() then body_part_type:setCut(false, false) end --Lacerations - if body_part_type:getFractureTime() > 0 then body_part_type:setFractureTime(0) end -end - -function TocDeleteOtherAmputatedLimbs(side) - - -- if left hand is cut and we cut left lowerarm, then delete hand - - - for _, limb in pairs(TOC_limbs) do - local part_name = "TOC.Amputation_" .. side .. "_" .. limb - local amputated_limb = getPlayer():getInventory():FindAndReturn(part_name) - if amputated_limb then - getPlayer():getInventory():Remove(amputated_limb) - end - - end - -end function TocGetKitInInventory(surgeon) local playerInv = surgeon:getInventory(); @@ -93,79 +15,6 @@ function TocGetKitInInventory(surgeon) end -function TocGetSawInInventory(surgeon) - - local player_inv = surgeon:getInventory() - local item = player_inv:getItemFromType("Saw") or player_inv:getItemFromType("GardenSaw") or - player_inv:getItemFromType("Chainsaw") - return item -end - -function TocDamagePlayerDuringAmputation(patient, part_name) - - -- Since we're cutting that specific part, it only makes sense that the bleeding starts from there. - -- Then, we just delete the bleeding somewhere else before applying the other damage to to upper part of the limb - local body_part_type = TocGetBodyPartFromPartName(part_name) - local body_damage = patient:getBodyDamage() - local body_damage_part = body_damage:getBodyPart(body_part_type) - - - body_damage_part:setBleeding(true) - body_damage_part:setCut(true) - body_damage_part:setBleedingTime(ZombRand(10, 20)) -end - ----@param heal_bite boolean -function TocSetParametersForMissingLimb(body_part, heal_bite) - body_part:setBleeding(false) - body_part:setBleedingTime(0) - body_part:setDeepWounded(false) - body_part:setDeepWoundTime(0) - body_part:setScratched(false, false) -- why the fuck are there 2 booleans TIS? - body_part:setScratchTime(0) - body_part:setCut(false) - body_part:setCutTime(0) - - if heal_bite then - body_part:SetBitten(false) - body_part:setBiteTime(0) - end - -end --- OperateLimb -local function FixSingleBodyPartType(body_part_type, use_oven) - body_part_type:setDeepWounded(false) --Basically like stitching - body_part_type:setDeepWoundTime(0) - if use_oven then - body_part_type:AddDamage(100) - body_part_type:setAdditionalPain(100); - body_part_type:setBleeding(false) - body_part_type:setBleedingTime(0) -- no bleeding since it's been cauterized - else - -- TODO Think a little better about this, do we want to trigger bleeding or not? - body_part_type:setBleeding(false) - - --body_part_type:setBleedingTime(ZombRand(1, 5)) -- Reset the bleeding, maybe make it random - end -end - -function SetBodyPartsStatusAfterOperation(player, limbs_data, part_name, use_oven) - --for _, v in ipairs(GetBodyParts()) do - - - local body_part_type = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(part_name)) - FixSingleBodyPartType(body_part_type, use_oven) - - for _, v in ipairs(limbs_data[part_name].depends_on) do - local depended_body_part_type = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(v)) - FixSingleBodyPartType(depended_body_part_type, use_oven) - - end -end - - - - -- Unequip Prosthesis local function PartNameToBodyLocationProsthesis(name) @@ -200,6 +49,11 @@ function TocFindItemInProstBodyLocation(part_name, patient) end + + + + + -- Debug cheat and update every minute for cicatrization function TocFindAmputationOrProsthesisName(part_name, player, choice) local worn_items = player:getWornItems() @@ -225,47 +79,6 @@ end ------------------------------------- -- Override helper - -function CheckIfItemIsAmputatedLimb(item) - -- TODO Benchmark if this is faster - local item_full_type = item:getFullType() - - - if string.find(item_full_type, "TOC.Amputation_") then - return true - else - return false - end - - -end - -function CheckIfItemIsProsthesis(item) - - -- TODO find a cleaner way - local item_full_type = item:getFullType() - local prosthesis_list = GetProsthesisList() - - for _, v in pairs(prosthesis_list) do - if v == item_full_type then - return true - end - end - - return false - -end - -function CheckIfItemIsInstalledProsthesis(item) - local item_full_type = item:getFullType() - if string.find(item_full_type, "TOC.Prost_") then - return true - else - return false - end - -end - function TocPopulateCanBeHeldTable(can_be_held, limbs_data) for _, side in ipairs(TOC_sides) do diff --git a/media/lua/client/TOC_LocalActions.lua b/media/lua/client/TOC_LocalActions.lua index 8a0ad45..1ad255e 100644 --- a/media/lua/client/TOC_LocalActions.lua +++ b/media/lua/client/TOC_LocalActions.lua @@ -12,7 +12,7 @@ function TocOperateLocal(_, player, part_name, use_oven) if use_oven then ISTimedActionQueue.add(ISOperateLimb:new(player, player, _, part_name, use_oven)); else - local kit = TocGetKitInInventory(player) + local kit = TocGetKitInInventory(player) -- TODO Why is it here and only for local? if kit ~= nil then ISTimedActionQueue.add(ISOperateLimb:new(player, player, kit, part_name, false)) else diff --git a/media/lua/client/TOC_OperateLimb.lua b/media/lua/client/TOC_OperateLimb.lua new file mode 100644 index 0000000..5379e83 --- /dev/null +++ b/media/lua/client/TOC_OperateLimb.lua @@ -0,0 +1,69 @@ +------------------------------------------ +-------- THE ONLY CURE BUT BETTER -------- +------------------------------------------ +--------- OPERATE LIMB FUNCTIONS --------- + +local function FixSingleBodyPartType(body_part_type, use_oven) + body_part_type:setDeepWounded(false) --Basically like stitching + body_part_type:setDeepWoundTime(0) + if use_oven then + body_part_type:AddDamage(100) + body_part_type:setAdditionalPain(100); + body_part_type:setBleeding(false) + body_part_type:setBleedingTime(0) -- no bleeding since it's been cauterized + else + -- TODO Think a little better about this, do we want to trigger bleeding or not? + body_part_type:setBleeding(false) + + --body_part_type:setBleedingTime(ZombRand(1, 5)) -- Reset the bleeding, maybe make it random + end +end + +local function SetBodyPartsStatusAfterOperation(player, limbs_data, part_name, use_oven) + --for _, v in ipairs(GetBodyParts()) do + + + local body_part_type = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(part_name)) + FixSingleBodyPartType(body_part_type, use_oven) + + for _, v in ipairs(limbs_data[part_name].depends_on) do + local depended_body_part_type = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(v)) + FixSingleBodyPartType(depended_body_part_type, use_oven) + + end +end + +---------------------------------------------------------------------------------- + + +---Main function to operate a limb after amputation +---@param part_name any +---@param surgeon_factor any +---@param use_oven boolean wheter using oven instead of a kit or not +function TocOperateLimb(part_name, surgeon_factor, use_oven) + + local player = getPlayer() + local limbs_data = player:getModData().TOC.Limbs + + if use_oven then + local stats = player:getStats() + stats:setEndurance(100) + stats:setStress(100) + end + + if limbs_data[part_name].is_operated == false and limbs_data[part_name].is_cut == true then + limbs_data[part_name].is_operated = true + limbs_data[part_name].cicatrization_time = limbs_data[part_name].cicatrization_time - (surgeon_factor * 200) + if use_oven then limbs_data[part_name].is_cauterized = true end + for _, depended_v in pairs(limbs_data[part_name].depends_on) do + limbs_data[depended_v].is_operated = true + limbs_data[depended_v].cicatrization_time = limbs_data[depended_v].cicatrization_time - + (surgeon_factor * 200) + if use_oven then limbs_data[depended_v].is_cauterized = true end -- TODO does this make sense? + + end + + end + + SetBodyPartsStatusAfterOperation(player, limbs_data, part_name, use_oven) +end diff --git a/media/lua/client/TOC_ProsthesisMethods.lua b/media/lua/client/TOC_ProsthesisMethods.lua new file mode 100644 index 0000000..7445c7e --- /dev/null +++ b/media/lua/client/TOC_ProsthesisMethods.lua @@ -0,0 +1,68 @@ + +------------------------------------------ +-------- THE ONLY CURE BUT BETTER -------- +------------------------------------------ +---------- PROSTHESIS FUNCTIONS ---------- + + +---Equip a prosthesis transforming a normal item into a clothing item +---@param part_name string +---@param prosthesis_base_name string +function TocEquipProsthesis(part_name, prosthesis_base_name) + local player = getPlayer() + + local toc_data = player:getModData().TOC + + local prosthesis_name = TocFindCorrectClothingProsthesis(prosthesis_base_name, part_name) + local added_prosthesis = player:getInventory():AddItem(prosthesis_name) + + if part_name ~= nil then + + if added_prosthesis ~= nil then + toc_data.Limbs[part_name].is_prosthesis_equipped = true + toc_data.Limbs[part_name].equipped_prosthesis = toc_data.Prosthesis[prosthesis_base_name][part_name] + + if player:isFemale() then + added_prosthesis:getVisual():setTextureChoice(1) + else + added_prosthesis:getVisual():setTextureChoice(0) + end + player:setWornItem(added_prosthesis:getBodyLocation(), added_prosthesis) + + + + end + end + + + + + +end + +---Unequip a prosthesis clothing item and returns it to the inventory as a normal item +---@param part_name string +function TheOnlyCure.UnequipProsthesis(patient, part_name) + + + local toc_data = patient:getModData().TOC + toc_data.Limbs[part_name].is_prosthesis_equipped = false + + + local equipped_prosthesis = toc_data.Limbs[part_name].equipped_prosthesis -- TODO Test this + local equipped_prosthesis_full_type = equipped_prosthesis:getFullType() + + + for _, prost_v in ipairs(GetProsthesisList()) do + local prosthesis_name = string.match(equipped_prosthesis_full_type, prost_v) + if prosthesis_name then + patient:getInventory():AddItem("TOC." .. prosthesis_name) + patient:setWornItem(equipped_prosthesis:getBodyLocation(), nil) + patient:getInventory():Remove(equipped_prosthesis) + toc_data.Limbs[part_name].equipped_prosthesis = nil + end + + end + + +end \ No newline at end of file diff --git a/media/lua/client/TOC_Update.lua b/media/lua/client/TOC_Update.lua index fbc9b73..2cd2a37 100644 --- a/media/lua/client/TOC_Update.lua +++ b/media/lua/client/TOC_Update.lua @@ -117,6 +117,16 @@ local function SetHealthStatusForBodyPart(part_data, part_name, player) end + --Wound cleanliness + -- TODO we need to check the upper body part since that's what getting wounded eheh + + + local amputated_limb_item = TocGetAmputationItemInInventory(player, part_name) + + + + --getDirtyness + -- Cicatrization check if not part_data[part_name].is_cicatrized then if part_data[part_name].cicatrization_time < 0 then diff --git a/media/lua/client/TOC_main.lua b/media/lua/client/TOC_main.lua index cb5359a..fc3e596 100644 --- a/media/lua/client/TOC_main.lua +++ b/media/lua/client/TOC_main.lua @@ -5,20 +5,25 @@ end TOC_sides = { "Left", "Right" } TOC_limbs = { "Hand", "LowerArm", "UpperArm" } +local function TocCutLimbForTrait(player, limbs_data, part_name) + local amputation_clothing_item = player:getInventory():AddItem("TOC.Amputation_" .. part_name) + TocSetCorrectTextureForAmputation(amputation_clothing_item, player, true) -function TheOnlyCure.InitTheOnlyCure(_, player) + player:setWornItem(amputation_clothing_item:getBodyLocation(), amputation_clothing_item) + limbs_data[part_name].is_cut = true + limbs_data[part_name].is_operated = true + limbs_data[part_name].is_amputation_shown = true + limbs_data[part_name].is_cicatrized = true - local mod_data = player:getModData() - if mod_data.TOC == nil then - TocSetInitData(mod_data, player) - else - TocCheckCompatibilityWithOlderVersions(mod_data) - TocUpdateBaseData(mod_data) -- Since it's gonna be common to update stuff + for _, v in pairs(limbs_data[part_name].depends_on) do + limbs_data[v].is_cut = true + limbs_data[v].is_operated = true + limbs_data[v].is_amputation_shown = false + limbs_data[v].is_cicatrized = true end - end -function TocSetInitData(mod_data, player) +local function TocSetInitData(mod_data, player) print("TOC: Creating mod_data.TOC") @@ -139,7 +144,7 @@ function TocSetInitData(mod_data, player) end -function TocUpdateBaseData(mod_data) +local function TocUpdateBaseData(mod_data) -- TODO The prosthetic knife needs to be a weapon first and foremost, so other than a -- clothing item it needs to be a weapon too (an invisible one maybe?) @@ -191,6 +196,20 @@ function TocUpdateBaseData(mod_data) end + +function TheOnlyCure.InitTheOnlyCure(_, player) + + local mod_data = player:getModData() + if mod_data.TOC == nil then + TocSetInitData(mod_data, player) + else + TocCheckCompatibilityWithOlderVersions(mod_data) + TocUpdateBaseData(mod_data) -- Since it's gonna be common to update stuff + end + +end + + function TheOnlyCure.DeclareTraits() local amp1 = TraitFactory.addTrait("Amputee_Hand", getText("UI_trait_Amputee_Hand"), -8, getText("UI_trait_Amputee_Hand_desc"), false, false) @@ -211,214 +230,6 @@ function TheOnlyCure.DeclareTraits() TraitFactory.setMutualExclusive("Amputee_LowerArm", "Amputee_UpperArm") end ------------------------------------------------------------------------ -function TheOnlyCure.CutLimb(part_name, surgeon_factor, bandage_table, painkiller_table) - - -- TODO Separate Cut Limb in side and limb instead of single part_name - - -- Items get unequipped in ISCutLimb.Start - - local player = getPlayer() - local toc_data = player:getModData().TOC - local limbs_data = toc_data.Limbs - - - - -- TODO Stop for a bit, - - -- Cut Hand -> Damage in forearm - -- Cut Forearm -> Damage in Upperarm - -- Cut UpperArm -> Damage to torso - - local body_damage = player:getBodyDamage() - local body_part = body_damage:getBodyPart(TocGetBodyPartFromPartName(part_name)) - local adiacent_body_part = player:getBodyDamage():getBodyPart(TocGetAdiacentBodyPartFromPartName(part_name)) - - local stats = player:getStats() - - - - -- Reset the status of the first body part, since we just cut it off it shouldn't be bleeding anymore - -- The bit will be checked later since we're not sure if the player is not infected from another wound - TocSetParametersForMissingLimb(body_part, false) - - -- Set damage, stress, and low endurance after amputation - adiacent_body_part:AddDamage(100 - surgeon_factor) - adiacent_body_part:setAdditionalPain(100 - surgeon_factor) - adiacent_body_part:setBleeding(true) - adiacent_body_part:setBleedingTime(100 - surgeon_factor) - adiacent_body_part:setDeepWounded(true) - adiacent_body_part:setDeepWoundTime(100 - surgeon_factor) - stats:setEndurance(surgeon_factor) - stats:setStress(100 - surgeon_factor) - - - -- Set malus for strength and fitness - player:LoseLevel(Perks.Fitness) - player:LoseLevel(Perks.Strength) - - - - -- If bandages are available, use them - adiacent_body_part:setBandaged(bandage_table.use_bandage, 10, bandage_table.is_bandage_sterilized, - bandage_table.bandage_type) - - - - -- If painkillers are available, use them - -- TODO add painkiller support - - -- Use a tourniquet if available - -- TODO add tourniquet - - if limbs_data[part_name].is_cut == false then - limbs_data[part_name].is_cut = true - limbs_data[part_name].is_amputation_shown = true - limbs_data[part_name].cicatrization_time = limbs_data[part_name].cicatrization_base_time - surgeon_factor * 50 - - for _, depended_v in pairs(limbs_data[part_name].depends_on) do - limbs_data[depended_v].is_cut = true - limbs_data[depended_v].is_amputation_shown = false - limbs_data[depended_v].cicatrization_time = limbs_data[part_name].cicatrization_base_time - - surgeon_factor * 50 - - local should_depended_v_be_healed_of_bite = limbs_data[depended_v].is_infected and - body_damage:getInfectionLevel() < 20 - local depended_body_part = body_damage:getBodyPart(TocGetBodyPartFromPartName(depended_v)) - TocSetParametersForMissingLimb(depended_body_part, should_depended_v_be_healed_of_bite) - - if should_depended_v_be_healed_of_bite then - limbs_data[depended_v].is_infected = false - end - - - - end - - - -- Heal the infection here - local body_damage = player:getBodyDamage() - if limbs_data[part_name].is_infected and body_damage:getInfectionLevel() < 20 then - limbs_data[part_name].is_infected = false - - -- NOT THE ADIACENT ONE!!! - body_part:SetBitten(false) - body_part:setBiteTime(0) - - -- Second check, let's see if there is any other infected limb. - if TocCheckIfStillInfected(limbs_data) == false then - TocCureInfection(body_damage, part_name) - getPlayer():Say("I'm gonna be fine...") -- TODO Make it visible to other players, check True Actions as reference - else - getPlayer():Say("I'm still gonna die...") - end - end - - - - -- Check for older amputation models and deletes them from player's inventory - local side = string.match(part_name, '(%w+)_') - TocDeleteOtherAmputatedLimbs(side) - - --Equip new model for amputation - local amputation_clothing_item = player:getInventory():AddItem(TocFindAmputatedClothingFromPartName(part_name)) - TocSetCorrectTextureForAmputation(amputation_clothing_item, player, false) - player:setWornItem(amputation_clothing_item:getBodyLocation(), amputation_clothing_item) - - - -- Set blood on the amputated limb - TocSetBloodOnAmputation(getPlayer(), adiacent_body_part) - end - - - - -end - -function TocOperateLimb(part_name, surgeon_factor, use_oven) - - local player = getPlayer() - local limbs_data = player:getModData().TOC.Limbs - - if use_oven then - local stats = player:getStats() - stats:setEndurance(100) - stats:setStress(100) - end - - if limbs_data[part_name].is_operated == false and limbs_data[part_name].is_cut == true then - limbs_data[part_name].is_operated = true - limbs_data[part_name].cicatrization_time = limbs_data[part_name].cicatrization_time - (surgeon_factor * 200) - if use_oven then limbs_data[part_name].is_cauterized = true end - for _, depended_v in pairs(limbs_data[part_name].depends_on) do - limbs_data[depended_v].is_operated = true - limbs_data[depended_v].cicatrization_time = limbs_data[depended_v].cicatrization_time - - (surgeon_factor * 200) - if use_oven then limbs_data[depended_v].is_cauterized = true end -- TODO does this make sense? - - end - - end - - SetBodyPartsStatusAfterOperation(player, limbs_data, part_name, use_oven) -end - -function TheOnlyCure.EquipProsthesis(part_name, prosthesis_base_name) - local player = getPlayer() - - local toc_data = player:getModData().TOC - - local prosthesis_name = TocFindCorrectClothingProsthesis(prosthesis_base_name, part_name) - local added_prosthesis = player:getInventory():AddItem(prosthesis_name) - - if part_name ~= nil then - - if added_prosthesis ~= nil then - toc_data.Limbs[part_name].is_prosthesis_equipped = true - toc_data.Limbs[part_name].equipped_prosthesis = toc_data.Prosthesis[prosthesis_base_name][part_name] - - if player:isFemale() then - added_prosthesis:getVisual():setTextureChoice(1) - else - added_prosthesis:getVisual():setTextureChoice(0) - end - player:setWornItem(added_prosthesis:getBodyLocation(), added_prosthesis) - - - - end - end - - - - - -end - -function TheOnlyCure.UnequipProsthesis(part_name, equipped_prosthesis) - local player = getPlayer() - - local toc_data = player:getModData().TOC - - - -- we've got equipped_prosthesis, so we should be able to get it directly - toc_data.Limbs[part_name].is_prosthesis_equipped = false - local equipped_prosthesis_full_type = equipped_prosthesis:getFullType() - - - for _, prost_v in ipairs(GetProsthesisList()) do - local prosthesis_name = string.match(equipped_prosthesis_full_type, prost_v) - if prosthesis_name then - player:getInventory():AddItem("TOC." .. prosthesis_name) - player:setWornItem(equipped_prosthesis:getBodyLocation(), nil) - player:getInventory():Remove(equipped_prosthesis) - end - - end - - -end - function TryTocAction(_, part_name, action, surgeon, patient) -- TODO add checks so that we don't show these menus if a player has already beeen operated or amputated -- TODO at this point surgeon doesnt do anything. We'll fix this later diff --git a/media/lua/client/TimedActions/ISCutLimb.lua b/media/lua/client/TimedActions/ISCutLimb.lua index c41ab50..61687d7 100644 --- a/media/lua/client/TimedActions/ISCutLimb.lua +++ b/media/lua/client/TimedActions/ISCutLimb.lua @@ -116,7 +116,7 @@ function ISCutLimb:perform() if self.patient ~= self.surgeon and isClient() then SendCutLimb(self.patient, self.part_name, surgeon_factor, bandage_table, painkiller_table) else - TheOnlyCure.CutLimb(self.part_name, surgeon_factor, bandage_table, painkiller_table) + TocCutLimb(self.part_name, surgeon_factor, bandage_table, painkiller_table) end self.character:getEmitter():stopSoundByName("Amputation_Sound") diff --git a/media/lua/client/TimedActions/ISInstallProsthesis.lua b/media/lua/client/TimedActions/ISInstallProsthesis.lua index 15034e0..30ecbdb 100644 --- a/media/lua/client/TimedActions/ISInstallProsthesis.lua +++ b/media/lua/client/TimedActions/ISInstallProsthesis.lua @@ -56,7 +56,7 @@ function ISInstallProsthesis:perform() SendEquipProsthesis(self.patient, self.part_name, prosthesis_base_name) else - TheOnlyCure.EquipProsthesis(self.part_name, prosthesis_base_name) + TocEquipProsthesis(self.part_name, prosthesis_base_name) end diff --git a/media/lua/client/TimedActions/ISUninstallProsthesis.lua b/media/lua/client/TimedActions/ISUninstallProsthesis.lua index 20c86c3..47c00aa 100644 --- a/media/lua/client/TimedActions/ISUninstallProsthesis.lua +++ b/media/lua/client/TimedActions/ISUninstallProsthesis.lua @@ -4,7 +4,7 @@ ISUninstallProsthesis = ISBaseTimedAction:derive("ISUninstallProsthesis"); function ISUninstallProsthesis:isValid() - if self.item ~= nil then + if self.item ~= nil and self.is_prosthesis_equipped then return true else return false @@ -56,66 +56,20 @@ function ISUninstallProsthesis:perform() if self.patient ~= self.surgeon and isClient() then - SendUnequipProsthesis(self.patient, self.part_name, self.item) + SendUnequipProsthesis(self.patient, self.part_name) else - TheOnlyCure.UnequipProsthesis(self.part_name, self.item) + TheOnlyCure.UnequipProsthesis(self.patient, self.part_name) end - ISBaseTimedAction.perform(self) - - - - - - - - -- for _, v in ipairs(GetAcceptingProsthesisBodyPartTypes()) do - -- if self.bodyPart:getType() == v then - -- local part_name = TocGetPartNameFromBodyPartType(v) - - -- print("Found prost in " .. part_name) - -- if part_name then - -- toc_data.Limbs[part_name].is_prosthesis_equipped = false - -- local item_full_type = self.item:getFullType() - -- print("Searching for " .. item_full_type) - -- for _, prost_v in ipairs(GetProsthesisList()) do - -- local prosthesis_name = string.match(item_full_type, prost_v) - - -- if prosthesis_name then - -- self.character:getInventory():AddItem(prosthesis_name) - - -- self.character:setWornItem(self.item:getBodyLocation(), nil) - -- self.character:getInventory():Remove(self.item) - -- self.character:transmitModData() - - -- -- needed to remove from queue / start next. - -- ISBaseTimedAction.perform(self) - - -- end - -- end - - -- end - - - - - - - - - - -- end - -- end - - -- TODO Make the object currently on the hand return to the inventory - end function ISUninstallProsthesis:new(surgeon, patient, part_name) local o = ISBaseTimedAction.new(self, surgeon) - o.item = TocFindItemInProstBodyLocation(part_name, patient) + local toc_limbs_data = patient:getModData().TOC.Limbs + + o.item = toc_limbs_data[part_name].equipped_prosthesis o.character = surgeon -- For animation purposes o.patient = patient @@ -124,6 +78,7 @@ function ISUninstallProsthesis:new(surgeon, patient, part_name) o.part_name = part_name + o.is_prosthesis_equipped = toc_limbs_data[part_name].is_prosthesis_equipped o.maxTime = 100;