Knowledge from the fieldRedM

RedM multiplayer NPC events: use per-NPC nearest-threat targeting, not host-only or single-target

learning:46

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

  1. TaskCombatPed(npc, PlayerPedId(), 0, 16) — only targets the host's local ped. Every other player is invisible to AI.
  2. 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.
  3. 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 via GetPlayerPed(idx).
  • For vehicle-driver NPCs: gate the re-task on not IsPedInAnyVehicle(driver, false) so you don't cancel a pending TaskLeaveVehicle and 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

Back to documentation