1113 lines
72 KiB
JSON
1113 lines
72 KiB
JSON
{
|
||
"_comment": "SIDE QUESTS — the contracts posted on the JOB BOARD (the Explore drawer's Job Board slot — every SURFACE WORLD EXCEPT in the home system, data/actionbar.json → surface.explore.items). The board is a VIEW over js/quests/SideQuests.js: `sideQuestPostingsFor(seed, record, worldKey)` derives 1–3 deterministic postings from the galaxy seed + the system record + the WORLD (a planet's p<ordinal> / a station's s<n> — two worlds in one system stand two DIFFERENT boards; the same world posts the 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). Note: the board went PER-WORLD (from per-system) — old per-system ids (sq-<sys>-<cat>-<slot>) no longer stand a board, and in-flight contracts in old saves drop on load (a documented Path A trade). 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 boards read different contracts.",
|
||
"enabled": true,
|
||
"board": {
|
||
"_comment": "perWorld = the postings-per-surface-world roll [min,max] (seeded per world — Rng.derive(seed, seedLabel, <sysId>, <world>); 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).",
|
||
"perWorld": [
|
||
1,
|
||
3
|
||
],
|
||
"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 and BOUNTY HUNT are live — their rules under → patrol / → bounty; delivery and escort 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). A category may carry TWO MORE GATES beyond `enabled`: `minLevel` (the combat level the board demands — under it the posting still stands, but as a greyed LOCKED row whose accept is refused) and `contexts` (the boards that post it at all — ['neutral'] keeps a pirate-voice contract off the faction boards entirely; an omitted list means every context posts it).",
|
||
"patrol": {
|
||
"enabled": true,
|
||
"label": "PATROL",
|
||
"accent": "#00e5ff"
|
||
},
|
||
"delivery": {
|
||
"enabled": false,
|
||
"label": "DELIVERY",
|
||
"accent": "#ffc94d"
|
||
},
|
||
"bounty": {
|
||
"enabled": true,
|
||
"label": "BOUNTY HUNT",
|
||
"accent": "#ff2d6f",
|
||
"minLevel": 2,
|
||
"contexts": [
|
||
"neutral",
|
||
"faction"
|
||
]
|
||
},
|
||
"escort": {
|
||
"enabled": true,
|
||
"label": "ESCORT",
|
||
"accent": "#7ce8a4",
|
||
"minLevel": 3,
|
||
"contexts": [
|
||
"neutral",
|
||
"faction"
|
||
]
|
||
}
|
||
},
|
||
"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). The XP payout rides beside the credits: it is NOT a band — it is the contract's combat's WORTH, fixed on the route record at the accept (route.xp — js/quests/SideQuests.js → patrolEncounterXp: the patrol's defeated contacts × the wave's total × the band's roster xp, data/combat.json → enemy.xp / enemyTypes), and the claim (GameScene.claimSideQuest) grants it into the run's XP bank (js/combat/XpManager.js — the 'sidequest' source, beside the kills' 'kill' grants) in addition to paying the credits. A category without a route pays credits-only (its XP payout is 0 — the old saves' shape). 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": [
|
||
120,
|
||
175
|
||
]
|
||
},
|
||
"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 — js/quests/SideQuests.js → buildPatrolRoute + patrolTargetSystem; the scene's updatePatrol/check-ins read visitRadius. WAR MODEL: the patrol is ALWAYS the posting's OWN system (patrolTargetSystem stands home — the old neighbor rule is gone): the board's own space, cleaned of the sighted rival's fighters. The sighted enemy is ONE seeded opposing faction (the posting's enemyFaction — js/quests/SideQuests.js's seededOpposingFaction), and the encounter roster draws from THAT faction's combat.factions roster (patrolEnemyRoster's first rule; the bands below stand for neutral boards only). ACCEPT builds the route in the posting's 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). 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 ORDER — the route is a PATH flown 1, 2, 3, …; only the first unvisited waypoint logs). 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,
|
||
"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. XP REWARD — beside the credits, the claim pays the XP these defeated contacts are WORTH (js/quests/SideQuests.js → patrolEncounterXp: the contacts × the wave's total × the roster's type xp, data/combat.json → enemy.xp / enemyTypes): fixed on the route record at the accept (route.xp, beside route.credits — a signed contract is a signed contract) and granted into the run's XP bank on the claim (XpManager's 'sidequest' source — the kills' 'kill' grants' sibling).",
|
||
"enabled": true,
|
||
"counts": [
|
||
[
|
||
1,
|
||
0.2
|
||
],
|
||
[
|
||
2,
|
||
0.2
|
||
],
|
||
[
|
||
3,
|
||
0.6
|
||
]
|
||
],
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 6,
|
||
"maxConcurrent": 3,
|
||
"replacePerKill": 1
|
||
},
|
||
"bands": [
|
||
{
|
||
"_comment": "TIER 1 (levels 1–5, 1–2 hops) — the established type only. The low patrols never change: raiders, one rolling six, three at a time.",
|
||
"levels": [
|
||
1,
|
||
5
|
||
],
|
||
"hops": [
|
||
1,
|
||
2
|
||
],
|
||
"enemyTypes": [
|
||
"raider"
|
||
]
|
||
},
|
||
{
|
||
"_comment": "TIER 2 — THE LEVEL-6 JUMP: the wave grows 6→10 with four at a time, and the pack turns into a mix — raiders stay the anchor, spitters (spray) and bombers (lances) land. hops 1–99: past level 5 the LEVEL is the axis (any system the board can post).",
|
||
"levels": [
|
||
6,
|
||
8
|
||
],
|
||
"hops": [
|
||
1,
|
||
99
|
||
],
|
||
"roster": {
|
||
"raider": 5,
|
||
"spitter": 3,
|
||
"bomber": 2
|
||
},
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 10,
|
||
"maxConcurrent": 4,
|
||
"replacePerKill": 1
|
||
},
|
||
"xpScale": 0.7
|
||
},
|
||
{
|
||
"_comment": "TIER 3 (9–12) — the wave grows to 14 at five; stingers (bursts) and gunners (rapid fire) join the mix.",
|
||
"levels": [
|
||
9,
|
||
12
|
||
],
|
||
"hops": [
|
||
1,
|
||
99
|
||
],
|
||
"roster": {
|
||
"raider": 4,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2,
|
||
"bomber": 1
|
||
},
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 14,
|
||
"maxConcurrent": 5,
|
||
"replacePerKill": 1
|
||
},
|
||
"xpScale": 0.55
|
||
},
|
||
{
|
||
"_comment": "TIER 4 (13–18) — 18 at six; hunters (missiles) join. The contact-count odds skew toward three (every waypoint carrying a contact).",
|
||
"levels": [
|
||
13,
|
||
18
|
||
],
|
||
"hops": [
|
||
1,
|
||
99
|
||
],
|
||
"roster": {
|
||
"raider": 3,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2,
|
||
"hunter": 2,
|
||
"bomber": 1
|
||
},
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 18,
|
||
"maxConcurrent": 6,
|
||
"replacePerKill": 1
|
||
},
|
||
"counts": [
|
||
[
|
||
1,
|
||
0.1
|
||
],
|
||
[
|
||
2,
|
||
0.3
|
||
],
|
||
[
|
||
3,
|
||
0.6
|
||
]
|
||
],
|
||
"xpScale": 0.5
|
||
},
|
||
{
|
||
"_comment": "TIER 5 (19+, the cap) — 20 at six, the seats' ceiling; barrages (ring bursts) round out the mix. Past here the count holds and the mix's weight is the pressure.",
|
||
"levels": [
|
||
19,
|
||
99
|
||
],
|
||
"hops": [
|
||
1,
|
||
99
|
||
],
|
||
"roster": {
|
||
"raider": 3,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2,
|
||
"hunter": 2,
|
||
"barrage": 2
|
||
},
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 20,
|
||
"maxConcurrent": 6,
|
||
"replacePerKill": 1
|
||
},
|
||
"counts": [
|
||
[
|
||
1,
|
||
0.1
|
||
],
|
||
[
|
||
2,
|
||
0.3
|
||
],
|
||
[
|
||
3,
|
||
0.6
|
||
]
|
||
],
|
||
"xpScale": 0.45
|
||
}
|
||
],
|
||
"fallbackEnemyTypes": [
|
||
"raider"
|
||
]
|
||
},
|
||
"compass": {
|
||
"color": "#ffd60a",
|
||
"typeLabel": "Patrol"
|
||
},
|
||
"marker": {
|
||
"color": "#ffd60a",
|
||
"doneColor": "#67e863",
|
||
"contactColor": "#ff5c77"
|
||
}
|
||
},
|
||
"bounty": {
|
||
"_comment": "The BOUNTY HUNT category's rules (the second live type — the model: js/quests/SideQuests.js → deriveBountyPlan / bountyEngagements / bountyHuntXp / bountyRouteComplete / nextBountyWaypoint; the scene: GameScene._establishBountyHunt + updateBountyHunt). A hunt is a PATROL WITH A NAME ON IT: three waypoints along one pirate leader's recent travel lanes, flown IN ORDER (a patrol's waypoints too — the shared sequential law — and the chain's odds read a first, second and third leg), with the ending hidden from the player: the mark stands on ONE of the legs and the fight around them IS the contract. minLevel = the combat level the board demands before the contract can be taken (js/combat/XpManager.js's level; under it the row is LOCKED and GameScene.acceptSideQuest refuses it). contexts = the boards that post it — ['neutral','faction']: the neutral boards post the 20 pirate dossiers below (unchanged), and the FACTION boards post the WAR MODEL hunt (→ descriptions.faction.bounty) — the mark is a member of the TARGET system's own faction (one of the board's two rivals), the target system is a NEIGHBOR that faction controls (a jump-gate link — js/quests/SideQuests.js's hostileNeighborSystem), and the posting is LOCKED until the player's jump-gate capability is unlocked INTO that system (gates.jump.factionLock.minLevel — the posting's gateLevel, beside minLevel). The mark's frame + its pickets draw from the mark's OWN faction roster (deriveBountyPlan's opts.faction rule — the neutral pirate frames stand for neutral boards). waypoints = the leg count [min,max]: the design is exactly three, and the chain's guarantee reads the LENGTH (the LAST leg always holds the mark), so raising the max lengthens the hunt without touching code. Route placement reuses patrol's anchorClearance / minSeparation / regionInset unless this block overrides them; visitRadius = how close the ship must come for a leg to LOG.",
|
||
"minLevel": 2,
|
||
"contexts": [
|
||
"neutral"
|
||
],
|
||
"waypoints": [
|
||
3,
|
||
3
|
||
],
|
||
"visitRadius": 420,
|
||
"encounters": {
|
||
"_comment": "The hunt's CHAIN — rolled ONCE at the accept on the labelled fork (seed,'sidequests',<targetSystemId>,'bounty',<jobId>,'chain') and FIXED on the route record: a signed contract is a signed contract, so re-tuning these odds never re-rolls a standing hunt (and the plan is invisible until it fires — no UI, marker, compass entry or toast names the leg that holds anything). LEGS — every leg but the last rolls bountyChance for the mark; the LAST leg stands it at 100%. With bountyChance 0.2 and three legs that reads 20% on leg 1, 20% of what missed on leg 2 (16% overall), everything left on leg 3 (64%). A leg that does NOT hold the mark rolls skirmishChance for a pirate wave of its own — the leader's pickets working their own lane; the bounty leg never rolls pickets (the mark IS the fight), and once the mark is down no later leg owes anything. SKIRMISH — one rolling wave of the frame-0 established type, three at a time, each kill replaced: the patrol contact's shape with no elite in it. BOUNTY — one rolling wave of `total` NINE, three at a time: `raiders` frame-0 fighters plus ONE elite, the mark itself, flying the craft its own dossier names (→ descriptions.neutral.bounty[].craft, an id from data/combat.json → enemyTypes), buffed by healthScale × hull+shields and damageScale × its weapon's damage, deployed WITH the opening group (never buried at the back of the queue) and tagged `elite` so a kill that MATTERED is recognizable. An elite id that isn't in combat.enemyTypes (a data typo) falls back to a seeded pick from eliteFrames. TERMINATION — killing the mark halts every further deployment and replacement of that fight (js/combat/CombatSystem.js → haltWaves: the survivors already on the field stay hostile and must be put down); when the last of them drops the hunt is COMPLETE, every leg checks off at once, no further wave fires, and the reward stands ready to claim.",
|
||
"enabled": true,
|
||
"bountyChance": 0.2,
|
||
"skirmishChance": 0.5,
|
||
"skirmishWave": {
|
||
"kind": "rolling",
|
||
"total": 6,
|
||
"maxConcurrent": 3,
|
||
"replacePerKill": 1,
|
||
"roster": [
|
||
"raider"
|
||
]
|
||
},
|
||
"bountyWave": {
|
||
"kind": "rolling",
|
||
"total": 9,
|
||
"raiders": 8,
|
||
"maxConcurrent": 3,
|
||
"replacePerKill": 1,
|
||
"raiderType": "raider",
|
||
"eliteFrames": [
|
||
"bomber",
|
||
"spitter",
|
||
"stinger",
|
||
"hunter",
|
||
"gunner",
|
||
"barrage",
|
||
"warden"
|
||
],
|
||
"elite": {
|
||
"healthScale": 2,
|
||
"damageScale": 2
|
||
}
|
||
},
|
||
"bands": [
|
||
{
|
||
"id": "hunter",
|
||
"levels": [
|
||
2,
|
||
5
|
||
],
|
||
"_comment": "THE LIVE BAND — the level 2–5 bounty hunt this pass tunes: three legs, the chain's odds above, frame-0 pickets and a dossier-named mark at double armor and double damage. No wave overrides here (the band inherits the encounter block above); a band MAY carry its own skirmishWave / bountyWave / bountyChance / skirmishChance to retune a level window without touching the others."
|
||
},
|
||
{
|
||
"id": "marksman",
|
||
"levels": [
|
||
6,
|
||
10
|
||
],
|
||
"_comment": "TIER 2 — THE LEVEL-6 JUMP (the stub's pass, landed): the pickets grow 6→10 with four at a time and turn into a mix (spitters + bombers beside the raiders); the hunt grows 9→13 — a twelve-strong escort in the same three-at-a-time pressure with one more seat, and the mark's armor/damage scale steps 2→3. escortRoster = the hunt's escort MIX (weighted — js/quests/SideQuests.js → bountyEngagementScript draws it; a band without one is the plain raiderType count). xpScale — the tier's subtle XP dial (the fatter wave's worth, trimmed so the payout's pace stays with the curve): the tier's payout ≈ 298 XP (vs the base 372).",
|
||
"skirmishWave": {
|
||
"kind": "rolling",
|
||
"total": 10,
|
||
"maxConcurrent": 4,
|
||
"replacePerKill": 1,
|
||
"roster": {
|
||
"raider": 5,
|
||
"spitter": 3,
|
||
"bomber": 2
|
||
}
|
||
},
|
||
"bountyWave": {
|
||
"kind": "rolling",
|
||
"total": 13,
|
||
"raiders": 12,
|
||
"maxConcurrent": 4,
|
||
"replacePerKill": 1,
|
||
"escortRoster": {
|
||
"raider": 5,
|
||
"spitter": 2,
|
||
"bomber": 2
|
||
},
|
||
"elite": {
|
||
"healthScale": 3,
|
||
"damageScale": 3
|
||
}
|
||
},
|
||
"xpScale": 0.8
|
||
},
|
||
{
|
||
"id": "deadeye",
|
||
"levels": [
|
||
11,
|
||
14
|
||
],
|
||
"_comment": "TIER 3 (11–14) — pickets 14 at five (stingers + gunners join the mix); the hunt 17 — a sixteen-strong escort, the mark at 3.5× armor and damage.",
|
||
"skirmishWave": {
|
||
"kind": "rolling",
|
||
"total": 14,
|
||
"maxConcurrent": 5,
|
||
"replacePerKill": 1,
|
||
"roster": {
|
||
"raider": 4,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2
|
||
}
|
||
},
|
||
"bountyWave": {
|
||
"kind": "rolling",
|
||
"total": 17,
|
||
"raiders": 16,
|
||
"maxConcurrent": 5,
|
||
"replacePerKill": 1,
|
||
"escortRoster": {
|
||
"raider": 4,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2
|
||
},
|
||
"elite": {
|
||
"healthScale": 3.5,
|
||
"damageScale": 3.5
|
||
}
|
||
},
|
||
"xpScale": 0.7
|
||
},
|
||
{
|
||
"id": "apex",
|
||
"levels": [
|
||
15,
|
||
99
|
||
],
|
||
"_comment": "TIER 4 (15+, the cap) — pickets 18 at six (hunters join); the hunt 21 — a twenty-strong escort with barrages in the mix, the mark at 4× armor and damage. Past here the seats hold and the mix's weight + the mark's scales are the pressure.",
|
||
"skirmishWave": {
|
||
"kind": "rolling",
|
||
"total": 18,
|
||
"maxConcurrent": 6,
|
||
"replacePerKill": 1,
|
||
"roster": {
|
||
"raider": 3,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2,
|
||
"hunter": 2
|
||
}
|
||
},
|
||
"bountyWave": {
|
||
"kind": "rolling",
|
||
"total": 21,
|
||
"raiders": 20,
|
||
"maxConcurrent": 6,
|
||
"replacePerKill": 1,
|
||
"escortRoster": {
|
||
"raider": 3,
|
||
"spitter": 2,
|
||
"stinger": 2,
|
||
"gunner": 2,
|
||
"hunter": 2,
|
||
"barrage": 2
|
||
},
|
||
"elite": {
|
||
"healthScale": 4,
|
||
"damageScale": 4
|
||
}
|
||
},
|
||
"xpScale": 0.65
|
||
}
|
||
],
|
||
"fallbackBand": "hunter"
|
||
},
|
||
"compass": {
|
||
"color": "#ff2d6f",
|
||
"typeLabel": "Hunt"
|
||
},
|
||
"marker": {
|
||
"color": "#ff2d6f",
|
||
"doneColor": "#67e863",
|
||
"_comment": "NO contact color, deliberately: a patrol paints its contact waypoints red (→ patrol.marker.contactColor) because those contacts are the job; a hunt's legs must look IDENTICAL until something shoots at you, so only the NEXT leg in sequence lights and nothing marks where the mark is."
|
||
}
|
||
},
|
||
"escort": {
|
||
"_comment": "The ESCORT category's rules (the third live type — the model: js/quests/SideQuests.js → escortDestinationFor / deriveEscortPlan; the ship: js/combat/TransportShip.js + data/combat.json → transport; the scene: GameScene._establishEscort + updateEscort). An escort is a CONVOY JOB: a neutral TRANSPORT (its own ship class — ~2.5x the fighter's size, far heavier armor, a heavy lance) plus 1–2 escort fighters stands at a single RENDEZVOUS waypoint in the posting's own system (waypoints [1,1] — the route builder's shared placement law, the 'escort' fork). The player flies to the waypoint within visitRadius and the convoy LINKS (phase 'rendezvous' → 'transit') — from then on the transport + fighters hold their escort ring around the player through EVERY remaining leg, re-forming across jumps (the route record carries the transport's armor — a signed contract is a signed contract: a jump or a save never re-rolls a standing convoy). The DESTINATION is a planet or a free-space station 1–2 gate hops away (destinationHops [min,max], a seeded walk of the jump network — js/galaxy/JumpTravel.js's gate graph, the same links the player can actually fly), fixed at the accept and never re-rolled; the player flies the legs (1–2 jumps) and arrives at the destination object with the convoy intact. ENCOUNTERS — the lane is HOT: while the convoy is linked, the escort director (its own EncounterDirector instance — a short roll interval every 20–30 s at a middling chance, a long quiet) fires WAVES of mixed fighter types (bands, by the player's combat level — a weighted roster of enemyTypes ids, validated like the patrol's) with LARGER concurrent counts than a normal encounter (wave.total / maxConcurrent) — one at a time, the wave run's completion the quiet's gate, exactly the patrol contact's law. The TRANSPORT is the job: it fights alongside (its own lance, js/combat/TransportShip.js), it is a legal enemy target (the allies roster — pickEnemyTarget's escort aggro), and if it is DESTROYED the contract fails (phase 'failed', the convoy breaks off) — the player must LAND ON A PLANET to reset it (GameScene.startLanding's escort reset — a fresh rendezvous, a fresh transport, the same destination: retry the run). COMPLETION — the destination world (planet/free-space station) is VISIBLE ON SCREEN (circleInView against the camera's world rect — the player has flown it into view, not merely near it) with NO enemy fighter up (the craftVisible roster rule — the bounty field-clear's law): the contract enters its DELIVERY (phase 'delivering') — the convoy BREAKS OFF the wing, flies in beside the world, and FADES OUT (the touchdown: the transport + its fighters land, they are through, not destroyed; a fixed time-driven fly-in then fade, GameScene._runEscortDelivery), and on the fade's close the contract completes, the reward stands ready to claim. compass + marker = the escort's in-game face: the magenta next-stop arrow (the RENDEZVOUS waypoint pre-link, then the DESTINATION gate, then the destination object itself) and the in-world beacons (rendezvous = pulsing until linked, then the destination object's mark).",
|
||
"enabled": true,
|
||
"minLevel": 3,
|
||
"contexts": [
|
||
"neutral"
|
||
],
|
||
"waypoints": [
|
||
1,
|
||
1
|
||
],
|
||
"visitRadius": 460,
|
||
"destinationHops": [
|
||
1,
|
||
2
|
||
],
|
||
"escortCount": [
|
||
1,
|
||
2
|
||
],
|
||
"transportFrame": [
|
||
0,
|
||
3
|
||
],
|
||
"encounters": {
|
||
"_comment": "The escort's LANE COMBAT (the director's numbers + the wave's shape + the roster's bands): rollIntervalMin/Max + chanceMin/Max + cooldownMin/Max are the EscortDirector's own EncounterDirector config (data/combat.json → encounters' shape — seconds), tuned to a HOT lane: a short 20–30 s roll interval × a middling chance, a 15–30 s quiet after each fight — frequent engagements while the convoy is linked (roughly 2–8 per run, scaling with how long the legs take); wave = one rolling wave of `total` mixed fighters, `maxConcurrent` on screen at a time, each kill replaced (replacePerKill) — the patrol contact's rolling shape, bigger; bands = the roster by the player's COMBAT level (levels [lo,hi], roster = a weighted { type: weight } table over combat.enemyTypes ids — the unknown-id rule is the patrol's: a type that isn't in combat.enemyTypes never ships, a roster that empties takes the established type); no band standing → the fallback band's roster.",
|
||
"enabled": true,
|
||
"rollIntervalMin": 20,
|
||
"rollIntervalMax": 30,
|
||
"chanceMin": 0.4,
|
||
"chanceMax": 0.6,
|
||
"cooldownMin": 15,
|
||
"cooldownMax": 30,
|
||
"wave": {
|
||
"kind": "rolling",
|
||
"total": 8,
|
||
"maxConcurrent": 4,
|
||
"replacePerKill": 1
|
||
},
|
||
"bands": [
|
||
{
|
||
"levels": [
|
||
0,
|
||
4
|
||
],
|
||
"roster": {
|
||
"raider": 3,
|
||
"bomber": 1,
|
||
"spitter": 1
|
||
}
|
||
},
|
||
{
|
||
"levels": [
|
||
5,
|
||
99
|
||
],
|
||
"roster": {
|
||
"raider": 2,
|
||
"bomber": 1,
|
||
"spitter": 1,
|
||
"stinger": 1,
|
||
"hunter": 1
|
||
}
|
||
}
|
||
],
|
||
"fallbackRoster": {
|
||
"raider": 3,
|
||
"bomber": 1,
|
||
"spitter": 1
|
||
}
|
||
},
|
||
"compass": {
|
||
"color": "#e87cf5",
|
||
"typeLabel": "Escort"
|
||
},
|
||
"marker": {
|
||
"color": "#7ce8a4",
|
||
"doneColor": "#67e863"
|
||
}
|
||
},
|
||
"descriptions": {
|
||
"_comment": "The variant pools: context (neutral | faction) × category. The generator picks ONE variant per posting, seeded on (galaxy seed, system id, world key, category, slot) — a world's contract is STABLE (the board doesn't reshuffle between visits or saves), and different worlds 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. THE BOUNTY POOLS ARE DIFFERENT — descriptions.neutral.bounty is the BOUNTY HUNT's WANTED LIST: 20 dossiers, each a named pirate leader with an epithet, a crime, and the craft it flies (`craft` = a data/combat.json → enemyTypes id, spread across all seven frames, so the copy and the fight agree; `craftLabel` is the readout's plain words for it). descriptions.faction.bounty is deliberately EMPTY — a documented stub: categories.bounty.contexts is ['neutral'], so a faction board never draws a hunt, and the pool stays empty until a faction author posts its own wanted list (the generator would otherwise fall back to the neutral list and post pirate-hunt copy on a faction board).",
|
||
"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": "The Ninth Bell",
|
||
"issuer": "The Fuel Wardens",
|
||
"name": "Ilse Vanturi",
|
||
"epithet": "Ninth Bell",
|
||
"crime": "Taxing the halcyon run at cannon point",
|
||
"craft": "bomber",
|
||
"craftLabel": "salvade heavy bomber, one long lance",
|
||
"body": "Ilse Vanturi rang the chapel bell nine times for every ship she let through, and when the chapel burned she kept the bell. Now the fuel tanker crews count nine chimes on the emergency band before a single heavy bolt walks the length of their hull — that lance reaches further than our wardens' radios, and she knows it. Six tankers have paid her toll and two of them are still burning. The Wardens pay for the pirate who invented the bell to stop ringing. Bring her down and we'll ring it once more for you."
|
||
},
|
||
{
|
||
"title": "Nine Winters",
|
||
"issuer": "The Salvage Court",
|
||
"name": "Ostvik Halvardson",
|
||
"epithet": "Nine Winters",
|
||
"crime": "Shelling the Kite Line harvest",
|
||
"craft": "bomber",
|
||
"craftLabel": "icebreak-turned gun platform, slow and patient",
|
||
"body": "Nine winters Ostvik Halvardson has sat his patched icebreaker off the Kite Line, patient as weather, dropping one enormous bolt into whatever the haulers thought was cover. The Court has written off nine salvage claims and eleven bodies. He is not a pirate with a conscience — he is an icebreaker with a grudge. He will not maneuver with you. He will not outrun you. He will sit exactly where he is and make you come into a lance that has been aiming at the same spot since the last moon. End the count at nine."
|
||
},
|
||
{
|
||
"title": "Protection Money",
|
||
"issuer": "The Pilots' Guild",
|
||
"name": "Berta Ondaine",
|
||
"epithet": "The Slow Smile",
|
||
"crime": "Selling insurance nobody agreed to buy",
|
||
"craft": "bomber",
|
||
"craftLabel": "bulk-bodied bomber with a fuse like a eulogy",
|
||
"body": "Berta Ondaine delivers her quotes in person: a fat hull on your wing, a smile on the open channel, and a bolt already cook-off on the long lance if you decline. Three Guild pilots took the quote anyway and are now part of the belt. The Guild has paid off raiders before; it refuses to start with her. We want the collection stopped, and we want it stopped in the order she prefers — nobody quoting our members ever again."
|
||
},
|
||
{
|
||
"title": "Two Of A Kind",
|
||
"issuer": "The Ledger House",
|
||
"name": "Sable & Rue Spidleau",
|
||
"epithet": "the sisters who finish each other's sentences",
|
||
"crime": "Strafing the passenger ferry lane for sport",
|
||
"craft": "spitter",
|
||
"craftLabel": "twin-seat skiff, a fan of bolts per sentence",
|
||
"body": "One steers, one shoots, and neither stops talking. The Spidleau sisters cross the ferry lane screaming and open up with a fan of cheap bolts wide enough that dodging is a rumour — they've never hit anything worth hitting, which the Ledger House considers a moral emergency rather than luck. Two ferry hulls are patched so full of bolt-holes they fly in daylight. Take the pirate sisters off the lane before arithmetic does it for us."
|
||
},
|
||
{
|
||
"title": "The Firefight",
|
||
"issuer": "The Station Keeper",
|
||
"name": "Cassia Drumm",
|
||
"epithet": "Firehose",
|
||
"crime": "Putting out a depot fire by spraying the depot",
|
||
"craft": "spitter",
|
||
"craftLabel": "pump-rigged skiff throwing a wide cone",
|
||
"body": "Cassia Drumm was the best fire response on this station until she answered her own alarm with her ship's pump and a bad idea. Now she works the lane for the same instinct: get close, open a cone across everything you see, call it done. The keeper who let her keep the rig is the keeper who owes us a barge, and every hauler on the lane now pays a raider's rate in delay. Put the fire out for good."
|
||
},
|
||
{
|
||
"title": "Fan Favourite",
|
||
"issuer": "The Tally",
|
||
"name": "Havelock Vane",
|
||
"epithet": "Nine-Finger",
|
||
"crime": "Point-blank shakedown at the ore moorings",
|
||
"craft": "spitter",
|
||
"craftLabel": "ore-hauler refit, spray bars welded on",
|
||
"body": "Havelock Vane lost four fingers to his own spray rig and wears the rest as a threat — he'll show you the hand on the channel while the fan warms up. He shakes the ore moorings for whatever the crews have on them and paints the bulkheads when they don't. The Tally counts his takings in scraped hull plate and has decided that the count of this pirate is finished."
|
||
},
|
||
{
|
||
"title": "Three For The Road",
|
||
"issuer": "The Relay Masters",
|
||
"name": "Aruna Sekh",
|
||
"epithet": "Needle",
|
||
"crime": "Sprint-killing light freight above the relay field",
|
||
"craft": "stinger",
|
||
"craftLabel": "courier-racer hull, a tight three-shot burst",
|
||
"body": "Aruna Sekh used to fly mail for us and knew every relay gate in this system by sound. Now she comes off the relay field at racing speed, puts three bolts into your engine block in about a heartbeat, and is gone before your gunner has picked a side of the ship. The Masters pay for the pilot who taught them this lane to stop teaching it."
|
||
},
|
||
{
|
||
"title": "The Dark Side Visit",
|
||
"issuer": "The Warden Guild",
|
||
"name": "Ketch Marlowe",
|
||
"epithet": "Get-Dark",
|
||
"crime": "Ambush from moon-shadow with no running lights",
|
||
"craft": "stinger",
|
||
"craftLabel": "stripped scout, burst cannon and no transponder",
|
||
"body": "Ketch Marlowe flies dark on the shadow side of this system's moons and reads your approach like a menu — the burst lands while you're still calling out on an honest channel. Two wardens have gone chasing the dark and come back with fewer hulls than they left with. The Guild wants the dark side of these moons to be empty again, and it wants Marlowe to be the reason."
|
||
},
|
||
{
|
||
"title": "The Long Sting",
|
||
"issuer": "The Harbormaster",
|
||
"name": "Vessa Nkemdi",
|
||
"epithet": "Stingtail",
|
||
"crime": "Running the toll on the ice road",
|
||
"craft": "stinger",
|
||
"craftLabel": "fast picket with a burst tail-gun",
|
||
"body": "Vessa Nkemdi works the ice road alone and calls it a toll booth; harbor law says pirate, she says independent traffic warden. She hangs off your stern where your cameras are worst, stings three bolts into your drive every time you slow for the ice, and invoices the wrecks she makes. The harbor has paid her invoice twice. It would prefer to pay you instead."
|
||
},
|
||
{
|
||
"title": "He Never Loses A Scent",
|
||
"issuer": "The Remand Office",
|
||
"name": "Aurelian Costa",
|
||
"epithet": "The Bloodhound",
|
||
"crime": "Killing bond-jumpers who owed him nothing",
|
||
"craft": "hunter",
|
||
"craftLabel": "hunting craft with a heat-seeker on a long leash",
|
||
"body": "Aurelian Costa was a bounty hunter before he was a pirate and never saw the difference. His missile finds whatever is running, and it does not get bored — out-turn it if you can, but he has watched a lot of people try. He has been collecting people the Remand Office owed nobody. Bring him in and the Office stops apologising for what its own paperwork caused."
|
||
},
|
||
{
|
||
"title": "Last Confession",
|
||
"issuer": "The Longshore Chapel",
|
||
"name": "Marilou Dax",
|
||
"epithet": "The Confessor",
|
||
"crime": "Absolving nine crews from the inside of their own ships",
|
||
"craft": "hunter",
|
||
"craftLabel": "chapel-hulled hunter, one missile per blessing",
|
||
"body": "Sister Marilou opens a channel, asks for the truth of your voyage, hears it all the way down, and then launches a seeker she calls absolution. Nine crews have been absolved. The Chapel that unfrocked her is paying from its own box, which tells you how seriously it takes the habit. Make her finish her own penance."
|
||
},
|
||
{
|
||
"title": "Toll Hound",
|
||
"issuer": "The Tally",
|
||
"name": "Baz Ferreira",
|
||
"epithet": "Foxhound",
|
||
"crime": "Hunting smugglers who skipped his toll",
|
||
"craft": "hunter",
|
||
"craftLabel": "tracker with a missile and infinite patience",
|
||
"body": "Baz Ferreira charges smugglers for the privilege of being robbed by him, and his seeker is how he audits. The trouble is he has begun auditing honest traffic too, on the theory that anyone flying this lane owes somebody. The Tally finds the reasoning unsound and pays for a correction."
|
||
},
|
||
{
|
||
"title": "Collect In Full",
|
||
"issuer": "The Ledger House",
|
||
"name": "Sefane Adu",
|
||
"epithet": "Two Ledgers",
|
||
"crime": "Debt collection with a machine gun",
|
||
"craft": "gunner",
|
||
"craftLabel": "fast interceptor, rapid cannon, no patience for instalments",
|
||
"body": "Sefane Adu keeps two ledgers: one for what you owe, one for what the interest costs. When the second one opens she walks a stream of bolts down your spine until something gives, and she has never once lost a balance. The Ledger House disowned her paperwork and would like the collection agency retired."
|
||
},
|
||
{
|
||
"title": "Dead Air",
|
||
"issuer": "The Relay Masters",
|
||
"name": "Moira Bellamy",
|
||
"epithet": "Static",
|
||
"crime": "Jamming distress, then finishing the job",
|
||
"craft": "gunner",
|
||
"craftLabel": "jam-topped interceptor, rapid bolts on a short cooldown",
|
||
"body": "Moira Bellamy kills your radio before she kills anything else — static first, then a machine gun while you're still trying to raise somebody. Two wrecks in this system died calling into dead air. The Masters built the relay network and are paying for the one voice on it that ought to be silenced forever."
|
||
},
|
||
{
|
||
"title": "The Mill",
|
||
"issuer": "The Warden Guild",
|
||
"name": "Isaac Vowell",
|
||
"epithet": "The Miller",
|
||
"crime": "Grinding convoys down until something breaks",
|
||
"craft": "gunner",
|
||
"craftLabel": "long-burn interceptor that never lifts off the trigger",
|
||
"body": "Isaac Vowell does not ambush, taunt, or bargain. He gets on your wing and pours bolts at you for as long as either ship lasts, which he has calculated will always be him. Three convoy escorts have run out of shields before he ran out of ammunition. The Guild would like his arithmetic tested by somebody with better armor."
|
||
},
|
||
{
|
||
"title": "Do Not Approach",
|
||
"issuer": "The Salvage Court",
|
||
"name": "Gwendolane Fisk",
|
||
"epithet": "Hedge",
|
||
"crime": "Ring-fire at a salvage crew that came alongside",
|
||
"craft": "barrage",
|
||
"craftLabel": "armored barge that answers boarding with a full ring",
|
||
"body": "Gwendolane Fisk welded armor to an already slow hull and solved the problem of close-quarters combat by firing outward in every direction at once. A salvage crew went alongside to cut her loose and did not come back. The Court would like a ruling that nothing may be approached at point-blank, and this is the only way it gets one."
|
||
},
|
||
{
|
||
"title": "The Halo",
|
||
"issuer": "The Longshore Chapel",
|
||
"name": "Kaleo Tui",
|
||
"epithet": "Sunburst",
|
||
"crime": "Claiming a pilgrimage lane and everything on it",
|
||
"craft": "barrage",
|
||
"craftLabel": "armored pilgrim craft that blooms into a ring of bolts",
|
||
"body": "Brother Kaleo declared the pilgrimage lane his own diocese, and every ship that uses it pays tithe or eats a halo of bolts fired in every direction at once. He broadcasts hymns while he does it, which the Chapel says is not what hymns are for. Take his little kingdom apart and take the sound off the air."
|
||
},
|
||
{
|
||
"title": "The Widow's Claim",
|
||
"issuer": "The Pilots' Guild",
|
||
"name": "Dorra Vance",
|
||
"epithet": "Anvil",
|
||
"crime": "Claiming the belt on behalf of a dead husband",
|
||
"craft": "barrage",
|
||
"craftLabel": "heavy barge, ring gun, unbothered by return fire",
|
||
"body": "Dorra Vance says the belt belonged to her husband and that his death transferred the deed to anyone stubborn enough to collect it. She collects in bolts — a full ring each time, since she stopped bothering to aim at anything so small as a ship. The Guild has never once seen a title this thick, and would like it voided with extreme prejudice."
|
||
},
|
||
{
|
||
"title": "The Meridian Line",
|
||
"issuer": "The Warden Guild",
|
||
"name": "Kazimir Vohl",
|
||
"epithet": "Black Meridian",
|
||
"crime": "The Sable Convoy massacre",
|
||
"craft": "warden",
|
||
"craftLabel": "warden-class heavy — a lance and a seeker on every volley",
|
||
"body": "Admiral Vohl, self-appointed, commanded the escort that let the Sable Convoy burn and then wrote the report blaming the convoy. He flies like a man with a warship's patience: a heavy lance to hold you in place and a seeker to follow wherever you dodge. The Guild has buried four of its own who went after him. This contract is written by people who are done burying anybody else."
|
||
},
|
||
{
|
||
"title": "Grey Judgement",
|
||
"issuer": "The Harbormaster",
|
||
"name": "Sera Alkantari",
|
||
"epithet": "Grey Judgement",
|
||
"crime": "Executing three launch marshals on the pad",
|
||
"craft": "warden",
|
||
"craftLabel": "judicial warden, lance and missile fired like a sentence",
|
||
"body": "Sera Alkantari holds court in open space: she reads the charge, gives you one channel to answer, and then fires a heavy lance and a seeker whether your defence was good or not. Three launch marshals were executed for calling her hull unsafe. The harbor she served is paying for the last word on this one to be somebody else's."
|
||
}
|
||
],
|
||
"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": "A freighter and her screen stand ready at the buoy, and every pirate in the system knows the lane is theirs tonight. The Tally pays for hulls that arrive, and the Tally counts them at the gate — not for the story of the ones that didn't. Keep the big one in one piece, and 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 across 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."
|
||
},
|
||
{
|
||
"title": "Patient Hull",
|
||
"issuer": "The Salvage Court",
|
||
"body": "The Court's arbitration barge is the slowest ship in three systems, and the pirates know exactly what that means. She carries a verdict, not a cargo — a ruling that three of their toll posts are forfeit, sealed and witnessed. The barge has armor and she has guns, and she will get there eventually, one slow mile at a time. Your job is to make sure the eventually is short, and the miles stay quiet."
|
||
},
|
||
{
|
||
"title": "The Choir Ship",
|
||
"issuer": "The Longshore Chapel",
|
||
"body": "A pilgrim ship out of the chapel is carrying the season's choir — twelve voices and a pipe organ, all of it — to the far station for the solstice service. The lane is a kill-box and the organ does not fit in a fighter. Keep the ship honest, keep the choir alive, and the service happens. The chapel doesn't pay in credits first; it pays in the fact that you were the reason the music made it."
|
||
},
|
||
{
|
||
"title": "Bones in the Hold",
|
||
"issuer": "The Remand Office",
|
||
"body": "The Office is moving twelve condemned pirates off the local block to a proper holding station, sealed in the hold under a full guard. The transport is armed to the bulkheads and it does not ask forgiveness. Pirates are circling the lane because a kill like that is worth the fuel. Fly the point, keep the hold sealed, and deliver the whole lot — alive, guilty, and in one piece. The Office pays for the count, and the count has to match."
|
||
},
|
||
{
|
||
"title": "The Fuel King's Daughter",
|
||
"issuer": "The Harbormaster",
|
||
"body": "A refueling tender is running a full load of refined fuel to the outer post, and the tender is carrying the fuel king's daughter home with it. She's in the cabin, she's reading, and she doesn't know that the lane is a kill-box. The harbor master is paying for the fact that the king's daughter arrives reading, not on fire. Keep the tender in one piece, keep the fuel lit, and keep your wing where the pirates can see it."
|
||
},
|
||
{
|
||
"title": "The Ledger's Own",
|
||
"issuer": "The Ledger House",
|
||
"body": "The House is moving its own books — the physical ledgers, three seasons of every transaction in the system — to the archive station. The books are the House's memory, and the pirates know that a ledger in the wrong hands is a weapon. The transport is slow, it is armored, and it is carrying something that cannot be reprinted. Escort it across and the House will remember your name in the only book that matters — the one that lists who it trusts."
|
||
},
|
||
{
|
||
"title": "The Wrecker's Debt",
|
||
"issuer": "The Tally",
|
||
"body": "A wrecker's ship is carrying a full hold of salvaged hull plate to the smelting station, and the pirates who put it in that shape want it back. The Tally has already paid for the salvage, and the wreckers have already signed the deed. The ship is fast enough, the cargo is heavy, and the lane is the problem. Put the plate through and the Tally's books stay honest — that's the whole job, and the whole reward."
|
||
},
|
||
{
|
||
"title": "The Quiet Passenger",
|
||
"issuer": "The Pilots' Guild",
|
||
"body": "A courier is carrying a single sealed crate across the lane, and the crate has a passenger inside it who is not supposed to exist. The Guild won't say what's in the crate, and it won't say who's paying for the silence. What it will say is this: the lane is hot, the crate is heavy, and the pilot who puts it through gets paid in credits and in the fact that the Guild will never forget who kept the secret. Fly the wing, keep the crate sealed, and don't ask."
|
||
},
|
||
{
|
||
"title": "The Harvest Run",
|
||
"issuer": "The Warden Guild",
|
||
"body": "A harvest barge out of the outer field is carrying three seasons of grain to the depot, and the field is done producing — this is the last run of the season. The barge is slow, the grain is heavy, and the pirates know that a starving system is a system that pays. The Guild is paying for the fact that the grain arrives and the season doesn't end in a fire. Keep the barge moving, keep the hold dry, and put it through before the ice closes the lane."
|
||
},
|
||
{
|
||
"title": "The Marshal's Charge",
|
||
"issuer": "The Remand Office",
|
||
"body": "A marshal's transport is moving a full warrant of evidence — the physical records of a piracy case, sealed and witnessed — to the trial station. The pirates in the case know what's on that ship, and they know that the evidence is the only thing standing between them and the block. The transport is armed, the marshal is not asking forgiveness, and the lane is the problem. Escort the charge through and the Office will file your name in the record — as the reason the case held."
|
||
},
|
||
{
|
||
"title": "The Slow Smile's Freight",
|
||
"issuer": "The Tally",
|
||
"body": "A freighter is running a full load of ore to the smelting station, and the freighter has a pilot who used to fly for the pirates. The Tally doesn't care about the pilot's past, but the pirates care about the pilot's present — they want their old crew back, and they're willing to burn the freighter to get them. Keep the freighter in one piece, keep the ore moving, and the Tally will pay for the fact that the lane stayed open."
|
||
},
|
||
{
|
||
"title": "The Chapel Bell",
|
||
"issuer": "The Longshore Chapel",
|
||
"body": "A repair ship is carrying a new bell — the replacement for the one the pirates rang nine times for every ship they let through — to the chapel station. The bell is cast, it's blessed, and it's going to be rung for the first time at the solstice service. The lane is the problem and the bell is the weight. Put the bell through and the chapel will ring it once for you, in the only way it knows how — on the air, in every system, on the solstice."
|
||
},
|
||
{
|
||
"title": "The Toll Keepers' Pay",
|
||
"issuer": "The Harbormaster",
|
||
"body": "A pay transport is moving the season's toll payments to the outer posts, and the posts are three months behind on wages. The transport is carrying credits — not ore, not grain, credits — and the pirates know that a post with unpaid wardens is a post that can be bought. The harbor master is paying for the fact that the wardens get paid and the posts stay honest. Keep the transport moving, keep the credits sealed, and put it through before the wardens start to wonder."
|
||
},
|
||
{
|
||
"title": "The Courier's Last Run",
|
||
"issuer": "The Pilots' Guild",
|
||
"body": "A courier is making their last run before they retire, and the cargo is the Guild's own seal — the physical stamp, the one that makes a manifest real. The courier has flown this lane for twenty years and they know every gate, every shadow, every blind spot. The Guild is paying for the fact that the seal arrives and the courier retires with their name clean. Fly the wing, keep the seal sealed, and give the old pilot the send-off they earned."
|
||
},
|
||
{
|
||
"title": "The Ice Road Tender",
|
||
"issuer": "The Warden Guild",
|
||
"body": "A fuel tender is running a full load to the ice road post, and the post is the last honest fuel stop before the deep lane. The tender is slow, the fuel is volatile, and the ice road is a toll lane with a reputation. The Guild is paying for the fact that the post stays lit and the lane stays open. Keep the tender moving, keep the fuel safe, and put it through before the ice closes."
|
||
},
|
||
{
|
||
"title": "The Court's Witness",
|
||
"issuer": "The Salvage Court",
|
||
"body": "A witness transport is carrying a single witness — the only one who saw the Sable Convoy burn — to the trial station. The witness is alive, they are sealed in the cabin, and they are worth more than the ship that's carrying them. The pirates who burned the convoy know that a witness at the trial is a verdict, and they're willing to burn the transport to keep it. Escort the witness through and the Court will file your name in the record as the reason the truth held."
|
||
},
|
||
{
|
||
"title": "The Harbormaster's Tender",
|
||
"issuer": "The Harbormaster",
|
||
"body": "A harbor tender is carrying the season's repair parts to the outer dock, and the dock is the only honest repair yard in the system. The tender is slow, the parts are heavy, and the dock is three months behind on its parts order. The harbor master is paying for the fact that the dock gets its parts and the yard stays open. Keep the tender moving, keep the parts dry, and put it through before the dock starts to rust."
|
||
},
|
||
{
|
||
"title": "The Guild's Own Pilot",
|
||
"issuer": "The Warden Guild",
|
||
"body": "A Guild pilot is flying their own ship — the one they've flown for fifteen years — to the far station for the solstice service, and the lane is the problem. The ship is fast, the pilot is good, and the Guild is paying for the fact that the pilot arrives and the ship stays in one piece. The Guild doesn't pay for the story of the pilot who didn't make it. Fly the wing, keep the pilot alive, and put them through. That's the job, and the Guild will remember."
|
||
}
|
||
]
|
||
},
|
||
"faction": {
|
||
"patrol": [
|
||
{
|
||
"title": "Sighting Report",
|
||
"body": "Recon puts a {enemy} flight moving through {system} — fighters on a working pattern, not a transit. Sweep the grid and put them down. The {issuer} is paying for clean lanes and it doesn't care who asks twice."
|
||
},
|
||
{
|
||
"title": "Foreign Fighters",
|
||
"body": "Three of our outposts logged {enemy} transponders inside {system} this week. That's not a patrol line — it's a claim. Burn the claim out before it becomes a border. The {issuer} will credit the scrap to whoever files the wrecks."
|
||
},
|
||
{
|
||
"title": "Lane Watch",
|
||
"body": "The approach lanes run hot: {enemy} fighters have been working them at long range, taking nothing, watching everything. Show them which side of the lane pays. The {issuer} has a standing order that the lanes stay under our flag — this is the order, not a discussion."
|
||
}
|
||
],
|
||
"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": "WANTED — {enemy} Officer",
|
||
"issuer": "{issuer}",
|
||
"name": "The Reckoner",
|
||
"epithet": "First Officer of a {enemy} strike group",
|
||
"crime": "Raiding friendly lanes and holding their crews for ransom",
|
||
"craftLabel": "a {enemy} fighter — frame unknown, expect the works",
|
||
"body": "The {issuer} has a name for the officer who has been taking our lanes, and the name is a habit: same runs, same timing, same signature on the wrecks. Their base sits in a {enemy}-held system off our gates — the {issuer} will not send its own pilots there, so it is hiring yours. Find them, put them down, and file the hull. The {issuer} pays for the habit ending."
|
||
},
|
||
{
|
||
"title": "WANTED — {enemy} Officer",
|
||
"issuer": "{issuer}",
|
||
"name": "The Bellwether",
|
||
"epithet": "A {enemy} scout who leads other people's raids",
|
||
"crime": "Scouting the approach lanes and selling the timing",
|
||
"craftLabel": "a {enemy} fighter — fast, and it flies alone",
|
||
"body": "Every {enemy} raid we have lost this season started with a single long-dwell scout pass: one scout, long dwell, no weapons. The {issuer} wants the scout, not the wreckage of it. The scout lives in {enemy}-held space a gate-hop out — the {issuer} pays to have the question asked over their hull."
|
||
},
|
||
{
|
||
"title": "WANTED — {enemy} Officer",
|
||
"issuer": "{issuer}",
|
||
"name": "The Tollkeeper",
|
||
"epithet": "A {enemy} gunner taxing the outer lanes",
|
||
"crime": "Holding a friendly run at cannon point",
|
||
"craftLabel": "a {enemy} fighter — heavy on the guns, light on manners",
|
||
"body": "Something in a {enemy} hull has been standing on the outer lane and billing every ship that passes. Our manifest says the lane is ours, and the {issuer} says the bill is final — in their favor, against the tollkeeper. The tollkeeper's ground is a {enemy} system off our gates. Bring the ledger back. The {issuer} will settle the rest."
|
||
}
|
||
],
|
||
"escort": [
|
||
{
|
||
"title": "Stranded Freight",
|
||
"body": "A {faction} transport is sitting in {enemy}-held space, engines cold and its crew waiting it out. It flew in working, not hiding. Get to it, link the convoy, and fly it back through the gate into {system}. The {issuer} does not lose its freight to bad luck, and it will not let this one be the exception."
|
||
},
|
||
{
|
||
"title": "The Convoy That Stopped",
|
||
"body": "Our own freight ran a {enemy} patrol wrong and lost its escort wing; the ship is standing alone in {enemy}-held space with a full hold and a thin margin. Bring it home: link at its position, hold the lane, and put it down at {system} with its cargo intact. The {issuer} is paying for the run and for the lesson — in that order."
|
||
},
|
||
{
|
||
"title": "Freight Under Watch",
|
||
"body": "A {faction} freighter is trapped in {enemy} territory — the {enemy} have it under watch, not in tow, which means they are waiting for it to move. Make it move: link the convoy, and fly the whole run home through our gate to {system}. Keep the flag on the hull and the lane clear of {enemy} lights. The {issuer} considers the freight its own until it is back in its own system."
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"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",
|
||
"payoutXp": "PAYOUT — {reward} CR · +{xp} XP",
|
||
"accept": "ACCEPT CONTRACT",
|
||
"accepted": "CONTRACT ACCEPTED",
|
||
"active": "PATROL ACTIVE",
|
||
"activate": "SET PATROL ACTIVE",
|
||
"bountyActive": "HUNT ACTIVE",
|
||
"bountyActivate": "SET HUNT ACTIVE",
|
||
"escortActive": "CONVOY LINKED",
|
||
"escortActivate": "SET ESCORT ACTIVE",
|
||
"complete": "CONTRACT COMPLETE",
|
||
"claim": "CLAIM REWARD — {reward} CR",
|
||
"claimXp": "CLAIM REWARD — {reward} CR · +{xp} XP",
|
||
"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",
|
||
"textXp": "REWARD CLAIMED — +{reward} CR · +{xp} XP"
|
||
},
|
||
"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"
|
||
},
|
||
"_commentEscort": "The ESCORT contract's face (js/ui/JobBoardWindow.js + GameScene.updateEscort). escortActive = the row's live badge once the convoy links (the patrol's 'active' slot, re-labelled). escortRouteProgress = the row's progress line: the rendezvous leg, then the lane. escortLinkToast = the convoy forming on the player's wing. escortArrivingToast = the destination reached with the convoy intact (the delivery begins). escortArrivedToast = the touchdown closed (the contract completes). escortFailToast = the transport lost — the reset's call. escortResetToast = the landing's reset (a fresh convoy stands). escortRendezvousToast = the pre-link pointing. escortJumpHoldToast = the jump's flat denial while the convoy is linked but OUT OF VIEW (transport + its surviving escorts + the gate must all be on screen before the player jumps — GameScene.jumpThroughGate's escort guard). escortDeliveringToast = the jump's flat denial while the convoy is on its touchdown (hold until it lands). escortLandingDenyToast = the destination world's door (GameScene.startLanding's escort guard) — the planet/station the convoy is being delivered to holds its landing until the transport has REACHED it (phase 'delivered') or been DESTROYED (phase 'failed' — the landing's reset remedy). Every escort denial (jump hold + landing door) also arms OAC's 'escortDeny' visual comm (data/comms.json → oac-escort-wait — assets/speech/oac/escort-wait.mp3, the denial's voice).",
|
||
"escortRouteProgress": "LANE — {visited}/{total} SECTORS CROSSED",
|
||
"escortRendezvousToast": {
|
||
"glyph": "◈",
|
||
"color": "#7ce8a4",
|
||
"text": "CONVOY STANDING BY — REACH THE RENDEZVOUS TO LINK"
|
||
},
|
||
"escortLinkToast": {
|
||
"glyph": "⚓",
|
||
"color": "#7ce8a4",
|
||
"text": "CONVOY LINKED — {name} HOLDS YOUR WING THROUGH TO {dest}"
|
||
},
|
||
"escortArrivingToast": {
|
||
"glyph": "✈",
|
||
"color": "#7ce8a4",
|
||
"text": "CONVOY INBOUND — {name} IS BREAKING OFF TO SET DOWN AT {dest}"
|
||
},
|
||
"escortArrivedToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "CONVOY DELIVERED — {name} IS THROUGH, ITS REWARD IS READY TO CLAIM"
|
||
},
|
||
"escortFailToast": {
|
||
"glyph": "✗",
|
||
"color": "#ff5c77",
|
||
"text": "TRANSPORT LOST — THE CONVOY HAS BROKEN UP. LAND ON A PLANET TO RESET THE CONTRACT"
|
||
},
|
||
"escortResetToast": {
|
||
"glyph": "⚓",
|
||
"color": "#7ce8a4",
|
||
"text": "CONTRACT RESET — A FRESH CONVOY STANDS AT THE RENDEZVOUS"
|
||
},
|
||
"escortJumpHoldToast": {
|
||
"glyph": "⚓",
|
||
"color": "#ff5c77",
|
||
"text": "CONVOY OUT OF VIEW — BRING THE TRANSPORT, ITS ESCORTS AND THE GATE INTO VIEW TO JUMP"
|
||
},
|
||
"escortDeliveringToast": {
|
||
"glyph": "✈",
|
||
"color": "#7ce8a4",
|
||
"text": "CONVOY SETTING DOWN — HOLD POSITION UNTIL TOUCHDOWN"
|
||
},
|
||
"escortLandingDenyToast": {
|
||
"glyph": "✗",
|
||
"color": "#ff5c77",
|
||
"text": "ACCESS DENIED — THE CONVOY'S DESTINATION HOLDS UNTIL THE TRANSPORT LANDS"
|
||
},
|
||
"_commentBounty": "The BOUNTY HUNT's face (js/ui/JobBoardWindow.js + GameScene.updateBountyHunt). NOTE THE SILENCE: nothing here names the leg that holds the mark or a picket wave — the chain is hidden until it fires, so these lines only ever speak of what the player has already flown into. bountyLockBadge = the greyed row's plate (and the detail's lock line) under categories.bounty.minLevel; bountyAcceptDenyToast = the scene's refusal when a locked contract is pressed anyway. {bounty,escort}GateLockBadge / …GateLockSub / …GateDenyToast = the GATE ACCESS lock's words (the faction boards' hunts + rescues behind a hostile neighbor — the posting's gateLevel): the greyed row's badge, the detail's lock line, and the scene's refusal, each naming the target system the player needs access to FIRST ({system}) and the combat level that access opens at ({level}).",
|
||
"bountyLockBadge": "LOCKED — REQUIRES LEVEL {level}",
|
||
"bountyLockSub": "BRING YOUR RECORD UP TO LEVEL {level} AND THE BOARD WILL LIST YOU",
|
||
"bountyAcceptDenyToast": {
|
||
"glyph": "✗",
|
||
"color": "#ff5c77",
|
||
"text": "COMMISSION REFUSED — BOUNTY HUNTS STAND AT LEVEL {level}"
|
||
},
|
||
"dossierWanted": "WANTED — {name}",
|
||
"dossierEpithet": "{epithet}",
|
||
"dossierCrime": "CHARGES — {crime}",
|
||
"dossierCraft": "CRAFT — {craft}",
|
||
"bountyRouteProgress": "TRAVEL LANE — WAYPOINT {visited} OF {total} LOGGED",
|
||
"bountyLegToast": {
|
||
"glyph": "◈",
|
||
"color": "#ff2d6f",
|
||
"text": "WAYPOINT {i} OF {n} LOGGED — NOTHING ON THE LANE"
|
||
},
|
||
"bountySkirmishToast": {
|
||
"glyph": "⚔",
|
||
"color": "#ff5c77",
|
||
"text": "PIRATE PICKETS — {n} HOSTILES INBOUND"
|
||
},
|
||
"bountySightedToast": {
|
||
"glyph": "☠",
|
||
"color": "#ff2d6f",
|
||
"text": "THE MARK IS HERE — {name}, {epithet} · {n} HOSTILES INBOUND"
|
||
},
|
||
"bountyBroughtToBookToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "{name} BROUGHT TO BOOK — PUT DOWN THE LAST OF THE ESCORT"
|
||
},
|
||
"bountyCompleteToast": {
|
||
"glyph": "✓",
|
||
"color": "#67e863",
|
||
"text": "BOUNTY HUNT COMPLETE — {name} IS DOWN, ITS REWARD IS READY TO CLAIM"
|
||
},
|
||
"bountyGateLockBadge": "LOCKED — ACCESS TO {system} REQUIRED",
|
||
"bountyGateLockSub": "ACCESS TO {system} OPENS AT COMBAT LEVEL {level}",
|
||
"bountyGateDenyToast": {
|
||
"glyph": "✕",
|
||
"color": "#ff2d6f",
|
||
"text": "COMMISSION REFUSED — ACCESS TO {system} OPENS AT COMBAT LEVEL {level}"
|
||
},
|
||
"escortGateLockBadge": "LOCKED — ACCESS TO {system} REQUIRED",
|
||
"escortGateLockSub": "ACCESS TO {system} OPENS AT COMBAT LEVEL {level}",
|
||
"escortGateDenyToast": {
|
||
"glyph": "✕",
|
||
"color": "#ff2d6f",
|
||
"text": "COMMISSION REFUSED — ACCESS TO {system} OPENS AT COMBAT LEVEL {level}"
|
||
}
|
||
}
|
||
} |