diff --git a/lua/autorun/client/zcnpci_menu.lua b/lua/autorun/client/zcnpci_menu.lua index 58349c0..d608c99 100644 --- a/lua/autorun/client/zcnpci_menu.lua +++ b/lua/autorun/client/zcnpci_menu.lua @@ -43,6 +43,13 @@ local function PopulateRagdollSBXToolMenu(pnl) end local function PopulatePerformanceSBXToolMenu(pnl) + pnl:NumSlider("NPC ticks per second", "zcnpci_tps", 1, 66, 0) + pnl:ControlHelp("How many times NPCs should be processed per second. Will make them more responsive at the cost of performance.") + + pnl:Help(" ") + + pnl:Help(" ") + pnl:NumSlider("Activation range", "zcnpci_active_range", 0, 32768, 0) pnl:ControlHelp("How close the ragdoll has to be to a player to live when downed by direct damage. Enemies downed by other causes are unaffected.") @@ -56,6 +63,9 @@ local function PopulatePerformanceSBXToolMenu(pnl) pnl:CheckBox("Enable automatic corpse removal", "zcnpci_enable_corpse_removal") pnl:ControlHelp("Enable or disable the removal of dead corpses.") + pnl:NumSlider("Corpse time between loops", "zcnpci_corpse_loop_time", 1, 66, 0) + pnl:ControlHelp("How long should we wait in between checks?") + pnl:NumSlider("Max corpses", "zcnpci_max_corpses", -1, 64, 0) pnl:ControlHelp("The maximum amount of dead corpses that are allowed before one is removed. Set to -1 to disable") diff --git a/lua/zcnpci.lua b/lua/zcnpci.lua index 3d6010f..01fdff0 100644 --- a/lua/zcnpci.lua +++ b/lua/zcnpci.lua @@ -3,8 +3,10 @@ include("zcnpci/modules.lua") local enabled = CreateConVar("zcnpci_enabled", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local active_range = CreateConVar("zcnpci_active_range", 32768, 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 ticks_per_second = CreateConVar("zcnpci_tps", 20, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local remove_corpses = CreateConVar("zcnpci_enable_corpse_removal", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) +local corpse_loop_time = CreateConVar("zcnpci_corpse_loop_time", 2.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 min_corpse_distance = CreateConVar("zcnpci_min_corpse_distance", 500, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) @@ -17,7 +19,7 @@ local treat_near_death_as_dead = CreateConVar("zcnpci_treat_near_death_as_dead" local allow_extended_base_npcs = CreateConVar("zcnpci_allow_extended_base_npcs", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local allow_modded_npcs = CreateConVar("zcnpci_allow_modded_npcs", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) local auto_enable_humanoid_npcs = CreateConVar("zcnpci_auto_enable_humanoid_npcs", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) -local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "NPC-classes-here!", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) +local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "nb_example", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) -- The way I have to set up the npc whitelist client-side makes it so the host can't configure it without console commands, so we have to do this shit local set_modded_npc_whitelist = concommand.Add("zcnpci_set_modded_npc_whitelist", function(ply, cmd, args) @@ -105,8 +107,6 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll) hook.Run("RagdollDeath", ent, ragdoll) - --table.Merge(zb.net.list[rag], zb.net.list[ent]) - ragdoll.organism.owner = ragdoll ragdoll:CallOnRemove("organism", hg.organism.Remove, ragdoll) ragdoll.organism.owner.fullsend = true @@ -115,6 +115,10 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll) ent.organism = nil end + if ent.npcfakeknockback then + ragdoll:GetPhysicsObject():SetVelocity(ent.npcfakeknockback) + end + timer.Simple(0, function() ragdoll.organism.alive = true @@ -125,24 +129,55 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll) 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 +hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo) + if !enabled:GetBool() or !IsValid(dmginfo) then return end + if !ent:IsNPC() then + if !ent.organism or !ent.StartDie then return end - last_dmgpos[ent] = dmginfo:GetDamagePosition() + if dmginfo:IsDamageType(DMG_BULLET + DMG_BUCKSHOT + DMG_BLAST + DMG_CLUB + DMG_SLASH + DMG_GENERIC) then + -- Reset ragdoll get up timer -- don't want someone getting up mid-curbstomp + ent.StartDie = CurTime() + end + + return + end + + last_dmgpos[ent] = dmginfo:GetDamage() last_attacker[ent] = dmginfo:GetAttacker() + + if dmginfo:IsDamageType(DMG_BULLET + DMG_BUCKSHOT + DMG_BLAST) then + if dmginfo:GetDamage() > 1.5 then + ent:TakeDamage(ent:Health()) + end + elseif dmginfo:IsDamageType(DMG_CLUB + DMG_SLASH) then + + -- If it's hands and has more than 7.5 damage, it's a kick probably + if IsValid(dmginfo:GetInflictor()) and (dmginfo:GetDamage() >= 7.5) and ( + (dmginfo:GetInflictor():GetClass() == "weapon_hands_sh") or + (dmginfo:GetInflictor():GetClass() == "weapon_hg_coolhands") + ) then + ent.neednpcfake = true + local attacker_angle = dmginfo:GetAttacker():EyeAngles() + + local normal = attacker_angle:Forward(normal) + + ent.npcfakeknockback = normal * dmginfo:GetDamage() * 135 + end + end end) hook.Add("ScaleNPCDamage", "zcnpci", function(npc, hitgroup, dmginfo) - if not IsValid(npc) then return end + if !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 - +hook.Add("Tick", "zcnpci", function() + local do_corpse_loop = (CurTime() - last_corpse_tick) > corpse_loop_time:GetFloat() + local do_general_loop = (CurTime() - last_tick) > (1 / ticks_per_second:GetInt()) + if do_general_loop then + last_tick = CurTime() + if do_corpse_loop then last_corpse_tick = CurTime() @@ -160,7 +195,6 @@ hook.Add("Think", "zcnpci", function() 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 @@ -174,7 +208,8 @@ hook.Add("Think", "zcnpci", function() (ent.organism.consciousness <= 0.3) or (ent.organism.pain > 90) or ent:IsOnFire() or - debug_ragdoll_all:GetBool() + ent.neednpcfake or + debug_ragdoll_all:GetBool() ) then local damage_info = DamageInfo() damage_info:SetDamage(ent:Health()) @@ -281,45 +316,6 @@ 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 @@ -361,37 +357,4 @@ 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)]] \ No newline at end of file +end \ No newline at end of file diff --git a/lua/zcnpci/modules.lua b/lua/zcnpci/modules.lua index e1ed8b3..06f02a2 100644 --- a/lua/zcnpci/modules.lua +++ b/lua/zcnpci/modules.lua @@ -75,6 +75,7 @@ function ENTITY:GetClosestPhysBone(pos) end if !collides then return end + if type(pos) != "Vector" then return end local closest_bone local dist = math.huge diff --git a/lua/zcnpci/modules/falling_legs.lua b/lua/zcnpci/modules/falling_legs.lua index 9c91efb..4b48c66 100644 --- a/lua/zcnpci/modules/falling_legs.lua +++ b/lua/zcnpci/modules/falling_legs.lua @@ -149,16 +149,19 @@ function MODULE:StartAnimationRoll() return end - --self.StartDie = nil + --target.StartDie = nil end function MODULE:Init() local seq = self:LookupSequence("Choked_Barnacle") if seq then self:ResetSequence(seq) end + + local target = self:GetTarget() + self:SetPlaybackRate(1) self.LastCollideTime = 0 self.LastGroundCollideTime = 0 - self.StartDie = nil + target.StartDie = nil self.AnimationRollEndTime = 0 self.StopProcessing = false self.LastThink = CurTime() @@ -251,11 +254,11 @@ function MODULE:PhysicsSimulate(phys, dt) target.is_npc_corpse = true - if !self.StartDie then self.StartDie = cur_time end + if !target.StartDie then target.StartDie = cur_time end -- Check for active animation if cur_time < self.AnimationRollEndTime then - --self.StartDie = nil -- Resetting the "death" timer + --target.StartDie = nil -- Resetting the "death" timer return true -- We use standard physics. end @@ -263,8 +266,8 @@ function MODULE:PhysicsSimulate(phys, dt) local f = target.organism.consciousness local minimum_down_timer = 0 - if self.StartDie then - minimum_down_timer = math_Clamp((cur_time - self.StartDie) / minimum_down_time:GetFloat(), 0, 1) + if target.StartDie then + minimum_down_timer = math_Clamp((cur_time - target.StartDie) / minimum_down_time:GetFloat(), 0, 1) end if !target.organism then @@ -277,7 +280,7 @@ function MODULE:PhysicsSimulate(phys, dt) self:Remove() return false -- Cut the bullshit elseif (target.organism.consciousness <= 0.5) or ((target.organism.lleg >= 0.85) and (target.organism.rleg >= 0.85)) then - self.StartDie = cur_time + target.StartDie = cur_time return false end @@ -363,7 +366,7 @@ function MODULE:PhysicsSimulate(phys, dt) self.last_pos = pos if offset_sqr < (10*10 * dt*dt) then - self.StartDie = self.StartDie or cur_time + target.StartDie = target.StartDie or cur_time end -- Physics correction after collision diff --git a/lua/zcnpci/modules/falling_torso.lua b/lua/zcnpci/modules/falling_torso.lua index e06f513..ef7a937 100644 --- a/lua/zcnpci/modules/falling_torso.lua +++ b/lua/zcnpci/modules/falling_torso.lua @@ -114,17 +114,20 @@ function MODULE:StartAnimationRoll() return end - self.StartDie = nil -- блять я заебался с этой хуйней + target.StartDie = nil -- блять я заебался с этой хуйней -- print("[Fedhoria AnimRoll] StartAnimationRoll initiated. Speed:", cv_anim_roll_playback_rate:GetFloat(), "Duration:", cv_anim_roll_duration:GetFloat(), "End Time:", self.AnimationRollEndTime) -- Debug end function MODULE:Init() local seq = self:LookupSequence("idleonfire") if seq then self:ResetSequence(seq) end + + local target = self:GetTarget() + self:SetPlaybackRate(1) self.LastCollideTime = 0 self.LastGroundCollideTime = 0 - self.StartDie = nil + target.StartDie = nil self.AnimationRollEndTime = 0 -- идте нахуй с этой хуйней @@ -172,7 +175,7 @@ function MODULE:PhysicsSimulate(phys, dt) -- проверка на физику if cur_time < self.AnimationRollEndTime then -- print("[Fedhoria Sim] In Animation Roll. Time left:", self.AnimationRollEndTime - cur_time) -- Debug - -- self.StartDie = nil -- Сбрасываем таймер смерти + -- target.StartDie = nil -- Сбрасываем таймер смерти return true -- стандартная физика пошла нахуй, у меня по ней 2 -- return false -- если физика нахуй идет @@ -188,7 +191,7 @@ function MODULE:PhysicsSimulate(phys, dt) local owner = target:GetOwningPlayer() -- владелец идот нахуй f = (IsValid(owner) and owner:Alive()) and 1 or 0 - self.StartDie = nil + target.StartDie = nil if f <= 0 then self.AnimationRollEndTime = 0 end end @@ -241,10 +244,10 @@ function MODULE:PhysicsSimulate(phys, dt) local offset_sqr = (pos - self.last_pos):LengthSqr() self.last_pos = pos if (offset_sqr < (10*10 * dt*dt) and not (ragmod and ragmod:IsRagmodRagdoll(target))) then -- uменьшил порог неподвижности - self.StartDie = self.StartDie or cur_time -- идите нахуй - -- print("[Fedhoria Sim] Torso seems stationary. StartDie:", self.StartDie) -- Debug + target.StartDie = target.StartDie or cur_time -- идите нахуй + -- print("[Fedhoria Sim] Torso seems stationary. StartDie:", target.StartDie) -- Debug else - -- self.StartDie = nil -- нахуй таймер + -- target.StartDie = nil -- нахуй таймер -- print("[Fedhoria Sim] Torso moved. Resetting StartDie.") -- Debug end