Skip to content

Rival Raiders

Source: PROJECT_CONTEXT.md §8.5, §8.6, §9 (#3); config.js bot; game.js mkBot, updateBot. Status: ✅ Implemented (simulated multiplayer — real PvP 🅿️ out of scope, §9 #3)

What it is

The map holds ~4 rival raider bots — AI opponents that loot, fight, and try to extract just like the player. They are the "other players" of the extraction loop: harder than mobs, matched to the player's Power, and carrying a haul you can steal by killing them. One is the Keybearer, who races to unlock the Vault.

How it works

  • Population & matchmaking (mkBot): count = map.bots (default 5). Each rival's Power is rolled around the player's: pwr = basePower × rand(0.62, 1.25) (Arc-style matching, so rivals stay a credible threat as the player gears up). HP, atk, and projDmg scale off that Power.
  • Per-rival loadout: each rolls one of the 4 ranged weapon archetypes (assault / smg / shotgun / sniper) — some snipe from range, some rush with a shotgun. Personality rolls: aggression, reaction, a starting haul, and an extractAfter timer.
  • AI (updateBot) — loot / flee / extract / combat:
  • Goal arbiter: default botState = "loot"; flips to extract once haul >= 3 or past its extractAfter time; flips to flee at low HP or when a mob threatens it.
  • Combat — kiting + burst-fire: on seeing the player it computes a bravery score (aggression minus a Power-disadvantage penalty); brave → fight, timid → flee. It reactively dodge-rolls incoming shots (botMaybeDodge, human-paced), backs away when hurt (fightBackoffDist), and burst-fires its weapon's magazine then reloads.
  • Aim/reaction delay (bot.aimTime): a rival tracks the player for aimTime before opening fire (not an instant snap-shot); aim bleeds off slowly out of sight, so a disengage-and-return re-pays the beat.
  • Fear of mobs: rivals treat nearby/alerted mobs as threats (mobThreatNear / mobThreatAlerted) and flee them — a genuine 3-way dynamic. Rivals are also harder for creatures to spot (stealth.raiderVsMob).
  • Self-extract: rivals call/board portals on the same rules as the player (extraction.boardBot = boardPassive = 9s).
  • Keybearer variant: rival index 0 gets hasKey, dropsKey, botGoal = "gate", name "Keybearer". It races to the locked Vault gate and channels it open (map.gateTime); the player can deny the channel by pressuring it at close range. The key mission is a commitment — generic haul/time extract triggers are suspended until bot.gateGiveUp (330s). When it cracks the gate, a banner broadcasts "ambush the looters!" (the concept §6 "let someone else unlock it, then steal" play). It won't race the gate below bot.gateMinHp (permanent — bots don't regen).
  • Harder than mobs — 360° sight, can't be backstabbed: mkBot gives rivals visA: Math.PI * 2 (full-circle vision) and visR = fog.radius, so they have no blind-spot cone to sneak up on. The first-raid intro coach explicitly frames rivals as "360° sight, no backstab" (§8.6) — they are a straight-up fight, unlike mobs.
  • Kill reward: a slain rival drops its haul on the ground to steal — hunting rivals for their loot is a core supported strategy (Pillar / §2).

Tunables

bot group (config.js):

key default meaning
mobThreatNear 130 mob within this px is always a threat
mobThreatAlerted 230 alerted mob within this px is a threat
fleeHpCrit 0.3 flee from any state below this HP fraction
fleeHpExtract 0.55 abort extraction below this HP if timid
fleeHpPost 0.5 after fleeing: extract if HP below this, else loot
fleeHpBackoff 0.6 back away from player in-fight below this HP
braveryFight 0.1 min bravery to stand and fight
braveryTimid 0.5 below = timid (bails on extraction when hurt)
fleeSprintMult 1.5 panic-sprint × (below player sprint)
aimTime 0.5 reaction delay (s) before opening fire
commitTime 2.2 fight commitment after engaging (s)
alertDecay 0.2 alert decay /s when not seeing anyone
fleeBreak 4.5 clear-contact (s) before flee reassesses
fightBackoffDist 240 px to player that triggers backing-away when hurt
gateMinHp 0.35 Keybearer won't race the gate below this HP
gateGiveUp 330 (s) after which the Keybearer abandons the key mission

Related: map.bots 5 (rival count), extraction.boardBot 9 (rival board time), enemyScale.enemySpeedMul 1.0 (rivals walk at player base pace) and enemyScale.atkCdMul 1.5 (applies to rival fire too).

Design intent

Rivals deliver the extraction-genre tension of "other players on the map" while staying single-player and shippable. They make every strategy in §2 live: avoid them, or hunt them for a fat haul. 360° sight / no-backstab makes them the genre's apex threat — the one enemy stealth can't trivialize — so a rival fight is a real Power test (Pillar 1's "head-on confrontation is always risky"). Matching their Power to the player keeps them dangerous through the gear curve. The Keybearer turns the Vault into an emergent flashpoint: race it yourself or let a rival open it and ambush the looters.

Open questions / deltas

  • Simulated, not networked (§9 #3): "other players" are AI bots, not humans. Real PvP is out of scope for the prototype — the Loot Station exposure design (§8.3.1) is described as "the foundation for the planned multiplayer," so the bot AI is the stand-in until/if networking lands. Flag for the Unity port: decide whether bots remain or are replaced by real players.
  • No-backstab is framing, not a hard mechanic block: rivals can't be sneaked up on (360° visA, no blind cone), which is how "no backstab" is enforced. The crit-arc check in doMelee is geometric, so confirm whether the Unity port wants an explicit hard rule vs. relying on full-circle sight.