Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move static body part fields to config #47

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions client/damage/damage-effects.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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.
Expand All @@ -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)

Expand Down
65 changes: 36 additions & 29 deletions client/damage/damage.lua
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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
})

Expand Down
88 changes: 20 additions & 68 deletions client/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,8 @@ WeaponsThatDamagedPlayer = {}

NumInjuries = 0

---@class BodyPart
---@field label string
---@field causeLimp boolean
---@field severity integer

---@alias BodyPartKey string

---@type table<BodyPartKey, BodyPart>
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<BodyPartKey, integer>
Injuries = {}

BleedLevel = 0
BleedTickTimer, AdvanceBleedTimer = 0, 0
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -159,7 +135,7 @@ local function resetMinorInjuries()
end

lib.callback('qbx_medical:server:syncInjuries', false, false,{
limbs = BodyParts,
injuries = Injuries,
isBleeding = BleedLevel
})

Expand All @@ -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
Expand All @@ -181,7 +154,7 @@ local function resetAllInjuries()
BlackoutTimer = 0

lib.callback('qbx_medical:server:syncInjuries', false, false,{
limbs = BodyParts,
injuries = Injuries,
isBleeding = BleedLevel
})

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions client/wounding.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading
Loading