Skip to content

Missions

Missions are bite-sized objectives a player accepts in exchange for credits, reputation, or items. They give the open-world economy a guided spine: when a player isn't sure what to do next, the mission board has an answer.

Three families of mission share the same accept / track / complete pipeline:

Family Issuer Persistence Notable trait
Faction missions NPC factions (FactionMission) Persistent table; admin or generator-created Affect faction standing
Random missions Procedurally generated, pulled from a hat Generated on demand, pinned for the duration Capped per player
Daily quests System-issued, refreshed each game day One per slot, per player Expire at next refresh

✅ Shipped — FactionMission model, mission availability API (get_available_missions), reputation-gated filtering, basic acceptance / completion endpoints.

🚧 Partial — random mission generator, daily-quest scheduler, in-game mission journal UI, mission-chain branching.

📐 Design-only — escort missions, time-limited racing missions, multi-player co-op missions.

Faction missions

models/faction.py:FactionMission defines the persistent record:

id, faction_id, title, description,
mission_type        in {cargo_delivery, combat, exploration, diplomatic}
min_reputation      gates acceptance (default -800: anyone)
min_level           gates acceptance (default 1)
credit_reward, reputation_reward, item_rewards
target_sector_id, cargo_type, cargo_quantity, target_faction_id
is_active, expires_at, created_at

Mission types

Type Objective Typical reward Notable side-effect
cargo_delivery Move cargo_quantity of cargo_type to target_sector_id Credits + small rep Mercantile Guild favors this type
combat Destroy a target (NPC, drone field, or player faction enemy) Credits + meaningful rep Federation / Military faction missions
exploration Visit target_sector_id and scan Smaller credits + rep + map data Nova Scientific / Frontier favor this
diplomatic Carry a courier package between factions Credits + rep with both faction and target_faction_id Cross-faction; check rivalry caps

✅ Shipped — model + types. 🚧 Partial — completion verification per mission type (cargo manifest checking, scan-confirmation, kill verification all need the in-game integration glue).

Acceptance flow

GET  /api/v1/missions/available?faction_id=...
   → returns missions where:
       is_active = 1
       expires_at IS NULL OR expires_at > now
       reputation[faction_id] >= min_reputation
       player.level >= min_level

POST /api/v1/missions/{mission_id}/accept
   → checks reputation gate again (TOCTOU)
   → marks mission as accepted by this player
   → records acceptance timestamp

A player can carry a small number of active missions concurrently (target cap: 5). When at cap, the accept call is rejected. ✅ Shipped (acceptance) — 📐 Design-only (concurrent cap enforcement).

Completion flow

POST /api/v1/missions/{mission_id}/complete
   → verify acceptance
   → verify objective (type-specific)
   → award credit_reward
   → update_reputation(player, faction, reputation_reward, "mission_complete")
   → grant item_rewards (if any)
   → emit mission_completed

🚧 Partial — completion verification per mission type. Cargo and exploration missions can be wired to existing trade and movement events; combat and diplomatic require richer hooks.

Abandonment flow

POST /api/v1/missions/{mission_id}/abandon
   → verify acceptance
   → drop without reward
   → small reputation penalty (target spec: -5 with the issuing faction)
   → emit mission_abandoned

📐 Design-only — abandonment penalty (currently a no-op apart from removing acceptance).

Random missions

A pool of templates seeds short-form missions on demand. The generator picks a template, fills in parameters from the player's current sector and recent activity, and offers the result through the same API surface as faction missions.

📐 Design-only.

Template pool seeds: - "Bounty hunt" — pick a low-reputation NPC or pirate captain in current cluster. - "Salvage" — visit a wreck sector and recover X. - "Smuggling" — Fringe Alliance only; carry contraband while avoiding patrols. - "Distress beacon" — dynamic event-tied; finite window.

Daily quests

A small set of quests refreshes every game day at a fixed wall-clock hour (target: 00:00 UTC, configurable per region). Each player gets the same set; completion is per-player.

Slots (target spec):

Slot Objective shape Reward
Trade Complete N trades Credits + small faction rep
Combat Win N PvE encounters Credits + reputation
Travel Visit N sectors Credits + ARIA exploration map data
Social Send N messages or join a fleet action Small credits

📐 Design-only — daily-quest scheduler, refresh job, slot definitions.

Reward structure

All rewards funnel through three channels:

credits        -> Player.credits += credit_reward
reputation     -> FactionService.update_reputation(player, faction, delta, reason)
item_rewards   -> attached to player inventory (cargo / equipment / special items)

Reputation rewards interact with rivalry caps — gaining standing with one faction can be capped by current standing with its rival (see factions-and-teams.md).

Diplomatic missions can award reputation with two factions — typically a small positive with the issuer and a small negative with the target faction. The rivalry cap is checked separately for each.

Mission state machine

   AVAILABLE  --(accept)-->  ACTIVE
       ^                       |
       |                  (objective met)
       |                       v
       |                   COMPLETED
       |                       |
       |                  (reward paid)
       +--(abandon)----<-- ABANDONED
                |
            (rep penalty)

A mission row exists once and can be in any of these states. For per-player tracking the target spec uses a MissionAcceptance(player_id, mission_id, status, accepted_at, completed_at) join table.

📐 Design-only — MissionAcceptance model is not yet implemented; current code only checks reputation gates without persisting per-player acceptance.

Expiration

FactionMission.expires_at is honored by get_available_missions (mission filtered out once expired). A scheduled job should also mark expired missions inactive to prevent log clutter.

📐 Design-only — expiration sweeper.

Mission UI surface

In the player client, missions live in a dedicated panel: - Available list (filterable by faction, type). - Active list with progress markers (cargo counts, sector visit checklist, kill counters). - Completion modal with reward animation.

🚧 Partial — the API exists; the client surface is rudimentary.

Source map

Concern Path (target)
Faction mission model services/gameserver/src/models/faction.py (FactionMission)
Faction service (availability, create) services/gameserver/src/services/faction_service.py
Mission acceptance/completion service services/gameserver/src/services/mission_service.py (target — not yet split out)
REST routes services/gameserver/src/api/routes/missions.py (target)
Random mission generator services/gameserver/src/services/mission_generator.py (target)
Daily quest scheduler services/gameserver/src/services/daily_quest_scheduler.py (target)
  • factions-and-teams.md — faction standing, rivalries, and the reputation table that gates mission access.
  • bounties.md — bounty hunting overlaps with combat-type faction missions but uses a separate mechanism.
  • SYSTEMS/turn-regeneration.md — daily-quest refresh shares scheduling infrastructure with turn ticks.