orbit/data/comms.json

219 lines
16 KiB
JSON

{
"$comment": "COMMS — the characters of the ship speaking to the player (OAC first). Three comm types: 'ack' pauses the action and holds the box open (muted looping video + text + voice) until the player clicks ACKNOWLEDGE; 'visual' shows the box (video plays once + text + voice) and fades out when the voice ends; 'audio' is voice only — no box, no pause. Comms are EVENTS: each one binds a trigger (when) + a sender (who) + text + a speech clip (what). Trigger vocabulary (live): 'newGame' — the fresh-run tutorial welcome (oac-intro → oac-tether → oac-scan; the hub's FIFO plays each right after the previous is acknowledged); 'firstScan' — oac-upgrade reacts to the player's first SCAN press (GameScene.startScan), 5 s after the click; 'tetherResearch' — oac-minerals → oac-fly-mine react to the player committing to the Tether Level 2 research (GameScene.beginResearch, held by the busy() contract until the console closes); 'firstCluster' — oac-first-cluster celebrates the run's first asteroid-cluster discovery (GameScene.celebrateDiscovery), 1.5 s after the chime so the discovery SFX lands first; 'minerals200' — oac-tether2 confirms the moment the run's lifetime mining first crosses 200 (the 'Mine 200 Minerals' quest line and the tether-l2 build cost; GameScene's ore event); 'tetherL2Launch' — oac-relaunch → oac-explore, the launch-back pair: SurfaceScene's take-off that puts the player in space after the home world's level-2 tether is installed (the run's build record is the witness); the hub's FIFO plays the pair back-to-back; 'firstWorld' — trestle-meetup → trestle-quest: the FIRST world the player discovers — the starter quest's own witness (discoveredWorldCount: any planet or space station, the home world never counts, in any system — the comm and the quest can never drift; GameScene.celebrateDiscovery, plus a scene-create arm for loaded saves that already hold discovered worlds), the hub's FIFO plays the pair back-to-back; 'researchComplete' — oac-research-complete, the AUDIO-ONLY sign-off on EVERY research completion (GameScene._completeResearch; once:false, held by the busy() contract while the research console is still open). Reserved for future comms: researchNew, questNew, questComplete, discovery, landing, jump, buildComplete. Assets are loaded ON DEMAND by the hub (js/comms/CommsHub.js) when a comm is due — never in a scene's preload, so the initial load stays lean.",
"enabled": true,
"audio": {
"$comment": "The comm's voice plays at its OWN volume (volume) — the manager's master is left untouched (in v4 `sound.setVolume` IS the master, so ducking it would quiet the voice too). While the voice talks, the other playing sounds (the game music) are ducked PER-SOUND by musicDuck (a fraction of each one's own volume) and restored exactly when the voice ends.",
"volume": 1.0,
"musicDuck": 0.3
},
"characters": {
"$comment": "The senders. label = the box's header; role = the small line beside it; video = the character clip (left panel of the box, ALWAYS played muted — the voice is the speech clip, never the video).",
"oac": {
"label": "O.A.C.",
"role": "ONBOARD A.I. COMPUTER",
"video": "assets/videos/characters/oac.mp4"
},
"trestle": {
"$comment": "Trestle — the out-of-system mentor (the 'A Friend' behind the starter quest, data/quests.json). Same box, same contracts; the clip + speech are his own (the speech key is folder-scoped, so his intro-01.mp3 never collides with OAC's).",
"label": "TRESTLE",
"role": "OUT-OF-SYSTEM MENTOR",
"video": "assets/videos/characters/trestle.mp4"
}
},
"comms": [
{
"$comment": "The fresh-run welcome: OAC introduces the ship. type 'ack' — the action pauses and the box holds (video loops silently) until ACKNOWLEDGE. delayMs beats the opening toast so the signal is clean.",
"id": "oac-intro",
"from": "oac",
"type": "ack",
"trigger": "newGame",
"text": "So you want to explore the galaxy do you?... Welcome to your ship... she's not much but she's got room to grow. I'm O.A.C. your Onboard A I Computer, and I'm here to help you get around.",
"audio": "assets/speech/oac/intro-01.mp3",
"once": true,
"delayMs": 1400
},
{
"$comment": "Welcome beat two (the tether region). Queued right behind oac-intro on newGame: the hub's FIFO plays it the moment the welcome is acknowledged — each 'ack' holds until its own ACKNOWLEDGE press, so the order is guaranteed.",
"id": "oac-tether",
"from": "oac",
"type": "ack",
"trigger": "newGame",
"text": "First things first. We are tethered to your home planet, this limits how far you can go and what you can explore. We can build more tethers on planets and space stations, but we're going to need to find another planet or space station before we can do that.",
"audio": "assets/speech/oac/intro-02.mp3",
"once": true
},
{
"$comment": "Welcome beat three (the first instruction): scan the tether region. The player clicks SCAN on the deck after acknowledging this — oac-upgrade (firstScan) is the reaction to that click.",
"id": "oac-scan",
"from": "oac",
"type": "ack",
"trigger": "newGame",
"text": "Let's begin by scanning. Scanning allows us to find other objects inside of our tether region. Lets see what we can scan right now. Click Acknowledge on this comms window, then click Scan on the bottom bar to scan your tether region.",
"audio": "assets/speech/oac/intro-03.mp3",
"once": true
},
{
"$comment": "The scan reaction: fires when the player clicks SCAN on the deck (GameScene.startScan → comms.trigger('firstScan')) and plays 5 s after that click (delayMs) — the sweep is well underway by then; the busy() contract holds it until the scene is free. once per run.",
"id": "oac-upgrade",
"from": "oac",
"type": "ack",
"trigger": "firstScan",
"text": "Good. Now you will see several indicators around your ship that point in the direction of where other objects are within your tether region. Hmm... I don't see any planets or space stations. We're going to need to upgrade our tether. Click Acknowledge, then click research below, and research a Tether Level 2 upgrade.",
"audio": "assets/speech/oac/intro-04.mp3",
"once": true,
"delayMs": 5000
},
{
"$comment": "The Tether Level 2 reaction (trigger 'tetherResearch' — GameScene.beginResearch, the moment the player commits to the tether_l2 node). Queued before oac-fly-mine: each ack holds until its own ACKNOWLEDGE press, so the pair plays back-to-back. The busy() contract holds it until the research console closes (comms never play over a full-screen window).",
"id": "oac-minerals",
"from": "oac",
"type": "ack",
"trigger": "tetherResearch",
"text": "Excellent, that's going to help a lot. We will upgrade the tether on your home planet itself, but we're going to need to mine 200 minerals to afford to do so.",
"audio": "assets/speech/oac/intro-05.mp3",
"once": true
},
{
"$comment": "Chained right after oac-minerals (same trigger, config order): the fly-to / continuous-fly instructions and the go signal to hunt asteroids.",
"id": "oac-fly-mine",
"from": "oac",
"type": "ack",
"trigger": "tetherResearch",
"text": "Let's press scan again to find those nearby objects. Then click in the direction of one of the gray indicators and you'll fly your ship to wherever you click. If you want to continuously fly in a direction, hold shift when you click. Now lets go find some asteroids to mine!",
"audio": "assets/speech/oac/intro-06.mp3",
"once": true
},
{
"$comment": "The first rock field (trigger 'firstCluster' — GameScene.celebrateDiscovery, the run's first asteroid-cluster discovery; the scene flag fires the event once, the comm's once-ledger dedupes across saves). delayMs beats the discovery chime (1.5 s, sfx.discovery) so it lands before OAC speaks.",
"id": "oac-first-cluster",
"from": "oac",
"type": "ack",
"trigger": "firstCluster",
"text": "Good work. You found your first asteroid cluster. Let's mine these until we reach 200 minerals. Just click on whichever asteroid you want to mine and your mining laser will do the rest. Keep mining until you reach 200 minerals or more.",
"audio": "assets/speech/oac/intro-07.mp3",
"once": true,
"delayMs": 1500
},
{
"$comment": "Every research completion (trigger 'researchComplete' — GameScene._completeResearch, the moment any project's clock runs out). AUDIO ONLY: no box, no pause — OAC's short sign-off rides under the action (the voice ducks whatever else is playing, per the audio section). once:false — it re-arms on EVERY completion (the FIFO serializes them). The busy() contract is TYPE-AWARE: the sign-off rides OVER in-progress actions (mining live, the scan sweep out — voice with no box and no pause), but still holds while a MODAL owns the screen (the research console, any window/panel, a jump in flight). delayMs beats the completion chime (1.5 s, sfx.discovery) so it lands before the voice.",
"id": "oac-research-complete",
"from": "oac",
"type": "audio",
"trigger": "researchComplete",
"audio": "assets/speech/oac/research-complete.mp3",
"once": false,
"delayMs": 1500
},
{
"$comment": "The 200-mineral threshold (trigger 'minerals200' — GameScene's ore event when the run's lifetime mining first crosses 200 — the 'Mine 200 Minerals' quest line and the tether-l2 build cost, data/builds.json). OAC confirms the build can be afforded and sends the player home to build it. The 1.5 s beat lets the HUD/quest beat land before the voice.",
"id": "oac-tether2",
"from": "oac",
"type": "ack",
"trigger": "minerals200",
"text": "Looks like we have enough minerals to afford that level 2 tether. To build it return to your home planet. You can auto pilot to it by clicking it's name in that little green box. When you land click the build menu and build the level 2 tether. Then launch back into space and we'll see if we can find another planet or space station.",
"audio": "assets/speech/oac/intro-08.mp3",
"once": true,
"delayMs": 1500
},
{
"$comment": "The launch-back beat (trigger 'tetherL2Launch' — SurfaceScene.finishTakeoff, the take-off that puts the player back in space; armed only when the run's build record shows the home world holding a level-2 tether — BuildState.isBuilt, which outlives the surface stay and saves with the run). OAC clears the player to scan again: planets green, stations purple.",
"id": "oac-relaunch",
"from": "oac",
"type": "ack",
"trigger": "tetherL2Launch",
"text": "OK we should be all set. Click Scan again and let's see what we can find. Planets show up as green and space stations show up as purple on our indicator.",
"audio": "assets/speech/oac/intro-09.mp3",
"once": true,
"delayMs": 1500
},
{
"$comment": "Chained right after oac-relaunch is acknowledged (same trigger, config order, delayMs 0 — the FIFO starts it the moment the previous is ACKed). OAC's send-off: the jump-gate primer, then good luck.",
"id": "oac-explore",
"from": "oac",
"type": "ack",
"trigger": "tetherL2Launch",
"text": "This should be everything you need to get around and explore. Once you discover all the objects in a solar system, you can research that systems jump gates and then use them to jump into other solar systems. I'll let you do some exploring for a while on your own now... Good luck.",
"audio": "assets/speech/oac/intro-10.mp3",
"once": true,
"delayMs": 0
},
{
"$comment": "Trestle's introduction (trigger 'firstWorld' — GameScene.celebrateDiscovery, the FIRST world the player discovers: the starter quest's own witness, discoveredWorldCount, the 'Discover another planet or space station' check — any planet or space station, the home world never counts, in any system, so the comm and the quest can never drift; the scene flag fires the event once per scene life, the comm's once-ledger dedupes across saves, and a scene-create arm covers loaded saves that already hold discovered worlds). delayMs 0 — it fires AT the moment of discovery: discovery happens 540 px out of the world's edge (data/game.json → discovery.distance), so the ack hold is up long before the player could be in a landing (landing is the comms-panel button — a two-step action), and the box's input gate blocks any landing click for the rest of the hold.",
"id": "trestle-meetup",
"from": "trestle",
"type": "ack",
"trigger": "firstWorld",
"text": "Hey Kid. Not bad.. not bad at all.. You're getting the hang of this quicker than I thought. Listen, I'm just out of system, but I think it's time we meet up. Finish exploring this system so you can unlock the jump gates. I'll ping you once you're ready.",
"audio": "assets/speech/trestle/intro-01.mp3",
"once": true,
"delayMs": 0
},
{
"$comment": "Chained right after trestle-meetup is acknowledged (same trigger, config order, delayMs 0 — the FIFO starts it the moment the previous is ACKed). Trestle points at the completed starter quest (data/quests.json → start_your_journey, the 200-mineral reward) and how to claim it.",
"id": "trestle-quest",
"from": "trestle",
"type": "ack",
"trigger": "firstWorld",
"text": "Oh and by the way, you just completed your first quest. If you click on the quest in the upper left, or click the quests button below, you can complete the quest and claim 200 minerals I set aside just for you. See you soon kid!",
"audio": "assets/speech/trestle/intro-02.mp3",
"once": true,
"delayMs": 0
}
],
"reservedTriggers": [
"researchNew",
"questNew",
"questComplete",
"discovery",
"landing",
"jump",
"buildComplete"
],
"box": {
"$comment": "The wide comm box, docked just below the mineral bar (its right edge sticks to the bar's right edge; topPad px of padding below the bar). Left: the sender's clip in a bracketed feed panel (muted, contain-fit). Right: the comm text decoding in, and — for 'ack' only — the ACKNOWLEDGE button below it. The height grows to the content; long comms just get taller.",
"width": 560,
"topPad": 12,
"pad": 14,
"headerGap": 8,
"videoSize": 150,
"videoGap": 14,
"text": {
"fontSize": 13,
"lineHeight": 18,
"letterSpacing": 0.4
},
"button": {
"label": "ACKNOWLEDGE",
"gap": 10,
"fontSize": 11,
"paddingX": 16,
"paddingY": 7,
"letterSpacing": 2
},
"pulse": {
"$comment": "The ACKNOWLEDGE button's attention pulse (ack comms only): the button wears the box's amber, an amber halo breathes under it, and two staggered sonar rings expand out — the primary action is unmistakable while the comm holds (the bottom deck is on standby until then).",
"enabled": true,
"color": "#ffd84d",
"periodMs": 1300
},
"animation": {
"inMs": 260,
"outMs": 420,
"visualHoldMs": 350,
"$comment": "visualHoldMs = the beat the box holds after the voice ends (visual comms) before it fades."
},
"colors": {
"panel": "#0a1120",
"panelAlpha": 0.94,
"border": "#22405f",
"borderAlpha": 0.9,
"notch": 10,
"neon": "#00e5ff",
"ink": "#eaf6ff",
"dim": "#7d92c4",
"faint": "#3d4c74",
"amber": "#ffc94d"
}
}
}