-- Neurotrauma human update functions -- Hooks Lua event "think" to update and use for applying NT specific character data (its called 'c') with -- values/functions defined here in NT.UpdateHuman, NT.LimbAfflictions and NT.Afflictions NT.UpdateCooldown = 0 NT.UpdateInterval = 120 NT.Deltatime = NT.UpdateInterval / 60 -- Time in seconds that transpires between updates Hook.Add("think", "NT.update", function() if HF.GameIsPaused() then return end NT.UpdateCooldown = NT.UpdateCooldown - 1 if NT.UpdateCooldown <= 0 then NT.UpdateCooldown = NT.UpdateInterval NT.Update() end NT.TickUpdate() end) -- gets run once every two seconds function NT.Update() local updateHumans = {} local amountHumans = 0 local updateMonsters = {} local amountMonsters = 0 -- fetchcharacters to update for key, character in pairs(Character.CharacterList) do if not character.IsDead then if character.IsHuman then table.insert(updateHumans, character) amountHumans = amountHumans + 1 else table.insert(updateMonsters, character) amountMonsters = amountMonsters + 1 end end end -- we spread the characters out over the duration of an update so that the load isnt done all at once for key, value in pairs(updateHumans) do -- make sure theyre still alive and human if value ~= nil and not value.Removed and value.IsHuman and not value.IsDead then Timer.Wait(function() if value ~= nil and not value.Removed and value.IsHuman and not value.IsDead then NT.UpdateHuman(value) end end, ((key + 1) / amountHumans) * NT.Deltatime * 1000) end end -- we spread the monsters out over the duration of an update so that the load isnt done all at once for key, value in pairs(updateMonsters) do -- make sure theyre still alive if value ~= nil and not value.Removed and not value.IsDead then Timer.Wait(function() if value ~= nil and not value.Removed and not value.IsDead then NT.UpdateMonster(value) end end, ((key + 1) / amountMonsters) * NT.Deltatime * 1000) end end end -- some local functions to avoid code duplicates local function limbLockedInitial(c, limbtype, key) return not NTC.GetSymptomFalse(c.character, key) and ( NTC.GetSymptom(c.character, key) or c.afflictions.t_paralysis.strength > 0 or NT.LimbIsAmputated(c.character, limbtype) or (HF.GetAfflictionStrengthLimb(c.character, limbtype, "bandaged", 0) <= 0 and HF.GetAfflictionStrengthLimb( c.character, limbtype, "dirtybandage", 0 ) <= 0 and NT.LimbIsDislocated(c.character, limbtype)) or ( HF.GetAfflictionStrengthLimb(c.character, limbtype, "gypsumcast", 0) <= 0 and NT.LimbIsBroken(c.character, limbtype) ) ) end NT.organDamageCalc = function(c, damagevalue, nomaxstrength) if damagevalue >= 99 and (nomaxstrength == nil or nomaxstrength == false) then return 100 end return damagevalue - 0.01 * c.stats.healingrate * c.stats.specificOrganDamageHealMultiplier * NT.Deltatime end local function kidneyDamageCalc(c, damagevalue) if damagevalue >= 99 then return 100 end if damagevalue >= 50 then if damagevalue <= 51 then return damagevalue end return damagevalue - 0.01 * c.stats.healingrate * c.stats.specificOrganDamageHealMultiplier * NT.Deltatime end return damagevalue - 0.02 * c.stats.healingrate * c.stats.specificOrganDamageHealMultiplier * NT.Deltatime end local function isExtremity(type) return type ~= LimbType.Torso and type ~= LimbType.Head end local limbtypes = { LimbType.Torso, LimbType.Head, LimbType.LeftArm, LimbType.RightArm, LimbType.LeftLeg, LimbType.RightLeg, } -- define all the afflictions and their update functions NT.Afflictions = { -- Arterial cuts t_arterialcut = {}, -- Fractures and amputations t_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.Torso)) * NT.Deltatime end end, }, h_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.Head)) * NT.Deltatime end end, }, la_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.LeftArm)) * NT.Deltatime end end, }, ra_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.RightArm)) * NT.Deltatime end end, }, ll_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.LeftLeg)) * NT.Deltatime end end, }, rl_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.RightLeg)) * NT.Deltatime end end, }, n_fracture = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + 2 * HF.BoolToNum(not HF.HasAfflictionLimb(c.character, "gypsumcast", LimbType.Head)) * NT.Deltatime end end, }, tla_amputation = {}, tra_amputation = {}, tll_amputation = {}, trl_amputation = {}, sla_amputation = {}, sra_amputation = {}, sll_amputation = {}, srl_amputation = {}, t_paralysis = {}, alv = {}, -- artificial ventilation needlec = { update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - 0.15 * NT.Deltatime end, }, forceprone = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and not c.character.IsClimbing and ( NTC.GetSymptom(c.character, i) or (c.stats.lockleftleg and c.stats.lockrightleg and not c.stats.wheelchaired) or c.character.IsKeyDown(InputType.Attack) ), 2 ) end, }, onwheelchair = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.stats.wheelchaired), 2 ) end, }, -- Organ conditions cardiacarrest = { update = function(c, i) -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_cardiacarrest") and ( NTC.GetSymptom(c.character, "triggersym_cardiacarrest") or c.stats.stasis or c.afflictions.heartremoved.strength > 0 or c.afflictions.brainremoved.strength > 0 or (c.afflictions.heartdamage.strength > 99 and HF.Chance(0.3)) or (c.afflictions.traumaticshock.strength > 40 and HF.Chance(0.1)) or (c.afflictions.coma.strength > 40 and HF.Chance(0.03)) or (c.afflictions.hypoxemia.strength > 80 and HF.Chance(0.01)) or ( c.afflictions.fibrillation.strength > 20 and HF.Chance((c.afflictions.fibrillation.strength / 100) ^ 4) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 10 end end, }, respiratoryarrest = { update = function(c, i) -- passive regen c.afflictions[i].strength = c.afflictions[i].strength - (0.05 + HF.BoolToNum(c.afflictions.sym_unconsciousness.strength < 0.1, 0.45)) * NT.Deltatime -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_respiratoryarrest") and ( NTC.GetSymptom(c.character, "triggersym_respiratoryarrest") or c.stats.stasis or c.afflictions.lungremoved.strength > 0 or c.afflictions.brainremoved.strength > 0 or c.afflictions.opiateoverdose.strength > 60 or (c.afflictions.lungdamage.strength > 99 and HF.Chance(0.8)) or (c.afflictions.traumaticshock.strength > 30 and HF.Chance(0.2)) or ( (c.afflictions.cerebralhypoxia.strength > 100 or c.afflictions.hypoxemia.strength > 70) and HF.Chance(0.05) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 10 end end, }, pneumothorax = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = HF.Clamp( c.afflictions[i].strength + NT.Deltatime * ( 0.5 -- gain 0.5/s - HF.BoolToNum(c.afflictions[i].strength > 15) * HF.Clamp(c.afflictions.needlec.strength, 0, 1) ), -- ...except if needled and >15%, then lose 0.5/s 0, 100 ) end end, }, tamponade = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = c.afflictions[i].strength + NT.Deltatime * 0.5 end if c.afflictions.heartremoved.strength > 0 then c.afflictions[i].strength = 0 end end, }, heartattack = { update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_heartattack") and not c.stats.stasis and c.afflictions.afstreptokinase.strength <= 0 and c.afflictions.heartremoved.strength <= 0 and ( NTC.GetSymptom(c.character, "triggersym_heartattack") or ( c.afflictions.bloodpressure.strength > 150 and HF.Chance( NTConfig.Get("NT_heartattackChance", 1) * ((c.afflictions.bloodpressure.strength - 150) / 50 * 0.02) ) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 50 end if c.afflictions.heartremoved.strength > 0 then c.afflictions[i].strength = 0 end end, }, -- Organs removed brainremoved = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = 1 + HF.BoolToNum(HF.HasAfflictionLimb(c.character, "retractedskin", LimbType.Head, 99), 99) end end, }, heartremoved = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = 1 + HF.BoolToNum(HF.HasAfflictionLimb(c.character, "retractedskin", LimbType.Torso, 99), 99) end end, }, lungremoved = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = 1 + HF.BoolToNum(HF.HasAfflictionLimb(c.character, "retractedskin", LimbType.Torso, 99), 99) end end, }, liverremoved = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = 1 + HF.BoolToNum(HF.HasAfflictionLimb(c.character, "retractedskin", LimbType.Torso, 99), 99) end end, }, kidneyremoved = { update = function(c, i) if c.afflictions[i].strength > 0 then c.afflictions[i].strength = 1 + HF.BoolToNum(HF.HasAfflictionLimb(c.character, "retractedskin", LimbType.Torso, 99), 99) end end, }, -- Organ damage cerebralhypoxia = { max = 200, update = function(c, i) if c.stats.stasis then return end -- calculate new neurotrauma local gain = ( -0.1 * c.stats.healingrate -- passive regen + c.afflictions.hypoxemia.strength / 100 -- from hypoxemia + HF.Clamp(c.afflictions.stroke.strength, 0, 20) * 0.1 -- from stroke + c.afflictions.sepsis.strength / 100 * 0.4 -- from sepsis + c.afflictions.liverdamage.strength / 800 -- from liverdamage + c.afflictions.kidneydamage.strength / 1000 -- from kidneydamage + c.afflictions.traumaticshock.strength / 100 -- from traumatic shock ) * NT.Deltatime if gain > 0 then gain = gain * NTC.GetMultiplier(c.character, "neurotraumagain") -- NTC multiplier * NTConfig.Get("NT_neurotraumaGain", 1) -- Config multiplier * (1 - HF.Clamp(c.afflictions.afmannitol.strength, 0, 0.5)) -- half if mannitol end c.afflictions[i].strength = c.afflictions[i].strength + gain c.afflictions[i].strength = HF.Clamp(c.afflictions[i].strength, 0, 200) end, }, heartdamage = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = NT.organDamageCalc( c, c.afflictions[i].strength + NTC.GetMultiplier(c.character, "heartdamagegain") * (c.stats.neworgandamage + HF.Clamp(c.afflictions.heartattack.strength, 0, 0.5) * NT.Deltatime) ) end, }, lungdamage = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = NT.organDamageCalc( c, c.afflictions.lungdamage.strength + NTC.GetMultiplier(c.character, "lungdamagegain") * (c.stats.neworgandamage + math.max(c.afflictions.radiationsickness.strength - 25, 0) / 800 * NT.Deltatime) ) end, }, liverdamage = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = NT.organDamageCalc( c, c.afflictions.liverdamage.strength + NTC.GetMultiplier(c.character, "liverdamagegain") * c.stats.neworgandamage ) if c.afflictions[i].strength >= 99 and not NTC.GetSymptom(c.character, "sym_hematemesis") and HF.Chance(0.05) then -- if liver failed: 5% chance for 6-20 seconds of blood vomiting and internal bleeding NTC.SetSymptomTrue(c.character, "sym_hematemesis", math.random(3, 10)) c.afflictions.internalbleeding.strength = c.afflictions.internalbleeding.strength + 2 end end, }, kidneydamage = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = kidneyDamageCalc( c, c.afflictions.kidneydamage.strength + NTC.GetMultiplier(c.character, "kidneydamagegain") * (c.stats.neworgandamage + HF.Clamp((c.afflictions.bloodpressure.strength - 120) / 160, 0, 0.5) * NT.Deltatime * 0.5) ) if c.afflictions[i].strength >= 60 and not NTC.GetSymptom(c.character, "sym_vomiting") and HF.Chance((c.afflictions[i].strength - 60) / 40 * 0.07) then -- at 60% kidney damage: 0% chance for vomiting -- at 100% kidney damage: 7% chance for vomiting NTC.SetSymptomTrue(c.character, "sym_vomiting", math.random(3, 10)) end end, }, bonedamage = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = NT.organDamageCalc( c, c.afflictions.bonedamage.strength + NTC.GetMultiplier(c.character, "bonedamagegain") * (c.afflictions.sepsis.strength / 500 + c.afflictions.hypoxemia.strength / 1000 + math.max( c.afflictions.radiationsickness.strength - 25, 0 ) / 600) * NT.Deltatime ) if c.afflictions[i].strength < 90 then c.afflictions[i].strength = c.afflictions[i].strength - (c.stats.bonegrowthCount * 0.3) * NT.Deltatime elseif c.stats.bonegrowthCount >= 6 then c.afflictions[i].strength = c.afflictions[i].strength - 2 * NT.Deltatime end if c.afflictions.kidneydamage.strength > 70 then c.afflictions[i].strength = c.afflictions[i].strength + (c.afflictions.kidneydamage.strength - 70) / 30 * 0.15 * NT.Deltatime end end, }, organdamage = { max = 200, update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = NT.organDamageCalc(c, c.afflictions.organdamage.strength + c.stats.neworgandamage, true) end, }, -- Blood sepsis = { update = function(c, i) if c.afflictions.afantibiotics.strength > 0.1 then c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime end if c.stats.stasis then return end if c.afflictions[i].strength > 0.1 then c.afflictions[i].strength = c.afflictions[i].strength + 0.05 * NT.Deltatime end end, }, immunity = { default = -1, min = 5, update = function(c, i) if c.afflictions[i].strength == -1 then -- no immunity affliction! -- assume it has been wiped by "revive" or "heal all", attempt to assign new blood type if NT.HasBloodtype(c.character) then -- if blood type is already here, set immunity to the minimum c.afflictions[i].strength = 5 else -- no bloodtype -> all afflictions have been cleared, set immunity to maximum c.afflictions[i].strength = 100 NT.TryRandomizeBlood(c.character) end end if c.stats.stasis then return end -- immunity regeneration c.afflictions[i].strength = HF.Clamp(c.afflictions[i].strength + (0.5 + c.afflictions[i].strength / 100) * NT.Deltatime, 5, 100) end, }, bloodloss = { max = 200 }, bloodpressure = { min = 5, max = 200, default = 100, update = function(c, i) -- fix people not having a blood pressure if not HF.HasAffliction(c.character, i) then HF.SetAffliction(c.character, i, 100) end if c.stats.stasis then return end -- calculate new blood pressure local desiredbloodpressure = ( c.stats.bloodamount - c.afflictions.tamponade.strength / 2 -- -50 if full tamponade - HF.Clamp(c.afflictions.afpressuredrug.strength * 5, 0, 45) -- -45 if blood pressure medication - HF.Clamp(c.afflictions.anesthesia.strength, 0, 15) -- -15 if propofol (fuck propofol) + HF.Clamp(c.afflictions.afadrenaline.strength * 10, 0, 30) -- +30 if adrenaline + HF.Clamp(c.afflictions.afsaline.strength * 5, 0, 30) -- +30 if saline + HF.Clamp(c.afflictions.afringerssolution.strength * 5, 0, 30) -- +30 if ringers ) * (1 + 0.5 * ((c.afflictions.liverdamage.strength / 100) ^ 2)) -- elevated if full liver damage * (1 + 0.5 * ((c.afflictions.kidneydamage.strength / 100) ^ 2)) -- elevated if full kidney damage * (1 + c.afflictions.alcoholwithdrawal.strength / 200) -- elevated if alcohol withdrawal * HF.Clamp((100 - c.afflictions.traumaticshock.strength * 2) / 100, 0, 1) -- none if half or more traumatic shock * ((100 - c.afflictions.fibrillation.strength) / 100) -- lowered if fibrillated * (1 - math.min(1, c.afflictions.cardiacarrest.strength)) -- none if cardiac arrest * NTC.GetMultiplier(c.character, "bloodpressure") local bloodpressurelerp = 0.2 * NTC.GetMultiplier(c.character, "bloodpressurerate") -- adjust three times slower to heightened blood pressure if desiredbloodpressure > c.afflictions.bloodpressure.strength then bloodpressurelerp = bloodpressurelerp / 3 end c.afflictions.bloodpressure.strength = HF.Clamp( HF.Round(HF.Lerp(c.afflictions.bloodpressure.strength, desiredbloodpressure, bloodpressurelerp), 2), 5, 200 ) end, }, hypoxemia = { update = function(c, i) if c.stats.stasis then return end -- completely cancel out hypoxemia regeneration if penumothorax is full c.stats.availableoxygen = math.min(c.stats.availableoxygen, 100 - c.afflictions.pneumothorax.strength / 2) local hypoxemiagain = NTC.GetMultiplier(c.character, "hypoxemiagain") local regularHypoxemiaChange = (-c.stats.availableoxygen + 50) / 8 if regularHypoxemiaChange > 0 then -- not enough oxygen, increase hypoxemia regularHypoxemiaChange = regularHypoxemiaChange * hypoxemiagain else -- enough oxygen, decrease hypoxemia regularHypoxemiaChange = HF.Lerp(regularHypoxemiaChange * 2, 0, HF.Clamp((50 - c.stats.bloodamount) / 50, 0, 1)) end c.afflictions.hypoxemia.strength = HF.Clamp( c.afflictions.hypoxemia.strength + ( -math.min(0, (c.afflictions.bloodpressure.strength - 70) / 7) * hypoxemiagain -- loss because of low blood pressure (+10 at 0 bp) - math.min(0, (c.stats.bloodamount - 60) / 4) * hypoxemiagain -- loss because of low blood amount (+15 at 0 blood) + regularHypoxemiaChange -- change because of oxygen in lungs (+6.25 <> -12.5) ) * NT.Deltatime, 0, 100 ) end, }, hemotransfusionshock = {}, -- Other oxygenlow = { max = 200, update = function(c, i) -- respiratory arrest? -> oxygen in lungs rapidly decreases if c.afflictions.respiratoryarrest.strength > 0 then c.afflictions.oxygenlow.strength = c.afflictions.oxygenlow.strength + 15 * NT.Deltatime end end, }, radiationsickness = { max = 200, update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime * 0.02 end, }, stasis = {}, table = {}, internalbleeding = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime * 0.02 * c.stats.clottingrate if c.afflictions[i].strength > 0 then c.afflictions.bloodloss.strength = c.afflictions.bloodloss.strength + c.afflictions[i].strength * (1 / 40) * NT.Deltatime end end, }, acidosis = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = c.afflictions[i].strength + HF.BoolToNum(c.afflictions.hypoventilation.strength > 0 and c.afflictions.alv.strength <= 0.1) * 0.09 * NT.Deltatime + HF.BoolToNum( ( c.afflictions.cardiacarrest.strength + c.afflictions.respiratoryarrest.strength * HF.BoolToNum(c.afflictions.alv.strength <= 0.1) ) > 0 ) * 0.18 * NT.Deltatime + math.max(0, c.afflictions.kidneydamage.strength - 80) / 20 * 0.1 * NT.Deltatime - NT.Deltatime * 0.03 end, }, alkalosis = { update = function(c, i) if not c.stats.stasis then c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime * 0.03 + HF.Clamp(c.afflictions.hyperventilation.strength, 0, 1) * 0.09 * NT.Deltatime + HF.Clamp(c.afflictions.sym_vomiting.strength, 0, 1) * 0.1 * NT.Deltatime + HF.Clamp(HF.GetAfflictionStrength(c.character, "nausea", 0), 0, 1) * 0.1 * NT.Deltatime end if c.afflictions.acidosis.strength > 1 and c.afflictions.alkalosis.strength > 1 then local min = math.min(c.afflictions.acidosis.strength, c.afflictions.alkalosis.strength) c.afflictions.acidosis.strength = c.afflictions.acidosis.strength - min c.afflictions.alkalosis.strength = c.afflictions.alkalosis.strength - min end end, }, seizure = { update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_seizure") and not c.stats.stasis and ( NTC.GetSymptom(c.character, "triggersym_seizure") or (c.afflictions.stroke.strength > 1 and HF.Chance(0.05)) or (c.afflictions.acidosis.strength > 60 and HF.Chance(0.05)) or (c.afflictions.alkalosis.strength > 60 and HF.Chance(0.05)) or HF.Chance(HF.Minimum(c.afflictions.radiationsickness.strength, 50, 0) / 200 * 0.1) or (c.afflictions.alcoholwithdrawal.strength > 50 and HF.Chance( c.afflictions.alcoholwithdrawal.strength / 1000 )) or ( c.afflictions.opiateoverdose.strength > 60 and HF.Chance(c.afflictions.opiateoverdose.strength / 500) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 10 end -- check for spasm trigger if c.afflictions[i].strength > 0.1 then for type in limbtypes do if HF.Chance(0.5) then HF.AddAfflictionLimb(c.character, "spasm", type, 10) end end end end, }, stroke = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = c.afflictions[i].strength - (1 / 20) * c.stats.clottingrate * NT.Deltatime -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_stroke") and not c.stats.stasis and ( NTC.GetSymptom(c.character, "triggersym_stroke") or ( c.afflictions.bloodpressure.strength > 150 and HF.Chance( NTConfig.Get("NT_strokeChance", 1) * ( (c.afflictions.bloodpressure.strength - 150) / 50 * 0.02 + HF.Clamp(c.afflictions.afstreptokinase.strength, 0, 1) * 0.05 ) ) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 5 end end, }, coma = { update = function(c, i) if c.stats.stasis then return end c.afflictions[i].strength = c.afflictions[i].strength - NT.Deltatime / 5 -- triggers if not NTC.GetSymptomFalse(c.character, "triggersym_coma") and not c.stats.stasis and ( NTC.GetSymptom(c.character, "triggersym_coma") or (c.afflictions.cardiacarrest.strength > 1 and HF.Chance(0.05)) or (c.afflictions.stroke.strength > 1 and HF.Chance(0.05)) or ( c.afflictions.acidosis.strength > 60 and HF.Chance(0.05 + (c.afflictions.acidosis.strength - 60) / 100) ) ) then c.afflictions[i].strength = c.afflictions[i].strength + 14 end end, }, stun = { max = 30, update = function(c, i) if c.afflictions.t_paralysis.strength > 0 or c.afflictions.anesthesia.strength > 15 then c.afflictions[i].strength = math.max(5, c.afflictions[i].strength) end end, apply = function(c, i, newval) -- using the character stun property to apply instead of an affliction so that the networking doesnt shit itself (hopefully) c.character.Stun = newval end, }, slowdown = { lateupdate = function(c, i) c.afflictions[i].strength = HF.Clamp(100 * (1 - c.stats.speedmultiplier), 0, 100) end, }, givein = { max = 1, update = function(c, i) c.afflictions[i].strength = HF.BoolToNum(c.afflictions.t_paralysis.strength > 0 or c.afflictions.sym_unconsciousness.strength > 0) end, }, lockedhands = { update = function(c, i) -- arm locking local leftlockitem = c.character.Inventory.FindItemByIdentifier("armlock2", false) local rightlockitem = c.character.Inventory.FindItemByIdentifier("armlock1", false) -- handcuffs local handcuffs = c.character.Inventory.FindItemByIdentifier("handcuffs", false) local handcuffed = handcuffs ~= nil and c.character.Inventory.FindIndex(handcuffs) <= 6 if handcuffed then -- drop non-handcuff items local leftHandItem = HF.GetItemInLeftHand(c.character) local rightHandItem = HF.GetItemInRightHand(c.character) if leftHandItem ~= nil and leftHandItem ~= handcuffs and leftlockitem == nil then leftHandItem.Drop(c.character) end if rightHandItem ~= nil and rightHandItem ~= handcuffs and rightlockitem == nil then rightHandItem.Drop(c.character) end end local leftarmlocked = leftlockitem ~= nil and not handcuffed local rightarmlocked = rightlockitem ~= nil and not handcuffed if leftarmlocked and not c.stats.lockleftarm then HF.RemoveItem(leftlockitem) end if rightarmlocked and not c.stats.lockrightarm then HF.RemoveItem(rightlockitem) end if not leftarmlocked and c.stats.lockleftarm then HF.ForceArmLock(c.character, "armlock2") end if not rightarmlocked and c.stats.lockrightarm then HF.ForceArmLock(c.character, "armlock1") end c.afflictions[i].strength = HF.BoolToNum((c.stats.lockleftarm and c.stats.lockrightarm) or handcuffed, 100) end, }, traumaticshock = { update = function(c, i) local shouldReduce = (c.stats.sedated and c.afflictions.table.strength > 0) or c.afflictions.anesthesia.strength > 15 c.afflictions[i].strength = c.afflictions[i].strength - (0.5 + HF.BoolToNum(shouldReduce, 1.5)) * NT.Deltatime if c.afflictions[i].strength > 5 and c.afflictions.sym_unconsciousness.strength < 0.1 then HF.AddAffliction(c.character, "shockpain", 10 * NT.Deltatime) HF.AddAffliction(c.character, "psychosis", c.afflictions[i].strength / 100 * NT.Deltatime) end end, }, alcoholwithdrawal = {}, opiatewithdrawal = {}, chemwithdrawal = {}, opiateoverdose = {}, -- Drugs analgesia = { max = 200 }, -- propofol (i hate it) anesthesia = { update = function(c, i) if c.afflictions[i].strength <= 0 then return end -- cause bloody vomiting or hallucinations sometimes (real sideeffects of propofol!) if HF.Chance(0.06) then local case = math.random() local casecount = 7 if case < 1 / casecount then NTC.SetSymptomTrue(c.character, "sym_hematemesis", 5 + math.random() * 10) elseif case < 2 / casecount then NTC.SetSymptomTrue(c.character, "sym_blurredvision", 5 + math.random() * 10) elseif case < 3 / casecount then NTC.SetSymptomTrue(c.character, "sym_confusion", 5 + math.random() * 10) elseif case < 4 / casecount then NTC.SetSymptomTrue(c.character, "sym_fever", 5 + math.random() * 10) elseif case < 5 / casecount then NTC.SetSymptomTrue(c.character, "triggersym_seizure", 1 + math.random() * 2) elseif case < 6 / casecount then NT.Fibrillate(c.character, 5 + math.random() * 30) else HF.AddAffliction(c.character, "psychosis", 10) end end end, }, drunk = { max = 200 }, afadrenaline = {}, afantibiotics = {}, afthiamine = {}, afsaline = {}, afringerssolution = {}, afstreptokinase = {}, afmannitol = {}, afpressuredrug = { update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - 0.25 * NT.Deltatime end, }, concussion = { update = function(c, i) c.afflictions[i].strength = c.afflictions[i].strength - 0.01 * NT.Deltatime if c.afflictions[i].strength <= 0 then return end -- cause headaches, blurred vision, nausea, confusion if HF.Chance(HF.Clamp(c.afflictions[i].strength / 10 * 0.08, 0.02, 0.08)) then local case = math.random() if case < 0.25 then NTC.SetSymptomTrue(c.character, "sym_nausea", 5 + math.random() * 10) elseif case < 0.5 then NTC.SetSymptomTrue(c.character, "sym_blurredvision", 5 + math.random() * 9) elseif case < 0.75 then NTC.SetSymptomTrue(c.character, "sym_headache", 6 + math.random() * 8) else NTC.SetSymptomTrue(c.character, "sym_confusion", 6 + math.random() * 8) end end end, }, -- /// Symptoms /// --============================================================================== sym_unconsciousness = { update = function(c, i) local isUnconscious = not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.stats.stasis or c.afflictions.brainremoved.strength > 0 or (not HF.HasAffliction(c.character, "implacable", 0.05) and (c.character.Vitality <= 0 or c.afflictions.hypoxemia.strength > 80)) or c.afflictions.cerebralhypoxia.strength > 100 or c.afflictions.coma.strength > 15 or c.afflictions.t_arterialcut.strength > 0 or c.afflictions.seizure.strength > 0.1 or c.afflictions.opiateoverdose.strength > 60 ) c.afflictions[i].strength = HF.BoolToNum(isUnconscious, 2) if isUnconscious then c.afflictions.stun.strength = math.max(7, c.afflictions.stun.strength) end end, }, tachycardia = { update = function(c, i) -- harmless symptom (doesnt lead to fibrillation) local hasSymHarmless = not NTC.GetSymptomFalse(c.character, i) and c.afflictions.cardiacarrest.strength < 1 and c.afflictions.heartremoved.strength < 1 and ( NTC.GetSymptom(c.character, i) or c.afflictions.sepsis.strength > 20 or c.stats.bloodamount < 60 or c.afflictions.acidosis.strength > 20 or c.afflictions.pneumothorax.strength > 30 or c.afflictions.afadrenaline.strength > 1 or c.afflictions.alcoholwithdrawal.strength > 75 ) c.afflictions[i].strength = math.max(c.afflictions[i].strength, HF.BoolToNum(hasSymHarmless, 2)) -- harmful symptom (leads to fibrillation and cardiac arrest) local fibrillationSpeed = -0.1 + HF.Clamp(c.afflictions.t_arterialcut.strength, 0, 2) -- aortic rupture (very fast) + HF.Clamp(c.afflictions.acidosis.strength / 200, 0, 0.5) -- acidosis (slow) + HF.Clamp( 0.9 - ( -- low blood pressure (varies) ( c.afflictions.bloodpressure.strength + HF.Clamp(c.afflictions.afpressuredrug.strength * 5, 0, 20) -- less fibrillation from low blood pressure if blood pressure reducing medicines active ) / 90 ), 0, 1 ) * 2 + HF.Clamp(c.afflictions.hypoxemia.strength / 100, 0, 1) * 1.5 -- hypoxemia (varies) + HF.Clamp((c.afflictions.traumaticshock.strength - 5) / 40, 0, 3) -- traumatic shock (fast) - HF.Clamp(c.afflictions.afadrenaline.strength, 0, 0.9) -- faster defib if adrenaline if fibrillationSpeed > 0 and c.afflictions.afadrenaline.strength > 0 then -- if adrenaline, fibrillate half as fast fibrillationSpeed = fibrillationSpeed / 2 end if c.afflictions.cardiacarrest.strength > 0 or c.afflictions.heartremoved.strength > 0 then fibrillationSpeed = -1000 c.afflictions.fibrillation.strength = 0 c.afflictions[i].strength = 0 end -- fibrillation multiplier if fibrillationSpeed > 0 then fibrillationSpeed = fibrillationSpeed * NTC.GetMultiplier(c.character, "fibrillation") * NTConfig.Get("NT_fibrillationSpeed", 1) end if c.afflictions.fibrillation.strength <= 0 then -- havent reached fibrillation yet c.afflictions[i].strength = c.afflictions[i].strength + fibrillationSpeed * 5 * NT.Deltatime -- we reached max tachycardia, switch over to fibrillation if c.afflictions[i].strength >= 100 then c.afflictions.fibrillation.strength = 5 c.afflictions[i].strength = 0 end else -- have reached fibrillation c.afflictions[i].strength = 0 -- set tachycardia to 0 c.afflictions.fibrillation.strength = c.afflictions.fibrillation.strength + fibrillationSpeed * NT.Deltatime end end, }, fibrillation = { update = function(c, i) -- see above for vfib accumulation logic if NTC.GetSymptomFalse(c.character, i) or c.afflictions.cardiacarrest.strength >= 1 or c.afflictions.heartremoved.strength >= 1 then c.afflictions[i].strength = 0 end end, }, hyperventilation = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.respiratoryarrest.strength < 1 and ( NTC.GetSymptom(c.character, i) or c.afflictions.hypoxemia.strength > 10 or c.afflictions.bloodpressure.strength < 80 or c.afflictions.afadrenaline.strength > 1 or c.afflictions.pneumothorax.strength > 15 or c.afflictions.sepsis.strength > 15 ), 2 ) end, }, hypoventilation = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.respiratoryarrest.strength < 1 and ( NTC.GetSymptom(c.character, i) or c.afflictions.analgesia.strength > 20 or c.afflictions.anesthesia.strength > 40 or c.afflictions.opiateoverdose.strength > 30 ), 2 ) if c.afflictions.hyperventilation.strength > 0 and c.afflictions.hypoventilation.strength > 0 then c.afflictions.hyperventilation.strength = 0 c.afflictions.hypoventilation.strength = 0 end end, }, dyspnea = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.respiratoryarrest.strength <= 0 and ( NTC.GetSymptom(c.character, i) or c.afflictions.heartattack.strength > 1 or c.afflictions.heartdamage.strength > 80 or c.afflictions.hypoxemia.strength > 20 or c.afflictions.lungdamage.strength > 45 or c.afflictions.pneumothorax.strength > 40 or c.afflictions.tamponade.strength > 10 or ( c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 70 ) ), 2 ) end, }, sym_cough = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and c.afflictions.lungremoved.strength <= 0 and ( NTC.GetSymptom(c.character, i) or c.afflictions.lungdamage.strength > 50 or c.afflictions.heartdamage.strength > 50 or c.afflictions.tamponade.strength > 20 ), 2 ) end, }, sym_paleskin = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.stats.bloodamount < 60 or c.afflictions.bloodpressure.strength < 50 ), 2 ) end, }, sym_lightheadedness = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.afflictions.bloodpressure.strength < 60), 2 ) end, }, sym_blurredvision = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.afflictions.bloodpressure.strength < 55), 2 ) end, }, sym_confusion = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and ( NTC.GetSymptom(c.character, i) or c.afflictions.acidosis.strength > 15 or c.afflictions.bloodpressure.strength < 30 or c.afflictions.hypoxemia.strength > 50 or c.afflictions.sepsis.strength > 40 or c.afflictions.alcoholwithdrawal.strength > 80 ), 2 ) end, }, sym_headache = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and not c.stats.sedated and ( NTC.GetSymptom(c.character, i) or c.stats.bloodamount < 50 or c.afflictions.acidosis.strength > 20 or c.afflictions.stroke.strength > 1 or c.afflictions.hypoxemia.strength > 40 or c.afflictions.bloodpressure.strength < 60 or c.afflictions.alcoholwithdrawal.strength > 50 or c.afflictions.h_fracture.strength > 0 ), 2 ) end, }, sym_legswelling = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and HF.GetAfflictionStrength(c.character, "rl_cyber", 0) < 0.1 and ( NTC.GetSymptom(c.character, i) or c.afflictions.liverdamage.strength > 40 or c.afflictions.kidneydamage.strength > 60 or c.afflictions.heartdamage.strength > 80 ), 2 ) end, }, sym_weakness = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.afflictions.tamponade.strength > 30 or c.stats.bloodamount < 40 or c.afflictions.acidosis.strength > 35 ), 2 ) end, }, sym_wheezing = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.respiratoryarrest.strength <= 0 and ( NTC.GetSymptom(c.character, i) or ( c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 90 ) ), 2 ) end, }, sym_vomiting = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.afflictions.drunk.strength > 100 or (c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 40) or c.afflictions.alcoholwithdrawal.strength > 60 ), 2 ) end, }, sym_nausea = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.afflictions.kidneydamage.strength > 60 or c.afflictions.radiationsickness.strength > 80 or (c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 90) or c.stats.withdrawal > 40 ), 2 ) end, }, sym_hematemesis = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and (NTC.GetSymptom(c.character, i) or c.afflictions.internalbleeding.strength > 50), 2 ) end, }, fever = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.afflictions.sepsis.strength > 5 or c.afflictions.alcoholwithdrawal.strength > 90 ), 2 ) end, }, sym_abdomdiscomfort = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.afflictions.liverdamage.strength > 65), 2 ) end, }, sym_bloating = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and (NTC.GetSymptom(c.character, i) or c.afflictions.liverdamage.strength > 50), 2 ) end, }, sym_jaundice = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and (NTC.GetSymptom(c.character, i) or c.afflictions.liverdamage.strength > 80), 2 ) end, }, sym_sweating = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and ( NTC.GetSymptom(c.character, i) or c.afflictions.heartattack.strength > 1 or c.stats.withdrawal > 30 ), 2 ) end, }, sym_palpitations = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.cardiacarrest.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.afflictions.alkalosis.strength > 20), 2 ) end, }, sym_craving = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and (NTC.GetSymptom(c.character, i) or c.stats.withdrawal > 20), 2 ) end, }, pain_abdominal = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and not c.stats.sedated and ( NTC.GetSymptom(c.character, i) or (c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 80) or c.afflictions.t_arterialcut.strength > 0 ), 2 ) end, }, pain_chest = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum( not NTC.GetSymptomFalse(c.character, i) and c.afflictions.sym_unconsciousness.strength <= 0 and ( NTC.GetSymptom(c.character, i) or (c.afflictions.hemotransfusionshock.strength > 0 and c.afflictions.hemotransfusionshock.strength < 60) or c.afflictions.t_fracture.strength > 0 or c.afflictions.t_arterialcut.strength > 0 ), 2 ) end, }, luabotomy = { update = function(c, i) c.afflictions[i].strength = 0 end, }, modconflict = { update = function(c, i) c.afflictions[i].strength = HF.BoolToNum(NT.modconflict, 1) end, }, -- Heelge: this really does the same thing as vanilla burns, why does it even exists? --sym_scorched = { -- update = function(c, i) -- c.afflictions[i].strength = HF.BoolToNum(c.stats.burndamage > 500, 10) -- end, --}, } -- define all the limb specific afflictions and their update functions NT.LimbAfflictions = { bandaged = { update = function(c, limbaff, i) -- turning a bandage into a dirty bandage local wounddamage = limbaff.burn.strength + limbaff.lacerations.strength + limbaff.gunshotwound.strength + limbaff.bitewounds.strength + limbaff.explosiondamage.strength local bandageDirtifySpeed = 0.1 + HF.Clamp(wounddamage / 100, 0, 0.4) + limbaff.bleeding.strength / 20 if limbaff[i].strength > 0 then limbaff[i].strength = limbaff[i].strength - bandageDirtifySpeed * NT.Deltatime if limbaff[i].strength <= 0 then -- transition to dirty bandage limbaff.dirtybandage.strength = math.max(limbaff.dirtybandage.strength, 1) limbaff[i].strength = 0 end end if limbaff.dirtybandage.strength > 0 then limbaff.dirtybandage.strength = limbaff.dirtybandage.strength + bandageDirtifySpeed * NT.Deltatime end -- bandage slowdown if limbaff[i].strength > 0 or limbaff.dirtybandage.strength > 0 then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.9 end end, }, dirtybandage = {}, -- for bandage dirtifaction logic see above iced = { update = function(c, limbaff, i, type) -- over time skin temperature goes up again if limbaff[i].strength > 0 then limbaff[i].strength = limbaff[i].strength - 1.7 * NT.Deltatime end -- iced slowdown if limbaff[i].strength > 0 then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.95 end end, }, gypsumcast = { update = function(c, limbaff, i, type) -- gypsum slowdown and fracture healing if limbaff[i].strength > 0 then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.8 NT.BreakLimb(c.character, type, -(100 / 300) * NT.Deltatime) end end, }, ointmented = {}, bonegrowth = { update = function(c, limbaff, i, type) if limbaff[i].strength <= 0 then -- check for bone death fracture triggers if c.afflictions.bonedamage.strength > 90 and HF.Chance(0.01) then NT.BreakLimb(c.character, type) end end end, }, arteriesclamp = {}, -- damage bleeding = { update = function(c, limbaff, i) if limbaff[i].strength > 0 and math.abs(c.stats.clottingrate - 1) > 0.05 then limbaff[i].strength = limbaff[i].strength - (c.stats.clottingrate - 1) * 0.1 * NT.Deltatime end end, }, burn = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 50 then limbaff[i].strength = limbaff[i].strength - (c.afflictions.immunity.prev / 3000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1) * c.stats.healingrate * NT.Deltatime end end, }, acidburn = { max = 200, update = function(c, limbaff, i) -- convert acid burns to regular burns if limbaff[i].strength > 0 then limbaff.burn.strength = limbaff.burn.strength + limbaff[i].strength limbaff[i].strength = 0 end end, }, lacerations = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 50 then limbaff[i].strength = limbaff[i].strength - (c.afflictions.immunity.prev / 3000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1) * c.stats.healingrate * NT.Deltatime end end, }, gunshotwound = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 50 then limbaff[i].strength = limbaff[i].strength - (c.afflictions.immunity.prev / 3000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1) * c.stats.healingrate * NT.Deltatime end end, }, bitewounds = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 100 then limbaff[i].strength = limbaff[i].strength - (c.afflictions.immunity.prev / 3000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1) * c.stats.healingrate * NT.Deltatime end end, }, explosiondamage = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 50 then limbaff[i].strength = limbaff[i].strength - (c.afflictions.immunity.prev / 3000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1) * c.stats.healingrate * NT.Deltatime end end, }, blunttrauma = { max = 200, update = function(c, limbaff, i) if limbaff[i].strength < 100 then limbaff[i].strength = limbaff[i].strength - ( c.afflictions.immunity.prev / 8000 + HF.Clamp(limbaff.bandaged.strength, 0, 1) * 0.1 + HF.Clamp(limbaff.iced.strength, 0, 1) * 0.3 ) * c.stats.healingrate * NT.Deltatime end end, }, internaldamage = { max = 200, update = function(c, limbaff, i, type) limbaff[i].strength = limbaff[i].strength + ( -HF.BoolToNum(limbaff[i].strength < 50, 0.05 * c.stats.healingrate) + HF.BoolToNum( not c.stats.sedated and limbaff.gypsumcast.strength <= 0 and ( ( NT.LimbIsBroken(c.character, type) and ( HF.LimbIsExtremity(type) or (limbaff.bandaged.strength <= 0 and limbaff.dirtybandage.strength <= 0) ) ) or ( NT.LimbIsDislocated(c.character, type) and limbaff.bandaged.strength <= 0 and limbaff.dirtybandage.strength <= 0 ) ), 0.1 ) ) * NT.Deltatime end, }, -- other infectedwound = { update = function(c, limbaff, i) if c.stats.stasis then return end local infectindex = ( -c.afflictions.immunity.prev / 200 - HF.Clamp(limbaff.bandaged.strength, 0, 1) * 1.5 - limbaff.ointmented.strength * 3 + limbaff.burn.strength / 20 + limbaff.lacerations.strength / 40 + limbaff.bitewounds.strength / 30 + limbaff.gunshotwound.strength / 40 + limbaff.explosiondamage.strength / 40 ) * NT.Deltatime local wounddamage = limbaff.burn.strength + limbaff.lacerations.strength + limbaff.gunshotwound.strength + limbaff.bitewounds.strength + limbaff.explosiondamage.strength -- open wounds and a dirty bandage? :grimacing: if limbaff.dirtybandage.strength > 10 and wounddamage > 5 then infectindex = infectindex + (wounddamage / 40 + limbaff.dirtybandage.strength / 20) * NT.Deltatime end if infectindex > 0 then infectindex = infectindex * NTConfig.Get("NT_infectionRate", 1) end limbaff[i].strength = limbaff[i].strength + infectindex / 5 c.afflictions.immunity.strength = c.afflictions.immunity.strength - HF.Clamp(infectindex / 3, 0, 10) end, }, foreignbody = { update = function(c, limbaff, i, type) if limbaff[i].strength < 15 then limbaff[i].strength = limbaff[i].strength - 0.05 * c.stats.healingrate * NT.Deltatime end -- check for arterial cut triggers and foreign body sepsis local foreignbodycutchance = ((HF.Minimum(limbaff[i].strength, 20) / 100) ^ 6) * 0.5 if limbaff.bleeding.strength > 80 or HF.Chance(foreignbodycutchance) then NT.ArteryCutLimb(c.character, type) end -- sepsis local sepsischance = HF.Minimum(limbaff.gangrene.strength, 15, 0) / 400 + HF.Minimum(limbaff.infectedwound.strength, 50) / 1000 + foreignbodycutchance if HF.Chance(sepsischance) then c.afflictions.sepsis.strength = c.afflictions.sepsis.strength + NT.Deltatime end end, }, gangrene = { update = function(c, limbaff, i, type) -- see foreignbody for sepsis chance if isExtremity(type) then -- surgical amputation prevents all gangrene on that stump if NT.LimbIsSurgicallyAmputated(c.character, type) then limbaff[i].strength = 0 return end if limbaff[i].strength < 15 and limbaff[i].strength > 0 then limbaff[i].strength = limbaff[i].strength - 0.01 * c.stats.healingrate * NT.Deltatime end if c.afflictions.sepsis.strength > 5 then limbaff[i].strength = limbaff[i].strength + HF.BoolToNum(HF.Chance(0.04), 0.5 + c.afflictions.sepsis.strength / 150) * NTConfig.Get("NT_gangrenespeed", 1) * NT.Deltatime end if limbaff.arteriesclamp.strength > 0 then limbaff[i].strength = limbaff[i].strength + HF.BoolToNum(HF.Chance(0.1), 1) * 0.5 * NTConfig.Get("NT_gangrenespeed", 1) * NT.Deltatime end end end, }, pain_extremity = { max = 10, update = function(c, limbaff, i, type) if c.afflictions.sym_unconsciousness.strength > 0 then limbaff[i].strength = 0 return end limbaff[i].strength = limbaff[i].strength + ( -0.5 + HF.BoolToNum( type ~= LimbType.Torso and limbaff.gypsumcast.strength <= 0 and ( ( NT.LimbIsBroken(c.character, type) and ( HF.LimbIsExtremity(type) or (limbaff.bandaged.strength <= 0 and limbaff.dirtybandage.strength <= 0) ) ) or ( NT.LimbIsDislocated(c.character, type) and limbaff.bandaged.strength <= 0 and limbaff.dirtybandage.strength <= 0 ) ), 2 ) - HF.BoolToNum(c.stats.sedated, 100) ) * NT.Deltatime end, }, -- limb symptoms inflammation = { update = function(c, limbaff, i) limbaff[i].strength = limbaff[i].strength + ( -0.1 + HF.BoolToNum(limbaff.infectedwound.strength > 10 or limbaff.foreignbody.strength > 15, 0.15) ) * NT.Deltatime end, }, burn_deg1 = { update = function(c, limbaff, i) if limbaff.burn.strength < 1 or limbaff.burn.strength > 20 then limbaff[i].strength = 0 else limbaff[i].strength = limbaff.burn.strength * 5 end end, }, burn_deg2 = { update = function(c, limbaff, i) if limbaff.burn.strength <= 20 or limbaff.burn.strength > 50 then limbaff[i].strength = 0 else limbaff[i].strength = math.max(5, (limbaff.burn.strength - 20) / 30 * 100) end end, }, burn_deg3 = { update = function(c, limbaff, i) if limbaff.burn.strength <= 50 then limbaff[i].strength = 0 else limbaff[i].strength = HF.Clamp((limbaff.burn.strength - 50) / 50 * 100, 5, 100) end end, }, } -- define the stats and multipliers NT.CharStats = { healingrate = { getter = function(c) return NTC.GetMultiplier(c.character, "healingrate") end, }, specificOrganDamageHealMultiplier = { getter = function(c) return NTC.GetMultiplier(c.character, "anyspecificorgandamage") + HF.Clamp(c.afflictions.afthiamine.strength, 0, 1) * 4 end, }, neworgandamage = { getter = function(c) return ( c.afflictions.sepsis.strength / 300 + c.afflictions.hypoxemia.strength / 400 + math.max(c.afflictions.radiationsickness.strength - 25, 0) / 400 ) * NTC.GetMultiplier(c.character, "anyorgandamage") * NTConfig.Get("NT_organDamageGain", 1) * NT.Deltatime end, }, clottingrate = { getter = function(c) return HF.Clamp(1 - c.afflictions.liverdamage.strength / 100, 0, 1) * c.stats.healingrate * HF.Clamp(1 - c.afflictions.afstreptokinase.strength, 0, 1) * NTC.GetMultiplier(c.character, "clottingrate") end, }, bloodamount = { getter = function(c) return HF.Clamp(100 - c.afflictions.bloodloss.strength, 0, 100) end, }, stasis = { getter = function(c) return c.afflictions.stasis.strength > 0 end, }, sedated = { getter = function(c) return c.afflictions.analgesia.strength > 0 or c.afflictions.anesthesia.strength > 10 or c.afflictions.drunk.strength > 30 or c.stats.stasis end, }, withdrawal = { getter = function(c) return math.max( c.afflictions.opiatewithdrawal.strength, c.afflictions.chemwithdrawal.strength, c.afflictions.alcoholwithdrawal.strength ) end, }, availableoxygen = { getter = function(c) local res = HF.Clamp(c.character.Oxygen, 0, 100) -- heart isnt pumping blood? no new oxygen is getting into the bloodstream, no matter how oxygen rich the air in the lungs res = res * (1 - c.afflictions.fibrillation.strength / 100) -- and uuuh, maybe also dont let people without lungs use the oxygen where their lungs should be if c.afflictions.cardiacarrest.strength > 1 or c.afflictions.lungremoved.strength > 0.1 then res = 0 end return res end, }, speedmultiplier = { getter = function(c) local res = 1 if c.afflictions.t_paralysis.strength > 0 then res = -9001 end if c.afflictions.sym_vomiting.strength > 0 then res = res * 0.8 end if c.afflictions.sym_nausea.strength > 0 then res = res * 0.9 end if c.afflictions.anesthesia.strength > 0 then res = res * 0.5 end if c.afflictions.opiateoverdose.strength > 50 then res = res * 0.5 end if c.stats.withdrawal > 80 then res = res * 0.5 elseif c.stats.withdrawal > 40 then res = res * 0.7 elseif c.stats.withdrawal > 20 then res = res * 0.9 end if c.afflictions.drunk.strength > 80 then res = res * 0.5 elseif c.afflictions.drunk.strength > 40 then res = res * 0.7 elseif c.afflictions.drunk.strength > 20 then res = res * 0.8 end res = res + c.afflictions.afadrenaline.strength / 100 -- mitigate slowing effects if doped up on epinephrine res = res * NTC.GetSpeedMultiplier(c.character) return res end, }, lockleftarm = { getter = function(c) return limbLockedInitial(c, LimbType.LeftArm, "lockleftarm") end, }, lockrightarm = { getter = function(c) return limbLockedInitial(c, LimbType.RightArm, "lockrightarm") end, }, lockleftleg = { getter = function(c) return limbLockedInitial(c, LimbType.LeftLeg, "lockleftleg") end, }, lockrightleg = { getter = function(c) return limbLockedInitial(c, LimbType.RightLeg, "lockrightleg") end, }, wheelchaired = { getter = function(c) local outerwearItem = c.character.Inventory.GetItemAt(4) local res = outerwearItem ~= nil and outerwearItem.Prefab.Identifier.Value == "wheelchair" if res then c.stats.lockleftleg = c.stats.lockleftarm c.stats.lockrightleg = c.stats.lockrightarm end -- leg and wheelchair slowdown if c.stats.lockleftleg or c.stats.lockrightleg or res then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.5 end local isProne = c.stats.lockleftleg and c.stats.lockrightleg -- okay climbing ability if isProne and c.character.IsClimbing then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.5 end -- moving prone with one arm or 95% slowdown when no arms if (isProne or res) and c.stats.lockleftarm and c.stats.lockrightarm then c.stats.speedmultiplier = 0.05 elseif isProne and (c.stats.lockleftarm or c.stats.lockrightarm) then c.stats.speedmultiplier = c.stats.speedmultiplier * 0.8 end -- if isProne then -- c.character.AnimController.RagdollParams.ColliderHeightFromFloor = 4.0 -- end - Heelge: collider adjustment scrapped for now, lets wait for proper method in Workshop return res end, }, bonegrowthCount = { getter = function(c) local res = 0 for type in limbtypes do if HF.GetAfflictionStrengthLimb(c.character, type, "bonegrowth", 0) > 0 then res = res + 1 end end return res end, }, burndamage = { getter = function(c) local res = 0 for type in limbtypes do res = res + HF.GetAfflictionStrengthLimb(c.character, type, "burn", 0) end return res end, }, } function NT.UpdateHuman(character) -- pre humanupdate hooks for key, val in pairs(NTC.PreHumanUpdateHooks) do val(character) end local charData = { character = character, afflictions = {}, stats = {} } -- fetch all the current affliction data for identifier, data in pairs(NT.Afflictions) do local strength = HF.GetAfflictionStrength(character, identifier, data.default or 0) charData.afflictions[identifier] = { prev = strength, strength = strength } end -- fetch and calculate all the current stats for identifier, data in pairs(NT.CharStats) do if data.getter ~= nil then charData.stats[identifier] = data.getter(charData) else charData.stats[identifier] = data.default or 1 end end -- update non-limb-specific afflictions for identifier, data in pairs(NT.Afflictions) do if data.update ~= nil then data.update(charData, identifier) end end -- update and apply limb specific stuff local function FetchLimbData(type) local keystring = tostring(type) .. "afflictions" charData[keystring] = {} for identifier, data in pairs(NT.LimbAfflictions) do local strength = HF.GetAfflictionStrengthLimb(character, type, identifier, data.default or 0) charData[keystring][identifier] = { prev = strength, strength = strength } end end local function UpdateLimb(type) local keystring = tostring(type) .. "afflictions" for identifier, data in pairs(NT.LimbAfflictions) do if data.update ~= nil then data.update(charData, charData[keystring], identifier, type) end end end local function ApplyLimb(type) local keystring = tostring(type) .. "afflictions" for identifier, data in pairs(charData[keystring]) do local newval = HF.Clamp( data.strength, NT.LimbAfflictions[identifier].min or 0, NT.LimbAfflictions[identifier].max or 100 ) if newval ~= data.prev then if NT.LimbAfflictions[identifier].apply == nil then HF.SetAfflictionLimb(character, identifier, type, newval) else NT.LimbAfflictions[identifier].apply(charData, identifier, type, newval) end end end end -- stasis completely halts activity in limbs if not charData.stats.stasis then for type in limbtypes do FetchLimbData(type) end for type in limbtypes do UpdateLimb(type) end for type in limbtypes do ApplyLimb(type) end end -- non-limb-specific late update (useful for things that use stats that are altered by limb specifics) for identifier, data in pairs(NT.Afflictions) do if data.lateupdate ~= nil then data.lateupdate(charData, identifier) end end -- apply non-limb-specific changes for identifier, data in pairs(charData.afflictions) do local newval = HF.Clamp(data.strength, NT.Afflictions[identifier].min or 0, NT.Afflictions[identifier].max or 100) if newval ~= data.prev then if NT.Afflictions[identifier].apply == nil then HF.SetAffliction(character, identifier, newval) else NT.Afflictions[identifier].apply(charData, identifier, newval) end end end -- compatibility NTC.TickCharacter(character) -- humanupdate hooks for key, val in pairs(NTC.HumanUpdateHooks) do val(character) end NTC.CharacterSpeedMultipliers[character] = nil end function NT.UpdateMonster(character) -- trade bloodloss on this creature for organ damage so that creatures can still bleed out local bloodloss = HF.GetAfflictionStrength(character, "bloodloss", 0) local oxygenlow = HF.GetAfflictionStrength(character, "oxygenlow", 0) if bloodloss > 0 then HF.AddAffliction(character, "organdamage", bloodloss * 2) HF.SetAffliction(character, "bloodloss", 0) elseif oxygenlow > 50 then HF.AddAffliction(character, "organdamage", (oxygenlow - 50) * 2) HF.SetAffliction(character, "oxygenlow", 50) end end -- gets run every tick, shouldnt be used unless necessary function NT.TickUpdate() for key, value in pairs(NT.tickTasks) do value.duration = value.duration - 1 if value.duration <= 0 then NT.tickTasks[key] = nil end end end NT.tickTasks = {} NT.tickTaskID = 0 function NT.AddTickTask(type, duration, character) local newtask = {} newtask.type = type newtask.duration = duration newtask.character = character NT.tickTasks[NT.tickTaskID] = newtask NT.tickTaskID = NT.tickTaskID + 1 end