RedM multiplayer NPC events: use per-NPC nearest-threat targeting, not host-only or single-target
Context
Multiplayer event with one elected host spawning networked NPCs (guards/outlaws/bandits) that engage approaching players.
Three anti-patterns
TaskCombatPed(npc, PlayerPedId(), 0, 16)— only targets the host's local ped. Every other player is invisible to AI.- Pick closest player to SPAWN POINT once, every NPC targets them — late-comers walk in from another angle and clear loot risk-free while NPCs are pinned on the first engagement.
- Re-task every tick without guard — NPCs spam "start combat" and never move.
The pattern that works
Per-NPC nearest-threat, re-evaluated each ~1s, gated by IsPedInCombat:
if aggroed then
for _, npc in ipairs(spawnedNpcs) do
if DoesEntityExist(npc) and not IsEntityDead(npc) then
local nx, ny, nz = table.unpack(GetEntityCoords(npc))
local threat = nearestPlayerPedTo(nx, ny, nz, 120.0)
if threat and not IsPedInCombat(npc, threat) then
TaskCombatPed(npc, threat, 0, 16)
end
end
end
end
nearestPlayerPedTo iterates GetActivePlayers() (player peds streamed by host) and returns the closest live one to the NPC's own coords.
Why this beats the alternatives
- Crews from multiple angles split naturally. North-side NPCs target north attackers, south-side targets south.
- Late-comers can't farm. A new player approaching from the rear becomes the closest threat to rear NPCs — they redirect.
- Camping has cost. Player A behind a wall still pulls NPCs nearest to A, but teammates B/C drawing the rest mean A doesn't get a safe spot AND clean loot.
- Solo player works identically. When only one player is in range, every NPC's "nearest threat" is the same person.
Implementation notes
IsPedInCombat(ped, target)(0x4859F1FC66A6278E) is the gate — only re-task when false. Without it, NPCs animate "starting combat" forever and never move/shoot.- Aggro trigger (waking from TaskStandStill) should check "any player within R of any NPC", not just R of the spawn point. Players can sneak close to one NPC before the rest see anyone.
GetActivePlayers()returns currently-streamed player indices — exactly the threat-relevant set inside the host's streaming radius. Convert viaGetPlayerPed(idx).- For vehicle-driver NPCs: gate the re-task on
not IsPedInAnyVehicle(driver, false)so you don't cancel a pendingTaskLeaveVehicleand lock the driver inside the coach.
Verified
Verified 2026-05-28 on FXServer 1.0.0.25770, RedM client, GameBuild 1491. Wagon-robbery event with 5 networked Cornwall guards; first version targeted host only and late-comers free-looted, switching to per-NPC nearest-threat made the AI split correctly between attackers at different bearings.
Linked natives
IS_PED_IN_COMBAT(0x4859F1FC66A6278E)
Tags: ai, combat, multiplayer, events, task
Category: uncategorized
Source: scandi_dynamic_events aggro redesign
Created: 2026-05-28T11:43:12.582Z