1431 lines
109 KiB
JavaScript
1431 lines
109 KiB
JavaScript
window.GDD = window.GDD || {};
|
||
|
||
function GameplayPage() {
|
||
const [activeTab, setActiveTab] = React.useState('loop');
|
||
|
||
return (
|
||
<div className="content-inner">
|
||
<h1 style={{ marginBottom: '8px' }}>MVP Gameplay Loop</h1>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.95rem', maxWidth: '680px' }}>
|
||
The core loop: connect → spawn → navigate → mine → inventory → station → <strong style={{ color: 'var(--accent)' }}>sell on the market</strong> → chat.
|
||
Steps 1–7 work in Era 1 (single-player). Step 8 (Chat) requires multiplayer and ships in Era 2 (Phase 11).
|
||
Each step is UI-driven. The player's main interface is tables, charts, and panels — not a cockpit.
|
||
</p>
|
||
|
||
<div style={{ display: 'flex', gap: 'var(--sp-2)', marginBottom: 'var(--sp-6)', flexWrap: 'wrap' }}>
|
||
{[
|
||
{ id: 'loop', label: 'Core Loop' },
|
||
{ id: 'security', label: 'Security Levels' },
|
||
{ id: 'pirates', label: 'NPC Pirates' },
|
||
{ id: 'concord', label: 'CONCORD' },
|
||
{ id: 'insurance', label: 'Insurance' },
|
||
{ id: 'missions', label: 'Missions' },
|
||
{ id: 'travel', label: '🚀 Travel & Warp' },
|
||
{ id: 'events', label: 'World Events UX' },
|
||
{ id: 'balancer', label: '⚖ Balancing Agent' },
|
||
].map(t => (
|
||
<button key={t.id} className={`btn btn-sm${activeTab === t.id ? ' btn-primary' : ''}`}
|
||
onClick={() => setActiveTab(t.id)}>{t.label}</button>
|
||
))}
|
||
</div>
|
||
|
||
{activeTab === 'loop' && (<>
|
||
{/* Loop steps */}
|
||
<div style={{ marginTop: 'var(--sp-6)' }}>
|
||
{[
|
||
{ step: 1, title: 'Connect', desc: 'Player opens the app and connects to SpacetimeDB. Identity is established, player row loaded.', color: 'var(--cyan)' },
|
||
{ step: 2, title: 'Spawn', desc: 'A player row and ship row exist; the ship appears in the shared star system for all subscribers.', color: 'var(--cyan)' },
|
||
{ step: 3, title: 'Navigate (click & autopilot)', desc: 'Player clicks a point of interest — asteroid, station, hostile — and the ship automatically pilots there. No manual flight control at all. The player sets <em>intent</em>, the ship executes.', color: 'var(--green)' },
|
||
{ step: 4, title: 'Mine (activate & wait)', desc: 'Player clicks an asteroid to approach, then activates mining modules. The ship navigates on its own. Mining runs on a timer. The decision is <em>what</em> to mine and <em>when</em>, not <em>how</em>.', color: 'var(--accent)' },
|
||
{ step: 5, title: 'Inventory', desc: 'Ore appears in inventory panel. Quantity, type, and value visible. Player manages cargo space.', color: 'var(--purple)' },
|
||
{ step: 6, title: 'Dock at Station', desc: 'Player docks at a station. Station UI becomes available: sell, market, refit.', color: 'var(--cyan)' },
|
||
{ step: 7, title: 'Sell Ore', desc: 'Player sells ore through station UI for ISK (in-game currency). Simple fixed pricing for MVP; market orders later.', color: 'var(--accent)' },
|
||
{ step: 8, title: 'Chat', desc: 'Players send and receive messages in current system. Basic rate limiting and length validation. Requires multiplayer — ships in Phase 11 (Era 2).', color: 'var(--green)' },
|
||
].map((s, i) => (
|
||
<div key={i} className="phase-item">
|
||
<div className="phase-marker">
|
||
<div className="phase-dot" style={{ background: s.color, boxShadow: `0 0 8px ${s.color}40` }} />
|
||
{i < 7 && <div className="phase-line" />}
|
||
</div>
|
||
<div className="phase-content">
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 'var(--sp-3)', marginBottom: 'var(--sp-1)' }}>
|
||
<span style={{ fontFamily: 'var(--font-mono)', fontSize: '0.7rem', color: s.color }}>STEP {s.step}</span>
|
||
<h4 style={{ margin: 0 }}>{s.title}</h4>
|
||
</div>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>{s.desc}</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-8)' }}>
|
||
<span className="section-num">GP-UI</span>
|
||
<h2 style={{ margin: 0 }}>Screen Specifications</h2>
|
||
</div>
|
||
|
||
<div className="grid-2">
|
||
{[
|
||
{ name: 'Login / Connect', color: 'var(--cyan)', items: ['Display current SpacetimeDB identity', 'Show connection status indicator', 'Enter/choose display name'] },
|
||
{ name: '3D Star Map', color: 'var(--accent)', items: ['Render ships, asteroids, station', 'Click-to-move navigation', 'Entity selection and info panel', 'Camera orbit/zoom controls'] },
|
||
{ name: 'Ship Status', color: 'var(--green)', items: ['Ship name, class, owner', 'Current status (idle/mining/warping)', 'Cargo capacity used/total', 'Active action timer'] },
|
||
{ name: 'Inventory', color: 'var(--purple)', items: ['Item type + quantity grid', 'Sell button (when docked)', 'Cargo capacity bar', 'Item value estimation'] },
|
||
{ name: 'Station Panel', color: 'var(--cyan)', items: ['Dock/undock controls', 'Quick-sell ore for ISK', 'View station market orders', 'Fit ship (when docked)'] },
|
||
{ name: 'Market', color: 'var(--accent)', items: ['Order book (buy/sell)', 'Price per unit + quantity', 'Place sell order from inventory', 'Station-filtered view'] },
|
||
{ name: 'Chat', color: 'var(--green)', items: ['Local/system channel (instant)', 'Private messages (delayed by range)', 'Sender name + timestamp', 'Auto-scroll to latest'] },
|
||
{ name: 'Combat HUD', color: 'var(--red)', items: ['Target selection + lock timer', 'Module activation buttons', 'Capacitor / shield / armor bars', 'Combat log / damage notifications'] },
|
||
{ name: 'Bounty Board', color: 'var(--accent)', items: ['Active bounties by tier', 'Place bounty on player', 'Kill feed (galaxy-wide)', 'Your bounty status'] },
|
||
{ name: 'Debug Panel', color: 'var(--muted)', items: ['Reducer call log with timestamps', 'Error display with stack trace', 'Connection metrics (latency, subscription count)', 'Entity count / state dump', 'SpacetimeDB table row counts', 'Agent tick scheduler status', 'Force-spawn NPC/entity controls (dev mode)', 'Game time display (tick counter, sim time)'] },
|
||
{ name: 'Galaxy Map', color: 'var(--accent)', items: ['Region/constellation/system hierarchy', 'Faction territory overlay', 'Active world events (icons)', 'Fauna migration routes', 'Anomaly locations and timers', 'Story log access'] },
|
||
{ name: 'World Event Panel', color: 'var(--green)', items: ['Active events in current region', 'Event countdown timers', 'Participation status', 'Story log for this event', 'Sensor alerts for nearby events'] },
|
||
].map((screen, i) => (
|
||
<div key={i} className="card">
|
||
<h4 style={{ color: screen.color, marginBottom: 'var(--sp-3)' }}>{screen.name}</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.82rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
{screen.items.map((item, j) => <li key={j}>{item}</li>)}
|
||
</ul>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Combat Model */}
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-8)' }}>
|
||
<span className="section-num">GP-COMBAT</span>
|
||
<h2 style={{ margin: 0 }}>Combat Model</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Combat style — FTL power management, not action.</strong> The player never directly controls the ship's movement or aiming.
|
||
Instead, the player clicks a hostile target and the ship <strong>automatically navigates to engagement range and engages</strong>.
|
||
The player's job is <strong>resource allocation</strong> — inspired by FTL: distribute reactor power between weapons, shields, engines,
|
||
and auxiliary systems. Modules auto-cycle when powered. The skill is in <strong>when to reroute power</strong> (e.g. divert from engines
|
||
to shields during a spike), <strong>which subsystem to target</strong> on the enemy, and <strong>fitting choices made before the fight</strong>.
|
||
Combat exists to create economic consequences (ship loss, loot, insurance), not to be a reflex game.
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>PvE Content</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>NPC pirates spawn in belts and at gates</li>
|
||
<li>Difficulty scales with system security level</li>
|
||
<li>High-sec: weak frigates, easy kills</li>
|
||
<li>Low-sec/null: cruiser+ NPCs, dangerous but rewarding</li>
|
||
<li>Bounty payouts + module drops as loot</li>
|
||
<li>NPC ratting is a primary ISK faucet</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Player Pirating</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Players can attack other players in low-sec and null-sec</li>
|
||
<li>High-sec attacks trigger CONCORD response (ship destruction)</li>
|
||
<li>Pirates can loot cargo from destroyed ships</li>
|
||
<li>Piracy lowers security status → eventually locked out of high-sec</li>
|
||
<li>Bounty system creates natural consequences</li>
|
||
<li>Creates risk/reward dynamics for haulers and miners</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Combat Flow (FTL-style resource management)</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
1. <span style={{ color: 'var(--cyan)' }}>Click hostile target</span> — ship auto-navigates to engagement range, no manual piloting<br/>
|
||
2. <span style={{ color: 'var(--accent)' }}>Auto-lock & engage</span> — targeting computer locks on, weapons begin auto-cycling<br/>
|
||
3. <span style={{ color: 'var(--red)' }}>Manage reactor power</span> — FTL-style: drag power between Weapons / Shields / Engines / Aux<br/>
|
||
4. <span style={{ color: 'var(--green)' }}>Pick subsystem to attack</span> — target enemy shields, weapons, engines, or hull directly<br/>
|
||
5. <span style={{ color: 'var(--purple)' }}>React to damage</span> — reroute power mid-fight: divert engines→shields when taking fire, shields→weapons to finish<br/>
|
||
6. <span style={{ color: 'var(--fg)' }}>Monitor capacitor</span> — all systems drain energy; running dry = modules go offline<br/>
|
||
7. <span style={{ color: 'var(--red)' }}>Destroy or flee</span> — hull reaches 0 → ship explodes, loot drops, economic consequences
|
||
</div>
|
||
<div style={{ marginTop: 'var(--sp-3)', padding: 'var(--sp-3)', background: 'rgba(34,211,238,0.06)', borderRadius: '6px', borderLeft: '3px solid var(--cyan)' }}>
|
||
<span style={{ fontSize: '0.8rem', color: 'var(--cyan)', fontWeight: 600 }}>FTL DNA:</span>
|
||
<span style={{ fontSize: '0.8rem', color: 'var(--fg-dim)' }}> The player's only input during combat is power allocation and subsystem targeting.
|
||
The ship flies itself. Weapons fire themselves. The player is the <em>chief engineer</em> deciding where
|
||
the reactor output goes — not the pilot or gunner.</span>
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-6)' }}>
|
||
<span className="section-num">GP-FAIL</span>
|
||
<h2 style={{ margin: 0 }}>Power Allocation Failure Modes</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-warn" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>No free lunch.</strong> Every subsystem needs energy. When power is diverted away from a subsystem,
|
||
it doesn't merely weaken — it fails. The reactor produces a fixed total output, and every allocation decision
|
||
creates a vulnerability somewhere else. This is the core tension of the combat system.
|
||
</div>
|
||
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Subsystem</th><th>Powered Behavior</th><th>Unpowered Failure Mode</th><th>Reroute Time</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><span className="pill pill-red">Weapons</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Turrets auto-cycle at full rate. Missile launchers reload. Damage output at fitted value.</td>
|
||
<td style={{ color: 'var(--red)' }}><strong>No firing.</strong> Turrets cease fire. Missiles cannot launch. Active weapons go offline after 3s. Cannot deal damage.</td>
|
||
<td className="mono">2s to full power</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-cyan">Shields</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Shield booster recharges shield HP. Passive regen active. Damage absorption at full.</td>
|
||
<td style={{ color: 'var(--red)' }}><strong>No recharge.</strong> Shield HP stops regenerating. Existing shield HP decays at 2%/s. After 15s, shields at 0% and all damage hits armor directly.</td>
|
||
<td className="mono">3s to full regen</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-green">Engines</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Ship maintains orbit speed. Can close distance or withdraw. Evasion against tracking.</td>
|
||
<td style={{ color: 'var(--red)' }}><strong>Ship immobile.</strong> Speed drops to 0. No orbit, no approach, no withdrawal. Sitting duck — all hostile weapons have perfect tracking. Cannot flee.</td>
|
||
<td className="mono">2s to full speed</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-purple">Auxiliary</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Active modules cycle normally: ECM jamming, sensor boosters, cap boosters, warfare links.</td>
|
||
<td style={{ color: 'var(--red)' }}><strong>No special abilities.</strong> All auxiliary modules go offline. ECM stops jamming. Sensors degrade. No capacitor boosting. Warfare links disconnect.</td>
|
||
<td className="mono">1.5s to full power</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>⚠ Red Alert Mode</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
When the ship takes shield-piercing damage (shields below 25% and taking armor hits), the HUD
|
||
automatically enters <strong style={{ color: 'var(--red)' }}>Red Alert</strong>. Non-essential HUD elements collapse:
|
||
chat minimizes, commodity ticker hides, overview panel shrinks to hostiles-only. The combat HUD
|
||
expands to fill the viewport: shield/armor/hull bars enlarge, power allocation bars gain prominent markers,
|
||
and a pulsing red border frames the screen. Audio alarm plays once.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem', color: 'var(--muted)' }}>
|
||
Trigger: shields < 25% AND armor damage incoming · Clears: shields restored above 50% · Cannot be disabled
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Reroute Timing</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Power rerouting is not instant — there's a 1.5–3 second spool-up depending on the subsystem.
|
||
This prevents instant reactive ping-pong between subsystems. The player must <em>commit</em>
|
||
to a power distribution and accept the vulnerability window. Rerouting to shields (3s) is deliberately
|
||
slower than rerouting to weapons (2s), creating a "damage race vs. survival" decision.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem', color: 'var(--muted)' }}>
|
||
During spool-up: subsystem operates at 50% capacity · Visual: power bar fills with animation · Audio: reactor hum changes pitch
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-danger" style={{ marginTop: 'var(--sp-5)' }}>
|
||
<strong>On death:</strong> Ship destroyed, cargo and modules partially lost (50% drop as loot, 50% destroyed).
|
||
Player respawns at home station in a rookie frigate. Ship insurance partially reimburses the loss.
|
||
See Ships & Fitting → DEATH (Ship Destruction) for full details.
|
||
</div>
|
||
|
||
{/* ═══ DYNAMIC WORLD ═══ */}
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-8)' }}>
|
||
<span className="section-num">GP-WORLD</span>
|
||
<h2 style={{ margin: 0 }}>Dynamic Galaxy — Living World Events</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>The galaxy is alive.</strong> The server simulates a single persistent galaxy with hundreds of star systems, planets,
|
||
moons, asteroid belts, space stations, wormholes, and anomalies. On top of this static geography runs a <strong>world simulation layer</strong>
|
||
that spawns PvE events dynamically, creating a unique story for every server. No two servers ever tell the same tale.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Galaxy Structure</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Single Galaxy, Many Systems</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
All players share one galaxy. The galaxy contains multiple regions, each with dozens of star systems.
|
||
Systems are connected by stargates forming a navigable graph. Travel between systems takes time,
|
||
creating <strong style={{ color: 'var(--fg)' }}>geographic identity</strong> — the frontier feels different from the core.
|
||
</p>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Orbiting Objects & Celestials</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
Each system has a star, planets, moons, asteroid belts, and stations. Planets orbit their star on slow cycles;
|
||
moons orbit planets. This is not cosmetic — <strong style={{ color: 'var(--fg)' }}>orbital positions affect mining yields,
|
||
travel times, and line-of-sight for sensors</strong>. The galaxy has real spatial rhythm.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>World Event Categories</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>⚔ Faction Conflicts</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
NPC factions have territory, resources, and grievances. The server tracks faction relations as a dynamic matrix.
|
||
When tensions cross a threshold, war erupts — faction fleets clash in contested systems, trade routes are disrupted,
|
||
and players can choose sides or profit from the chaos.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Triggers: resource disputes, border skirmishes, diplomatic insults, player provocations
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--purple)' }}>
|
||
<h4 style={{ color: 'var(--purple)' }}>🌀 Space Anomalies</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
The galaxy spawns temporary spatial phenomena — wormholes, nebulae, radiation storms, gravity wells, dark matter corridors.
|
||
Anomalies appear unannounced and expire on their own schedule. Some are dangerous, some are lucrative,
|
||
all create <strong style={{ color: 'var(--fg)' }}>time-limited opportunities</strong> that reward the first to arrive.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Lifespan: 15 min – 48 hrs · Rarity scales with distance from trade hubs
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>🐋 Space Fauna Migrations</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
Massive space creatures migrate across the galaxy on seasonal cycles — space whales, crystal leviathans, plasma mantas.
|
||
Their migration routes cross player space, creating <strong style={{ color: 'var(--fg)' }}>temporary resource hotspots</strong>
|
||
(biological materials, rare isotopes) and navigation hazards. Players can hunt, follow, or study them.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Cycle: real-time weeks · Route shifts each migration · First contact is always a surprise
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>🏛 NPC Faction Events</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
NPC factions expand, contract, build stations, abandon outposts, and respond to player activity.
|
||
A mining rush in a remote system might attract NPC traders, who attract pirates, who attract bounty hunters.
|
||
The world <strong style={{ color: 'var(--fg)' }}>reacts to player density and economic activity</strong> organically.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Includes: station construction, pirate raids, convoy escorts, refugee crises, tech discoveries
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>🌑 Cosmic Catastrophes</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
Rare galaxy-shaking events — a star going supernova, a rogue planet entering a system, a dormant wormhole network
|
||
activating. These are the <strong style={{ color: 'var(--fg)' }}>server-defining moments</strong> that players talk about for months.
|
||
"Were you online when the Rhea star collapsed?" becomes server legend.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Frequency: ~1 per month · Permanently alters the galaxy map · Foreshadowed days in advance
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--fg-dim)' }}>
|
||
<h4 style={{ color: 'var(--fg-dim)' }}>📡 Signals & Mysteries</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-2) 0' }}>
|
||
Unknown signals appear at random — derelict stations, alien artifacts, encrypted transmissions. Players investigate,
|
||
decode, and sometimes trigger chain events. Some mysteries are one-shot puzzles; others are the opening move
|
||
of a multi-week server arc that the world simulation has been building toward.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Discovery: player-initiated · Can trigger larger events · Some are red herrings
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>How the World Simulation Works</h3>
|
||
<div className="card card-accent" style={{ padding: 'var(--sp-6) var(--sp-8)', marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>World Simulation Pipeline</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--cyan)' }}>Galaxy State</span> — persistent topology: systems, gates, planets, stations, faction territories<br/>
|
||
<span style={{ color: 'var(--accent)' }}>World Tick</span> — every 5 min, server evaluates galaxy state + player density + event cooldowns + faction matrix<br/>
|
||
<span style={{ color: 'var(--green)' }}>Event Spawn</span> — world tick may spawn an event: choose type, location, duration, severity based on weighted probabilities<br/>
|
||
<span style={{ color: 'var(--purple)' }}>Event Propagation</span> — nearby players get sensor readings; distant players hear through news feed with delay<br/>
|
||
<span style={{ color: 'var(--red)' }}>Event Resolution</span> — events end by timer, player action, or cascading trigger; outcomes feed back into galaxy state<br/>
|
||
<span style={{ color: 'var(--fg)' }}>Story Log</span> — every event is recorded in a server-wide story timeline; players can read "the history of this galaxy"
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--accent)' }}>Player-Event Interaction</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Players can <strong style={{ color: 'var(--fg)' }}>participate</strong> in events (fight invaders, escort convoys, study anomalies)</li>
|
||
<li>Player actions can <strong style={{ color: 'var(--fg)' }}>escalate or defuse</strong> events (kill the pirate boss → raid ends)</li>
|
||
<li>Player density <strong style={{ color: 'var(--fg)' }}>attracts</strong> certain events (trade hubs get more NPC activity)</li>
|
||
<li>Player inaction lets events <strong style={{ color: 'var(--fg)' }}>escalate naturally</strong> (uncontested raids grow larger)</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--cyan)' }}>Server-Uniqueness</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Event seed is randomized per server — no two galaxies evolve the same way</li>
|
||
<li>Faction relationships drift based on <strong style={{ color: 'var(--fg)' }}>what players actually do</strong></li>
|
||
<li>A server where players are peaceful traders develops different world events than a server of pirates</li>
|
||
<li>The story timeline is the server's unique identity — "this is the galaxy where the Kaalani wiped out the Vren homeworld"</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-warn" style={{ marginTop: 'var(--sp-5)' }}>
|
||
<strong>Design intent:</strong> The world simulation ensures that even when players are doing routine economic loops,
|
||
<em>something</em> is always happening somewhere. The galaxy never feels static. A player who takes a week off returns
|
||
to find the political map has shifted, a new anomaly appeared in their home system, or a migration route has changed.
|
||
The world remembers, the world evolves, and the world tells a story that belongs to <strong>this server's</strong> players alone.
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ SECURITY LEVELS ═══ */}
|
||
{activeTab === 'security' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-SEC</span>
|
||
<h2 style={{ margin: 0 }}>Security Level System</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Security levels define the rules of engagement.</strong> Every star system has a security status from <strong>+1.0</strong> (safest) to <strong>−1.0</strong> (lawless).
|
||
Security 0.0 is explicitly <strong>null-sec</strong> — there is no border case. Systems at exactly 0.0 have the same rules as systems at −0.4: no CONCORD, no gate guns, full PvP freedom.
|
||
This single number controls CONCORD response, NPC pirate spawns, PvE difficulty, and the economic risk/reward balance.
|
||
Inspired by EVE Online's sec-space but simplified for the prototype's scope.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Security Bands</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Band</th><th>Sec Range</th><th>PvP Rules</th><th>CONCORD</th><th>NPC Pirates</th><th>Risk / Reward</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ band: 'High-Sec', range: '+0.5 → +1.0', color: 'var(--green)', pvp: 'Aggression triggers CONCORD. PvP possible but punished.', concord: 'Immediate (3–8s). Lethal.', pirates: 'Weak frigates. Easy kills, low bounties.', risk: 'Very low risk. Baseline ore prices. Starter systems.' },
|
||
{ band: 'Low-Sec', range: '+0.1 → +0.4', color: 'var(--accent)', pvp: 'No CONCORD. Gate/station guns fire on aggressors. PvP is free.', concord: 'None. Gate/station guns only.', pirates: 'Mixed frigates/destroyers. Moderate bounties.', risk: 'Medium risk. Better ore. Faction missions. Trade route choke points.' },
|
||
{ band: 'Null-Sec', range: '0.0 → −0.4', color: 'var(--red)', pvp: 'No rules. No guns. Anything goes.', concord: 'None.', pirates: 'Cruiser+ NPCs. Dangerous. High bounties + rare loot.', risk: 'High risk. Richest ore. Best anomalies. Faction conflict zones.' },
|
||
{ band: 'Deep Null', range: '−0.5 → −1.0', color: 'var(--purple)', pvp: 'No rules. Wormhole connections only.', concord: 'None.', pirates: 'Battlecruiser/battleship NPCs. Elite loot tables.', risk: 'Extreme risk. Unique resources. Story event spawning grounds.' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td><span style={{ color: row.color, fontWeight: 600 }}>{row.band}</span></td>
|
||
<td className="mono">{row.range}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.pvp}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.concord}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.pirates}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.risk}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Player Security Status</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>Gaining Status</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Destroying NPC pirates: +0.01 to +0.05 per kill (scaled by NPC tier)</li>
|
||
<li>Completing NPC missions: +0.1 to +0.3 per mission</li>
|
||
<li>Passive recovery: +0.01 per hour while clean (no hostile acts)</li>
|
||
<li>Maximum: +5.0 ("exemplary citizen")</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>Losing Status</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Attacking a player in high-sec: −0.5 to −2.0 (scaled by victim's ship value)</li>
|
||
<li>Destroying a player ship in high-sec: −2.0 to −5.0</li>
|
||
<li>Podding (if applicable): −5.0 (extreme penalty)</li>
|
||
<li>Below −2.0: barred from +0.8+ systems (CONCORD patrols eject)</li>
|
||
<li>Below −5.0: freely attackable anywhere ("outlaw")</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="section-header">
|
||
<span className="section-num">GP-SEC-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Schema Changes</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--accent)' }}>systems</span> — add column: <code>security_level</code> (Float, range −1.0 to +1.0, immutable at galaxy gen time)<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>players</span> — add column: <code>security_status</code> (Float, range −10.0 to +5.0, default 0.0)<br/>
|
||
<span style={{ color: 'var(--green)' }}>ships</span> — add column: <code>combat_flag</code> (Enum: none / weaponstimer / suspect / criminal, with timestamp)<br/>
|
||
<span style={{ color: 'var(--red)' }}>New reducer:</span> <code>adjust_security_status(player_id, delta, reason)</code> — server-side only, never client-callable
|
||
</div>
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ NPC PIRATES ═══ */}
|
||
{activeTab === 'pirates' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-NPC</span>
|
||
<h2 style={{ margin: 0 }}>NPC Pirate AI</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>NPC pirates are the primary PvE threat and a core ISK faucet.</strong>
|
||
They spawn in asteroid belts, at stargates, and in combat anomalies.
|
||
Their difficulty scales with system security level — easy frigates in high-sec,
|
||
deadly battleships in deep null. The pirate AI uses simple behavior templates, not machine learning:
|
||
deterministic state machines that create <em>believable</em> behavior without unpredictable edge cases.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Spawning Rules</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Spawn Locations</h4>
|
||
<table className="data-table">
|
||
<thead><tr><th>Location</th><th>Spawn Rate</th><th>Trigger</th></tr></thead>
|
||
<tbody>
|
||
{[
|
||
{ loc: 'Asteroid belt', rate: '1–3 NPCs per belt', trigger: 'Player enters belt or world tick' },
|
||
{ loc: 'Stargate', rate: '0–2 NPCs per gate', trigger: 'World tick (low-sec/null only)' },
|
||
{ loc: 'Combat anomaly', rate: '3–8 NPCs (waves)', trigger: 'Player warps to anomaly' },
|
||
{ loc: 'Mission site', rate: 'Scripted per mission', trigger: 'Player accepts mission' },
|
||
].map((r, i) => (
|
||
<tr key={i}>
|
||
<td style={{ color: 'var(--fg)' }}>{r.loc}</td>
|
||
<td className="mono">{r.rate}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{r.trigger}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Spawn Conditions</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Player proximity:</strong> NPCs spawn when a player enters a belt or anomaly ("pull" model). Gates spawn NPCs on world ticks only in low-sec/null.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Density cap:</strong> max 10 active NPCs per system. If at cap, oldest idle NPCs despawn.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Despawn:</strong> NPCs that have been idle (no aggro) for 5 minutes despawn. Combat NPCs persist until destroyed or player leaves system for 2+ minutes.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>No spawn zones:</strong> within 20km of stations (safe zone). On-grid with a station = no NPC spawn.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>World tick spawns:</strong> every 5 minutes, world tick may add NPCs to low-pop systems to keep them feeling dangerous.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Difficulty Tiers by Security Level</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Sec Band</th><th>NPC Classes</th><th>Hull HP</th><th>Bounty</th><th>Behavior</th><th>Loot</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ band: 'High-Sec', classes: 'Frigate (T1)', hp: '200–400', bounty: '500–2,000 ₢', behavior: 'Passive orbit. Low aggression. Flees below 30% HP.', loot: 'Basic modules, small ammo, common ore' },
|
||
{ band: 'Low-Sec', classes: 'Frigate (T2), Destroyer', hp: '400–800', bounty: '2,000–8,000 ₢', behavior: 'Aggressive orbit. Target priority (weakest ship). Kites if outgunned.', loot: 'T2 modules, blueprint fragments, mid-tier ore' },
|
||
{ band: 'Null-Sec', classes: 'Destroyer, Cruiser', hp: '800–2,500', bounty: '8,000–30,000 ₢', behavior: 'Coordinated packs. Spider tanking (remote reps). Escorts target jamming.', loot: 'Rare modules, full blueprints, rare minerals' },
|
||
{ band: 'Deep Null', classes: 'Cruiser, Battlecruiser, Boss', hp: '2,500–12,000', bounty: '30,000–200,000 ₢', behavior: 'Boss mechanics. Phase triggers. Spawns reinforcements. Requires fleet tactics.', loot: 'Officer modules, ship BPCs, unique cosmetics, story items' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: ['var(--green)', 'var(--accent)', 'var(--red)', 'var(--purple)'][i] }}>{row.band}</td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>{row.classes}</td>
|
||
<td className="mono">{row.hp}</td>
|
||
<td className="mono">{row.bounty}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.behavior}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.loot}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>AI Behavior Templates</h3>
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Deterministic state machines.</strong> Each NPC has a behavior template with a fixed set of states and transitions.
|
||
No randomness in decision-making — the "intelligence" comes from the state machine's design, not from randomness.
|
||
This makes NPC behavior predictable enough to learn but complex enough to be engaging.
|
||
</div>
|
||
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>NPC State Machine</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--muted)' }}>IDLE</span> → orbit spawn point, passive scan every 2s (aggro_scan agent)<br/>
|
||
<span style={{ color: 'var(--accent)' }}>AGGRO</span> → target detected in aggro range (30km default) → transition to COMBAT<br/>
|
||
<span style={{ color: 'var(--red)' }}>COMBAT</span> → execute behavior template (orbit/approach/kite) → fight to death or flee threshold<br/>
|
||
<span style={{ color: 'var(--purple)' }}>FLEE</span> → HP below flee threshold (30% default) → MWD away from player, warp out if possible<br/>
|
||
<span style={{ color: 'var(--green)' }}>DEAD</span> → generate loot, award bounty to damage contributor(s), schedule respawn
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
{[
|
||
{
|
||
name: 'Orbit Kiter', color: 'var(--cyan)',
|
||
desc: 'Maintains optimal range (15–20km). Orbits target at speed. Fires long-range weapons. If player closes distance, thrusts away. Good against slow ships.',
|
||
stats: 'Preferred range: 15–20km · Speed bonus: +20% · Damage: low · Survivability: high',
|
||
},
|
||
{
|
||
name: 'Brawler', color: 'var(--red)',
|
||
desc: 'Burns directly toward target. Gets into close range (2–5km) and applies heavy short-range damage. Vulnerable to kiting but devastating if they close.',
|
||
stats: 'Preferred range: 2–5km · Speed bonus: +10% · Damage: high · Survivability: medium',
|
||
},
|
||
{
|
||
name: 'Shield Tank', color: 'var(--green)',
|
||
desc: 'Prioritizes shield regeneration over damage. Self-reps during combat. Slow but durable. Good at outlasting opponents.',
|
||
stats: 'Preferred range: 10–15km · Shield regen: +50% · Damage: medium · Survivability: very high',
|
||
},
|
||
{
|
||
name: 'Support / EWAR', color: 'var(--purple)',
|
||
desc: 'Stays at range, jams target locks, disrupts targeting. Weak in direct combat but makes the pack deadlier. Always spawns with escorts.',
|
||
stats: 'Preferred range: 20–30km · EWAR strength: medium · Damage: very low · Survivability: low (prioritizes escape)',
|
||
},
|
||
].map((tmpl, i) => (
|
||
<div key={i} className="card" style={{ borderLeft: `3px solid ${tmpl.color}` }}>
|
||
<h4 style={{ color: tmpl.color, marginBottom: 'var(--sp-2)' }}>{tmpl.name}</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>{tmpl.desc}</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>{tmpl.stats}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="section-header">
|
||
<span className="section-num">GP-NPC-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>New Tables & Agents</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--red)' }}>npc_entities</span> — <code>npc_id, system_id, class_id, behavior_template, x/y/z, hull/armor/shield, target_id, state (idle/combat/flee/dead), spawn_location, spawn_time</code><br/>
|
||
<span style={{ color: 'var(--accent)' }}>npc_class_templates</span> — <code>class_id, name, tier, hull_base, armor_base, shield_base, speed, damage, behavior, loot_table_id, bounty</code><br/>
|
||
<span style={{ color: 'var(--green)' }}>loot_tables</span> — <code>table_id, entries (item_type, min_qty, max_qty, drop_chance), security_band</code><br/>
|
||
<span style={{ color: 'var(--cyan)' }}>New agents:</span> <code>pirate_spawn</code> (conditional, 300s), <code>pirate_combat_tick</code> (fixed, 1s per engaged NPC), <code>pirate_loot_drop</code> (one-shot, 0s on death)
|
||
</div>
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ CONCORD ═══ */}
|
||
{activeTab === 'concord' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-CONC</span>
|
||
<h2 style={{ margin: 0 }}>CONCORD — Law Enforcement</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>CONCORD is the NPC police force in high-security space.</strong>
|
||
They do not prevent crime — they <em>punish</em> it. High-sec is not safe; it is <em>consequential</em>.
|
||
A determined player can destroy a target in high-sec, but they will lose their ship to CONCORD.
|
||
This creates a cost equation: is the target's loot worth more than the attacker's ship? Most of the time, it isn't.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Response Model</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>System Sec</th><th>Response Time</th><th>CONCORD Force</th><th>Outcome</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ sec: '1.0', time: '3s', force: '2 Battleships + 2 Cruisers', outcome: 'Near-instant destruction. No time for a second volley.' },
|
||
{ sec: '0.9', time: '4s', force: '1 Battleship + 2 Cruisers', outcome: 'Quick destruction. Alpha-strike kills possible on soft targets.' },
|
||
{ sec: '0.8', time: '5s', force: '1 Battleship + 1 Cruiser', outcome: 'Brief window for damage. Tanky ships can survive one cycle.' },
|
||
{ sec: '0.7', time: '8s', force: '2 Cruisers', outcome: 'Meaningful attack window. Destroyers can kill frigates before CONCORD arrives.' },
|
||
{ sec: '0.6', time: '12s', force: '1 Cruiser', outcome: 'Extended window. Cruiser can kill a mining barge before response.' },
|
||
{ sec: '0.5', time: '15s', force: '2 Frigates', outcome: 'Longest high-sec response. Organized ganks are viable. The cost equation shifts toward attackers.' },
|
||
{ sec: '≤0.4', time: '∞ (no response)', force: 'None', outcome: 'No CONCORD. Gate/station guns fire in 0.1–0.4. Nothing in ≤0.0.' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td className="mono" style={{ fontWeight: 600, color: parseFloat(row.sec) >= 0.5 ? 'var(--green)' : parseFloat(row.sec) >= 0 ? 'var(--accent)' : 'var(--red)' }}>{row.sec}</td>
|
||
<td className="mono" style={{ color: 'var(--cyan)' }}>{row.time}</td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>{row.force}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.outcome}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>How CONCORD Works</h3>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--red)' }}>1. Aggression</span> — Player A attacks Player B in high-sec. <code>combat_flag</code> set to <strong>criminal</strong>.<br/>
|
||
<span style={{ color: 'var(--accent)' }}>2. CONCORD Spawn</span> — Server spawns CONCORD NPCs at attacker's location. Response time based on system sec.<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>3. Point + Web</span> — CONCORD warp-scrambles and stasis-webs the attacker. No escape.<br/>
|
||
<span style={{ color: 'var(--red)' }}>4. Destruction</span> — CONCORD applies overwhelming damage. Ship destroyed. No survival possible.<br/>
|
||
<span style={{ color: 'var(--green)' }}>5. Status Penalty</span> — Attacker's security status reduced. Large bounty placed automatically at low status.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>6. Kill Log</span> — Event logged in kill feed. Galaxy-wide notification if bounty collected.
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>Anti-Exploit Rules</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>CONCORD cannot be avoided, tanked, or outrun — response is guaranteed</li>
|
||
<li>Warping away delays CONCORD by ≤2s; they follow and catch up</li>
|
||
<li>CONCORD damage scales to always exceed attacker's EHP (no tanking)</li>
|
||
<li>If a player exploits a bug to avoid CONCORD, server admin can force-destroy the ship</li>
|
||
<li>"Criminal" flag persists through session — logging out doesn't clear it</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Suspect vs. Criminal</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li><strong style={{ color: 'var(--accent)' }}>Suspect</strong> — stole loot from another player's wreck. Anyone can attack the suspect freely. No CONCORD response for attacking a suspect. 15-minute timer.</li>
|
||
<li><strong style={{ color: 'var(--red)' }}>Criminal</strong> — attacked an innocent in high-sec. CONCORD responds. Ship will be destroyed. Security status penalty applied. 15-minute weapons timer.</li>
|
||
<li><strong style={{ color: 'var(--green)' }}>Weapons Timer</strong> — 60s after any aggressive module activation. Cannot dock, gate-jump, or tether during timer. Prevents "dock games."</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-warn">
|
||
<strong>Design intent:</strong> High-sec is not safe — it is <em>punitively expensive</em> to attack there.
|
||
The gank-vs-cost equation is the core balance lever. If ganking becomes too easy, reduce CONCORD response time.
|
||
If high-sec is too safe, increase response time slightly or reduce CONCORD force.
|
||
The goal is a living ecosystem where piracy exists but is a <em>strategic choice</em>, not a griefing tool.
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ INSURANCE ═══ */}
|
||
{activeTab === 'insurance' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-INS</span>
|
||
<h2 style={{ margin: 0 }}>Ship Insurance</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Insurance is both an ISK sink (premiums) and an ISK faucet (payouts).</strong>
|
||
It cushions ship loss without eliminating risk. A fully insured ship still costs the player money to replace —
|
||
modules, cargo, and the deductible are never covered. Insurance makes the game playable for casual players
|
||
while keeping ship loss meaningful for everyone.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Coverage Tiers</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Tier</th><th>Premium</th><th>Payout (% of hull value)</th><th>Duration</th><th>Best For</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ tier: 'None', premium: 'Free', payout: '0%', duration: '—', best: 'Rookie frigates (free replacement anyway)' },
|
||
{ tier: 'Basic', premium: '10% of hull value', payout: '40%', duration: '30 days', best: "Cheap ships you don't care about" },
|
||
{ tier: 'Standard', premium: '25% of hull value', payout: '70%', duration: '30 days', best: 'Default choice for most ships' },
|
||
{ tier: 'Platinum', premium: '50% of hull value', payout: '95%', duration: '30 days', best: 'Expensive ships, PvP main combat ships, mission runners' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: ['var(--muted)', 'var(--green)', 'var(--cyan)', 'var(--accent)'][i] }}>{row.tier}</td>
|
||
<td className="mono">{row.premium}</td>
|
||
<td className="mono" style={{ fontWeight: 600 }}>{row.payout}</td>
|
||
<td className="mono">{row.duration}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.best}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>How Insurance Works</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
1. Player buys insurance at station (deducted from wallet)<br/>
|
||
2. Policy active for 30 days or until ship is destroyed<br/>
|
||
3. On ship destruction, payout queued (30–120s delay via insurance_payout agent)<br/>
|
||
4. Payout = hull value × coverage %<br/>
|
||
5. ISK deposited to player wallet<br/>
|
||
6. Policy consumed — must re-insure new ship
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>What Insurance Does NOT Cover</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Fitted modules (separate loss — 50% destroyed, 50% loot)</li>
|
||
<li>Cargo (destroyed or looted — separate system)</li>
|
||
<li>AI crew injuries / medical costs</li>
|
||
<li>Rig slots (permanently destroyed on ship loss)</li>
|
||
<li>Market value above base hull price</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Economic Balance</h3>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Insurance as ISK Faucet/Sink</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--red)' }}>ISK sink:</span> Premium payments leave the economy (25% of hull value for Standard = net ISK destruction)<br/>
|
||
<span style={{ color: 'var(--green)' }}>ISK faucet:</span> Payouts inject ISK (70% of hull value for Standard = net ISK creation when ship is destroyed)<br/>
|
||
<span style={{ color: 'var(--accent)' }}>Net effect:</span> At Standard tier, each ship loss creates ISK equal to 70% − 25% = 45% of hull value. This is the "cost of dying" net ISK injection. Balanced by: ship replacement costs (minerals), module losses, and the fact that hulls are manufactured from player-mined resources (zero ISK creation).<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>Delay purpose:</span> The 30–120s payout delay prevents instant-rebuy combat loops. You can't die, collect insurance, and re-ship in the same fight.
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-danger">
|
||
<strong>Anti-abuse:</strong> Self-destructing a ship for insurance payout is an exploit.
|
||
Insurance payout never exceeds premium paid unless the ship was destroyed by a <em>different</em> player.
|
||
NPC kills pay full insurance. Self-destruct pays 0%. Alt-character kills are tracked via IP/connection heuristics
|
||
and flagged for review (bounty system uses the same check). For MVP: if killer and victim are the same player, payout = 0.
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-6)' }}>
|
||
<span className="section-num">GP-INS-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>New Tables & Reducers</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--accent)' }}>insurance_policies</span> — <code>policy_id, player_id, ship_id, tier, premium_paid, payout_value, purchased_at, expires_at, active (bool)</code><br/>
|
||
<span style={{ color: 'var(--cyan)' }}>ship_type_base_values</span> — <code>ship_type_id, base_hull_value (ISK), insurance_premium_mult (per tier)</code><br/>
|
||
<span style={{ color: 'var(--green)' }}>New reducer:</span> <code>purchase_insurance(ship_id, tier)</code> — validate docked + wallet, deduct premium, create policy<br/>
|
||
<span style={{ color: 'var(--red)' }}>New reducer:</span> <code>process_insurance_payout(ship_id)</code> — called by insurance_payout agent, validate policy active + ship destroyed, credit ISK
|
||
</div>
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ MISSIONS ═══ */}
|
||
{activeTab === 'missions' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-MIS</span>
|
||
<h2 style={{ margin: 0 }}>Mission System</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Missions are a core ISK faucet and the primary PvE progression path.</strong>
|
||
NPC agents at stations offer missions that send players on scripted encounters — kill pirates, haul cargo,
|
||
mine specific ores, survey anomalies, or escort convoys. Missions scale with security band, player standing,
|
||
and skill level. They are repeatable but not grindable: each agent has a limited pool that refreshes on a timer.
|
||
The mission system is the "guided content" that teaches new players the game loop and gives veteran players
|
||
a reliable ISK income alongside market trading and PvP.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Mission Types</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>⚔ Kill Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Warp to a deadspace pocket and destroy NPC hostiles. Difficulty scales with agent tier and system security.
|
||
May include multiple waves, a boss NPC, or structure destruction. The bread-and-butter of PvE combat.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: Bounty + mission bonus · Time limit: 24h · Standing: +0.05 to +0.30 per completion
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>📦 Courier Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Transport goods from one station to another. Cargo may be large (requiring a hauler) or valuable
|
||
(attracting pirates). Low-sec courier missions pay more. Creates organic hauler traffic that pirates can hunt.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: Flat fee + time bonus · Time limit: 1–6h · Standing: +0.03 to +0.15 · Risk: low-sec route = ambush
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>⛏ Mining Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Mine a specific quantity of a specific ore type and deliver it to the agent. May require traveling to a
|
||
mission-only asteroid belt (deadspace). Sometimes includes NPC spawns in the belt for added risk.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: ISK + ore market value · Time limit: 24h · Standing: +0.03 to +0.10 · Dual income: sell excess ore
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>📡 Survey / Exploration Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Travel to a specific system or anomaly and scan/interact with objects. May involve hacking, analyzing,
|
||
or simply being at a location for a duration. Low combat risk, high travel time. Good for exploring the galaxy.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: Flat fee + loot from sites · Time limit: 6–24h · Standing: +0.02 to +0.10 · Unlocks exploration content
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--purple)' }}>
|
||
<h4 style={{ color: 'var(--purple)' }}>🚀 Escort Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Protect an NPC convoy as it travels between systems. NPCs spawn ambushes along the route. The convoy must
|
||
survive. Failure = no reward + standing loss. Success = high reward + standing bonus. Group content (post-MVP).
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: High ISK + faction items · Time limit: 1–2h · Standing: +0.10 to +0.30 · Group recommended
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--amber)' }}>
|
||
<h4 style={{ color: '#f59e0b' }}>🔄 Trade Mission</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Buy a specific commodity at market price and deliver it to the agent. The agent reimburses cost + bonus.
|
||
Risk: market price may have moved since you accepted. Teaches market awareness and trade route planning.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Reward: Reimbursement + 10–30% bonus · Time limit: 2–6h · Standing: +0.02 to +0.08 · Market risk
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>NPC Agent Interaction</h3>
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Every station has 1–3 NPC agents.</strong> Agents are persistent characters with names, factions,
|
||
and specialties. A player's relationship with each agent is tracked via <strong>standing</strong> — a value from −10.0 to +10.0
|
||
that determines what missions the agent offers and what rewards they give. Higher standing unlocks harder missions
|
||
with better payouts.
|
||
</div>
|
||
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Agent Interaction Flow</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--cyan)' }}>1. Dock at station</span> — Agent Panel shows available agents at this station (with name, faction icon, standing, available missions count)<br/>
|
||
<span style={{ color: 'var(--accent)' }}>2. Select agent</span> — Agent portrait + dialogue box. Agent greets based on standing level (hostile/neutral/friendly/loyal). Lists available missions.<br/>
|
||
<span style={{ color: 'var(--green)' }}>3. Browse missions</span> — Each mission shows: type, brief description, reward estimate, location hint, time limit, difficulty tier. Player picks one.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>4. Accept mission</span> — Mission added to active journal. Waypoint auto-created in navigation. Objective markers appear on overview and map.<br/>
|
||
<span style={{ color: 'var(--red)' }}>5. Complete objectives</span> — Kill targets, deliver cargo, mine ore, scan sites. Journal tracks progress (0/5 pirates killed, etc.).<br/>
|
||
<span style={{ color: 'var(--fg)' }}>6. Turn in</span> — Return to agent (or any agent of same faction for courier). Reward paid. Standing updated. New mission unlocked.r/>
|
||
<span style={{ color: 'var(--muted)' }}>Fail: Time expires or objective becomes impossible → standing loss (−0.05 to −0.50). Can be declined before accepting with no penalty.</span>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Standing Mechanics</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Standing Range</th><th>Agent Attitude</th><th>Mission Access</th><th>Reward Modifier</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ range: '−10.0 → −2.0', attitude: 'Hostile', access: 'None — agent refuses to talk', reward: 'N/A' },
|
||
{ range: '−2.0 → +1.0', attitude: 'Neutral', access: 'Level 1 missions only (easy)', reward: 'Base reward ×0.8' },
|
||
{ range: '+1.0 → +3.0', attitude: 'Friendly', access: 'Level 1–2 missions', reward: 'Base reward ×1.0' },
|
||
{ range: '+3.0 → +6.0', attitude: 'Trusted', access: 'Level 1–3 missions (medium)', reward: 'Base reward ×1.2' },
|
||
{ range: '+6.0 → +8.0', attitude: 'Loyal', access: 'Level 1–4 missions (hard)', reward: 'Base reward ×1.5 + rare loot' },
|
||
{ range: '+8.0 → +10.0', attitude: 'Inner Circle', access: 'All levels + exclusive storyline arc', reward: 'Base reward ×2.0 + unique items + COSMOS missions' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td className="mono" style={{ fontWeight: 600, color: ['var(--red)', 'var(--red)', 'var(--fg-dim)', 'var(--green)', 'var(--cyan)', 'var(--accent)'][i] }}>{row.range}</td>
|
||
<td style={{ color: 'var(--fg)' }}>{row.attitude}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.access}</td>
|
||
<td className="mono">{row.reward}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>Gaining Standing</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Complete missions: +0.05 to +0.30 per mission (scaled by difficulty)</li>
|
||
<li>Faction-wide: completing a mission for Agent A improves standing with Agent B of the same faction (at 50% rate)</li>
|
||
<li>Storyline missions: every 16 missions of the same level triggers a storyline mission with large standing boost (+1.0 to +3.0)</li>
|
||
<li>Derived standing: faction standing affects all agents in that faction. corp standing is agent-specific.</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>Losing Standing</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Fail a mission: −0.05 to −0.50 (scaled by mission level)</li>
|
||
<li>Decline 2+ missions from same agent in 4h: −0.02 per decline after the first</li>
|
||
<li>Attack NPC of a faction: −0.10 to −1.0 (scaled by NPC importance)</li>
|
||
<li>Fail storyline mission: −1.0 to −3.0 (harsh penalty)</li>
|
||
<li>Standing decays toward 0.0 at 1% per day (prevents permanent locks)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Reward Scaling</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Level</th><th>Base Reward</th><th>Time Bonus</th><th>Loyalty Points</th><th>Skill Req.</th><th>Security Band</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ level: '1', reward: '5,000 – 15,000 ₢', bonus: '+20% if <30 min', lp: '50–150', skill: 'None', sec: 'High-sec' },
|
||
{ level: '2', reward: '15,000 – 40,000 ₢', bonus: '+25% if <45 min', lp: '150–400', skill: 'Industry II or Gunnery II', sec: 'High/Low' },
|
||
{ level: '3', reward: '40,000 – 100,000 ₢', bonus: '+30% if <60 min', lp: '400–1,000', skill: 'Industry III or Gunnery III', sec: 'Low/Null' },
|
||
{ level: '4', reward: '100,000 – 300,000 ₢', bonus: '+35% if <90 min', lp: '1,000–3,000', skill: 'Industry IV or Gunnery IV + ship class skill', sec: 'Null/Deep' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: ['var(--green)', 'var(--cyan)', 'var(--accent)', 'var(--red)'][i] }}>Level {row.level}</td>
|
||
<td className="mono">{row.reward}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.bonus}</td>
|
||
<td className="mono">{row.lp}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.skill}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.sec}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="callout callout-warn" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Loyalty Points (LP):</strong> Completing missions earns LP with the agent's faction. LP can be spent at faction stations
|
||
for faction-specific items (modules, ships, BPCs) at below-market prices. This creates a secondary currency that rewards
|
||
mission runners and cannot be traded between players. LP stores are faction-specific — Caldari LP can't be spent at Gallente stations.
|
||
</div>
|
||
|
||
<div className="section-header">
|
||
<span className="section-num">GP-MIS-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>New Tables, Reducers & Agent Updates</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--accent)' }}>npc_agents</span> — <code>agent_id, name, faction_id, station_id, specialty (kill/courier/mining/survey/trade/escort), quality (u32), mission_levels_offered, dialogue_seed</code><br/>
|
||
<span style={{ color: 'var(--cyan)' }}>mission_templates</span> — <code>template_id, type (enum), level (1–4), title, description_template, objectives_json, reward_base, time_limit_seconds, security_band_min, skill_requirements_json, faction_id</code><br/>
|
||
<span style={{ color: 'var(--green)' }}>active_missions</span> — <code>mission_id, player_id, agent_id, template_id, objectives_state_json, status (active/completed/failed/expired), accepted_at, expires_at, completed_at</code><br/>
|
||
<span style={{ color: 'var(--red)' }}>player_standing</span> — <code>player_id, entity_id (agent or faction), entity_type (agent/faction), standing (f64, −10 to +10), last_mission_at</code><br/>
|
||
<span style={{ color: 'var(--purple)' }}>player_loyalty_points</span> — <code>player_id, faction_id, lp_balance (u64), lifetime_earned (u64)</code><br/>
|
||
<span style={{ color: 'var(--fg)' }}>mission_offers</span> — <code>offer_id, agent_id, station_id, template_id, reward_modifier, expires_at, generated_at</code><br/>
|
||
<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>Reducers:</span> <code>accept_mission(offer_id)</code>, <code>complete_mission_objective(mission_id, objective_idx)</code>, <code>turn_in_mission(mission_id)</code>, <code>decline_mission(offer_id)</code>, <code>fail_mission(mission_id)</code><br/>
|
||
<span style={{ color: 'var(--accent)' }}>Agent update:</span> <code>npc_mission_refresh</code> (existing, 1800s) — generates 2–5 new offers per agent from template pool, weighted by faction state, player activity, and standing. Removes expired offers.
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-info">
|
||
<strong>Mission journal UI:</strong> A docked-only panel showing all active missions with objective progress, time remaining,
|
||
reward estimate, and a "set waypoint" button. In Flight Mode, active mission objectives appear as HUD indicators
|
||
(e.g., "Pirates remaining: 3/5" in the top-right corner). Mission completion triggers a notification toast.
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ TRAVEL & WARP ═══ */}
|
||
{activeTab === 'travel' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-TRAVEL</span>
|
||
<h2 style={{ margin: 0 }}>Travel & Warp Mechanics</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Click to autopilot — the player sets intent, the ship executes.</strong>
|
||
There is no manual flight control. The player clicks a destination (asteroid, station, stargate, bookmark,
|
||
or any point in space) and the ship navigates there. Travel has three modes: sub-warp (slow, in-system),
|
||
warp (fast, in-system), and gate jump (instant, inter-system). Each mode has different speed, acceleration,
|
||
and interaction rules. Travel time is the primary "geography tax" that makes distant systems feel distant
|
||
and creates real trade route logistics.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Travel Modes</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Mode</th><th>Speed</th><th>Use Case</th><th>Player Input</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ mode: 'Sub-Warp', speed: '150–300 m/s (ship speed stat)', use: 'Approach objects within 500km. Orbiting, mining range, docking approach.', input: 'Click target → “Approach.” Ship moves at base speed.' },
|
||
{ mode: 'Warp', speed: '3.0–6.0 AU/s (ship class dependent)', use: 'Travel within a system. Warp to station, belt, gate, bookmark, or any celestials.', input: 'Click target → “Warp To.” Ship aligns, then enters warp.' },
|
||
{ mode: 'Gate Jump', speed: 'Instant', use: 'Travel between star systems. Jump through a stargate to the paired gate in the destination system.', input: 'Click stargate → “Jump.” Must be within 2,500m of gate.' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: ['var(--cyan)', 'var(--accent)', 'var(--green)'][i] }}>{row.mode}</td>
|
||
<td className="mono">{row.speed}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.use}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.85rem' }}>{row.input}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Warp Mechanics — Detailed</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Warp Sequence</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--cyan)' }}>1. Align:</span> Ship turns toward destination. Align time = 2–8s by ship class (frigate fastest, battleship slowest).<br/>
|
||
<span style={{ color: 'var(--accent)' }}>2. Accelerate:</span> Ship reaches 75% of max speed while aligned. ~1s for frigates, ~3s for battleships.<br/>
|
||
<span style={{ color: 'var(--green)' }}>3. Enter Warp:</span> Ship enters warp tunnel. Speed ramps from 0 to max warp speed over 2s.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>4. Cruise:</span> Ship travels at warp speed (3–6 AU/s). Deceleration starts at 50% of remaining distance.<br/>
|
||
<span style={{ color: 'var(--red)' }}>5. Exit Warp:</span> Ship decelerates from warp speed to 0 over 2s. Appears 0–50km from destination.
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Warp Speed by Ship Class</h4>
|
||
<table className="data-table">
|
||
<thead><tr><th>Class</th><th>Warp Speed</th><th>Align Time</th><th>System Cross (30 AU)</th></tr></thead>
|
||
<tbody>
|
||
{[
|
||
{ cls: 'Frigate', warp: '6.0 AU/s', align: '2s', cross: '~7s' },
|
||
{ cls: 'Destroyer', warp: '5.0 AU/s', align: '3s', cross: '~9s' },
|
||
{ cls: 'Cruiser', warp: '4.5 AU/s', align: '4s', cross: '~11s' },
|
||
{ cls: 'Battlecruiser', warp: '3.5 AU/s', align: '6s', cross: '~14s' },
|
||
{ cls: 'Battleship', warp: '3.0 AU/s', align: '8s', cross: '~18s' },
|
||
].map((r, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: 'var(--accent)' }}>{r.cls}</td>
|
||
<td className="mono">{r.warp}</td>
|
||
<td className="mono">{r.align}</td>
|
||
<td className="mono" style={{ color: 'var(--fg-dim)' }}>{r.cross}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-warn" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Warp disruption:</strong> A warp scrambler module (medium slot, combat module) prevents the target ship from
|
||
entering warp while the scrambler is active and the target is within scram range (10km). If a ship is scrambled
|
||
while aligning, the warp is cancelled. If scrambled during warp exit, the next warp is blocked. This is the primary
|
||
PvP tackle mechanic. NPCs do not use warp scramblers in MVP (Phase 3+ only).
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Stargate Mechanics</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>Gate Jump Sequence</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
1. Warp to stargate (arrive 0–20km from gate)<br/>
|
||
2. Sub-warp approach to within <strong style={{ color: 'var(--fg)' }}>2,500m</strong> (activation range)<br/>
|
||
3. Click <strong style={{ color: 'var(--accent)' }}>"Jump"</strong> — ship activates gate<br/>
|
||
4. <strong style={{ color: 'var(--cyan)' }}>Jump delay:</strong> 5s (global cooldown per character, prevents rapid gate-hopping)<br/>
|
||
5. Ship appears at paired gate in destination system<br/>
|
||
6. <strong style={{ color: 'var(--purple)' }}>Gate cloak:</strong> 30s invulnerability after jump (ship is invisible to other players, cannot be targeted, cannot activate modules). Breaks early if you move or activate anything.<br/>
|
||
7. Player must warp away from gate before cloak expires or risk being targeted
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>Gate Guns & Security</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li><strong style={{ color: 'var(--fg)' }}>High-sec gates:</strong> No gate guns needed — CONCORD handles aggression.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Low-sec gates (+0.1 to +0.4):</strong> Gate guns fire on any aggressor within 150km. Moderate damage — can be tanked by battlecruiser+ for a short time. Guns do not prevent aggression, they punish it.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Null-sec gates (0.0 and below):</strong> No gate guns. No rules. Anything goes. Gate camps are a primary PvP activity.</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Weapons timer:</strong> 60s after any aggressive module activation. Cannot jump gates during weapons timer. Prevents "shoot and jump" tactics ("gate games").</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Docking & Undocking</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Docking</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
1. Warp to station (arrive 0–20km)<br/>
|
||
2. Approach to within <strong style={{ color: 'var(--fg)' }}>500m</strong> (docking range)<br/>
|
||
3. Click <strong style={{ color: 'var(--accent)' }}>"Dock"</strong><br/>
|
||
4. Docking is instant — ship disappears from space, player enters Station Mode<br/>
|
||
5. Cannot dock while weapons timer is active (60s after aggressive action)
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Undocking</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
1. Click <strong style={{ color: 'var(--accent)' }}>"Undock"</strong> in Station Mode<br/>
|
||
2. Ship appears outside station, moving at base speed away from station<br/>
|
||
3. <strong style={{ color: 'var(--green)' }}>Undock invulnerability:</strong> 20s. Cannot be targeted. Cannot activate modules. Breaks if you change direction or activate anything.<br/>
|
||
4. Player has 20s to assess the situation and warp to a safe location<br/>
|
||
5. No "station games" — you always get a safe undock window
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Autopilot & Route Planning</h3>
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Autopilot flies the route automatically, but at a cost.</strong> Players can set a multi-system route
|
||
(via waypoints) and activate autopilot. The ship will warp to each gate, jump, warp to the next gate, and repeat.
|
||
Autopilot is <em>slower</em> than manual piloting: it warps to 15km from each gate instead of 0km, requiring a
|
||
sub-warp approach each time. Manual pilots who click precisely arrive faster. Autopilot is a convenience,
|
||
not a replacement for active play.
|
||
</div>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--green)' }}>Manual Warp</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Click gate → "Warp To 0m" → arrive on grid</li>
|
||
<li>Jump immediately (within activation range)</li>
|
||
<li>Fastest possible travel</li>
|
||
<li>Requires active player attention at each gate</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--accent)' }}>Autopilot</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li>Set route → activate autopilot</li>
|
||
<li>Warps to 15km from each gate, approaches, jumps</li>
|
||
<li>~30% slower than manual (extra approach time per gate)</li>
|
||
<li>Vulnerable during gate approach (PvP risk in low/null)</li>
|
||
<li>Can be cancelled at any time by clicking anywhere</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-6)' }}>
|
||
<span className="section-num">GP-TRAVEL-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Travel-Related State & Reducers</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--accent)' }}>ships</span> — add column: <code>travel_mode</code> (enum: idle / aligning / in_warp / gate_jump / sub_warp_approach / docked)<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>ships</span> — add column: <code>gate_cloak_until</code> (timestamp, null when not cloaked). 30s after gate jump.<br/>
|
||
<span style={{ color: 'var(--green)' }}>ships</span> — add column: <code>undock_invuln_until</code> (timestamp, null when not active). 20s after undock.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>ships</span> — add column: <code>weapons_timer_until</code> (timestamp, null when not active). 60s after aggressive action.<br/>
|
||
<span style={{ color: 'var(--red)' }}>ships</span> — add column: <code>jump_cooldown_until</code> (timestamp). 5s global per character after gate jump.<br/>
|
||
<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>New reducer:</span> <code>warp_to(ship_id, target_system_entity_id, distance_km)</code> — validate not scrambled, begin align sequence.<br/>
|
||
<span style={{ color: 'var(--green)' }}>New reducer:</span> <code>jump_gate(ship_id, gate_id)</code> — validate within 2,500m, validate no weapons timer, validate cooldown expired, execute jump.<br/>
|
||
<span style={{ color: 'var(--accent)' }}>New reducer:</span> <code>dock(ship_id, station_id)</code> — validate within 500m, validate no weapons timer, set docked.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>New reducer:</span> <code>undock(ship_id)</code> — validate docked, place ship outside station, set 20s invulnerability.<br/>
|
||
<span style={{ color: 'var(--fg)' }}>New reducer:</span> <code>set_autopilot(ship_id, route_id)</code> — begin automated route following.<br/>
|
||
<span style={{ color: 'var(--red)' }}>New reducer:</span> <code>cancel_autopilot(ship_id)</code> — stop route following, resume idle.
|
||
</div>
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ WORLD EVENTS UX ═══ */}
|
||
{activeTab === 'events' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-EVT</span>
|
||
<h2 style={{ margin: 0 }}>World Event Player UX</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>The player needs to see, understand, and act on world events without leaving their current activity.</strong>
|
||
The backend pipeline (spawn → propagate → resolve → story log) is fully specified in the Dynamic Galaxy tab.
|
||
This tab specifies the <em>player-facing surface</em>: how events appear, what information is shown, and how
|
||
players interact with events in both Flight Mode and Station Mode.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Event Notification Tiers</h3>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.9rem', maxWidth: '680px', marginBottom: 'var(--sp-5)' }}>
|
||
Not all events are equally urgent. The notification system uses three tiers that determine how aggressively
|
||
the player is interrupted:
|
||
</p>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Tier</th><th>Trigger</th><th>Flight Mode</th><th>Station Mode</th><th>Examples</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ tier: '⚡ Critical', trigger: 'Event in current system, player directly affected', flight: 'HUD alert flash + audio ping + top-center banner. Pause-safe: combat continues but banner demands attention. Banner auto-dismisses after 10s or on click.', station: 'Modal dialog with event details + action buttons ("Warp to site"). Market panel may show price impact callout.', examples: 'Supernova warning, pirate raid on your station, faction invasion of your home system' },
|
||
{ tier: '📍 Nearby', trigger: 'Event in adjacent system or current region', flight: 'Side panel notification (slides in from right). No audio. Click to expand details. Dismisses when event resolves or player leaves region.', station: 'News feed sidebar item. Glowing dot on region map. Agent dialogue may reference it.', examples: 'Anomaly detected 2 jumps away, convoy departing nearby station, faction skirmish in adjacent constellation' },
|
||
{ tier: '📰 Background', trigger: 'Event anywhere in galaxy, not in player region', flight: 'Chat-style ticker in bottom-left corner. No interruption. Logged in story journal for later review.', station: 'Galaxy News tab in station UI. Story log entry. Price impact shown in market history charts.', examples: 'Distant faction war, migration route shift, station construction completed, cosmic catastrophe aftermath' },
|
||
].map((row, i) => (
|
||
<tr key={i}>
|
||
<td style={{ fontWeight: 600, color: ['var(--red)', 'var(--accent)', 'var(--fg-dim)'][i] }}>{row.tier}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.trigger}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.flight}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.station}</td>
|
||
<td style={{ color: 'var(--fg-dim)', fontSize: '0.82rem' }}>{row.examples}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Event Detail Panel</h3>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.9rem', maxWidth: '680px', marginBottom: 'var(--sp-5)' }}>
|
||
Clicking on any event notification opens the Event Detail Panel — a shared component used in both Flight and Station modes.
|
||
The panel shows everything the player needs to decide whether and how to participate:
|
||
</p>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Event Detail Panel Layout</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--red)' }}>Header:</span> Event icon + name + severity gauge (1–5 bar) + countdown timer to resolution/escalation<br/>
|
||
<span style={{ color: 'var(--accent)' }}>Location:</span> System name + region + distance in jumps + security level of target system<br/>
|
||
<span style={{ color: 'var(--cyan)' }}>Narrative:</span> 2–3 sentence in-universe description. "A Guristas raiding fleet has been spotted massing at the Ostingale gate. Local defense forces are overwhelmed."
|
||
<br/>
|
||
<span style={{ color: 'var(--green)' }}>Rewards:</span> Participation reward tier (bronze/silver/gold based on contribution). Expected ISK + LP. Special loot possibilities.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>Participants:</span> Live count of players at the event site. "12 pilots engaged" — signals competition or cooperation opportunity.<br/>
|
||
<span style={{ color: 'var(--fg)' }}>Actions:</span> <code>[Warp to Site]</code> (if in-system) / <code>[Set Route]</code> (if distant) / <code>[Watch]</code> (track without participating) / <code>[Dismiss]</code><br/>
|
||
<span style={{ color: 'var(--muted)' }}>History:</span> Collapsible log of event progression. "14:23 — First wave defeated. 14:31 — Boss spawned. 14:35 — CMDR Riker destroyed."
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Event Map Integration</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>System Map (Era 1)</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Events in the current system appear as pulsing icons at their location. Clicking an event icon on the map
|
||
opens the Event Detail Panel. Active events have a glowing radius showing their area of effect.
|
||
Resolved events fade to a dim marker for 5 minutes before disappearing.
|
||
</p>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>Galaxy Map (Era 2)</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Events across all systems appear as icons on the galaxy map, sized by severity and colored by type.
|
||
A filter sidebar lets players show/hide by type (faction conflict, anomaly, migration, catastrophe).
|
||
Hover shows tooltip with event name + countdown. Click opens Event Detail Panel.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Event Participation & Contribution Tracking</h3>
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Contribution determines reward.</strong> Players who arrive first and contribute most get the best rewards.
|
||
This is tracked server-side and is resistant to AFK exploitation.
|
||
</div>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>Contribution Metrics</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Damage dealt:</strong> to event NPCs (primary metric for combat events)</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Time on-site:</strong> must be present for ≥60s to qualify (anti-AFK)</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Logistics:</strong> remote repairs to other participants count at 80% of damage value</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Objective completion:</strong> hacking a can, mining a special asteroid, escorting the convoy</li>
|
||
<li><strong style={{ color: 'var(--fg)' }}>Early arrival:</strong> first 5 participants get a 10% bonus (rewards information speed)</li>
|
||
</ul>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>Reward Tiers</h4>
|
||
<ul style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0, paddingLeft: 'var(--sp-5)' }}>
|
||
<li><span style={{ color: '#cd7f32' }}>Bronze:</span> Any contribution. 50% base reward. Common loot table.</li>
|
||
<li><span style={{ color: '#c0c0c0' }}>Silver:</span> Top 50% contributors. 100% base reward + 100 LP. Uncommon loot table.</li>
|
||
<li><span style={{ color: '#ffd700' }}>Gold:</span> Top 10% contributors. 200% base reward + 500 LP + rare loot. Name appears in story log.</li>
|
||
<li><span style={{ color: 'var(--muted)' }}>AFK check:</span> If no client input for 90s while on event site, contribution pauses. Must take an action (module activate, move, target) to resume.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Story Log</h3>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Galaxy Story Log — The Server's History</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--cyan)' }}>Access:</span> Station Mode → Story Log tab. Also accessible from Galaxy Map sidebar.<br/>
|
||
<span style={{ color: 'var(--accent)' }}>Format:</span> Chronological timeline of all events, filterable by region/type/era. Each entry has headline + body + timestamp + participants list.<br/>
|
||
<span style={{ color: 'var(--green)' }}>Personal history:</span> A separate filter shows "Events I participated in" — the player's personal saga.<br/>
|
||
<span style={{ color: 'var(--purple)' }}>Persistence:</span> Story log is permanent. Even years later, a player can look back at "the Battle of Jita" and see the full narrative.<br/>
|
||
<span style={{ color: 'var(--fg)' }}>Search:</span> Full-text search across all entries. "What happened in Pure Blind last week?" → search results with highlighted entries.<br/>
|
||
<span style={{ color: 'var(--muted)' }}>Export:</span> Copy link to any story log entry for sharing in chat. "Did you see [this]?" with a clickable link to the event.
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-warn">
|
||
<strong>Design intent:</strong> The event UX must feel like <em>news</em>, not like a quest log. Players should discover events naturally
|
||
— through sensor alerts, chat rumors, price changes, or map icons — not through a mandatory event panel.
|
||
The notification system provides <em>awareness</em>; the detail panel provides <em>information</em>; the decision to participate
|
||
is always the player's choice. The best stories are the ones players tell each other: "You should have been at Jita yesterday —
|
||
there was a massive Guristas raid and I scored a faction BPC from the gold tier."
|
||
</div>
|
||
</>)}
|
||
|
||
{/* ═══ BALANCING AGENT ═══ */}
|
||
{activeTab === 'balancer' && (<>
|
||
<div className="section-header">
|
||
<span className="section-num">GP-BAL</span>
|
||
<h2 style={{ margin: 0 }}>Balancing Agent — Adaptive Economy & PvE Control</h2>
|
||
</div>
|
||
|
||
<div className="callout callout-info" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>This is at heart a PvE game.</strong> The environment has hostile elements — NPC pirates, faction raids,
|
||
anomalies — that challenge players and drain resources. But a static PvE difficulty can't adapt to a changing player
|
||
population or economy. The <strong>Balancing Agent</strong> is an automated system (similar to the world event agent) that
|
||
monitors key economic and gameplay metrics and adjusts hostile encounter rates, ISK faucet rates, and difficulty
|
||
to keep the game within healthy parameters. It is the invisible hand that keeps the galaxy challenging but fair.
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Metrics Monitored</h3>
|
||
<div style={{ overflowX: 'auto', marginBottom: 'var(--sp-6)' }}>
|
||
<table className="data-table">
|
||
<thead>
|
||
<tr><th>Metric</th><th>Source</th><th>Healthy Range</th><th>Tick Interval</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><span className="pill pill-green">ISK Velocity</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Total ISK earned per player-hour (faucets)</td>
|
||
<td className="mono">2,000–8,000 \u2262/hr</td>
|
||
<td className="mono">15 min</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-cyan">Price Index</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Weighted basket of commodity prices vs. baseline</td>
|
||
<td className="mono">0.85–1.15 (inflation-adjusted)</td>
|
||
<td className="mono">30 min</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-red">Player Death Rate</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Ship destructions per active player per hour</td>
|
||
<td className="mono">0.1–0.5 deaths/hr</td>
|
||
<td className="mono">10 min</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-purple">Faucet/Sink Ratio</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Total ISK created vs. destroyed per tick</td>
|
||
<td className="mono">0.95–1.05 (near balance)</td>
|
||
<td className="mono">30 min</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span className="pill pill-amber">Player Engagement</span></td>
|
||
<td style={{ color: 'var(--fg-dim)' }}>Active players / total registered players</td>
|
||
<td className="mono">> 40%</td>
|
||
<td className="mono">60 min</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Control Levers</h3>
|
||
<div className="grid-2" style={{ marginBottom: 'var(--sp-6)' }}>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--red)' }}>
|
||
<h4 style={{ color: 'var(--red)' }}>NPC Spawn Rate Multiplier</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Adjusts the base spawn rate of NPC pirates across all security bands. If ISK velocity is too high
|
||
(players are earning too fast), spawn rate increases to create more danger and ship losses.
|
||
If players are dying too much, spawn rate decreases to ease pressure.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Range: 0.5\u00d7–2.0\u00d7 · Applied per security band · Smooth transition (10% per tick)
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--accent)' }}>
|
||
<h4 style={{ color: 'var(--accent)' }}>NPC Difficulty Tier</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Shifts the NPC class distribution within each security band. Higher difficulty means more cruisers
|
||
in low-sec instead of frigates. This affects bounty payouts (ISK faucet) and ship destruction rates (ISK sink via insurance).
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Range: \u22121 tier to +1 tier from baseline · Applied per region · Shifts over 6 ticks
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--green)' }}>
|
||
<h4 style={{ color: 'var(--green)' }}>ISK Faucet Multiplier</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Directly scales all ISK faucets: NPC bounties, mission rewards, insurance payouts.
|
||
Used as a last resort when spawn rate and difficulty aren't enough. If the price index shows deflation
|
||
(players can't afford ships), faucet multiplier increases. If inflating, it decreases.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Range: 0.8\u00d7–1.2\u00d7 · Applied globally · Changed max once per 24h
|
||
</div>
|
||
</div>
|
||
<div className="card" style={{ borderLeft: '3px solid var(--cyan)' }}>
|
||
<h4 style={{ color: 'var(--cyan)' }}>World Event Frequency</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
Controls how often world events spawn. More events = more ISK entering the economy (event rewards)
|
||
and more engagement. Fewer events = calmer galaxy. Tied to engagement metric — if players are logging off,
|
||
event frequency increases to create excitement.
|
||
</p>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--muted)' }}>
|
||
Range: 0.5\u00d7–1.5\u00d7 spawn weight · Applied per event type · Updated hourly
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style={{ marginBottom: 'var(--sp-4)' }}>Agent Behavior</h3>
|
||
<div className="card card-accent" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>Balancing Agent Tick Pipeline</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2.2 }}>
|
||
<span style={{ color: 'var(--cyan)' }}>1. Collect metrics</span> — query ISK velocity, price index, death rate, faucet/sink ratio from SpacetimeDB aggregation tables<br/>
|
||
<span style={{ color: 'var(--accent)' }}>2. Compare to thresholds</span> — each metric has a healthy range; deviations trigger adjustment signals<br/>
|
||
<span style={{ color: 'var(--green)' }}>3. Weighted decision</span> — adjustments are weighted: spawn rate (40%), difficulty (30%), faucet multiplier (20%), events (10%)<br/>
|
||
<span style={{ color: 'var(--purple)' }}>4. Smooth application</span> — changes apply gradually (10% per tick toward target) to avoid jarring player experience<br/>
|
||
<span style={{ color: 'var(--red)' }}>5. Safety clamp</span> — all multipliers clamped to their ranges. If multiple metrics conflict, death rate takes priority (don't kill the newbies)<br/>
|
||
<span style={{ color: 'var(--fg)' }}>6. Log intervention</span> — every adjustment is logged in a balance_audit table for developer review. No silent changes.
|
||
</div>
|
||
</div>
|
||
|
||
<div className="callout callout-warn" style={{ marginBottom: 'var(--sp-5)' }}>
|
||
<strong>Visibility to players:</strong> The Balancing Agent is invisible by default. Players should never feel "the game
|
||
is adjusting difficulty." However, observant players may notice that NPC spawns increase after a quiet period or that
|
||
bounties are slightly lower during a gold rush. Zora may comment on market conditions ("NPC activity has been high
|
||
in this region lately") without revealing the underlying mechanism. The agent is a safety net, not a theme park ride.
|
||
</div>
|
||
|
||
<div className="section-header">
|
||
<span className="section-num">GP-BAL-DB</span>
|
||
<h2 style={{ margin: 0 }}>Backend Impact</h2>
|
||
</div>
|
||
<div className="card card-accent">
|
||
<h4 style={{ marginBottom: 'var(--sp-4)' }}>New Tables & Agent</h4>
|
||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.82rem', color: 'var(--fg-dim)', lineHeight: 2 }}>
|
||
<span style={{ color: 'var(--accent)' }}>balance_metrics</span> — <code>metric_name, current_value, healthy_min, healthy_max, last_updated, trend (rising/falling/stable)</code><br/>
|
||
<span style={{ color: 'var(--cyan)' }}>balance_levers</span> — <code>lever_name, current_multiplier, target_multiplier, clamp_min, clamp_max, last_adjusted_at</code><br/>
|
||
<span style={{ color: 'var(--green)' }}>balance_audit</span> — <code>audit_id, tick_time, metrics_snapshot_json, adjustments_json, reason</code><br/>
|
||
<br/>
|
||
<span style={{ color: 'var(--red)' }}>New agent:</span> <code>balancing_tick</code> (fixed interval, 900s) — collects metrics, evaluates thresholds, adjusts levers, logs audit entry
|
||
</div>
|
||
</div>
|
||
</>)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
window.GDD.GameplayPage = GameplayPage;
|