From f25d19a009a80b57d63f026b6a8931174b3c4364 Mon Sep 17 00:00:00 2001 From: Manason Date: Mon, 20 Nov 2023 09:02:58 -0800 Subject: [PATCH] refactor: split injuries from body parts --- client/damage/damage-effects.lua | 34 ++++++------ client/damage/damage.lua | 65 ++++++++++++----------- client/main.lua | 88 ++++++++------------------------ client/wounding.lua | 6 +-- config.lua | 27 ++++++++-- server/main.lua | 16 +----- 6 files changed, 101 insertions(+), 135 deletions(-) diff --git a/client/damage/damage-effects.lua b/client/damage/damage-effects.lua index 5aa4aa7..1c04a66 100644 --- a/client/damage/damage-effects.lua +++ b/client/damage/damage-effects.lua @@ -4,10 +4,10 @@ local headCount = 0 ---based off of injuries to leg bodyparts of a certain severity. ---@param bodyPartKey BodyPartKey ----@param bodyPart BodyPart +---@param severity number ---@return boolean isLegDamaged if leg is considered damaged -local function isLegDamaged(bodyPartKey, bodyPart) - return (bodyPartKey == 'LLEG' and bodyPart.severity > 1) or (bodyPartKey == 'RLEG' and bodyPart.severity > 1) or (bodyPartKey == 'LFOOT' and bodyPart.severity > 2) or (bodyPartKey == 'RFOOT' and bodyPart.severity > 2) +local function isLegDamaged(bodyPartKey, severity) + return (bodyPartKey == 'LLEG' and severity > 1) or (bodyPartKey == 'RLEG' and severity > 1) or (bodyPartKey == 'LFOOT' and severity > 2) or (bodyPartKey == 'RFOOT' and severity > 2) end ---shake camera and ragdoll player forward @@ -29,18 +29,18 @@ end ---checks if left arm is damaged based off of injury location and severity. ---@param bodyPartKey BodyPartKey ----@param bodyPart BodyPart +---@param severity integer ---@return boolean isDamaged true if the left arm is damaged -local function isLeftArmDamaged(bodyPartKey, bodyPart) - return (bodyPartKey == 'LARM' and bodyPart.severity > 1) or (bodyPartKey == 'LHAND' and bodyPart.severity > 1) or (bodyPartKey == 'LFINGER' and bodyPart.severity > 2) +local function isLeftArmDamaged(bodyPartKey, severity) + return (bodyPartKey == 'LARM' and severity > 1) or (bodyPartKey == 'LHAND' and severity > 1) or (bodyPartKey == 'LFINGER' and severity > 2) end ---checks if either arm is damaged based on injury location and severity. ---@param bodyPartKey BodyPartKey ----@param bodyPart BodyPart +---@param severity integer ---@return boolean isDamaged true if either arm is damaged -local function isArmDamaged(bodyPartKey, bodyPart) - return isLeftArmDamaged(bodyPartKey, bodyPart) or (bodyPartKey == 'RARM' and bodyPart.severity > 1) or (bodyPartKey == 'RHAND' and bodyPart.severity > 1) or (bodyPartKey == 'RFINGER' and bodyPart.severity > 2) +local function isArmDamaged(bodyPartKey, severity) + return isLeftArmDamaged(bodyPartKey, severity) or (bodyPartKey == 'RARM' and severity > 1) or (bodyPartKey == 'RHAND' and severity > 1) or (bodyPartKey == 'RFINGER' and severity > 2) end ---enforce following arm disabilities on the player for a set time period: @@ -70,10 +70,10 @@ end ---returns whether the player's head is damaged based on injury location and severity. ---@param bodyPartKey BodyPartKey ----@param bodyPart BodyPart +---@param severity integer ---@return boolean -local function isHeadDamaged(bodyPartKey, bodyPart) - return bodyPartKey == 'HEAD' and bodyPart.severity > 2 +local function isHeadDamaged(bodyPartKey, severity) + return bodyPartKey == 'HEAD' and severity > 2 end ---flash screen, fade out, ragdoll, fade in. @@ -99,24 +99,24 @@ end function ApplyDamageEffects() local ped = cache.ped if IsDead or InLaststand then return end - for bodyPartKey, bodyPart in pairs(BodyParts) do - if isLegDamaged(bodyPartKey, bodyPart) then + for bodyPartKey, severity in pairs(Injuries) do + if isLegDamaged(bodyPartKey, severity) then if legCount >= Config.LegInjuryTimer then chancePedFalls(ped) legCount = 0 else legCount += 1 end - elseif isArmDamaged(bodyPartKey, bodyPart) then + elseif isArmDamaged(bodyPartKey, severity) then if armCount >= Config.ArmInjuryTimer then CreateThread(function() - disableArms(ped, isLeftArmDamaged(bodyPartKey, bodyPart)) + disableArms(ped, isLeftArmDamaged(bodyPartKey, severity)) end) armCount = 0 else armCount += 1 end - elseif isHeadDamaged(bodyPartKey, bodyPart) then + elseif isHeadDamaged(bodyPartKey, severity) then if headCount >= Config.HeadInjuryTimer then local chance = math.random(100) diff --git a/client/damage/damage.lua b/client/damage/damage.lua index 1c10f1a..6bf6a38 100644 --- a/client/damage/damage.lua +++ b/client/damage/damage.lua @@ -1,23 +1,30 @@ local playerArmor = nil ---Increases severity of an injury ----@param bodyPart BodyPart ----@param bone Bone -local function upgradeInjury(bodyPart, bone) - if bodyPart.severity >= 4 then return end +---@param bodyPartKey BodyPartKey +local function upgradeInjury(bodyPartKey) + if Injuries[bodyPartKey] >= 4 then return end + Injuries[bodyPartKey] += 1 +end - bodyPart.severity += 1 - DamageBodyPart(bone, bodyPart.severity) +---creates an injury on body part with random severity between 1 and maxSeverity. +---@param bodyPartKey BodyPartKey +---@param maxSeverity number +local function createInjury(bodyPartKey, maxSeverity) + if Injuries[bodyPartKey] then return end + local severity = math.random(1, maxSeverity) + Injuries[bodyPartKey] = severity + NumInjuries += 1 end ---create/upgrade injury at bone. ----@param bone Bone -local function injureBodyPart(bone) - local bodyPart = BodyParts[bone] - if bodyPart.severity == 0 then - CreateInjury(bodyPart, bone, 3) +---@param bodyPartKey BodyPartKey +local function injureBodyPart(bodyPartKey) + local severity = Injuries[bodyPartKey] + if not severity then + createInjury(bodyPartKey, 3) else - upgradeInjury(bodyPart, bone) + upgradeInjury(bodyPartKey) end end @@ -81,24 +88,24 @@ end ---applies a minor bleed if player has no armor and is hit in a critical area. ---also makes player stagger if hit in a certain body part. ---@param ped number ----@param bone Bone body part where player is damaged +---@param bodyPartKey BodyPartKey body part where player is damaged ---@param armor number -local function applyImmediateMinorEffects(ped, bone, armor) - if Config.CriticalAreas[bone] and armor <= 0 then +local function applyImmediateMinorEffects(ped, bodyPartKey, armor) + if Config.CriticalAreas[bodyPartKey] and armor <= 0 then ApplyBleed(1) end - local staggerArea = Config.StaggerAreas[bone] + local staggerArea = Config.StaggerAreas[bodyPartKey] if not staggerArea then return end applyStaggerEffect(ped, staggerArea.armored, staggerArea.minor, armor) end ---Applies bleed with probability based on armor and location hit. Also applies stagger effect. ---@param ped number ----@param bone Bone body part where player is damaged +---@param bodyPartKey BodyPartKey body part where player is damaged ---@param armor number -local function applyImmediateMajorEffects(ped, bone, armor) - local criticalArea = Config.CriticalAreas[bone] +local function applyImmediateMajorEffects(ped, bodyPartKey, armor) + local criticalArea = Config.CriticalAreas[bodyPartKey] if criticalArea then if armor > 0 and criticalArea.armored then if math.random(100) <= math.ceil(Config.MajorArmoredBleedChance) then @@ -117,22 +124,22 @@ local function applyImmediateMajorEffects(ped, bone, armor) end end - local staggerArea = Config.StaggerAreas[bone] + local staggerArea = Config.StaggerAreas[bodyPartKey] if not staggerArea then return end applyStaggerEffect(ped, staggerArea.armored, staggerArea.major, armor) end ---Apply bleeds and staggers effects on damage taken, taking into account armor. ---@param ped number ----@param bone Bone +---@param bodyPartKey BodyPartKey ---@param weapon number ---@param damageDone number -local function applyImmediateEffects(ped, bone, weapon, damageDone) +local function applyImmediateEffects(ped, bodyPartKey, weapon, damageDone) local armor = GetPedArmour(ped) if Config.MinorInjurWeapons[weapon] and damageDone < Config.DamageMinorToMajor then - applyImmediateMinorEffects(ped, bone, armor) + applyImmediateMinorEffects(ped, bodyPartKey, armor) elseif Config.MajorInjurWeapons[weapon] or (Config.MinorInjurWeapons[weapon] and damageDone >= Config.DamageMinorToMajor) then - applyImmediateMajorEffects(ped, bone, armor) + applyImmediateMajorEffects(ped, bodyPartKey, armor) end end @@ -144,14 +151,14 @@ end local function checkDamage(ped, boneId, weapon, damageDone) if not weapon then return end - local bone = Config.Bones[boneId] - if not bone or IsDead or InLaststand then return end + local bodyPartKey = Config.Bones[boneId] + if not bodyPartKey or IsDead or InLaststand then return end - applyImmediateEffects(ped, bone, weapon, damageDone) - injureBodyPart(bone) + applyImmediateEffects(ped, bodyPartKey, weapon, damageDone) + injureBodyPart(bodyPartKey) lib.callback('qbx_medical:server:syncInjuries', false, false,{ - limbs = BodyParts, + injuries = Injuries, isBleeding = BleedLevel }) diff --git a/client/main.lua b/client/main.lua index 5e0bae8..edbfedb 100644 --- a/client/main.lua +++ b/client/main.lua @@ -3,31 +3,8 @@ WeaponsThatDamagedPlayer = {} NumInjuries = 0 ----@class BodyPart ----@field label string ----@field causeLimp boolean ----@field severity integer - ----@alias BodyPartKey string - ----@type table -BodyParts = { - HEAD = { label = Lang:t('body.head'), causeLimp = false, severity = 0 }, - NECK = { label = Lang:t('body.neck'), causeLimp = false, severity = 0 }, - SPINE = { label = Lang:t('body.spine'), causeLimp = true, severity = 0 }, - UPPER_BODY = { label = Lang:t('body.upper_body'), causeLimp = false, severity = 0 }, - LOWER_BODY = { label = Lang:t('body.lower_body'), causeLimp = true, severity = 0 }, - LARM = { label = Lang:t('body.left_arm'), causeLimp = false, severity = 0, }, - LHAND = { label = Lang:t('body.left_hand'), causeLimp = false, severity = 0, }, - LFINGER = { label = Lang:t('body.left_fingers'), causeLimp = false, severity = 0, }, - LLEG = { label = Lang:t('body.left_leg'), causeLimp = true, severity = 0, }, - LFOOT = { label = Lang:t('body.left_foot'), causeLimp = true, severity = 0, }, - RARM = { label = Lang:t('body.right_arm'), causeLimp = false, severity = 0, }, - RHAND = { label = Lang:t('body.right_hand'), causeLimp = false, severity = 0, }, - RFINGER = { label = Lang:t('body.right_fingers'), causeLimp = false, severity = 0, }, - RLEG = { label = Lang:t('body.right_leg'), causeLimp = true, severity = 0, }, - RFOOT = { label = Lang:t('body.right_foot'), causeLimp = true, severity = 0, }, -} +---@type table +Injuries = {} BleedLevel = 0 BleedTickTimer, AdvanceBleedTimer = 0, 0 @@ -102,8 +79,8 @@ end) ---@return boolean isInjuryCausingLimp if injury causes a limp and is damaged. local function isInjuryCausingLimp() - for _, v in pairs(BodyParts) do - if v.causeLimp and v.severity > 0 then + for bodyPartKey in pairs(Injuries) do + if Config.BodyParts[bodyPartKey].causeLimp then return true end end @@ -117,13 +94,12 @@ local function doLimbAlert() local limbDamageMsg = '' if NumInjuries <= Config.AlertShowInfo then local injuriesI = 0 - for _, bodyPart in pairs(BodyParts) do - if bodyPart.severity > 0 then - limbDamageMsg = limbDamageMsg .. Lang:t('info.pain_message', { limb = bodyPart.label, severity = Config.woundLevels[bodyPart.severity].label}) - injuriesI += 1 - if injuriesI < NumInjuries then - limbDamageMsg = limbDamageMsg .. " | " - end + for bodyPartKey, severity in pairs(Injuries) do + local bodyPart = Config.BodyParts[bodyPartKey] + limbDamageMsg = limbDamageMsg .. Lang:t('info.pain_message', { limb = bodyPart.label, severity = Config.woundLevels[severity].label}) + injuriesI += 1 + if injuriesI < NumInjuries then + limbDamageMsg = limbDamageMsg .. " | " end end else @@ -144,9 +120,9 @@ end exports('makePedLimp', MakePedLimp) local function resetMinorInjuries() - for _, bodyPart in pairs(BodyParts) do - if bodyPart.severity > 0 and bodyPart.severity <= 2 then - bodyPart.severity = 0 + for bodyPartKey, severity in pairs(Injuries) do + if severity <= 2 then + Injuries[bodyPartKey] = nil end end @@ -159,7 +135,7 @@ local function resetMinorInjuries() end lib.callback('qbx_medical:server:syncInjuries', false, false,{ - limbs = BodyParts, + injuries = Injuries, isBleeding = BleedLevel }) @@ -169,10 +145,7 @@ local function resetMinorInjuries() end local function resetAllInjuries() - for _, v in pairs(BodyParts) do - v.severity = 0 - end - + Injuries = {} NumInjuries = 0 BleedLevel = 0 BleedTickTimer = 0 @@ -181,7 +154,7 @@ local function resetAllInjuries() BlackoutTimer = 0 lib.callback('qbx_medical:server:syncInjuries', false, false,{ - limbs = BodyParts, + injuries = Injuries, isBleeding = BleedLevel }) @@ -193,27 +166,6 @@ local function resetAllInjuries() lib.callback('qbx_medical:server:resetHungerAndThirst') end -function DamageBodyPart(bone, severity) - BodyParts[bone].severity = severity -end - ----creates an injury on body part with random severity between 1 and maxSeverity. ----@param bodyPart BodyPart ----@param bone Bone ----@param maxSeverity number -function CreateInjury(bodyPart, bone, maxSeverity) - if bodyPart.severity > 0 then return end - - local severity = math.random(1, maxSeverity) - DamageBodyPart(bone, severity) - bodyPart.severity = severity - NumInjuries += 1 -end - -exports('createInjury', function(bodyPart, bone, maxSeverity) - CreateInjury(bodyPart, bone, maxSeverity) -end) - ---notify the player of bleeding to their body. function SendBleedAlert() if IsDead or BleedLevel == 0 then return end @@ -254,12 +206,12 @@ CreateThread(function() end) ---Convert wounded body part data to a human readable form ----@param damagedBodyParts BodyParts ---@return string[] -local function getPatientStatus(damagedBodyParts) +local function getPatientStatus() local status = {} - for _, bodyPart in pairs(damagedBodyParts) do - status[#status + 1] = bodyPart.label .. " (" .. Config.woundLevels[bodyPart.severity].label .. ")" + for bodyPartKey, severity in pairs(Injuries) do + local bodyPart = Config.BodyParts[bodyPartKey] + status[#status + 1] = bodyPart.label .. " (" .. Config.woundLevels[severity].label .. ")" end return status end diff --git a/client/wounding.lua b/client/wounding.lua index 68409a9..6d8a10b 100644 --- a/client/wounding.lua +++ b/client/wounding.lua @@ -2,9 +2,9 @@ local prevPos = vec3(0.0, 0.0, 0.0) local function getWorstInjury() local level = 0 - for _, bodyPart in pairs(BodyParts) do - if bodyPart.severity > level then - level = bodyPart.severity + for _, severity in pairs(Injuries) do + if severity > level then + level = severity end end diff --git a/config.lua b/config.lua index d44f474..5719713 100644 --- a/config.lua +++ b/config.lua @@ -114,10 +114,29 @@ Config.AlwaysBleedChanceWeapons = { -- Define which weapons will always cause bl } Config.AlwaysBleedChance = 70 -- Set the chance out of 100 that if a player is hit with a weapon, that also has a random chance, it will cause bleeding -Config.BodyPart = { - NONE = 0, - HEAD = 1, - +---@alias BodyPartKey string + +---@class BodyPart +---@field label string +---@field causeLimp boolean + +---@type table +Config.BodyParts = { + HEAD = { label = Lang:t('body.head'), causeLimp = false }, + NECK = { label = Lang:t('body.neck'), causeLimp = false }, + SPINE = { label = Lang:t('body.spine'), causeLimp = true }, + UPPER_BODY = { label = Lang:t('body.upper_body'), causeLimp = false }, + LOWER_BODY = { label = Lang:t('body.lower_body'), causeLimp = true }, + LARM = { label = Lang:t('body.left_arm'), causeLimp = false, }, + LHAND = { label = Lang:t('body.left_hand'), causeLimp = false, }, + LFINGER = { label = Lang:t('body.left_fingers'), causeLimp = false, }, + LLEG = { label = Lang:t('body.left_leg'), causeLimp = true, }, + LFOOT = { label = Lang:t('body.left_foot'), causeLimp = true, }, + RARM = { label = Lang:t('body.right_arm'), causeLimp = false, }, + RHAND = { label = Lang:t('body.right_hand'), causeLimp = false, }, + RFINGER = { label = Lang:t('body.right_fingers'), causeLimp = false, }, + RLEG = { label = Lang:t('body.right_leg'), causeLimp = true, }, + RFOOT = { label = Lang:t('body.right_foot'), causeLimp = true, }, } ---@type table diff --git a/server/main.lua b/server/main.lua index 2e78987..1f0c49b 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,5 +1,5 @@ ---@class PlayerStatus ----@field limbs BodyParts +---@field injuries table ---@field isBleeding number ---@alias Source number @@ -47,18 +47,6 @@ lib.callback.register('qbx_medical:server:syncInjuries', function(source, data) playerStatus[source] = data end) ----@param limbs BodyParts ----@return BodyParts -local function getDamagedBodyParts(limbs) - local bodyParts = {} - for bone, bodyPart in pairs(limbs) do - if bodyPart.severity > 0 then - bodyParts[bone] = bodyPart - end - end - return bodyParts -end - ---@param playerId number lib.callback.register('hospital:GetPlayerStatus', function(_, playerId) local playerSource = exports.qbx_core:GetPlayer(playerId).PlayerData.source @@ -81,7 +69,7 @@ lib.callback.register('hospital:GetPlayerStatus', function(_, playerId) local playerInjuries = playerStatus[playerSource] if playerInjuries then damage.bleedLevel = playerInjuries.isBleeding or 0 - damage.damagedBodyParts = getDamagedBodyParts(playerInjuries.limbs) + damage.damagedBodyParts = playerInjuries.injuries end damage.weaponWounds = WeaponsThatDamagedPlayers[playerSource] or {}