314 lines
23 KiB
JSON
314 lines
23 KiB
JSON
{
|
||
"_comment": "SIDE QUESTS — the contracts posted on the JOB BOARD (the Explore drawer's Job Board slot — every system EXCEPT the home system, data/actionbar.json → surface.explore.items). The board is a VIEW over js/quests/SideQuests.js: `sideQuestPostingsFor(seed, record)` derives 3–4 deterministic postings from the galaxy seed + the system record (same seed + system ⇒ same contracts, across visits, scene restarts, and saves), and the run's accepted/completed set rides the saves as the SideQuestState ledger (registry 'sidequests', record.sidequests). CATEGORIES — the four job types (→ categories): patrol / delivery / bounty / escort. Every category is ACCOUNTED FOR (its slot machinery, its description pool below, its reward band, the window's row + contract readout, the ledger, the accept seam) behind its OWN `enabled` gate. PATROL is the first live type (enabled:true — its rules: → patrol below, js/quests/SideQuests.js → buildPatrolRoute + patrolTargetSystem, the scene's updatePatrol); the other three stay OFFLINE until their objective/completion rule sets land. The gate is the contract: a category's jobs appear on the board ONLY when its rules land and its flag flips (flip enabled:true in this file — the board's standby plate lifts and its postings stand). FLAVOR — the variant pools split by SYSTEM CONTEXT (→ descriptions): NEUTRAL systems post about keeping their system safe from PIRATES; a FACTION's systems post about pushing the OTHER factions out of their space (the pools carry {faction}/{issuer}/{enemies} placeholders — {enemies} resolves to the other two factions' labels; {issuer} to the faction's board name below; {system} to the system's name — resolved at generation, js/quests/SideQuests.js → resolveSideQuestText). Each pool holds 3+ variants so different systems read different contracts.",
|
||
"enabled": true,
|
||
"board": {
|
||
"_comment": "perSystem = the postings-per-system roll [min,max] (seeded per system — Rng.derive(seed, seedLabel, <sysId>); the roll itself is stable for the run). seedLabel = the Rng fork label under the galaxy seed (the worldgen determinism contract: a labelled fork, independent of call order).",
|
||
"perSystem": [
|
||
3,
|
||
4
|
||
],
|
||
"seedLabel": "sidequests"
|
||
},
|
||
"categories": {
|
||
"_comment": "The four job types. ORDER = the canonical slot order (patrol, delivery, bounty, escort). `enabled` is the per-type availability gate — OFFLINE until that type's objective + completion logic is built (patrol is live — its rules under → patrol; the other three are stubs); flip a category to true and its jobs stand on the board with their pool + reward band already wired. `accent` = the row's category chip + the contract title (data colors, js/quests/SideQuests.js reads them through).",
|
||
"patrol": {
|
||
"enabled": true,
|
||
"label": "PATROL",
|
||
"accent": "#00e5ff"
|
||
},
|
||
"delivery": {
|
||
"enabled": false,
|
||
"label": "DELIVERY",
|
||
"accent": "#ffc94d"
|
||
},
|
||
"bounty": {
|
||
"enabled": false,
|
||
"label": "BOUNTY",
|
||
"accent": "#ff2d6f"
|
||
},
|
||
"escort": {
|
||
"enabled": false,
|
||
"label": "ESCORT",
|
||
"accent": "#7ce8a4"
|
||
}
|
||
},
|
||
"rewards": {
|
||
"_comment": "The per-category CREDITS band [min,max] at the home rim — the base payout; it scales OUT with the system's home→far diagonal d (record.d) as (1 + d * distanceScale) — the economy's 'a hop is a hop, and danger pays' rule (the far systems' boards pay more for the same risk). The band is rolled seeded per posting (round to 5 CR, floor 5 CR). Tune per category as the types' rules land; a category with no band here falls back to [40,80] in code.",
|
||
"distanceScale": 0.75,
|
||
"patrol": [
|
||
40,
|
||
70
|
||
],
|
||
"delivery": [
|
||
50,
|
||
90
|
||
],
|
||
"bounty": [
|
||
80,
|
||
140
|
||
],
|
||
"escort": [
|
||
70,
|
||
110
|
||
]
|
||
},
|
||
"factions": {
|
||
"_comment": "The faction boards' ISSUER names (the {issuer} placeholder in the faction pools — data/factions.json's faction ids: apex / mindweave / zenith).",
|
||
"apex": "Apex War Ministry",
|
||
"mindweave": "MindWeave Chorus",
|
||
"zenith": "Zenith Concord"
|
||
},
|
||
"patrol": {
|
||
"_comment": "The PATROL category's rules (the first live type — js/quests/SideQuests.js → buildPatrolRoute + patrolTargetSystem; the scene's updatePatrol/check-ins read visitRadius). ACCEPT builds the patrol's ROUTE in the posting's target system: waypoints [min,max] of plain coordinates, inside the system's UNLOCKED tether regions (the live tether field's union, the player's range there) when the target is the system the player stands in, and inside ONE tether region (a level-1 radius, tether.level1Radius) of any of the target's planets / space stations / jump gates when it is a system the player hasn't unlocked yet (a NEIGHBOR — below). Placement keeps the points ISOLATED: anchorClearance px clear of every anchor (planet/station/gate center) and minSeparation px apart, retrying seeded, relaxing the clearance and separation (never the region) if the field is tight. visitRadius = the ship is this far from a waypoint when it counts as REACHED (checked off, in any order). neighborMinD = the '40% mark diagonally from home' (the system record's d — the home→far diagonal, 0 at the home corner): in a FACTION system at d ≥ neighborMinD, a patrol may instead be assigned to a NEIGHBORING system (a jump-gate link) controlled by ANOTHER faction — the push-them-out voice made a route; neighborChance is the per-posting seeded odds of the neighbor draw (the posting's target stands stable for the run). compass + marker = the in-game face of the active patrol: the yellow next-waypoint arrow on the off-screen compass (js/ui/DiscoveryCompass's color override — the route gate's orange precedent) and the in-world waypoint beacons (unvisited = pulsing, visited = the dimmed done mark).",
|
||
"waypoints": [
|
||
3,
|
||
5
|
||
],
|
||
"visitRadius": 420,
|
||
"anchorClearance": 1100,
|
||
"minSeparation": 1500,
|
||
"regionInset": 96,
|
||
"neighborMinD": 0.4,
|
||
"neighborChance": 0.5,
|
||
"encounters": {
|
||
"_comment": "The patrol's ENEMY ENCOUNTERS — the contract's hostile CONTACTS standing on route waypoints (the data contract: data/sidequests.json → patrol.encounters; the logic: js/quests/SideQuests.js → derivePatrolEncounters + patrolEncounterScript; the firing: the scene's updatePatrol → _firePatrolContact — the wave starts when the ship checks in at a CONTACT's waypoint, and the cleared mark lands on the wave run's COMPLETION — the witness is the completion, not the attempt: a mid-fight quit re-arms the contact on return, the combatDone precedent — and the route's completion, with the reward's door, waits for every contact). COUNTS — the odds of how many CONTACTS a patrol carries (1 contact on 20% of patrols, 2 on 20%, 3 on 60%): [count, odds] pairs, drawn SEED-STABLE at the accept from the labelled fork (seed, 'sidequests', <targetSystemId>, 'patrol', <jobId>, 'encounters') and fixed on the route record — a signed contract is a signed contract: a later re-tune of the odds can't re-roll a standing contract's combat. WAVE — each contact's fight: ONE rolling wave of the band's roster (equal weights — a single-type band is a pure type + total), the data's shape — six hostiles, three at a time, each kill replaced — the combat.waves rolling mechanic (js/combat/Waves.js); the script is built by patrolEncounterScript (no named entry in data/combat.json — the roster comes from the band below). BANDS — the difficulty's first axis (the player's COMBAT level × the target system's HOPS from home — the jump network's tree depth, galaxy.jumpNetwork.depth — the 'systems 1–2 hops out' rule): the FIRST band in list order whose levels AND hops windows both contain the player stands, and its enemyTypes are the hostiles its contacts fly (validated against combat.enemyTypes — js/combat/EnemyTypes.js — an unknown id never ships). No band stands, or a roster empties, → fallbackEnemyTypes. TODAY the low band — levels 1–5 at 1–2 hops from home — flies the ESTABLISHED type only (raider — the base craft's named id, the 'Pirate Problems' wave's own type); the farther/higher bands — with the enemy types they introduce — append to this list when those types land, and the other difficulty axes (the distance's own scaling, the level's bonus) wire onto this same seam. POSITIONING — the contacts stand on route waypoints SPREAD evenly across the route (patrolEncounterPositions): for ≥ 2 contacts, the most evenly spread subset of the route's waypoints (scored by its MINIMUM pairwise separation — maximin — then its total: on a near-linear route that's the ends and the middle; a 3–5-point route's contacts never cluster); a single contact stands on the waypoint nearest the route's centroid (the patrol's middle). Deterministic — a pure function of the seed, the contract, and the route's geometry.",
|
||
"enabled": true,
|
||
"counts": [
|
||
[1, 0.2],
|
||
[2, 0.2],
|
||
[3, 0.6]
|
||
],
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 6,
|
||
"maxConcurrent": 3,
|
||
"replacePerKill": 1
|
||
},
|
||
"bands": [
|
||
{
|
||
"levels": [
|
||
1,
|
||
5
|
||
],
|
||
"hops": [
|
||
1,
|
||
2
|
||
],
|
||
"enemyTypes": [
|
||
"raider"
|
||
]
|
||
}
|
||
],
|
||
"fallbackEnemyTypes": [
|
||
"raider"
|
||
]
|
||
},
|
||
"compass": {
|
||
"color": "#ffd60a",
|
||
"typeLabel": "Patrol"
|
||
},
|
||
"marker": {
|
||
"color": "#ffd60a",
|
||
"doneColor": "#67e863",
|
||
"contactColor": "#ff5c77"
|
||
}
|
||
},
|
||
"descriptions": {
|
||
"_comment": "The variant pools: context (neutral | faction) × category. The generator picks ONE variant per posting, seeded on (galaxy seed, system id, category, slot) — a system's contract is STABLE (the board doesn't reshuffle between visits or saves), and different systems draw different ones (3+ variants per pool keeps the galaxy's boards from reading as one repeated ad). Placeholders (resolved at generation, never stored): {system} = the system's name; in the faction pools {faction} = the system's faction label (data/factions.json), {issuer} = that faction's board name (→ factions above), {enemies} = the OTHER two factions ('MindWeave and Zenith'). The NEUTRAL pools are the pirate-safety voice; the FACTION pools are the push-the-other-factions-out voice.",
|
||
"neutral": {
|
||
"patrol": [
|
||
{
|
||
"title": "Lane Watch",
|
||
"issuer": "The Harbormaster",
|
||
"body": "Three raiders keep running the outer gate at night, and the toll keepers are done pretending they aren't there. Work the lane, keep your lights up, and make the run a bad idea. We don't want their bodies, we want them gone — the board pays for the silence, and the board pays on time."
|
||
},
|
||
{
|
||
"title": "Quiet the Field",
|
||
"issuer": "The Warden Guild",
|
||
"body": "The {system} belt is a graveyard with a population. Something in the debris has been firing at passing hulls, and the Guild is paying for a field where the wrecks are the only thing that shoots. Work the rocks until they're quiet — and mind your hull out here, the field is as honest as the rest of this system."
|
||
},
|
||
{
|
||
"title": "The Lighthouse Run",
|
||
"issuer": "The Station Keeper",
|
||
"body": "The buoy out past the ice line keeps going dark, and it isn't breaking — someone is cutting its fuel line. Find out who and convince them to stop, in whatever order you like. That light runs every safe lane in the system, and the pirates out here only like it for one reason: it's on. Keep it on."
|
||
}
|
||
],
|
||
"delivery": [
|
||
{
|
||
"title": "Dead Freight",
|
||
"issuer": "The Tally",
|
||
"body": "A sealed crate for the keeper at the edge of the system. It isn't marked, and that isn't an accident. The raiders who want it are already circling the lane, and they're better funded than they look. Get it there before they get to you — or get it there through them. The Tally pays either way the crate arrives."
|
||
},
|
||
{
|
||
"title": "The Long Way Home",
|
||
"issuer": "The Harbormaster",
|
||
"body": "Supply drops for the outer watch posts. The direct lane has been a pirate kill-box for a week, so you take the long way, fly slow, and keep your engines quiet. Nobody asks what's in the crates, and nobody asks what the watch posts are for either. That's the whole job — the cargo moves, the posts stay lit."
|
||
},
|
||
{
|
||
"title": "Fuel for the Wards",
|
||
"issuer": "The Warden Guild",
|
||
"body": "Two drums of fuel for the sentinel posts, and the posts need them before the moon turns. A raider skiff was seen nosing around the fuel depot an hour ago — assume it was a scout and move the fuel like it was. The Guild's accounts are open and the Guild's patience isn't. Get the drums there and the wardens keep the lanes honest."
|
||
}
|
||
],
|
||
"bounty": [
|
||
{
|
||
"title": "Salt the Raiders",
|
||
"issuer": "The Tally",
|
||
"body": "A crew has been taking ships in this system for a month, and the bounties on their heads have grown into a small library. Bring us the leader's hull, its drive, and one of their names — in that order, or in whatever order you can manage. The Tally doesn't ask how you finish a pirate. The Tally asks that it be finished."
|
||
},
|
||
{
|
||
"title": "One Name on the List",
|
||
"issuer": "The Warden Guild",
|
||
"body": "The Guild is paying for a single name on the wanted board, and no questions about the rest of the crew. The mark flies a stolen hull with a blue stripe on the bow and a habit for boarding from the dark side. You'll know it when you see it. Bring the mark down and the name comes off the list — the rest stays yours."
|
||
},
|
||
{
|
||
"title": "The Last Skiff",
|
||
"issuer": "The Harbormaster",
|
||
"body": "Every raider in the system has been driven out but one. A little black skiff, half the speed of its owners' nerve, and a cargo hold the harbor can't get a read on. Bring it in whole if you can — the wardens want to see what it's carrying — and if it breaks before it bows, bring the pieces. Either way the board is closed when it's done."
|
||
}
|
||
],
|
||
"escort": [
|
||
{
|
||
"title": "See Her Home",
|
||
"issuer": "The Station Keeper",
|
||
"body": "A refugger out of the outer belt is asking for a pilot who can outrun pirates, and the lane is theirs right now. She's carrying people, not cargo, and the keeper is paying in gratitude first and credits after. Fly her through to the gate, keep her hull in one piece, and stay on her wing long enough that she forgets to be afraid. That's the job."
|
||
},
|
||
{
|
||
"title": "Convoy Night",
|
||
"issuer": "The Tally",
|
||
"body": "Three lighters move out of the debris line tonight, and every pirate in the system knows it — they've heard it the way you hear a storm. Fly the point, hold the line, and put them through the far gate. The Tally pays for hulls that arrive, and the Tally counts them at the gate. Count them yourself too."
|
||
},
|
||
{
|
||
"title": "The Long Dark",
|
||
"issuer": "The Warden Guild",
|
||
"body": "A courier ship has a sealed manifest and a hard deadline, and the lane she has to cross is pirate country. Escort her to the system edge and stay on her wing until the gate swallows her. Whatever she's carrying, it's worth more than your ship — that's probably why the Guild wants you, not their own pilots."
|
||
}
|
||
]
|
||
},
|
||
"faction": {
|
||
"patrol": [
|
||
{
|
||
"title": "Sweep the Lanes",
|
||
"body": "A foreign surveyor has been working the outer gate for a week, and it doesn't belong here. {enemies} think this system is a neutral route — it isn't. Sweep the lane until there's nothing left on it but our own flag. Report the wrecks to the {issuer} and leave the survivors to them. That's the whole job."
|
||
},
|
||
{
|
||
"title": "No Foreign Lights",
|
||
"body": "We've logged foreign transponders on the approach lanes since the last moon. {enemies} are running their people through our space like it's a corridor they paid for. It isn't, and it won't stay that way. Show them the difference, one hull at a time, until the lanes run clean under {faction} lights again."
|
||
},
|
||
{
|
||
"title": "The Gate Watch",
|
||
"body": "The gate is the only honest road in this system, and foreign traffic keeps trying to use it. Keep the approach lanes free of {enemies} flags — the {issuer} is paying for the lesson, and it would rather never have to teach it. If you meet them out there, remember which side of the line you're on."
|
||
}
|
||
],
|
||
"delivery": [
|
||
{
|
||
"title": "Flagged Cargo",
|
||
"body": "Parts for the gate works, under full {faction} flag. {enemies} runners will smell it and come for it, because that's what they do. Fly the direct lane, keep the flag on the hull, and don't let it off your wing. The works don't wait for delays, the {issuer} doesn't wait for excuses, and neither does the flag."
|
||
},
|
||
{
|
||
"title": "The Wrong Kind of Freight",
|
||
"body": "The crate is sealed and the manifest is sealed, and that's the whole job. {enemies} have two scouts in the system and they're bad at this — that's the good news. Deliver the crate to the depot before the scouts find out what it is. After that the crate belongs to them, and the job belongs to you. The {issuer} is paying for the order of operations."
|
||
},
|
||
{
|
||
"title": "Supply Run, War Terms",
|
||
"body": "The outer posts run on our rations and your nerve. {enemies} want the lane to starve them out, and they've said so in the intercepts. Run the lane anyway. Put the posts in the dark they wanted or in the light we pay for — the {issuer} is paying for the light, and only the light."
|
||
}
|
||
],
|
||
"bounty": [
|
||
{
|
||
"title": "A Foreign Flag",
|
||
"body": "There is a {enemies} vessel working the system with its lights off, and it's been here longer than is polite. Bring us its hull. The {issuer} is paying for the wreckage and the silence that follows, and the {issuer} has never once paid twice for the same silence. Bring the flag home in pieces."
|
||
},
|
||
{
|
||
"title": "One Operative",
|
||
"body": "A {enemies} operative has been buying our people and selling their secrets. We have a face, we have a name, and we don't have time. Bring us one or the other and the {issuer} will tell you which. The job ends when the system stops leaking — this is usually the last step, but not always. Be the last step."
|
||
},
|
||
{
|
||
"title": "The Surveyor",
|
||
"body": "They've been charting our lanes. {enemies} surveyors chart what they intend to take, and this system isn't for sale. Bring us the surveyor and its instruments, intact enough to ask questions. The {issuer} is paying extra for intact — the answers are worth more than the hull, and the hull is worth a fair sum."
|
||
}
|
||
],
|
||
"escort": [
|
||
{
|
||
"title": "Convoy Under Flag",
|
||
"body": "A convoy moves through the system under {faction} colors, and {enemies} scouts have been seen in the approach lanes. Fly the point, hold the line, and keep the colors in the lead. The {issuer} pays for the convoy that arrives — not for the story of the one that didn't. The story is for the dead, and we can afford the convoy."
|
||
},
|
||
{
|
||
"title": "The Minister's Courier",
|
||
"body": "The courier carries a seal, not cargo, and the lane is foreign country tonight. {enemies} will know the moment it launches, because they've been watching our docks since the last moon. Stay on the wing, keep the seal aboard, and put the courier through. What's in the case is the difference between a system and a battlefield — deliver it and keep the system a system."
|
||
},
|
||
{
|
||
"title": "Long Haul, Short Fuse",
|
||
"body": "Three lighters, one lane, and {enemies} scouts already circling the fuel line. Escort them to the gate and keep the line intact — no drops, no detours, no negotiations. The {issuer} counts hulls at the gate and pays per hull that arrives. Count them yourself too, and keep the extra for your nerve."
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"ui": {
|
||
"_comment": "The board's contract copy (js/ui/JobBoardWindow.js). standby* = the state where NO category is live (the current one — the board's face until the first type flips on). accept* = the ACCEPT action's button + the scene's toasts (SurfaceScene.acceptSurfaceJob — the claimSurfaceQuest precedent: the ledger + sfx are the GameScene's, the note is the surface's).",
|
||
"standbyMain": "NO CONTRACTS ON FILE",
|
||
"standbySub": "THE BOARD’S POSTINGS LAND HERE",
|
||
"selectMain": "SELECT A JOB",
|
||
"selectSub": "PICK A LISTING TO READ ITS CONTRACT",
|
||
"statusStandby": "BOARD STANDBY — NO CONTRACTS ON FILE",
|
||
"statusLive": "{n} CONTRACTS ON FILE",
|
||
"rewardUnit": "CR",
|
||
"payout": "PAYOUT — {reward} CR",
|
||
"accept": "ACCEPT CONTRACT",
|
||
"accepted": "CONTRACT ACCEPTED",
|
||
"active": "PATROL ACTIVE",
|
||
"activate": "SET PATROL ACTIVE",
|
||
"complete": "CONTRACT COMPLETE",
|
||
"claim": "CLAIM REWARD — {reward} CR",
|
||
"claimed": "REWARD CLAIMED",
|
||
"destination": "DESTINATION — {name}",
|
||
"routeProgress": "ROUTE — {visited}/{total} WAYPOINTS LOGGED",
|
||
"contactProgress": "CONTACTS — {cleared}/{total} CLEARED",
|
||
"patrolContactToast": {
|
||
"glyph": "⚔",
|
||
"color": "#ff5c77",
|
||
"text": "HOSTILE CONTACT — {n} ENEMIES INBOUND"
|
||
},
|
||
"patrolContactClearedToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "CONTACT CLEARED — {i} OF {n}"
|
||
},
|
||
"acceptToast": {
|
||
"glyph": "◆",
|
||
"color": "#ffc94d",
|
||
"text": "CONTRACT ACCEPTED — {title}"
|
||
},
|
||
"acceptDenyToast": {
|
||
"glyph": "✗",
|
||
"color": "#ff5c77",
|
||
"text": "COMMISSION DENIED — CONTRACT NOT ON FILE"
|
||
},
|
||
"activateToast": {
|
||
"glyph": "▸",
|
||
"color": "#ffd60a",
|
||
"text": "PATROL ACTIVE — {title}"
|
||
},
|
||
"claimToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "REWARD CLAIMED — +{reward} CR"
|
||
},
|
||
"claimDenyToast": {
|
||
"glyph": "✗",
|
||
"color": "#ff5c77",
|
||
"text": "NOTHING TO CLAIM — ROUTE NOT COMPLETE"
|
||
},
|
||
"patrolWaypointToast": {
|
||
"glyph": "◈",
|
||
"color": "#ffd60a",
|
||
"text": "WAYPOINT {i} OF {n} LOGGED"
|
||
},
|
||
"patrolCompleteToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "PATROL ROUTE COMPLETE — ITS REWARD IS READY TO CLAIM"
|
||
}
|
||
}
|
||
}
|