Skip to content

Controls (Hunter Assassin scheme)

Source: PROJECT_CONTEXT.md §4; config.js move, melee, combat; game.js onTap/findPath/smoothPath/updatePlayerAttacks/autoBackstabPlayer/backstabReady/backstabTell/doMelee/tryMelee. Status: ✅ Implemented

What it is

The player's entire input layer, modeled on Hunter Assassin: tap to move, no dedicated attack button. Combat happens automatically from positioning — the skill is where you go, not aiming. Reproducing Hunter Assassin's movement feel is a stated priority (§4).

How it works

  • Tap to move. Tap a point; the raider auto-paths there by the shortest route (findPath = A*, then smoothPath = LOS smoothing). onTap resolves a tap by priority: enemy → chest/loot/gate/extract → bare move.
  • Double-tap sprint. A second tap within move.doubleTapMs requests a sprint (if there's somewhere to run and enough stamina); costs stamina (move.sprintDrain/s), move.sprintMult speed.
  • Swipe dodge-roll. A fast swipe (move.swipeMin px within move.swipeMs) triggers a roll: burst of speed with i-frames — you can't be spotted or hit during the invuln window (stealth.invulnWindow). Costs move.dodgeCost stamina, on move.dodgeCd cooldown.
  • No dedicated attack button — attacks are automatic:
  • Auto-melee backstab. Standing directly behind a visible enemy → a silent crit fires unprompted (autoBackstabPlayerbackstabReady). The passive trigger uses the stricter rear-only arc combat.autoBackstabArc (wider than the landed-crit arc, so a side-brush won't auto-kill). A pulsing 🗡️ kill-zone tell (backstabTell, shown within the wider combat.backstabTellRange as you close in) signals when you're in the blind spot. It's a stealth opener, fired once: the first hit sets the enemy's target to you, which disarms the auto-trigger (backstabReady returns false once en.target === player) so it won't chain a second crit while the enemy turns. Re-arm by breaking line of sight (it loses you) or commit a tapped strike to follow up. A silent backstab also briefly mutes auto-fire (combat.meleeToFireLock) so the stealth kill isn't blown by a loud shot.
  • Tap an enemy to hunt. Tap a perceived enemy to actively chase it for melee (onTap sets meleeTarget; homes in with clear LOS, A-paths around cover otherwise) — for finishing fleeing/aware enemies or committing to a frontal swing. A committed strike still crits across the wider* combat.backstabArc (decided in doMelee), so deliberately flanking to a side and striking is still a backstab — only the hands-off auto-trigger is held to the tighter cone.
  • Auto-ranged on sight. Entering an enemy's vision (mutual: it sees you and you see it) → both sides auto open ranged fire (updatePlayerAttacksnearestEngaged). Symmetric — while hidden, nothing fires.
  • (Stance note: combat.autoMelee arbitrates one stance at a time — melee when a threat is in your face with ranged suppressed, ranged otherwise, with hysteresis. See the combat doc.)
  • Tap an object → walk-and-interact. Tap a chest, gate, loot, or extract; the raider walks to it and auto-interacts on arrival (onTap sets interactTarget).
  • Sustained interactions. Some objects need continued presence — cracking a chest takes ~loot.chestTime (4.0s) and you must stay close the whole time or it resets.

Tunables

Group Key Default
move baseMove 80 (ungeared pace, px/s)
move sprintMult 1.9
move sprintDrain / stamRegen 32 / 24 (stamina/s)
move stamMax 100
move doubleTapMs 300 (sprint double-tap window)
move dodgeCost / dodgeTime / dodgeCd 30 / 0.25 / 0.55
move dodgeSpeed / dodgeEase 500 / 1.0 (peak roll speed; brake curve)
move swipeMin / swipeMs 46 / 320 (dodge-swipe gesture)
melee dmgMult / simpleMult 2.0 / 0.7 (mob lunge vs simple)
melee windup / lockLead 0.65 / 0.18 (lunge telegraph; dodge cue)
combat backstabArc 0.55 (× PI; landed-crit rear/side arc)
combat autoBackstabArc 0.72 (× PI; stricter passive auto-stab arc)
combat critBase 1.5 (backstab base crit ×)
combat meleeToFireLock 0.5 (auto-fire mute after silent backstab, s)
combat meleeReach 25 (extra strike reach, px)
combat backstabTellRange 72 (🗡️ approach radius, px)
combat backstabHitstop 0.13 (freeze-frame on backstab kill, s)
stealth invulnWindow 0.34 (dodge i-frames, s)

Design intent

Directly serves Hide-and-kill (backstab = crit; head-on is risky) and Route over reflexes (§2): with no attack button, the only thing the player controls is movement and positioning, so all combat outcomes flow from where you stand. The stricter autoBackstabArc + fired-once lock keep the auto-stab a deliberate stealth opener rather than auto-DPS, preserving the "tactical stealth, positioning, deception, timing" pillar (§2.3).

Open questions / deltas

  • Stamina + dodge i-frames (§9.5): not in the concept doc — a prototype addition fleshing out the tension/readability pillars; carry forward to Unity unless cut.
  • 2.5D tap unprojection (§9.1): taps are unprojected through the isometric tilt (onTap uses unproject); a flat top-down Unity build would simplify this — port decision pending.