ACTUALLY make NPC targeting actually work

This commit is contained in:
toasterpanic 2026-06-01 18:58:51 -04:00
parent e8112ffd8a
commit 6906b0ba6f
3 changed files with 45 additions and 6 deletions

View file

@ -1,3 +1,16 @@
local function PopulateAISBXToolMenu(pnl)
pnl:CheckBox("Allow NPCs to target downed NPCs", "zcnpci_npc_targeting_enabled")
pnl:ControlHelp("If enabled, NPCs target downed hostile NPCs.")
pnl:CheckBox("NPCs should target head", "zcnpci_target_should_follow_head")
pnl:ControlHelp("Should NPCs target the player's head? This can result in more effective targeting.")
pnl:CheckBox("NPCs shouldn't target unconscious NPCs", "zcnpci_no_unconscious_targeting")
pnl:CheckBox("NPCs shouldn't target unconscious players", "zcnpci_no_unconscious_targeting_players")
pnl:ControlHelp("This may or may not work.")
end
local function PopulateCustomNPCSBXToolMenu(pnl)
local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "NPC-classes-here!", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
@ -25,7 +38,7 @@ local function PopulateCustomNPCSBXToolMenu(pnl)
pnl:AddItem(text)
pnl:Help("One NPC class per line. No spaces or other characters. Can only be set by a superadmin or server operator.")
pnl:Help("A list of NPC classes, seperated by spaces or line breaks. Can only be set by a superadmin or server operator.")
end
local function PopulateRagdollSBXToolMenu(pnl)
@ -125,6 +138,11 @@ if engine.ActiveGamemode() == "sandbox" then
PopulateRagdollSBXToolMenu(pnl)
end)
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "AISettings", "AI", "", "", function(pnl)
pnl:ClearControls()
PopulateAISBXToolMenu(pnl)
end)
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "MainSettings", "Main", "", "", function(pnl)
pnl:ClearControls()
PopulateMainSBXToolMenu(pnl)

View file

@ -4,7 +4,12 @@ ENT.Type = "ai"
ENT.Base = "base_ai"
ENT.AutomaticFrameAdvance = true
local debug_show_ragdoll_targets = CreateConVar("zcnpci_debug_show_ragdoll_targets", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
local debug_show_ragdoll_targets = CreateConVar("zcnpci_debug_show_ragdoll_targets", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
local should_follow_head = CreateConVar("zcnpci_target_should_follow_head", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
local stop_targeting_when_unconscious = CreateConVar("zcnpci_no_unconscious_targeting", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
local vector_offset_to_shoot_at = Vector(0, 0, 8)
local function UpdateRelationship(ent, me)
if !IsValid(ent) or !ent:IsNPC() then return end
@ -28,15 +33,23 @@ local function RemoveRelationship(ent, me)
end
end
function ENT:Classify()
return self.dummy_entity:Classify()
end
function ENT:Initialize()
if SERVER then
self:SetModel("models/maxofs2d/hover_basic.mdl")
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
self:SetCollisionGroup(COLLISION_GROUP_NONE)
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 = nil
-- Have to use this collision group otherwise ragdoll will obstruct visibility of target
self.ragdoll_to_follow:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
hook.Add("OnEntityCreated", "zcnpci-"..self:GetCreationID(), function(new_entity)
if !IsValid(new_entity) or !new_entity:IsNPC() then return end
@ -52,18 +65,23 @@ function ENT:Think()
local ragdoll = self.ragdoll_to_follow
if !IsValid(ragdoll) then return end
self:SetPos(ragdoll:GetPos())
if should_follow_head:GetBool() then
local head = ragdoll:GetPhysicsObjectNum(ragdoll:TranslateBoneToPhysBone(ragdoll:LookupBone("ValveBiped.Bip01_Head1")))
self:SetPos(head:GetPos() + vector_offset_to_shoot_at)
else
self:SetPos(ragdoll:GetPos())
end
self:SetNoDraw(!debug_show_ragdoll_targets:GetBool())
if !ragdoll.organism then return true end
local should_stop_targeting = (
local should_stop_targeting = !zcnpci_no_unconscious_targeting:GetBool() or (
(ragdoll.organism.consciousness <= 0.4) or
(ragdoll.organism.critical)
)
if should_stop_targeting != self.last_stop_targeting then
if true or (should_stop_targeting != self.last_stop_targeting) then
self.last_stop_targeting = should_stop_targeting
if should_stop_targeting then

View file

@ -100,6 +100,9 @@ local minimum_down_time = CreateConVar("zcnpci_down_time", "5", {FCVAR_ARCHIVE,
local can_unfake = CreateConVar("zcnpci_unfake_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Whether an NPC can unfake")
local unfake_time = CreateConVar("zcnpci_unfake_time", "1.5", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Time it takes for an NPC to unfake")
-- Targeting
local npc_targeting_enabled = CreateConVar("zcnpci_npc_targeting_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Should NPCs target downed NPCs")
--[[-------------------------------------------------------------------------
Tug function
Applies a random impulse to one of the leg bones.