summaryrefslogtreecommitdiffstats
path: root/src/server.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-03 23:36:58 +0100
committersalmonik <salmonik@tuta.io>2026-11-03 23:36:58 +0100
commit5ee8eb4a2b96b4a9916f85ddec5b43ae24ca93d1 (patch)
treef618c930aa6bcd51f396598872194943c442b172 /src/server.cpp
parentWorld: add prop tint and fog override (diff)
downloadhl2h-5ee8eb4a2b96b4a9916f85ddec5b43ae24ca93d1.tar.gz
hl2h-5ee8eb4a2b96b4a9916f85ddec5b43ae24ca93d1.zip
AI: treat scripted NPCs as neutral; Lamarr neutral
Read the server m_NPCState and mark NPC_STATE_SCRIPT actors neutral so cutscene NPCs and scripted pets are not aimbot targets and draw in the neutral colour. Add Lamarr (Kleiner's pet headcrab) to the neutral model list as requested. Also log state changes in the NPC debug line and resolve/log m_NPCState in the server datamap summary.
Diffstat (limited to 'src/server.cpp')
-rw-r--r--src/server.cpp18
1 files changed, 16 insertions, 2 deletions
diff --git a/src/server.cpp b/src/server.cpp
index 19be144..c2864c8 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -50,6 +50,7 @@ static int g_srv_relationship = -1;
50static int g_srv_followtarget = -1; 50static int g_srv_followtarget = -1;
51static int g_srv_spawnflags = -1; 51static int g_srv_spawnflags = -1;
52static int g_srv_hacked = -1; 52static int g_srv_hacked = -1;
53static int g_srv_npcstate = -1;
53static bool g_srv_ready = false; 54static bool g_srv_ready = false;
54static bool g_srv_checked = false; 55static bool g_srv_checked = false;
55 56
@@ -139,15 +140,16 @@ bool resolve_server_netvars() {
139 // CBaseEntity::m_spawnflags is a DEFINE_KEYFIELD at a low offset. 140 // CBaseEntity::m_spawnflags is a DEFINE_KEYFIELD at a low offset.
140 g_srv_spawnflags = datamap_offset("m_spawnflags", FIELD_INTEGER, 0x4); 141 g_srv_spawnflags = datamap_offset("m_spawnflags", FIELD_INTEGER, 0x4);
141 g_srv_hacked = datamap_offset("m_bHackedByAlyx", FIELD_BOOLEAN); 142 g_srv_hacked = datamap_offset("m_bHackedByAlyx", FIELD_BOOLEAN);
143 g_srv_npcstate = datamap_offset("m_NPCState", FIELD_INTEGER);
142 g_srv_ready = g_srv_health > 0; 144 g_srv_ready = g_srv_health > 0;
143 if (g_srv_ready) { 145 if (g_srv_ready) {
144 logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " 146 logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d "
145 "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d " 147 "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d "
146 "followtarget=%d spawnflags=%d hacked=%d", 148 "followtarget=%d spawnflags=%d hacked=%d npcstate=%d",
147 g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, 149 g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate,
148 g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, 150 g_srv_modelindex, g_srv_absvelocity, g_srv_velocity,
149 g_srv_activeweapon, g_srv_relationship, g_srv_followtarget, 151 g_srv_activeweapon, g_srv_relationship, g_srv_followtarget,
150 g_srv_spawnflags, g_srv_hacked); 152 g_srv_spawnflags, g_srv_hacked, g_srv_npcstate);
151 fail_logged = false; 153 fail_logged = false;
152 } else if (!fail_logged) { 154 } else if (!fail_logged) {
153 fail_logged = true; 155 fail_logged = true;
@@ -254,6 +256,18 @@ int server_npc_relation(int idx, int local_idx) {
254 return class_relation; 256 return class_relation;
255} 257}
256 258
259// NPC_STATE_SCRIPT = 4 (ai_npcstate.h). Scripted NPCs are passive: cutscene
260// actors, Kleiner's Lamarr, scripted soldiers standing down, and so on.
261int server_npc_state(int idx) {
262 if (!g_srv_ready || g_srv_npcstate < 0)
263 return -1;
264 void *base = nullptr;
265 server_entity_health(idx, nullptr, nullptr, &base);
266 if (!base)
267 return -1;
268 return *(int *)((uintptr_t)base + g_srv_npcstate);
269}
270
257bool server_npc_has_follow_target(int idx) { 271bool server_npc_has_follow_target(int idx) {
258 if (!g_srv_ready || g_srv_followtarget < 0) 272 if (!g_srv_ready || g_srv_followtarget < 0)
259 return false; 273 return false;