acdcb5515b
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.
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import type { Vector3Tuple } from "@/types/three/three";
|
|
import type {
|
|
RepairMissionId,
|
|
RepairMissionTriggerConfig,
|
|
} from "@/types/gameplay/repairMission";
|
|
import { EBIKE_WORLD_POSITION } from "@/data/ebike/ebikeConfig";
|
|
import { PYLON_WORLD_POSITION } from "@/data/gameplay/pylonConfig";
|
|
|
|
export const REPAIR_MISSION_ANCHOR_IDS: Partial<
|
|
Record<RepairMissionId, string>
|
|
> = {
|
|
pylon: "repair:pylon",
|
|
};
|
|
|
|
const EBIKE_REPAIR_POSITION = EBIKE_WORLD_POSITION satisfies Vector3Tuple;
|
|
|
|
const REPAIR_MISSION_POSITIONS = {
|
|
ebike: EBIKE_REPAIR_POSITION,
|
|
pylon: PYLON_WORLD_POSITION,
|
|
farm: [-24, 0, 42],
|
|
} as const satisfies Record<RepairMissionId, Vector3Tuple>;
|
|
|
|
// 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,
|
|
).map(([mission, position]) => ({
|
|
mission: mission as RepairMissionId,
|
|
position,
|
|
})) satisfies readonly {
|
|
mission: RepairMissionId;
|
|
position: Vector3Tuple;
|
|
}[];
|