Phase 8: recognition, pursuit, and losing them
Cover is now a state you can lose. Suspicion builds while enemy eyes are on you, squared with proximity so one patrol beside the car outweighs a crowd across the street, and blocked by buildings like everything else. It cannot build at all behind your own lines. Ramming, being shot at and running somebody over skip the meter and land in full. At the top of it you are hunted: nearby enemies drop what they were doing and come, and keep joining as you drive past fresh patrols, since a chase you could outrun by passing more of them would be no chase. Being hunted is also now the only reason the enemy shoots at you — a target is a state, not a property of the road you happen to be on. Two ways out. Break line of sight for fourteen seconds, with any glimpse resetting the clock; hunters drive to where they last saw you rather than where you are, so turning a corner and changing direction is the move. Or let your own side occupy them — hunters are patrols, not fanatics, and enough peeling off ends the chase outright. Escaping leaves suspicion at 0.6 rather than zero: they know there is a car worth looking for. Tuning a test caught: the post-escape value sat a hair above the "suspicious" threshold, so the afterglow expired within a second and the rule may as well not have existed. Decay slowed to match, so cover is earned back by being dull rather than by turning one corner. Verified end to end in the running game: loitering beside a patrol in occupied ground filled the meter and pulled three hunters, fleeing out of sight cleared it after exactly fourteen seconds, and a visible player was closed on from 61m to 12m while taking hits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,14 @@ export interface HudModel {
|
||||
bearing: number;
|
||||
} | null;
|
||||
control: Control;
|
||||
pursuit: {
|
||||
/** 0..1 toward being recognised. */
|
||||
meter: number;
|
||||
alert: 'clear' | 'suspicious' | 'hunted';
|
||||
hunters: number;
|
||||
/** Seconds of staying out of sight before they give up. */
|
||||
losingIn: number;
|
||||
};
|
||||
/** Rounds in the air nearby. Not a health bar — a reason to keep moving. */
|
||||
danger: number;
|
||||
completed: number;
|
||||
@@ -57,6 +65,24 @@ const arrowFor = (bearing: number): string => {
|
||||
return ARROWS[((sector % 8) + 8) % 8]!;
|
||||
};
|
||||
|
||||
/**
|
||||
* The one meter the player is meant to watch. Deliberately not a number: it is
|
||||
* "how close am I to being made", and it wants reading at a glance while
|
||||
* driving.
|
||||
*/
|
||||
function pursuitLines(pursuit: HudModel['pursuit']): string[] {
|
||||
if (pursuit.alert === 'hunted') {
|
||||
return [
|
||||
`HUNTED — ${pursuit.hunters} on you`,
|
||||
pursuit.losingIn > 0
|
||||
? `break line of sight · ${pursuit.losingIn.toFixed(0)}s to lose them`
|
||||
: 'they can see you',
|
||||
];
|
||||
}
|
||||
if (pursuit.meter <= 0.02) return ['cover intact'];
|
||||
return [`noticed ${bar(pursuit.meter)}${pursuit.alert === 'suspicious' ? ' — being watched' : ''}`];
|
||||
}
|
||||
|
||||
const CONTROL_WORDS: Record<Control, string> = {
|
||||
liberated: 'liberated — nobody is watching the roads here',
|
||||
contested: 'contested — the roads remember, slowly',
|
||||
@@ -105,6 +131,7 @@ export function createHud(seed: number) {
|
||||
...(model.quest ? questLines(model.quest) : ['no mission — find a base']),
|
||||
'',
|
||||
CONTROL_WORDS[model.control],
|
||||
...pursuitLines(model.pursuit),
|
||||
...(model.danger > 0 ? [`⚠ rounds in the air nearby (${model.danger})`] : []),
|
||||
'',
|
||||
// Debug only. The real game signals heat through the road itself —
|
||||
|
||||
Reference in New Issue
Block a user