refactor(ebike): drop redundant 'locked' substate, single entry trigger

The ebike mission previously had two redundant entry-point sub-states
('locked' and 'waiting') that were behaviorally identical from the
player's perspective:
- both showed the same 'Lancer le Repair Game' prompt
- both allowed the press-E handler in Ebike.tsx to jump to 'inspected'

In addition, the locked state caused two latent bugs:
- the static-map ebike node (GameMap) and the live <Ebike> component
  were rendered simultaneously at the same world position
- a generic RepairMissionTrigger anchor sphere was rendered in
  parallel to Ebike's own InteractableObject (two triggers, same area)

Changes:
- useGameStore: ebike's initial currentStep + completeIntroState target
  is now 'waiting' (pylon/farm still init at 'locked' — they need it).
- Ebike.tsx: drop dead === 'locked' branches in repairGameOwnsEbikeModel
  and the press-E handler.
- EbikeRepairNarrator: only reset the played-set on 'waiting'.
- RepairGame: drop 'locked' from the ebike livePosition guard.
- REPAIR_MISSION_TRIGGERS: empty array (the duplicate ebike anchor
  sphere is gone). Keep the array + RepairMissionTrigger component for
  future re-use.
- GameMap: hide the static-map ebike node as soon as
  mainState === 'ebike' (was: only when ebikeStep !== 'locked').
- repairMissionState.getPreviousMissionStep: ebike rewinds from
  'waiting' to 'waiting' (cap), pylon to 'npc-return', farm to 'locked'.

The 'locked' value is intentionally kept in the MissionStep type union
because the farm mission still uses it as a meaningful kickoff state
driving FarmNarrativeFlow's auto-transition to electricienne_history.
This commit is contained in:
Tom Boullay
2026-06-03 04:02:32 +02:00
parent 5ad2e27a89
commit acdcb5515b
7 changed files with 27 additions and 23 deletions
+8 -7
View File
@@ -20,13 +20,14 @@ const REPAIR_MISSION_POSITIONS = {
farm: [-24, 0, 42],
} as const satisfies Record<RepairMissionId, Vector3Tuple>;
export const REPAIR_MISSION_TRIGGERS = [
{
mission: "ebike",
label: "Réparer l'e-bike",
radius: 4,
},
] as const satisfies readonly RepairMissionTriggerConfig[];
// Currently empty: the ebike mission entry point is handled directly by
// `Ebike.tsx`'s own InteractableObject ("Lancer le Repair Game"), and the
// pylon/farm missions transition through their narrative flows
// (PylonNarrativeFlow / FarmNarrativeFlow). Keep the array typed so we
// can re-introduce a generic anchor trigger in the future without
// touching the consumer in `GameStageContent.tsx`.
export const REPAIR_MISSION_TRIGGERS: readonly RepairMissionTriggerConfig[] =
[];
export const REPAIR_MISSION_POSITION_ENTRIES = Object.entries(
REPAIR_MISSION_POSITIONS,
+6 -1
View File
@@ -105,7 +105,12 @@ export function getPreviousMissionStep(
case "npc-return":
return "arrived";
case "waiting":
return mission === "pylon" ? "npc-return" : "locked";
// Ebike no longer has a "locked" entry state — its mission starts
// directly at "waiting". Pylon rewinds to its NPC return loop, farm
// rewinds to its narrative-driven locked kickoff.
if (mission === "pylon") return "npc-return";
if (mission === "farm") return "locked";
return "waiting";
case "inspected":
return "waiting";
case "fragmented":