include("zcnpci/modules.lua") local enabled = CreateConVar("zcnpci_enabled", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local active_range = CreateConVar("zcnpci_active_range", 3000, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local always_active_on_player_kill = CreateConVar("zcnpci_always_active_on_player_kill", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local remove_corpses = CreateConVar("zcnpci_enable_corpse_removal", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local max_corpses = CreateConVar("zcnpci_max_corpses", 8, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local max_corpse_time = CreateConVar("zcnpci_max_corpse_time", 120, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local max_corpse_distance = CreateConVar("zcnpci_max_corpse_distance", 2500, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local no_corpse_removal_near_player = CreateConVar("zcnpci_disable_corpse_removal_near_player", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local treat_crippled_as_dead = CreateConVar("zcnpci_treat_crippled_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local treat_near_death_as_dead = CreateConVar("zcnpci_treat_near_death_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local debug_ragdoll_all = CreateConVar("zcnpci_debug_ragdoll_all", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_PROTECTED)) local last_dmgpos = {} local last_hitgroup = {} local last_attacker = {} local corpses = {} local last_corpse_tick = CurTime() local last_tick = CurTime() hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll) if !ent.organism then return end if !enabled:GetBool() then return end local dmgpos = last_dmgpos[ent] local active_by_default = false if always_active_on_player_kill:GetBool() then if last_attacker[ent] and last_attacker[ent]:IsPlayer() then active_by_default = true end end if !active_by_default then local entity_position = ragdoll:GetPos() local in_range = false local players = player.GetAll() for i, loop_player in pairs(players) do local player_position = loop_player:GetPos() local distance = entity_position:Distance(player_position) if distance <= active_range:GetFloat() then in_range = true break end end if !in_range then return end end local phys_bone, lpos if dmgpos then phys_bone = ragdoll:GetClosestPhysBone(dmgpos) if phys_bone then local phys = ragdoll:GetPhysicsObjectNum(phys_bone) lpos = phys:WorldToLocal(dmgpos) end end ragdoll.class_in_previous_life = ent:GetClass() timer.Simple(0, function() ragdoll.organism.alive = true if !IsValid(ragdoll) then return end zcnpci.StartModule(ragdoll, "stumble_legs", phys_bone, lpos) last_dmgpos[ent] = nil end) end) hook.Add("EntityTakeDamage", "zcnpci", function(ent, dmginfo) if !enabled:GetBool() then return end if (!ent:IsNPC() or dmginfo:GetDamage() < ent:Health()) then return end last_dmgpos[ent] = dmginfo:GetDamagePosition() last_attacker[ent] = dmginfo:GetAttacker() end) hook.Add("ScaleNPCDamage", "zcnpci", function(npc, hitgroup, dmginfo) if not IsValid(npc) then return end last_hitgroup[npc] = hitgroup end) hook.Add("Think", "zcnpci", function() local do_corpse_loop = (CurTime() - last_corpse_tick) > 2.0 local do_general_loop = (CurTime() - last_tick) > 0.1 if do_general_loop then if do_corpse_loop then last_corpse_tick = CurTime() for i, ent in pairs(corpses) do if !IsValid(ent) then table.RemoveByValue(corpses, ent) end end if (max_corpses:GetFloat() != -1) and (#corpses > max_corpses:GetFloat()) then if IsValid(corpses[1]) then corpses[1]:Remove() end table.remove(corpses, 1) end end for i, ent in pairs(ents.GetAll()) do if !IsValid(ent) then continue end if !ent.organism then continue end if ent:IsNPC() then -- Knock them down if something is off if ( ((ent.organism.lleg >= 1) and (ent.organism.rleg >= 1)) or ent.organism.llegamputated or ent.organism.rlegamputated or (ent.organism.consciousness <= 0.3) or (ent.organism.pain > 90) or ent:IsOnFire() or debug_ragdoll_all:GetBool() ) then local damage_info = DamageInfo() damage_info:SetDamage(ent:Health()) damage_info:SetAttacker(ent) damage_info:SetDamageType( DMG_DIRECT ) damage_info:SetDamageForce(Vector(0, 0, 0)) ent:TakeDamageInfo(damage_info) end elseif do_corpse_loop and remove_corpses and ent.is_npc_corpse then local clearable = false if !ent.organism.alive then clearable = true end if treat_crippled_as_dead:GetBool() and ( ent.organism.llegamputated or ent.organism.rlegamputated or ent.organism.larmamputated or ent.organism.rarmamputated or ((ent.organism.lleg >= 1) and (ent.organism.rleg >= 1)) ) then clearable = true end if treat_near_death_as_dead:GetBool() and ( ent.organism.heartstop or (ent.organism.brain > 0.6) or !ent.organism.lungsfunction or (ent.organism.blood < 3000) or (ent.organism.pulse < 10) ) then clearable = true end if !clearable then return end -- Add to corpse list if not there already if !table.HasValue(corpses, ent) then table.insert(corpses, ent) end -- Get nearest player for future checks local nearby_player local players = player.GetAll() for i, loop_player in pairs(players) do local player_position = loop_player:GetPos() local distance = ent:GetPos():Distance(player_position) if (distance <= max_corpse_distance:GetFloat()) or (max_corpse_distance:GetFloat() == -1) then nearby_player = loop_player break end end if nearby_player and IsValid(nearby_player) and no_corpse_removal_near_player:GetBool() then continue elseif (max_corpse_distance:GetFloat() != -1) and !nearby_player then ent:Remove() continue end if max_corpse_time:GetFloat() != -1 then if !ent.corpse_timestamp then ent.corpse_timestamp = CurTime() elseif (CurTime() - ent.corpse_timestamp) > max_corpse_time:GetFloat() then ent:Remove() continue end print((CurTime() - ent.corpse_timestamp) > max_corpse_time:GetFloat()) end end end end end) --[[hook.Add("OnNPCKilled", "Fedhoria", function(ent, attacker, inflictor) if (!enabled:GetBool() or !npcs:GetBool()) then return end if (!ent:IsNPC() or dmginfo:GetDamage() < ent:Health()) then return end last_dmgpos[ent] = dmginfo:GetDamagePosition() end)]] local once = true --RagMod/TTT support --[[hook.Add("OnEntityCreated", "Fedhoria", function(ent) --If RagMod isn't installed remove this hook if once then once = nil if (!RMA_Ragdolize and !CORPSE) then hook.Remove("OnEntityCreated", "Fedhoria") return end --these hooks fucks shit up if RMA_Ragdolize then hook.Remove( "PlayerDeath", "RM_PlayerDies") hook.Add( "PostPlayerDeath", "RemoveRagdoll", function(ply) if IsValid(ply.RM_Ragdoll) then SafeRemoveEntity(ply:GetRagdollEntity()) ply:SpectateEntity(ply.RM_Ragdoll) end end) end end if (!enabled:GetBool() or !players:GetBool() or !ent:IsRagdoll()) then return end timer.Simple(0, function() if !IsValid(ent) then return end if CORPSE then local ply = ent:GetDTEntity(CORPSE.dti.ENT_PLAYER) if (IsValid(ply) and ply:IsPlayer()) then fedhoria.StartModule(ent, "stumble_legs") return end end for _, ply in ipairs(player.GetAll()) do if (ply.RM_IsRagdoll and ply.RM_Ragdoll == ent) then fedhoria.StartModule(ent, "stumble_legs") return end end end) end)]] local PLAYER = FindMetaTable("Player") local oldCreateRagdoll = PLAYER.CreateRagdoll local dolls = {} local function CreateRagdoll(self) SafeRemoveEntity(dolls[self]) local ragdoll = ents.Create("prop_ragdoll") ragdoll:SetModel(self:GetModel()) ragdoll:SetPos(self:GetPos()) ragdoll:SetAngles(self:GetAngles()) ragdoll:Spawn() ragdoll:SetSkin(self:GetSkin()) for i = 0, self:GetNumBodyGroups() - 1 do ragdoll:SetBodygroup(i, self:GetBodygroup(i)) end for i = 0, ragdoll:GetPhysicsObjectCount()-1 do local phys = ragdoll:GetPhysicsObjectNum(i) local bone = ragdoll:TranslatePhysBoneToBone(i) local matrix = self:GetBoneMatrix(bone) local pos, ang = matrix:GetTranslation(), matrix:GetAngles()--self:GetBonePosition(bone) phys:SetPos(pos) phys:SetAngles(ang) phys:SetVelocity(self:GetVelocity()) end self:SpectateEntity(ragdoll) self:Spectate(OBS_MODE_CHASE) dolls[self] = ragdoll end local oldGetRagdollEntity = PLAYER.GetRagdollEntity local function GetRagdollEntity(self) return dolls[self] or NULL end --[[ if enabled:GetBool() then PLAYER.CreateRagdoll = CreateRagdoll PLAYER.GetRagdollEntity = GetRagdollEntity end]] --[[ cvars.AddChangeCallback("fedhoria_enabled", function(name, old, new) if (new == "1") then if players:GetBool() then PLAYER.CreateRagdoll = CreateRagdoll PLAYER.GetRagdollEntity = GetRagdollEntity end else PLAYER.CreateRagdoll = oldCreateRagdoll PLAYER.GetRagdollEntity = oldGetRagdollEntity end end) cvars.AddChangeCallback("fedhoria_players", function(name, old, new) if (new == "1") then if enabled:GetBool() then if (debug.getinfo(PLAYER.CreateRagdoll).short_src == "[C]") then PLAYER.CreateRagdoll = CreateRagdoll PLAYER.GetRagdollEntity = GetRagdollEntity end end else PLAYER.CreateRagdoll = oldCreateRagdoll PLAYER.GetRagdollEntity = oldGetRagdollEntity end end)]]