Gameplay Systems¶
NPC factions, mission tables, and the regional governance / diplomacy stack. The turn system is implemented as plain integer counters on Player (turns, turn_reset_at) and Galaxy.default_turns_per_day rather than a dedicated entity, so it doesn't get its own model section.
Faction¶
Source: services/gameserver/src/models/faction.py
Purpose: NPC political/economic entity. Controls territory, biases prices, and gates faction-locked sectors via player reputation.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(100) | unique, not null, indexed | |
| faction_type | Enum factiontype (custom FactionTypeDB) |
not null | Archetype slot for the lore faction. Six archetype values plus Pirates; the lore name lives on Faction.name. See FEATURES/gameplay/faction-lore.md for the canonical lore-name ↔ archetype mapping (Terran Federation, Mercantile Guild, Frontier Coalition, Astral Mining Consortium, Nova Scientific Institute, Fringe Alliance, Pirates). |
| description | Text | nullable | |
| territory_sectors | ARRAY(UUID) | default [] | sector UUIDs under faction control |
| home_sector_id | UUID | nullable | primary HQ sector (no FK constraint) |
| base_pricing_modifier | Float | default 1.0 | 0.8 = 20% discount, 1.2 = 20% markup |
| trade_specialties | ARRAY(String) | default [] | commodities focus |
| aggression_level | Integer | default 5 | 1-10, drives NPC behavior |
| diplomacy_stance | String(50) | default neutral |
hostile/neutral/friendly |
| color_primary, color_secondary | String(7) | nullable | hex |
| logo_url | String(255) | nullable |
Relationships:
- reputation_records → Reputation (1:many cascade).
- missions → FactionMission (1:many cascade).
Faction.get_pricing_modifier(player_reputation) and can_access_territory(player_reputation) encode price tiers and access gating.
FactionMission¶
Source: services/gameserver/src/models/faction.py
Purpose: Faction-issued mission with rewards and reputation effects.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| faction_id | UUID FK factions.id | not null, CASCADE, indexed | |
| title | String(255) | not null | |
| description | Text | nullable | |
| mission_type | String(50) | not null | cargo_delivery/combat/exploration/… |
| min_reputation | Integer | default -800 | gate |
| min_level | Integer | default 1 | |
| credit_reward | Integer | default 0 | |
| reputation_reward | Integer | default 0 | signed |
| item_rewards | ARRAY(String) | default [] | |
| target_sector_id | UUID | nullable | no FK |
| cargo_type | String(50) | nullable | for delivery missions |
| cargo_quantity | Integer | nullable | |
| target_faction_id | UUID | nullable | for diplomatic/combat missions |
| is_active | Integer | default 1 | stored as integer 0/1 |
| expires_at | DateTime | nullable |
Relationships: faction.
Player Ranking (in-place on Player)¶
Ranking is not a separate table. Player.military_rank (String, default Recruit) and Player.rank_points (Integer) hold progression. Personal alignment is Player.personal_reputation (-1000..+1000) with cached reputation_tier and name_color strings. See ./player.md for the full Player schema. Rank/reputation columns were added in migration fe22441146b1.
Regional Governance Stack¶
These models live in services/gameserver/src/models/region.py alongside Region itself (covered in ./galaxy.md). They implement the in-game political loop: membership → vote weight → elections, treaties, policies.
RegionalMembership¶
Purpose: A player's standing inside a specific region.
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | not null | |
| region_id | UUID FK regions.id | not null | |
| membership_type | String(50) | default visitor |
visitor/resident/citizen |
| reputation_score | Integer | default 0, -1000..1000 | check constraint |
| local_rank | String(50) | nullable | |
| voting_power | DECIMAL(5,4) | default 1.0, 0.0–5.0 | check constraint |
| joined_at, last_visit | TIMESTAMP | server defaults | |
| total_visits | Integer | default 0 |
Unique: (player_id, region_id). Relationships: player, region.
InterRegionalTravel¶
Purpose: Tracks a single cross-region travel job and any asset transfer.
Columns: id, player_id FK, source_region_id FK, destination_region_id FK (must differ — check), travel_method (platform_gate/player_gate/warp_jumper), travel_cost (≥0), assets_transferred JSONB, initiated_at, completed_at, status (in_transit/completed/failed/cancelled).
RegionalTreaty¶
Purpose: Bilateral region-to-region agreements.
Columns: region_a_id FK, region_b_id FK (must differ), treaty_type (trade_agreement/defense_pact/non_aggression/cultural_exchange), terms JSONB, signed_at, expires_at, status (default active). Unique on (region_a_id, region_b_id, treaty_type).
RegionalElection¶
Purpose: Election for a regional position (governor, council_member, ambassador).
Columns: region_id FK, position, candidates JSONB (array of {player_id, platform}), voting_opens_at, voting_closes_at (must be after open), results JSONB, status (pending/active/completed/cancelled).
Relationship: votes → RegionalVote (1:many cascade).
RegionalVote¶
Columns: election_id FK, voter_id FK players.id, candidate_id FK players.id, weight DECIMAL(5,4) default 1.0 (0.0-5.0), cast_at. Unique on (election_id, voter_id).
RegionalPolicy¶
Purpose: Policy proposal / referendum within a region.
Columns: region_id FK, policy_type (tax_rate/pvp_rules/trade_policy/…), title, description, proposed_changes JSONB, proposed_by FK players.id, proposed_at, voting_closes_at (after proposed_at), votes_for (≥0), votes_against (≥0), status (voting/passed/rejected/implemented).
approval_percentage, is_passing are computed from votes against Region.voting_threshold.
Game events¶
Source: services/gameserver/src/models/game_event.py (not detailed here — the file contains scheduled/active world events and is referenced by Galaxy.events JSONB and Sector.active_events). New code that touches event scheduling should refer to that model directly.
Notes¶
- Faction membership and player faction standing live in
Reputation(per-faction row, see./player.md). - Region-level reputation lives in
RegionalMembership.reputation_score. These two are independent: a player can be hated by Pirates faction (Reputation row) yet be a high-rep citizen of a player-owned region (RegionalMembership row). Player.military_rankandPlayer.rank_pointsare the achievement-progression dimension that is independent of either reputation system.