diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-03 23:36:58 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-03 23:36:58 +0100 |
| commit | 5ee8eb4a2b96b4a9916f85ddec5b43ae24ca93d1 (patch) | |
| tree | f618c930aa6bcd51f396598872194943c442b172 /src/server.cpp | |
| parent | World: add prop tint and fog override (diff) | |
| download | hl2h-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 '')
| -rw-r--r-- | src/server.cpp | 18 |
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; | |||
| 50 | static int g_srv_followtarget = -1; | 50 | static int g_srv_followtarget = -1; |
| 51 | static int g_srv_spawnflags = -1; | 51 | static int g_srv_spawnflags = -1; |
| 52 | static int g_srv_hacked = -1; | 52 | static int g_srv_hacked = -1; |
| 53 | static int g_srv_npcstate = -1; | ||
| 53 | static bool g_srv_ready = false; | 54 | static bool g_srv_ready = false; |
| 54 | static bool g_srv_checked = false; | 55 | static 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. | ||
| 261 | int 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 | |||
| 257 | bool server_npc_has_follow_target(int idx) { | 271 | bool 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; |
