Skip to content

Enemies & Bosses

Source: PROJECT_CONTEXT.md §8.3, §8.4, §8.5; config.js enemies, enemyScale, melee; game.js MOB_DEF, MOB_TIER, mkMob, updateMob, isLunger, meleeSequence. Status: ✅ Implemented (low-tier lunge 🅿️ Parked, config-gated)

What it is

The AI-mob roster the raider dodges, hunts, or backstabs while looting. Mobs are the PvE threat layer and a loot source — they drop valuable resources on death. They range from cheap tier-1 harassers up to the tier-4 Thornback Brute boss, and they read as creatures of the cute-fantasy Thornwood (spiders, goblins, wardens, a forest brute).

How it works

  • Roster (MOB_DEF = CONFIG.enemies), tiered by MOB_TIER:
  • Tier 1 — harassers: Cave Spider (spider, web:true), Emberling (emberball, ranged fire, floats), Goblin Scout (goblin), Thorn Hound (hound, pack:true), Bone Thug (skeleton, high HP/atk bruiser).
  • Tier 2: Forest Warden (warden, ranged) — also spawned as the Keykeeper variant (game.js Old Market: renamed, dropsKey=true, +120 HP / +8 atk) that drops the 🔑 vault key on death.
  • Tier 3 — heavies: Rocketeer (rocketeer, rocket), Bombardier (bombardier, bomb, lobbed), Stone Sentry (sentinel, stationary:true, long sight visR 370, slow speed 18).
  • Tier 4 — boss: Thornback Brute (boss, hp 1500, both melee and ranged/rocket).
  • Mob AI (updateMob) — perceive / suspect / patrol / chase / search:
  • perceive gates detection by sight radius (visR), vision-cone half-angle (visA), and line of sight; a bush shrinks an unaware mob's detect radius (stealth.bushDetectMult).
  • Gradual detection: cone exposure fills alert over time — < alertSpotted (0.5) unnoticed, 0.5–1 suspicious (turns/creeps toward, holds fire), 1 fully spotted (locks on, mutual fire, rallies the pack via alertPackTimed). This is the "back off in time" stealth window.
  • Lose-trail: breaking line of sight decays alert; ducking into a bush after breaking sight decays it fast (bushBreakDecay). Heavy mobs (tier ≥ combat.heavyTier) cling far longer (heavyTenacity) — you escape them by distance/dodging, not by ducking a bush; tier-1 harassers stay shakeable.
  • Stationary Sentry: tracks while noticing but only opens fire at full alert; otherwise idly sweeps its gaze.
  • Front armor + rear weak-point: shots to the front armor cone (armorFront) are reduced (armorFrontMult), flanks armorFlankMult, the glowing rear weak-point takes bonus damage (armorRearMult). A chasing mob's facing lags the target (turn rate in updateMob, melee turn 6 / ranged 3.4) so a circling attacker can reach the rear — and mobs juke side-to-side to defend it. A backstab bypasses armor and the Power check entirely.
  • Ranged charge wind-up telegraph: ranged mobs fire rarely but hard with a chargeDur wind-up (per-enemy) — a red telegraph that can be dodge-rolled.
  • Lunge gap-closer (isLunger, meleeSequence): melee mobs close a real gap with a telegraphed wind-up (melee.windup) → committed dash (lungeTime/lungeSpeed) → heavy hit (dmgMult). In reach they use quick simple attacks (simpleMult) instead. Currently melee.lungeMinTier = 2, so tier-1 melee just walk in (parked: they closed too fast — see §8.7).
  • Drops: mobs drop valuable resources on death; while in-run inventory is parked, loot spills on the ground (spillLoot) and auto-vacuums. Tier-1 trash is source-gated to blueprints only (loot.t1Valuables=false).

Tunables

enemies (per-mob MOB_DEFhp · atk · speed · visR · visA · fireRate · projDmg · chargeDur):

key name hp atk speed visR visA notes
spider Cave Spider 90 24 150 205 1.8 melee, web
emberball Emberling 80 14 58 250 2.0 ranged fire, float, projDmg 26
goblin Goblin Scout 86 28 102 205 1.5 melee
hound Thorn Hound 78 36 162 215 1.75 melee, pack
skeleton Bone Thug 180 50 82 180 1.4 melee bruiser
warden Forest Warden 210 20 76 340 1.15 ranged, projDmg 62 — Keykeeper variant
rocketeer Rocketeer 260 90 64 380 1.1 ranged rocket, projDmg 90
bombardier Bombardier 420 100 50 320 1.25 bomb, projDmg 100
sentinel Stone Sentry 300 40 18 370 1.95 stationary, long sight
boss Thornback Brute 1500 70 70 360 1.3 melee + ranged rocket

enemyScale: enemySpeedMul 1.0 (non-boss speed = player base pace), atkCdMul 1.5 (×on every enemy attack cooldown — attack less often, same per-hit dmg), powerRef 1500, hpPerPow 0.7, dmgPerPow 0.5 (HP/dmg ramp once player out-powers the reference).

melee: lungeRange 140, lungeMinRange 75, windup 0.65, lockLead 0.18, lungeTime 0.30, lungeSpeed 480, recover 0.15, dmgMult 2.0, cd 1.7, simpleMult 0.7, lungeMinTier 2 (1 = every melee lunges).

combat (armor/weak-point): armorFront 0.95, armorRear 2.1, armorFrontMult 0.25, armorRearMult 1.6, armorFlankMult 0.65; mobHpMult 2, mobDmgMult 0.5; heavyTier 3, heavyTenacity 0.35; mobMeleeCd 0.7.

Design intent

Serves Pillar 1 (hide-and-kill) and Pillar 2 (route over reflexes): front armor + rear weak-point + juking makes a head-on fight a slow, risky grind, while a stealthy rear approach is an instant assassination (backstab ignores armor and the Power check). Gradual detection and the bush window make "back off before it locks" a real skill. Tiering gives a risk gradient — harassers to skip, heavies to route around, the Brute as a set-piece — and weak-point combat keeps fights about positioning, not aim.

Open questions / deltas

  • Unity port (§9 #1): the 2.5D iso tilt affects how the rear weak-point and juking read on screen — confirm the look survives a flat-top-down decision.
  • Low-tier lunge parked (§8.7): melee.lungeMinTier=2 disables tier-1 gap-close pending a feel pass; flip to 1 to restore.
  • Prolonged-but-survivable knobs: combat.mobHpMult (2) and mobDmgMult (0.5) are the Diablo-direction dials, pending a playtest pass (PROJECT_CONTEXT §8.7 notes these defaulted to 1 in prose but config.js ships 2 / 0.5 — confirm intended values).