orbit/data/quests.json

209 lines
21 KiB
JSON

{
"_comment": "The QUESTS console (deck slot right of SHIP, main deck + surface deck). The window mirrors the RESEARCH/MAP consoles (js/ui/QuestWindow.js): a 2:3 archive feed (assets/videos/quests.mp4 — the same aspect as assets/videos/research.mp4; NO SIGNAL plate until the clip is authored) on the left, and on the right the category tabs (Main Story / Side Quests — side quests are LIVE: the board's accepted contracts, their patrol checkpoints as the checklist, claimed from this console or the tracker — data/sidequests.json), a THIN list of active quests, and the big detail plate below it: title, issuer, description, the requirement checklist, and the reward, with the CLAIM action. A quest's progress is evaluated LIVE from the run (research, lifetime minerals mined from asteroids, the home tether's level, discovery) and, once a step reads DONE, it is recorded on the ledger and stays done (monotonic — the home tether's step keeps standing after the ship leaves the home system). js/quests/QuestState.js tracks who holds which quest, which reward has been claimed, and which steps have stood — and that is what gets saved.",
"enabled": true,
"title": "OPERATIONS DOSSIER",
"meta": "MISSION LOG // ACTIVE CONTRACTS",
"video": {
"file": "quests.mp4",
"_comment": "The archive feed (assets/videos/). quests.mp4 mirrors the 2:3 aspect of research.mp4 — fit the same way.",
"aspect": [2, 3]
},
"sweep": {
"_comment": "The band that crawls down the feed (the research/map console's sweep, tuned for this window).",
"enabled": true,
"intervalMs": [5200, 9800],
"durationMs": [1400, 2200]
},
"glitch": {
"enabled": true,
"intervalMs": [4200, 9200],
"durationMs": [110, 260],
"slices": [1, 4],
"maxOffset": 9
},
"tabs": [
{
"id": "main",
"label": "Main Story",
"accent": "#00e5ff",
"_comment": "The campaign's spine. Live — the starter quest is granted on the run's first boot."
},
{
"id": "side",
"label": "Side Quests",
"accent": "#ffc94d",
"_comment": "LIVE — the board's accepted contracts (data/sidequests.json — patrol is the first live category): the ACCEPTED side quests stand here (GameScene.questSnapshot's category-'side' entries — the patrol's checklist is its route's waypoints, the reward is the contract's payout), with the same CLAIM REWARD / SET PRIORITY doors as the story tab (the console's claim/priority seams dispatch the sq- ids to the side ledger — js/quests/SideQuests.js). Empty until a contract is accepted at the board."
}
],
"sideStandbyNote": "SIDE QUESTS OFFLINE — NO CONTRACTS ON FILE YET",
"starterToast": {
"_comment": "The one-shot note when a quest lands on the ledger — the starter on the run's first boot (GameScene.create) and an unlock grant (leaving_the_nest, when the starter's reward is claimed — GameScene._grantUnlockedQuests).",
"glyph": "◆",
"color": "#ffc94d",
"text": "NEW QUEST — {title}"
},
"readyToast": {
"glyph": "◆",
"color": "#ffc94d",
"text": "QUEST READY — {title} · CLAIM ITS REWARD"
},
"claimToast": {
"glyph": "✓",
"color": "#67e863",
"text": "REWARD CLAIMED — {reward}"
},
"claimDenyToast": {
"glyph": "✗",
"color": "#ff5c77",
"text": "REQUIREMENTS INCOMPLETE — {missing}"
},
"capitalDenyToast": {
"_comment": "The capital world's landing gate (js/scenes/GameScene.js → startLanding — _capitalLandingBlocked): the 'Leaving the Nest' reward must be CLAIMED before the player can land on the neutral capital world (the quest completes when the ship arrives at the planet; the claim is the last step before the world opens). A landing request before the claim is this flat denial on the console (the comms panel already closed — the toast is the ack; the ✗ mark reads the deny).",
"glyph": "✗",
"color": "#ff5c77",
"text": "REQUEST DENIED. PLEASE CLAIM YOUR QUEST REWARD FIRST."
},
"tracker": {
"_comment": "The QUEST TRACKER HUD (js/ui/QuestTrackerHud.js) — the thin quest list that slides in from offscreen-left right below the system dossier ONCE the dossier has folded (auto-fold or the player's manual fold — first fold arms it; visible ⇔ dossier folded). ACTIVE = held + not claimed. Titles stack main-story-first then side-quests (the board's accepted contracts ride the same stack — GameScene.questSnapshot), up to maxVisible, the priority quest's checklist renders under its title and tracks LIVE (GameScene.questSnapshot); more than maxVisible → SHOW MORE (opens the QUESTS console on the first hidden quest). The ONE priority quest (js/quests/QuestState.js): the player sets/clears it (row popup + the console's SET PRIORITY — a side quest's set rides the side ledger's active slot, featured through this seam), else the first active quest is the priority (main story first, then side); claiming it auto-advances to the next active quest. priorityToast/clearToast fire on set/clear (data colors: green = the tracker accent, dim = the cleared note).",
"enabled": true,
"title": "QUESTS",
"noneTracked": "NONE TRACKED",
"showMore": "SHOW MORE",
"maxVisible": 5,
"slideMs": 320,
"shimmer": {
"_comment": "The READY row's DUAL-SHIMMER rim (js/ui/PerimeterShimmer.js): a constant amber base rim + soft glow, and two comets in counter-streams around the plate's cut-corner perimeter (comets[0] amber clockwise, comets[1] neon cyan counter-clockwise) — they cross twice per cycle. Runs until the reward is claimed: the row drops off with a one-shot rim flash (claimFlashMs). periodMs = one full lap; dashFrac = a comet's dash as a fraction of the perimeter; phaseOffsetPerRow staggers simultaneous READY rows; notch = the READY plate's corner-cut (the console's CLAIM plate in miniature).",
"enabled": true,
"notch": 6,
"periodMs": 2400,
"dashFrac": 0.3,
"phaseOffsetPerRow": 0.25,
"claimFlashMs": 150,
"base": { "color": "#ffc94d", "alpha": 0.55, "glowAlpha": 0.14, "width": 1.5 },
"comets": [
{ "color": "#ffc94d", "dir": 1, "phase": 0, "width": 2, "alpha": 1, "haloAlpha": 0.32 },
{ "color": "#00e5ff", "dir": -1, "phase": 0.5, "width": 2, "alpha": 0.9, "haloAlpha": 0.32 }
]
},
"priorityToast": {
"glyph": "◆",
"color": "#67e863",
"text": "PRIORITY SET — {title}"
},
"clearToast": {
"glyph": "·",
"color": "#7d92c4",
"text": "PRIORITY CLEARED"
}
},
"tutorial": {
"_comment": "The starter quest's POINTING FINGER (the beat table in js/quests/TutorialGuide.js, applied per frame by GameScene._applyTutorialHighlight): the ONE control asking for the player's attention during the opening arc, pulsing on the surface that owns it (ActionBar.setHighlight, ResearchWindow.setHighlight). The beats derive LIVE from the run's records — the comms' played-ledger (which of OAC's lines were heard — data/comms.json) + the research state — so nothing extra is saved and a loaded run picks the same beat back up: (1) the welcome sequence acknowledged (oac-intro/oac-tether/oac-scan all heard) and SCAN not yet pressed → scan.slot pulses on the deck; (2) oac-upgrade heard (the 'research a Tether Level 2 upgrade' line) → research.slot pulses while the console is closed, and inside the open console the console.category tab — then the console.node plate, once the player clicks it — wears the ACKNOWLEDGE button's own amber pulse (comms.box.pulse: halo + two staggered sonar rings, ResearchWindow._paintAckPulse); the finger rests the moment the node's research is in flight or done (its completion ignition + toasts carry the news). The rim hides under the deck's standby — while an 'ack' comm holds, the ACKNOWLEDGE button is the only live control.",
"enabled": true,
"scan": { "slot": "scan" },
"research": { "slot": "research" },
"console": { "category": "exploration", "node": "tether_l2" }
},
"quests": [
{
"id": "start_your_journey",
"category": "main",
"starter": true,
"icon": "diamond",
"title": "Start Your Journey",
"description": "The universe is cold, and it ain't gonna do you any favors kid. The sooner you discover that, the sooner you'll be able to start taking care of yourself. And what better way to discover the universe, than to discover the universe.",
"issuer": "A Friend",
"_comment": "The first quest, granted on the run's first boot (js/quests/QuestState.js → starters). Its checklist is the run's opening arc — research, mine, build, discover. The checks are evaluated LIVE (GameScene._questCheckEval): 'research' resolves against data/research/exploration.json (the Tether Level 2 node), 'mineralsMined' against the run's lifetime asteroid mining (the Mining sequence's onOre), 'tetherBuilt' against the home world's standing tether level, 'discoveredWorld' against the discovery ledger (any discovered world besides the home). Once a step reads DONE it is RECORDED on the ledger (QuestState's completed set — rides record.quests) and stays done: monotonic, the check keeps standing even where the live read can no longer see it (the home tether's standing once the ship has left the home system).",
"checks": [
{ "type": "research", "category": "exploration", "node": "tether_l2", "label": "Research Tether Level 2" },
{ "type": "mineralsMined", "amount": 200, "label": "Mine 200 Minerals from asteroids" },
{ "type": "tetherBuilt", "planet": "home", "level": 2, "label": "Build a Level 2 Tether on your Home world" },
{ "type": "discoveredWorld", "count": 1, "label": "Discover another planet or space station" }
],
"reward": {
"minerals": 200,
"_comment": "The completion reward — 200 Minerals, claimed via the CLAIM REWARD action (fits the ship's hold: ship.stats.mineralStorage)."
}
},
{
"id": "leaving_the_nest",
"category": "main",
"icon": "diamond",
"title": "Leaving the Nest",
"description": "The nest did its job — it kept you alive long enough to learn the sky. Now the sky is yours. Chart the whole system, light its gates, and come find me out past the gate. I'll be waiting.",
"issuer": "Trestle",
"_comment": "The run's SECOND quest — the starter's follow-up (the 'Leaving the Nest' arc). It GRANTS the moment the starter quest is COMPLETED AND CLAIMED (unlocks.claimed — QuestState.isUnlockMet, armed by GameScene._grantUnlockedQuests on the claim itself + on scene create for loaded saves whose starter is already paid out). Trestle — the 'A Friend' behind the starter — is the issuer: his firstWorld pair (data/comms.json) promised the meeting. The four checks are the run's exit arc, witnessed by the run's COMMS played-ledger (registry 'commsPlayed' — marked when a comm starts, saved with the run, so the witness survives reloads and a quit mid-sequence): the system's full NAV chart (the same set that gates the jumpgate research), the home system's gates ACTIVATED (the activateGates effect), Trestle's THREE-BRIEF sequence (trestle-brief-1/2/3, trigger 'trestleBrief' — armed when the home gates go online, GameScene._trestleBeats; ALL THREE heard = 'Talk to Trestle'), and his ARRIVAL PAIR when the player arrives at the destination planet — the NEUTRAL CAPITAL WORLD (trestle-arrive-1/2, trigger 'trestleArrival' — armed the moment the ship reaches the capital world, GameScene._checkDestinationReached, plus a scene-create arm for loaded saves; 'Meet Trestle'). Both Trestle checks are read data-driven from the trigger's comms (GameScene._questCheckEval).",
"unlocks": {
"_comment": "The grant condition: the listed quests' rewards CLAIMED (the ledger's paid-out set) — 'unlocked as soon as the first quest is completed and its reward collected'.",
"claimed": ["start_your_journey"]
},
"checks": [
{ "type": "systemCharted", "system": "home", "label": "Discover all Planets, Space Stations and Jump Gates in the system" },
{ "type": "gatesActivated", "system": "home", "label": "Activate System Jump Gates" },
{ "type": "trestleTalked", "label": "Talk to Trestle" },
{ "type": "trestleMet", "label": "Meet Trestle on the capital world" }
],
"reward": {
"credits": 200,
"_comment": "The completion reward — 200 Credits, claimed via the CLAIM REWARD action."
}
},
{
"id": "special_delivery",
"category": "main",
"icon": "diamond",
"title": "Special Delivery",
"description": "The mail routes are dead, and a sealed package that must reach the home world is sitting at the neutral capital's bar. Carol is paying for the run, and Trestle will see it off — the only question is whether your ship can hold the cargo. Meet the two of them at the bar, upgrade the hold, and deliver the package to the home world.",
"issuer": "Carol",
"_comment": "The run's THIRD quest (the 'Leaving the Nest' follow-up — the bar at the neutral capital). It GRANTS the moment 'Leaving the Nest' is COMPLETED AND CLAIMED (unlocks.claimed — the same chain mechanic as leaving_the_nest). The three checks: step 1 'vignettePlayed' (check.id 'special_delivery_bar_meeting' — the bar's dialogue scene in data/vignettes.json: Trestle + Carol, the run's played ledger registry 'vignettesPlayed' is the witness — VignetteHub marks it when the scene's DONE press completes it; the gate — the quest granted, unclaimed, this step open — is what plays it when the bar is entered). The CAPITAL LANDING runs the story ledger (registry 'story', saved as record.story — GameScene._recordLanding): the trade gate lifts (the shop's Buy/Sell tab — ShopView reads GameScene.isTradeUnlocked; the deck's Shop button itself is always live). The scene's DONE press (GameScene.onVignetteComplete) runs the handoff: FIRST the ship's hold is built out (the scene's effects.cargoHold — the run's ship starts with cargoHold 0, data/ship.json), THEN the SPECIAL PACKAGE — packageGood 'special-package', data/goods.json, sheet frame 114, tradeable:false so no shop floor touches it — lands in the hold (GameScene._handoffSpecialPackage), and — while the quest is HELD (granted, unclaimed) — the HOME WORLD becomes the destination (the delivery's route: the bar conversation is the trigger — Carol's 'just bring this package back to the merchant on your home world' line, and the compass points it for the flight home — GameScene.onVignetteComplete's beat 3, _specialDeliveryHeld re-reading the gate so a scene that outlived the quest can't re-aim the destination); step 2 'cargoUpgraded' (check.id 'special-package') — the witness is the PACKAGE ABOARD: it only fits once the hold is upgraded, so its presence IS the upgrade's proof (the scene's lines are the truth — Carol's crew built the bays); step 3 'packageDelivered' — the delivery's proof (story.delivered, MONOTONIC): the package SOLD on the HOME WORLD for ZERO CREDITS — the home world is the ONE floor that takes it (TradeGrid's questSell gate — the SELL grid refuses the bay everywhere else, the tooltip reads NOT FOR SALE), priced at the good's flat sellFor (0 cr — Economy.questCargoSellPrice; the shop's Confirm is ShopView.confirm → GameScene.onQuestPackageSold, which records it — the parcel in Carol's hands IS the delivery, landing alone no longer completes the step; the sale is not buyback-eligible). The capital's launch (SurfaceScene.finishTakeoff → GameScene.onSurfaceDeparture) records the delivery's trail (launchedFromCapital) and, once the sale stands, arms the payoff chain — it no longer touches the destination, so a post-quest visit to the capital (a 'Pirate Problems' return leg) leaves the player's destination alone. Reward: 200 credits (claimQuest's credit seam — the same as 'Leaving the Nest').",
"unlocks": {
"_comment": "The grant condition: the listed quests' rewards CLAIMED — the run's chain (leaving_the_nest paid out → this one grants).",
"claimed": ["leaving_the_nest"]
},
"packageGood": "special-package",
"checks": [
{ "type": "vignettePlayed", "id": "special_delivery_bar_meeting", "label": "Meet with Trestle and Carol at the neutral capital's bar" },
{ "type": "cargoUpgraded", "id": "special-package", "label": "Upgrade Ship to hold Cargo" },
{ "type": "packageDelivered", "label": "Deliver Package for Carol", "_comment": "Step 3 — the witness is the package's HOME-WORLD SALE at zero credits (story.delivered — GameScene.onQuestPackageSold, set by the shop's Confirm of that sale; the grid offers the sale on the home world only). Landing on the home world is no longer the proof." }
],
"reward": {
"credits": 200,
"_comment": "The completion reward — 200 Credits, claimed via the CLAIM REWARD action."
}
},
{
"_comment": "THE FOURTH QUEST — 'Pirate Problems' (the run's third link after 'Special Delivery'). It GRANTS the moment 'Special Delivery' is COMPLETED AND CLAIMED AND its payoff chain is HEARD ALL THE WAY THROUGH (unlocks.claimed + unlocks.acked — the deliveredLaunch four-beat: carol-delivered-1/2/3 + oac-delivered-1, every one of them ACKed, not merely started — the run's comms acked-ledger, registry 'commsAcked', owned by js/comms/CommsHub.js's onAck hook; GameScene._grantUnlockedQuests supplies it to QuestState.isUnlockMet, so the grant lands on whichever of the two conditions completes last: the claim (claimQuest) or the final ACK (_commEnded's grant pass)). On its grant the run turns: the player's DESTINATION is set to the Neutral Capital world (GameScene._questStartBeats) and Trestle's three-beat warning plays (data/comms.json → trigger 'trestleQ4' — trestle-q4-1/2/3 on trestle-q4-01/02/03.mp3; the 'Speak with Trestle' step's witness is that sequence in the played-ledger, the same _trestleCheck seam as 'Leaving the Nest'). Then the run's story turns on the pirates: with the quest live, the ambush fires at the MIDPOINT of the entry-jumpgate → capital-world stretch — the player ENTERS the capital's system at the gate (a full stretch from the world), and the raiders materialize once the ship is within HALF that gate-to-world distance of the capital (GameScene._maybeStartPirateAmbush: the entry gate is the destination's return gate for the last jump's source system — the restore's lastJumpFrom, staged in jumpThroughGate and saved in captureState — falling back to the gate nearest the spawn, then the spawn itself; the trigger is dist(gate, capital)/2 via JumpTravel.ambushTriggerDistance, and update() arms it the frame the ship crosses the halfway point) — ONE rolling wave of SIX frame-0 raiders (data/combat.json → waves.scripts.pirate_ambush; EnemyTypes: raider = frame 0), the wave ships materializing OFF-SCREEN around the player, each from a random direction (CombatSystem._spawnWaveEnemy — the same off-screen materialization as the ?combat pack), streaming in on their own chase AI (GameScene._maybeStartPirateAmbush fires the run); the wave's completion marks the 'combatDone' ledger (registry, SaveData-captured) — the 'Defend your ship from pirates' step's monotonic witness. 'Return to the Neutral Capital World' completes on the ARRIVAL itself — the ship within the capital world's keep-out rim with the quest held + unclaimed sets story.capitalReturned (GameScene._maybeWitnessCapitalReturn; the story ledger is SaveData-captured, monotonic). The bar's follow-up conversation is a later layer (the arrival is the step; the scene lands on it). The PAYOFF: on the quest's READY moment — all checks standing, the reward claimable (GameScene._questRefresh's once-per-quest announcement, the same moment the QUEST READY toast + chime fire) — the quest's payoffTrigger arms Trestle's two-beat sign-off (data/comms.json → trigger 'trestleQ4Payoff' — trestle-q4-4/5 on trestle-q4-04/05.mp3: the job boards' unlock — patrols, bounty hunts, escorts — + the level-5 hook, the run's next door; the comms' once-ledger keeps the pair a one-shot, a loaded save hears the unplayed beats).",
"id": "pirate_problems",
"category": "main",
"icon": "diamond",
"title": "Pirate Problems",
"description": "That delivery has gotten your ship noticed, kid. Local pirates are circling your trail now, and the only way to shake them is to make them regret it. Fight your way through them and get back to the bar — I'll be waiting.",
"issuer": "Trestle",
"unlocks": {
"claimed": ["special_delivery"],
"acked": ["carol-delivered-1", "carol-delivered-2", "carol-delivered-3", "oac-delivered-1"]
},
"payoffTrigger": "trestleQ4Payoff",
"checks": [
{
"type": "trestleTalked",
"trigger": "trestleQ4",
"label": "Speak with Trestle"
},
{
"type": "combatCleared",
"script": "pirate_ambush",
"label": "Defend your ship from pirates"
},
{
"type": "capitalReturned",
"label": "Return to the Neutral Capital World"
}
],
"reward": {
"credits": 200,
"_comment": "The completion reward — 200 Credits, claimed via the CLAIM REWARD action."
}
}
]
}