From 5af8fdc14ab10e2876d0a1050d4dd9fc01939b12 Mon Sep 17 00:00:00 2001 From: toasterpanic Date: Sat, 30 May 2026 21:35:28 -0400 Subject: [PATCH] Bug fixes of varying degrees --- README.md | 13 +++--- lua/entities/npc_ragdoll_target.lua | 21 +++++----- lua/zcnpci.lua | 40 +++++-------------- lua/zcnpci/modules/falling_legs.lua | 62 ++--------------------------- 4 files changed, 33 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index 1de6321..37be3b0 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,13 @@ It is, however, not compatbile with: - Most mods that modify the behavior of death ragdolls (Reagdoll, Artagdoll, especially Fedhoria.) - Mods that automatically remove death ragdolls (it will delete all ragdolled NPCs, even if they're still alive! Try the built-in automatic corpse removal instead.) -## Future plans +## Todo list -No guarantees any of this will become real. +- NPC targeting works, but works really weirdly (sometimes it just. keeps targeting corpses when it shouldn't.) Why? Who knows!!!! +- Look into improving the unfake animation? Really scared to try and touch it again but it would be worthwhile -- NPCs will back out of combat when injured. -- Friendly NPCs can heal each other. -- NPCs can heal themselves. \ No newline at end of file +Post release ideas: + +- Localization support for other languages +- ReaSFX integration would probably be nice. I mean there's so many SFX packs to choose from, so I don't even have to pack it in +- To be entirely honest Fedhoria isn't the best addon out there for euphoria physics. Maybe rebase to another addon (or alternatively build a new one?) \ No newline at end of file diff --git a/lua/entities/npc_ragdoll_target.lua b/lua/entities/npc_ragdoll_target.lua index cd52d4e..5a69122 100644 --- a/lua/entities/npc_ragdoll_target.lua +++ b/lua/entities/npc_ragdoll_target.lua @@ -10,7 +10,7 @@ local function UpdateRelationship(ent, me) if !IsValid(ent) or !ent:IsNPC() then return end if ent:Disposition(me.dummy_entity) == D_HT then - ent:AddEntityRelationship(me, D_HT) + ent:AddEntityRelationship(me, D_HT, -1) end end @@ -18,8 +18,13 @@ local function RemoveRelationship(ent, me) if !IsValid(ent) or !ent:IsNPC() then return end if ent:Disposition(me.dummy_entity) == D_HT then - ent:AddEntityRelationship(me, D_NU) + ent:AddEntityRelationship(me, D_NU, -1) ent:ClearEnemyMemory(me) + + if ent:GetEnemy() == me then + ent:SetEnemy(nil) + ent:ClearSchedule() + end end end @@ -30,7 +35,7 @@ function ENT:Initialize() self:SetHullType(HULL_TINY_CENTERED) self:SetNoDraw(!debug_show_ragdoll_targets:GetBool()) self.dummy_entity = ents.Create(self.ragdoll_to_follow.class_in_previous_life) - self.last_stop_targeting = debug_show_ragdoll_targets:GetBool() + self.last_stop_targeting = nil hook.Add("OnEntityCreated", "zcnpci-"..self:GetCreationID(), function(new_entity) if !IsValid(new_entity) or !new_entity:IsNPC() then return end @@ -39,10 +44,6 @@ function ENT:Initialize() UpdateRelationship(new_entity, self) end end) - - for i,ent in ipairs(ents.GetAll()) do - UpdateRelationship(ent, self) - end end end @@ -71,7 +72,7 @@ function ENT:Think() RemoveRelationship(ent, self) end else - self:SetColor(Color(0, 255, 0)) + self:SetColor(Color(0, 255, 0)) for i,ent in ipairs(ents.GetAll()) do UpdateRelationship(ent, self) end @@ -87,10 +88,12 @@ end function ENT:OnRemove() if SERVER then - print("I AM DYING!!!!!!") for i,ent in ipairs(ents.GetAll()) do RemoveRelationship(ent, self) end + + self.dummy_entity:Remove() + hook.Remove("OnEntityCreated", "zcnpci-"..self:GetCreationID()) end end \ No newline at end of file diff --git a/lua/zcnpci.lua b/lua/zcnpci.lua index 6194e3e..802acd2 100644 --- a/lua/zcnpci.lua +++ b/lua/zcnpci.lua @@ -19,7 +19,9 @@ 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", "nb_example", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) +local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "npc_example_class", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) + +local debug_ragdoll_all = CreateConVar("zcnpci_debug_ragdoll_all", 0, 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) @@ -30,8 +32,6 @@ local set_modded_npc_whitelist = concommand.Add("zcnpci_set_modded_npc_whitelis modded_npc_whitelist:SetString(args[1]) end) -local debug_ragdoll_all = CreateConVar("zcnpci_debug_ragdoll_all", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED)) - local last_dmgpos = {} local last_hitgroup = {} local last_attacker = {} @@ -139,31 +139,6 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll) end) end) -hook.Add("EntityTakeDamage", "zcnpci", function(ent, dmginfo) - if !IsValid(ent) or !IsValid(dmginfo) then return end - - print('damage taken') - - if ent:GetClass() == "bullseye_strider_focus" then - print("BULLSEYE!") - local npc_rag = IsValid(ent.npc_rag) and ent.npc_rag - - if IsValid(npc_rag) then - if !IsValid(dmginfo) then - print("FUUUUCK NO DMGINFO") - return true - end - print("DAMAGE MOVED") - - --ent.npc_rag:TakeDamageInfo(dmginfo) - - --hook.Run("HomigradDamage", , dmginfo) - end - - return true - end -end) - hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo) if !enabled:GetBool() or !IsValid(dmginfo) then return end @@ -187,13 +162,16 @@ hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo) table.insert(npcs_to_fake, ent) end elseif dmginfo:IsDamageType(DMG_CLUB + DMG_SLASH) then - local fists = dmginfo:GetAttacker():GetWeapon("weapon_hands_sh") - if !IsValid(fists) then fists = dmginfo:GetAttacker():GetWeapon("weapon_hg_coolhands") end + local attacker = dmginfo:GetAttacker() + if !IsValid(attacker) then return end + + local fists = attacker:HasWeapon("weapon_hands_sh") + if !fists then fists = dmginfo:GetAttacker():HasWeapon("weapon_hg_coolhands") end local attacker = dmginfo:GetAttacker() -- Kicks should knock NPCs down - if IsValid(dmginfo:GetInflictor()) and IsValid(fists) and attacker.InLegKick and ((attacker.InLegKick + 0.1) > CurTime()) then + if IsValid(dmginfo:GetInflictor()) and fists and attacker.InLegKick and ((attacker.InLegKick + 0.1) > CurTime()) then table.insert(npcs_to_fake, ent) local attacker_angle = dmginfo:GetAttacker():EyeAngles() diff --git a/lua/zcnpci/modules/falling_legs.lua b/lua/zcnpci/modules/falling_legs.lua index 8d14918..a694ebf 100644 --- a/lua/zcnpci/modules/falling_legs.lua +++ b/lua/zcnpci/modules/falling_legs.lua @@ -330,6 +330,8 @@ function MODULE:PhysicsSimulate(phys, dt) if parent_bone == -1 then continue end local parent_bone_matrix = parent:GetBoneMatrix(parent_bone) + if !parent_bone_matrix then continue end + local parent_bone_pos, parent_bone_angle = parent_bone_matrix:GetTranslation(), parent_bone_matrix:GetAngles() parent_bone_angle.y = parent_bone_angle.y + 90 @@ -479,6 +481,8 @@ function MODULE:PhysicsSimulate(phys, dt) ent:SetRenderMode(RENDERMODE_NONE) timer.Simple(self.FakeUpTime, function() + if !IsValid(ent) then return end + ent:SetNotSolid(false) ent:SetNPCState(NPC_STATE_IDLE) @@ -488,70 +492,12 @@ function MODULE:PhysicsSimulate(phys, dt) self:Remove() end) - --[[] - local parent = self.FakeParent - - if !self.ModelBoneList then - self.ModelBoneList = {} - - local i = 0 - - while i < target:GetBoneCount() do - table.insert(self.ModelBoneList, target:GetBoneName(i)) - i = i + 1 - end - end - - for i,v in pairs(self.ModelBoneList) do - print(v) - - print("I'm here") - - local bone = target:TranslateBoneToPhysBone(target:LookupBone(v)) - local object = target:GetPhysicsObjectNum(bone) - if !IsValid(object) then i = i + 1; continue end - - print("I'm getting to object") - - local parent_bone = parent:TranslateBoneToPhysBone(parent:LookupBone(v)) - if parent_bone == nil then i = i + 1; continue end - - print("I'm getting to parent object") - - object:Wake() - - local shadow_data = { - secondstoarrive = 0.01, - pos = LerpVector(0.1, object:GetPos(), parent:GetBonePosition(parent_bone)), - angle = LerpAngle(0.1, object:GetAngles(), parent:GetBoneMatrix(parent_bone):GetAngles()), - maxspeed = 5000, - maxangular = 5000, - maxspeeddamp = 2000, - maxangularspeeddamp = 2000, - } - - object:ComputeShadowControl(shadow_data) - - --object:SetPos(LerpVector(0.2, object:GetPos(), parent:GetBonePosition(parent_bone))) - --object:SetAngles(LerpAngle(0.2, object:GetAngles(), parent:GetBoneMatrix(parent_bone):GetAngles())) - - --object:EnableMotion(false) - - --object:SetVelocity(Vector()) - object:EnableGravity(false) - - i = i + 1 - end]] self.bullseye:Remove() return false end end - -- Getting up - -- Don't need to check for consciousness and the like because we've done it already above - - local phys_bone_id = phys:GetID() -- Main logic for the root bone