sots-re/findings/subsystems/ui-screen-map.md

207 lines
45 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SOTS1 — UI Screen Map & High-Level Flow
**Build analysed:** `sots.gob` / `sots_local_en.gob` dated 2010-04 (Complete Collection + Argos Naval Yard data set) driven by `Sword of the Stars.exe` 1.8.1 (GOG 2017 rebuild). So this is the *final* SOTS1 UI surface, not the 2006 launch one — cut/legacy remnants are called out in §5.
**Method (Ghidra-free):** the brief assumed a tree of per-screen `GUI/**/*.script` layouts. **That tree does not exist.** The whole archive holds exactly four `.script` files (`GUI/BorderSprites.script`, `GUI/StarMap/Lines.script`, `TechTree/TechTreeDisplay.script`, `Models/Planets/PlanetResources.script`), none of which is a widget layout — SOTS1 screens are **built in C++ on the `Mars` control framework**. The map below is therefore reconstructed from five independent evidence layers that all agree with each other:
| Layer | Source | Size |
|---|---|---|
| Texture folders | `GUI/**` in `list_sots.gob.txt` | 396 files in 19 folders, named per screen |
| Sprite table | `GUI/SpriteTable.csv` | ~1,950 sprites; names are `<SCREEN>_<WIDGET>_<STATE>` |
| String tokens | `Locale/EN/Strings.csv` | 5,200 rows in ~200 prefixes; prefix = screen/dialog |
| UI sound hooks | `Sounds/sound_ui.csv` | 50 events, several screen-specific |
| Class names | `classes-game.txt` (1,404) / `classes-mars.txt` (194) | ~300 `*Panel/*Dialog/*Screen/*View/*List` types |
| Layout constants | `Data/globals.txt`, `Data/tutorial.txt` | panel widths/colours, tutorial page list |
`Manual.pdf` (87 pp, in `sots-game/`) was used only as a cross-check of the flow; its TOC matches the screen list below 1:1.
---
## 1. The UI framework (`Mars`)
Engine side (`classes-mars.txt`):
- **Containers:** `Control` → `Panel`, `Dialog` (+`DialogUnderlay`), `DockablePanel`, `ClipPanel`, `ListPanel`, `ScrollPanel`(Game), `PanelManager`/`IPanelManager`, `Frame`/`ModelFrame`.
- **Widgets:** `Button`, `TextButton`, `IconButton`, `IconToggleButton`, `LCRButton` (left/centre/right 3-slice), `MicroButton`, `ToggleMicroButton`, `CheckBox`/`CheckBoxBase`/`CheckBoxList`, `DropDownList` (+`ListUnderlay`), `EditView`/`IEditView`, `ListBox`, `ListView`/`IListView`, `ListFramework` (+`Item`, `ClipPanel`), `ListColumn`, `TextListBase`, `Scrollbar`, `GradientSlider`, `TextView`/`TextViewBase`/`BulkTextPanel`, `Picture`, `Menu`/`IMenu`, `Movie` (Bink), `ProgressPainter`, `Font`/`ScalingFont`/`FontDictionary`, `GUIResources`.
- **Drag & drop:** `IDropSource` / `IDropData` / `IDropTarget` — used by the fleet manager, build queue, defence manager, combat reserves and lobby slots (`UI_DRAG_START/STOP` sound).
- **Sprites:** `Sprite`, `SpriteTable` (+`SpriteTableRowParser`). The table header documents the **9-slice convention**: `CORNER` (flipped), `VEDGE`/`HEDGE` (stretched), `CENTER`. Generic skins: `MARS_BUTTON_*`, `MARS_LCRBUTTON_*`, `MARS_SCROLLBAR_*`, `MARS_LIST_*`, `MARS_SLIDER`, `MARS_CHECKBOX`, `MARS_ARROW_BUTTON`, `MARS_FUZZY_BORDER` — all cut from `GUI/StarMapElements.tga` / `StarMapBorders.tga` / `Arrows.tga` / `fuzzyedge.tga`.
- **Sound:** `UISoundCSVRowParser` reads `sound_ui.csv` (button click/rollover, list open/close, tree expand, dialog query/ok/cancel, exit-screen, etc.).
- **Scripts:** `Script`/`IScriptable` parse the brace-block format; `Mars::Sprite` reads `BorderSprites.script` (the blue main-menu dialog border, 11 sprites from `GUI\MainMenu\MenuBorder.tga`).
Game-side generic UI (`classes-game.txt`): `Screen`, `ScreenBar` (+`ToggleList`), `TitleBar`, `PropSheet`/`PropPage`, `MessageBoxA`, `EditMessageBox`, `PlayerMessageBox`/`PlayerMessage`, `PieChartPanel`, `StatsGraphPanel`, `MoviePanel`, `ImageCheckBox`/`PlayerImageCheckBox`, `StackedSliderEditCombo`, `HealthIconPanel` (`Crosses.tga`/`xpoints.tga` danger/warning/good), `Rotator`, `MutexScreen`, `AutoJoin`/`AutoJoinBackground`.
Layout constants live in `Data/globals.txt` (`PANEL_SEPARATION 5`, `STATUSPANEL_MIN_WIDTH 480`, `BUDGETBAR_WIDTH 150`, `DESIGN_SIDEBAR_WIDTH 200`, `DESIGN_DESIGNLIST_WIDTH 180`, `EVENTSTICKER_OVERLAP 10`, popup/main-menu colours, all `COMBATHUD_*` model/marker settings) — i.e. what little is data-driven is *tuning*, not layout.
---
## 2. Screen catalog
Format: **Screen** — evidence (textures / sprites / tokens) → key labels → `Game::` classes → underlying subsystem.
### 2.1 Front end
| # | Screen | Evidence | Key labels | `Game::` UI classes | Subsystem |
|---|---|---|---|---|---|
| F1 | **Splash / intro** | `GUI/SplashArt/Frontend/Title/{gamespy_splash_A,kerberos_splash_B}.tga`; `UI_KERBEROS_SPLASH` (gui_growl.wav); `Movies/sotsintro.bik` | — | `IntroView`, `IntroViewCameraCtl`, `IntroCameraInfo`, `MainMoviePanel`, `IntroOverlay::MainMenuPanel` | `Mars::AppStartup`, `Mars::Movie` |
| F2 | **Main menu** (3-D nebula backdrop) | `GUI/MainMenu/{Title,IntroA-C,NebulaA-F}.tga`, `FrontEnd_Buttons.tga` (`MAINMENU_BUTTON`), `MenuBorder.tga` (`MAINMENU_DIALOGBG`), `BorderSprites.script`; `MAINMENU_BTN_*` | Profiles · Single Player · Host Multi-Player · Join Multi-Player · Load Game · Tutorial · Options · Credits · Cinematics · Exit; MOTD | `MainMenuPanel`, `MainMenuMOTD` (+`ClipPanel`), `MOTD` | MOTD fetched from `www.kerberos-productions.com/motd` |
| F3 | **Profile manager** | `PROFILEMAN_*`; `GUI/Achievements/*.tga` (56 badges); `Badges/`, `Avatars/` sprite sets | Create/Delete/Switch profile; Species / Played / Won / Lost; Badges Unlocked; "Highest Progression Wars Stage" | `ProfileManagerPanel`, `ProfileInfoPanel`, `CreateProfileDialog`, `DeleteProfileDialog`, `SwitchProfileDialog`, `PlayerAvatarSet`, `PlayerBadgeSet`, `PlayerColorSet` | `Profiles/Profile_*.ini`, `lastprofile.dat` (from string-intel) |
| F4 | **Options** | `OPTIONS_*` (38), `FILTER_*`, `HOTKEYS_*` (20), `KEYID_*` (113), `KEYMOD_*`; `Data/options.txt` (volume test sounds) | Audio (master/SFX/speech/GUI/music, channels, freq, bitrate, hardware) · Display (adapter, resolution, fullscreen, object/shader/texture detail, filtering, stars, brightness, particle distance) · Input / Key Bindings (tabs General/Strategy/Combat) | `OptionsPanel`, `AudioOptionsPanel`, `DisplayOptionsPanel` (+`InGameCheck`), `HotKeysPanel`, `HotKeysPropSheet`, `HotKeysPage`, `HotKeyList` | ini keys `adapter,width,height,fullscreen,antialiasing,brightness,MusicVolume…`; **key bindings are read-only in UI** ("can be changed in the profile ini file") |
| F5 | **Credits** | `GUI/Credits/{bink,gamespy}.tga`; `Data/credits.txt` (in *local* gob) | — | `CreditsPanel` | — |
| F6 | **Tutorial** | `Data/tutorial.txt` (page 0 = 7 videos `Movies/Tutorial/01-setup…07-combat.bik`; pages 1–14 text+image); `GUI/Tutorial/page*.tga` (pages 9–11 live in `sots_local_en.gob`); `TUTORIAL_*` | Tutorial · Combat · Strategy Screen · Research · Design · Build · Moving · Node Travel · Hiver Gates · Fleet Information · Planet Info · Colonizing · Special Functions · Final Notes | `TutorialPanel` (+`VideoButtonPanel`) | also a playable scenario `Scenarios/Tutorial/Tutorial.txt` ("Basic Tutorial") |
| F7 | **Cinematics** | `MAINMENU_BTN_MOVIES`; `Movies/{amocintro,antiquarians,bobintro,lhintro,sotsintro}.bik` | Cinematics | `MoviePanel` | Bink (`binkw32.dll`) |
| F8 | **Game-mode chooser** | `GUI/MainMenu/ChooseGameButtons.tga` (`GAMESETUPOPTIONS_ICON_{CUSTOM,SCENARIO,SINGLEPLAYER,INTERNET,LAN,BG}`); `GAMESETUPFE_*` | Custom / Scenario × Single Player / LAN / Internet; titles "Play Single Player", "Host Multiplayer", "Join Multiplayer", "Load Game" | `GameSetupOptions`, `GameSetupOptions_CheckBox` | — |
| F9 | **Game setup (custom)** | `GUI/GameSetup/GameSetupElements.tga` (icons AI/Player/Options/Timer/Money; **30 star-map shape icons**; 6 species); `GAMESETUP_*` (59), `MAPSHAPE_*` (25); `Maps/*.csv` custom maps; `UI_GAMESETUP_ROLLOVER/CONFIRM` | Star Map Setup (shape, Star Density, Number of Stars, Distance ly, Size, Resources, Suitability) · Available Species · Economic/Research Efficiency · AI Easy/Normal/Difficult · Initial Treasury/Colonies/Technologies · Options: Alliances, Random Encounters %, Lobby/Player Passwords, Teams (+Grouped), Win Ratio · Time: Strategic Turn Length, Combat Turn Length, Combat Query Time Limit (+per-additional-round) · Create Game / Cancel Game | `GameSetupPanel`, `CustomSetupPanel`, `CustomSetup_Maps`, `GameSetup_AI/LSE/MapSelect(+Impl)/MapView(+IconOverlay)/Money/Name/Option/Options/Player/Species/Time`, `CustomMapRowParser`; legacy `OldGameSetupPanel` | `StrategyGameCreateParams`, `StrategyGameParams`, `StrategyTimerParams`, `StarMapParams`, `Data/Strategy/starmap.txt`, `RealSpace.csv` |
| F10 | **Scenario setup** | `GUI/GameSetup/Scenario_Set_A…H.tga` (16 scenario images; `Set_C` is in the local gob); `SCENARIO_*` (149) | Description / Rules / Objectives pages; 14 scenarios: Jewels of the Crown, Hungry Children (HiverInvasion), Upstart Apes (key `EARTHVSTARKAS`), Holy Lands, A New Hope (CivilWar), His Master's Voice, Lords of a Broken Empire, The End of Flesh, Basic Tutorial, Tourney Space, Progression Wars, The Gathering, Land Grab (S/M/L), Antiquarians | `ScenarioSetupPanel`, `ScenarioSetup_Maps`, `GameSetup_ScenarioPages/ScenarioScene/ScenarioSelect`, `ScenarioPageBase`, `ScenarioDescPage`, `ScenarioObjPage`, `ScenarioRulesPage`, `ObjectivesPanel` | `SVScriptObject` → 33 `SVSO*` classes (one per scenario/encounter script) + `Scenarios/*.txt/.csv`, `StrategyScriptParams` |
| F11 | **Load game** | `GAMESETUP_LOAD_*`, `GAMELIST_*`, `GAMECARD_*`, `GAMEINFO_*` (12); `SOTS_GAME_{AUTOSAVE,AUTOSAVEBACKUP,REJOINSAVE,ENDTURN_AUTOSAVE,ENDTURN_AUTOSAVEBACKUP}` | Select saved game; card shows Galaxy Type, Stars, Players, Turn, Version, Economy, Research, Turn/Combat Time, Alliances, Encounters, Teams; Delete | `StrategyGameList` (+`Item`), `GameInfoPanel`, `CustomDataTable::StrategyGameLoader` | `StrategyGameLoadParams`, `.sav` |
| F12 | **Game browser** (Join MP) | `GAMEBROWSER_*`, `SERVERPAGE_*`, `FILTERDLG_*`, `MANUALJOIN_*`, `CHAT_*`, `CHATCHANNEL_*`, `MATCHINGSERVICE_*`, `NETERROR_*` (13, **none CD-key** — corrected by lane G2, see [[multiplayer-gamespy]] §1), `AUTOJOINERR_*`; `GUI/CrossFireLoad.tga` (`AUTOJOIN`) | Pages LAN / Internet / Internet Chat; server list (Game Name, Players, Ping, Password, Status, Version); Edit/Apply Filter; Join Manually (Favorites); Refresh; Join; `/join addr[:port]` command | `GameBrowserScreen`, `GameBrowserPanel` + nested `LANPage`, `InternetPage`, `ChatPage`, `ServerPage`, `ServerList`, `GameDisplay`, `GamePlayers`, `GBMOTD`, `FilterDialog`, `ManualJoinDialog`, `EnterPasswordDialog`; `AutoJoin`, `AutoJoinBackground`; `ChatMonitor`, `ChatHistoryView` | GameSpy master/chat (IRC-style), NatNeg; `StrategyJoin` (+`ProgressDialog`) |
| F13 | **Lobby** (host & join; also the MP *between-turns* room) | `GUI/Lobby/{LobbyBG,LobbyElementsA-C}.tga` (`SLOTPANEL_*`, `SLOT_BUTTON_{PASSWORD,KICK,OPEN,CUSTOMAI,AI}`, `SLOTUSER_{AI,DEAD}`, `SLOTSPECIES_*`, `LOBBY_COLOR_*`, `AVATAR_RANDOM`, `BADGE_RANDOM`); `LOBBY_*` (45), `LOBBYSTATUS_*`, `PLAYERSETUP_*` (17), `HOSTMIG*` (24), `TIMERSDLG_*`, `AIPOLICY_*`, `SYSTEMMSG_*` | Launch / Leave Game / Cancel Game / Ready; slots Open/Closed/AI/password/kick/lock; Player Setup (Name, Species, Color, Badge, Avatar, Team, Settings); Game Status (Strategic round… / Resolving combat… / Querying for combat…, "%s of %s players still playing", "%s battles in progress"); in-progress join ("will enter the game when the next turn begins"); Downloading game data; host migration | `StrategyLobbyScreen` (+`EnterPasswordDialog`, `MOTDDialog`, `PasswordStatus`, `SpeciesInfoPanel`, `TurnInfoPanel`), `SlotPanel`, `LobbySlotPanel`, `SlotDetailsPanel`, `PlayerSetupPanel`, `SpeciesSelectDialog`, `SpeciesDescPanel`, `LobbyChat`, `ChatDialog`, `AIPolicyDialog/Panel`, `SetTimersDialog`, `ServerMigrationStatusPanel` (+`ConfirmAbortDialog`), `ClientMigrationStatusPanel`, `StrategyHost` (+`ProgressDialog`, `ContinueDialog`, `SHMOTD`) | `SNMSlot*` (14 msgs), `SNMJoin*`, `SNMLobbyChat`, `SNMSetTimers`, `SNMSetAIPolicy`, `SNMMakePlayerAI`; `FNM*` chunked file transfer for migration/rejoin; `StrategySessionParams`, `StrategyHostParams` |
### 2.2 Strategy layer (the turn screen and its children)
| # | Screen | Evidence | Key labels | `Game::` UI classes | Subsystem |
|---|---|---|---|---|---|
| S1 | **Strategy map screen** (root of the turn) | `GUI/StarMapElements.tga` (136 sprites), `StarMapBorders.tga` (82), `GUI/StarMap/*` (lines, gate/move icons, `MapFade`, `PlayerColorBand`, `StatusBox`), `StarMap/Lines.script` (MoveLine green/red range segments, NodeLine, DistanceLine, FleetLine with per-drive arrow textures STL/Warp/Stutter/Node/Teleport/Farcast/Flock, GateLine, TradeLine); `Star.tga`, `disc.tga`, `ring.tga`, `piegradient.tga`; `UICSTR_*` strategic hotkeys | camera orbit/zoom; Home System; Focus/Zoom; Select Next/Prev Colony / Idle Fleet / Trade Sector | `StrategyMapScreen` (+`DebugOverlay`), `StarMapPanel`, `StarMapCameraPanel`, `StarMapEdgePanel`, `MiniStarMapPanel`, `StarMapNode`, `StarMapLine`, `StarMapNodeLine`, `StarMapLinePainter`, `NodeLinePainter`, `NodeLineDesc`, `FleetLine`, `GateLine`, `TradeLine`, `TradeLinePainter`, `TradePainter`, `TradeSectorPainter`, `StrategyClient`/`StrategyClientData` | `StarSystem`, `ClientNodeGraph`/`ServerNodeGraph`, `NodePath`/`NodeRoute`/`SimpleNodePath`, `StrategySim` |
| S1a | **Screen chrome** (bottom bar, status panel, empire bar, ticker) | sprites `SCREENBAR_*`, `SCREENBAR_EXIT`, `ENDTURN_*` (LCR button), `EXITSCREEN`, `TICKER_*`, `EMPIRE_OPENBTN` (`BudgetButton.tga`), `EMPIREBUDGET_*` / `EMPIRE_SLIDER_*`; `GUI/Bar_Buttons.tga` (`BARBUTTON_{POLMAP,TRADE,RESEARCH,DESIGN,BUILD,DIPLOMACY,INTEL,RANKINGS,EVENTS,TECHTREE,POPULATIONS,OLDTRADE,OLDALLIANCE}`), `ticker_buttons{,2,3}.tga` (`BARBUTTON_{CHAT,INFO,FLEETLINES,STARS,OBJECTIVES,SENSORNET,SURRENDER,TOGGLE,ENEMYNODES}`); `STRATEGY_END_TURN`, `STATUS_*`, `PLAYERSTATUS_*`, `TOOLTIP_BARBUTTON_*` (14), `COMMON_BUDGETBAR_LEFT/RIGHT` | End Turn / Game Over / Eliminated; Exit; savings↔research slider; status list NAME / STATUS / ROUNDS / TIME REMAINING with per-player status (Playing, Done, Querying, Staging, Fighting, Eliminated, AI) and alliance indicators; buttons Ranks / Diplomacy / Intel Analysis / Empire Civilian Settings; toggles Chat, Star Brightness, Fleet Lines, Objectives, Political Map, Trade View, Sensor Network, Enemy Node Paths, Galactic Axes, Options | `ScreenBar` (+`ToggleList`), `StatusPanel` (+`PlayersPanel`), `EmpireBar`, `EventsTickerPanel`, `ObjectivesPanel`, `ObjectiveListView(Item)`, `PlayerIconList` (+`Clipper`), `ChatControl`, `ChatEditControl`, `ChatInputControl`, `ChatHistoryPanel`/`ChatHistoryPanel2`, `ChatMessageListPanel`, `PlayerNotePanel`/`PlayerNoteButton` (`StickyNoteElements.tga`, `NOTEPAD_*`), `QuitStrategyGameDialog` (`STRATDLG_*`), `SaveGameDialog`/`SaveGameMessageBox` (`SAVEGAMEDLG_*`), `SurrenderDialog` (+`PlayersOverlay`, `ConfirmDialog`) | `TurnCommands`, `StrategyTurnInfo`, `SNMEndTurn`, `SNMTurnInfo`, `SETurnEnd*`; `PlayerNotes` |
| S2 | **System / planet panel** (selected star) | `GUI/SystemPanels.tga` (`SYSINFO_*`, `POPMAN_*_ICON`), `StarMap/SystemUI/*` (`SatRing`, `HomeSystem`, `Unexplored`, `SystemCaps`, asteroid ring, `PC_Insert`), `SYSINFO_*` (18), `SYSSUM_*` (24), `STATIONSUM_*`, `STATIONTYPE_*` (Command/Science/Repair/Sensors/Trade/Habitat); `ClimateHazard`/`Overharvest`/`SystemBudget` slider skins | Name, Owner, Size, Resources, Climate Hazard, Population (Imperial/Civilian/Slaves), Infrastructure, Industrial Output, Income, Gates, Defenses; **five sliders**: Overharvest, Construction↔Trade, Terraforming, Infrastructure, Ship Construction; buttons Research / Design / Build, Abandon, Manage Civilians / Slaves / Defenses, View Enemy Defenses, Notes; "Stations at %s" Activated/Deactivated/Under Construction | `SystemViewPanel`, `SystemSummaryPanel` (+`Overlay`), `SystemSummaryList`, `StrategySystemInfo`, `SystemRateSliders`, `SystemTradeSlider`, `ClimateControl`, `ClimateHazardBar/Slider`, `PopulationSlider`, `SpeciesSlider` (+`Overlay`), `StationSummaryPanel/Popup`, `StationDetailsPanel`, `StationIcons`, `SensorInfoPanel`, `ConfirmAbandonColonyDialog` | `StarSystem`, `Planet`, `ServerSystem`/`ClientSystem`, `SystemParams`, `Station`, `Population`, `SystemBuildQueue` |
| S3 | **Fleet panel** (fleets at selected system / sector / deep space) | `StarMap/FleetUI/RoundButton.tga`, `system_tab_fleet_icons.tga` + `UserHUDElements.tga` (`FLEETCARD_ICON_*` per race + Refugees/Artifact), `ACTION_ICON_*` (16 small + 16 large from `SystemUI/*.tga`), `GUI/RefuelElements.tga` (`SUPPORT_*`); `FLEETINFO_*` (15), `FLEETFILTER_*` (19), `FLEETSORT_*`, `FLEETDETAILS_*`, `FLEETMENUITEM_*`, `SHIPACTION_*` (15), `ACTIONDLG_*` (30), `MOVEWARNING_*` (17), `MISC_FLIGHTPLAN_*`, `SUPPORT_*`/`REFUEL_`/`REPAIR_`; `UI_AUTO_REFUEL/REPAIR` | "Fleets at %s / in %s / nearby"; Manage Fleets · Move · Special (Colonize, Deploy Gate, Mine, Refine, Dump Ore, Refuel, Repair, Stop, Scuttle, Build, Build/Deploy/Extract Spy, Colony/Mining Trap, Dismantle Trap, Transfer Slaves, Flag as Guard/Raider); Add To New Fleet / Split Ships / Add Note; filters (In Transit, Recent Combat, With Colonizers/Refineries/Miners/Repair/Tankers/Gate/CnC/NodeBore/Freighters/Slave/Police/Construction/Flagships/Deep Scans); move warnings (node range, gate capacity, node-bore path limits, trade-sector node rules) | `StrategyFleetInfo` (+`FleetMenuSource`, `FleetListDropTarget`), `FleetList` (+`Column`, `IconColumn`, `TextColumn`, `NoteColumn`, `Item`), `FleetListHeader`, `FleetShipList` (+`FleetsClipPanel`, `ShipsClipPanel`), `FleetSummaryPanel`, `PlayerFleetsPanel`, `MoveDestinationMenu`, `ConfirmMoveFleetDialog`, `ShipCmdDialog`, action dialogs `ColonizeDialog`, `GateDialog`, `RefineDialog`, `MineDialog`, `DumpOreDialog`, `DumpSlavesDialog`, `ScuttleDialog`, `StopDialog`, `BuildSpyDialog`, `DeploySpyDialog`, `PickupSpyDialog`, `SetColonyTrapDialog`, `SetMiningTrapDialog`, `ClearTrapDialog`; `SupportPanel`, `RefuelPanel`, `RepairPanel`, `SupportControl/Slider`, `RefuelAvailCell`, `RepairAvailCell`, `SupportAvailCell` | `StarFleet`, `StarShip`, `FlightPlan` (+`Waypoint`), `Can*` predicate functors (`CanColonize`… `CanSetTrapFtor`), `SpyCraft`, `ClientSpyManager` |
| S4 | **Fleet manager** | `GUI/FleetManager/*` (per-race `*_Destroyer.tga`, `*_ShipIcons.tga`, `StationsDrones_ShipIcons.tga`, `Defence_Sat.tga`), sprites `FLEETMAN_*`, `FLEETLIST_*`; `FLEETMAN_*` (8), `RESERVESSORT_*`, `SHIPSET_*`, `PLAYERFLEETS_*`, `TOOLTIP_FLEETLISTBTN_EDITLAYOUT` | Manage Fleets; First Wave / Reinforcements / Squads; Command Cost / Command Quota; Rename Fleet; "Fleet Layout Not Available"; Edit Layout | `FleetManagerPanel` (+`ButtonOverlay`, `DialogUnderlay`, `RenameFleetDialog`, `FleetMenuSource`), `FleetLayoutPanel`, `FleetLayoutGrid`, `ReservesList`, `ReserveQueueBox`, `ShipList` (+`ShipItem`), `ShipSetPanel` (+`BucketList`), `ShipAssignmentPanel`, drop plumbing `FleetManager_{FleetList,Layout,Reserves}DropTarget`, `ShipDropSource/Data`, `ReservesDropSource/Data/Target` | `FleetLayout`, `Reserves`, `FleetNameGenerator` |
| S5 | **Defense manager** | `DEFMAN_ARROW` (`Arrows.tga`), `SYSINFO_ICON_DEFSATS*`; `DEFENCEMAN_*`, `DEFMAN_*`, `UICSTR_OPEN_DEFENCEMAN` | Manage Defences; Command Quota/Cost; "Show Neighbors (by distance)"; right-drag to rotate fleet; Remove Fleet | `DefenceManager` (+`MapDropTarget`), `DefenceMap`, `DefenceLayout`, `DefenceFleetAssignment`, `DefenceFleetRotator`, `DefenceSummary`, `DefenceObject`, `DOFleet/DOPlanet/DOStation/DODefSat`, `DefenceDropSource/Data` | `DefencePlatform`, `DefenceManager` (sim side) |
| S6 | **Population manager / Empire population / Slave manager** | `POPMAN_*` (21), `GLOBALPOPMAN_*`, `SLAVEMAN_*`, `CONFIRM_*_CIVRATIOS_*`; `POPMAN_TITLE_ICON`, `GLOBALPOPMAN_TITLE_ICON` | Current/Maximum (Combined) Population, Combined Civilian Population, Climate Control, Morale, Morale Events; Empire: Maximum Civilians Per System, Apply Empire Settings; Slave Manager: Output, Death Rate | `PopulationManager`, `PopulationControl`, `PopulationGroup`, `PopulationSummary` (+`Overlay`), `MoraleEventsPanel`, `MoraleEventList`, `GlobalCiviliansControl`, `GlobalPopulationManager`, `CivilianRatios`, `SpeciesRatios`, `ConfirmCivilianRatiosDialog`, `ConfirmApplyCivilianRatiosDialog`, `SlaveManagerPanel` (+`SpeciesControls`) | `Population`, `Morale`/`MoraleEvent` (`MESTR_*` 38 morale strings), `PrisonerHold`, `Plague`/`ZuulInfestation` |
| S7 | **Build screen** | `BUILD_*` (21), `SHIPBUILD_*`, `BUILDERROR_*` (22), `TOOLTIP_BUILDPANEL_REMOVE_ORDER`; sprites `BUILD_ORDERINC/DEC`; globals `DESIGN_SIDEBAR_WIDTH` ("build/design screens") | Build; Available Designs; Add To Queue; Build Queue; Financial Details (Treasury, Fleet Maintenance current/queued/total); Ship Details (structure, turrets, speed, range, costs, "%s in service / built / destroyed"); construction-ship build ("Construction Ships:") | `BuildPanel` (+`MiniBudgetPanel`, `MiniEmpirePanel`, `PreviewPanel`), `BuildQueuePanel`, `BuildOrderListPanel` (+`Item`), `BuildOrderDropSource/Data/Target`, `ShipBuildPanel`/`IShipBuildPanel`, `BuilderList`, `DesignList` (+`PerClassList`), `ShipPreviewPanel`, `ShipStatsPanel` | `BuildQueue`, `ShipBuildQueue`, `ShipBuildOrder`, `SystemBuildQueue`, `CanBuild`, `SEBuildCompleted/Cancelled` |
| S8 | **Design screen** | `GUI/WeaponIcons{,_2}.tga` + `WeaponIconPlacements.txt` (362 KB icon atlas map), `WeaponIconOutline.tga`, `WeaponTitle.tga` (`WEAPONLIST_TAB_*`), `SHIPDESIGN_GROUP_BUTTON0-2`; `DESIGN_*`, `DESIGNERR_*`, `DESIGNCLASS_*` (Destroyer/Cruiser/Dreadnought/Station/Rider), `SHIPSTATS_*` (16), `WEAPONLIST_*`, `SECTIONNAME_*` (283) / `SECTIONDESC_*` (202); `UI_DESIGN_SECTION_CHANGED/WEAPON_ROLLOVER/WEAPON_SELECTED` | Ship Designs; section picker (command/mission/engine); Weapon Layout / Weapon Groups; Ship Stats (Savings/Construction cost, Armor, Mass, Range, Speed, Tactical/Turning Speed, turrets S/M/L/Special); Save Design / Remove Design; errors "Mismatched Sections", "AI Control Sections Disabled Due To AI Rebellion" | `ShipDesignPanel`, `SectionConfigPanel`, `SectionOverlay` (+`OptionIcon`), `WeaponPanel`, `WeaponPanel2`, `WeaponListPanel`, `WeaponSelectPanel_List/Tab`, `WeaponIconButton`, `WeaponGroups`, `WeaponGroupControls`, `WeaponControls`, `DesignInfoPanel/Popup`, `DesignPreviewPanel`, `DesignErrorPanel`, `TurretStatsPanel`, `SaveDesignDialog`, `RaidDesignPanel`, `ShipDesignCell` | `ShipDesignDef` (+`LegacyGunBank`), `ShipDesign`, `DesignList`, `ShipIconGenerator`, `SEAddDesign/SESyncDesign` |
| S9 | **Research screen** (3-D tech tree) | `TechTree/TechTreeDisplay.script` (12 branch models `TechTree_{BAL,BIO,CCC,DRV,EWP,IND,NRG,SLD,TRP,WHD,DRN,XNC}.X`, `Rings.X` background, state colours researched/researchable/researching/hidden), `GUI/ResearchElements.tga` (`TECHINFO_*`, `RESEARCH_*`), `TechTree/ShipArt/*` (`TECHSHIP_*` section icons); `RESEARCH_*` (21), `TECHNAME_*`/`TECHDESC_*` (293 each), `TECHBEN_*`, `TECHERA_*`, `SPRJ_*` (106, 103 of them `SPRJ_BACKENG_*`), `SPECPROJECT_*`, `SPINNERPANEL_*`; `UI_RES_SELECTION/ZOOMIN_ACROSS/ZOOMOUT/COMPLETE/BOOST/SHORT_AMBIENT` | Research; Researching … "%s turns to complete"; Research/Cancel; Boost Research (savings slider, Apply); Special Projects (Start/Cancel Project); History ("Turn %s"); Completed! dialog; Overbudget | `ResearchPanel` (+`DoubleClickPanel`, `TitlePanel`, `BudgetPanel::ResearchPanel`), `TechTreePanel`, `TechInfoPanel`, `TechNamePanel`, `TechDescPanel`, `TechBenefitPanel`, `ResearchListPanel`, `ResearchProjectPanel`, `ResearchHistoryPanel/List`, `ResearchSpecialPanel/Controls`, `ResearchBoostControls`, `ResearchSpinnerPanel`, `ResearchDonePanel`, `TechOptionsList` (+`Item`) | `TechTree`, `TechProject`, `SpecialProject(Impl)`, `BackEngProject`, `MonitorProject`, `JewelsProject`, `TechOfferProject`, `ObservedTech`, `MasterTechList.tech` |
| S10 | **Empire summary** (tabbed) | `EMPIRE_TABTITLE_*`, `BUDGET_*` (19), `EMPIREINFO_*`, `STATSGRAPH_*`/`STATSPAGE_*` (`GUI/Graph_buttons.tga` 9 graph types), `EMPIRE_PAGEBTN`, `EMPIRE_ENEMYINCOMING`; `UI_TAB_SELECTED` (gui_overview) | tabs Colonies/Budget · Fleets · Explored Systems · Enemy Colonies · History · Stats · Trade · Spies; Budget: Treasury, Income (Planetary, Trade, Ships, Foreign, Interest), Expenses (Planetary Development, Fleet Maintenance, Research, Aid, Special Projects, Additional), Projected Change/Treasury; graphs Population/Trade/Savings/Colonies/Techs/Battles/Ships/Lost/Killed, "Turns To Display" | `EmpireSummaryPanel`, `EmpireInfoPanel`, `BudgetPanel`, `BudgetPieChartPanel`, `PieChartPanel`, `SystemsPage`, `ExploredSystemsPage`, `EnemySystemsPage`, `EventsHistoryPanel`, `StatsPanel` (+`Overlay`), `StatsGraphPanel`, `StatsLegendPanel`, `TradeSummaryPanel`, `ShipSummaryPanel` | `PlayerTurnStats`, `PlayerTurnHistory`, `GameTurnHistory`, `ShipRecords` |
| S11 | **Trade view / sectors** | `GUI/TradePanel_Elements.tga`, `StarMap/TradeDot_Depart.tga`, `TradeLine_Depart.tga`, `STATIONICON_TRADE`; `TRADE_*`, `TRADESECTOR_*`, `TRADEROUTE_*`, `TROUTESTATUS_*` (Inactive/New/Developing/Established/Shutting Down), `SECTORSUMMARY_*`, `FREIGHTERCOUNT_*`, `UICSTR_NEXT/PREV_TRADESECTOR` | Trade Sectors; Sector %s secure/unsecured; Routes, Freighters, Income, Maximum Route Length; Build Freighter; raid targets | `TradeSectorPanel`/`ITradeSectorPanel`, `TradeRoutePanel`, `TradeSectorList`, `TradeSystemList`, `TradeSummaryPanel`, `RaidFleetList/Item`, `RaidSectorList/Item`, `RaidTargets` | `TradeManager`, `ServerTradeManager(Impl)`, `ClientTradeManager`, `TradeSector`, `TradeRoute`, `TradeSystemInfo`, `ServerTradeSector` (+`FreighterWarning`) |
| S12 | **Diplomacy screen** (+ Alliance manager, Aid, Joint projects, Intel) | `GUI/Alliance/*.tga` (11 "table" scenes: `DIPTABLE_HOST_*`/`GUEST_*`, `TECHTABLE_*` per race pairing), `DIPRELATION_ARROW`, `PoliticalButtons.tga`; `DIPSCREEN_*` (27), `ALLIANCEDLG_*` (45), `ALLIANCEMAN_*` (22), `GIVEAID_*` (19), `GIVETECH_*` (21), `SURRENDERDLG_*`, `EMPIRESURRENDER_*`, `INTEL_*`, `AIDIP_*` (755 AI diplomacy lines, ~125 per race); `UI_ALLY_SEND_AID`, `UI_ALLIANCE_ACCEPTED/REJECTED/BROKEN` | status War / Ceasefire / NAP / Ally; per-player Savings, Colonies, Homeworld, Hazard, Ships, Sats, Max Class/Power; Give Savings/Research, Compose Message, View Agreements, Demand Surrender; Alliance Manager lists (Alliance Members / Non-Aggressive / Cease Fire / Enemy Players), invites, downgrade dialogs; Aid Manager (per-turn savings/research for N turns); Joint Project (Offer Technology); Intel Analysis (Last Ships Observed, Known Empire Technology); "Research %s to engage in diplomatic relations" | `DiplomacyPanel`, `DiplomacyPlayerCard`, `DiplomacyStats`, `PlayerAlliancesPanel`, `PlayerAllianceControls/Popup`, `AllianceDialogCommon`, `AllianceInviteDialog(Std/Neg)`, `AllianceEventDialog`, `GiveAidPanel`, `GiveAidPlayerPanel` (+`Overlay`), `GiveAidControlPanel`, `TechOfferDialog(Base)`, `TechOffer{Accepted,Cancelled,Rejected,Query,QueryAccepted,QueryRejected}Dialog`, `IntelAnalysisPanel`, `IntelPlayerTab`, `IntelShipList`, `IntelTechList`, `IntelTechIcon` | `AllianceInvite`, `PlayerAid`, `TechOffer`, `AIRelationRecord`, `ObservedDesign/Tech/Weapon`, `SNMAlliance*`, `SNMDemandEmpireSurrender*`, `SNMTechOffer` |
| S13 | **Comm system** (structured diplomacy messaging) | `GUI/com_system/{com_system_icons,Com_InnerBorder,TabOutline}.tga` (33 message icons); `COMMSYSPAGE_*`, `COMMTAB_*`, `COMMDEC_*` (26), `COMMREQ_*` (30), `COMMRECIP_*`, `COMMEXP_*`, `COMMMSG_*`, `UIC_BEGIN_COMM`; `UI_CHAT_*` | pages Chat / Compose / Incoming / Outgoing; declarations (I Want, I Saw, I Like/Hate, Curse, Thanks, Sorry, Send System Info/Notes/All Colony Info, Severed alliance…) and requests (Rally/Attack/Defend at, Money, Research, Disposition, Harass X, Stop harassing/mining/colonizing, Sever alliance…); recipients Broadcast/Alliance; expiry ASAP/Never/By turn | `CommSystemPanel` (+`InnerBorderOverlay`), `CommSystem_Builder/Chat/Messages/Viewer`, `CommListPanel`, `CommIconList`, `CommIcon_{Player,Standard,System}`, `CommParamList/Page`, `CommMessageContainer` | `ICommMessage` → `CommDeclare*` (13) / `CommRequest*` (15) / `CommGenericMessage`; `SNMCommMessage`, `SEAIReceiveCommMessage`; `ChatTranslation` + `Locale/EN/ChatTrans.txt` |
| S14 | **Rankings** | `RANKINGS_*` (11) | Ranking by Income, Technologies, Colonies, Population, Output, Ships (Built/Lost/In Service/Enemy Killed) | `RankingsPanel` | `PlayerTurnStats` |
| S15 | **Political map overlay** | `StarMap/SystemUI/{InfluenceDisc,Core}.tga` (`POLMAP_HALO`, `POLMAP_MILITARY_THREAT`, `STARMAP_SENSOR_RANGE`, `POLMAP_CORE_*`), `PoliticalButtons.tga`; `POLMAP_*`, `UICSTR_TOGGLE_POLMAP_*` | views Political / Alliances / Recent Combats / Military / Sensor Network; "Analyzing Intel…" | `PoliticalMapPanel` | sensor model `SensorShadow`/`SphereSensorShadow`/`SensorJammerShadow` |
| S16 | **Events (turn news)** | `GUI/Events/*` (61 tga: per-race `*_tv_events512_1-4`, `special_events512_1-14`, `EventBG`, `EventButtons`, `static_screen`, `*_Victory/_Defeated`, `Draw`, `Progression*`); ~250 `EVENT_*` sprites; `EVENTMSG_*` (415), `EVENTSUM_*` (247), `TOOLTIP_EVENTS_CLOSE`; `UI_NEWS_OPEN/CLOSE/CHANGE` | one "TV" card per event with prev/next; ticker summaries | `EventPanel`, `EventPanel_ForLists`, `EventsDisplayPanel`, `EventsTickerPanel`, `EventsHistoryPanel/List` (+`Item`) | `EventStorage` (+`Event`, `TurnEvents`), `StrategyEvent`, `SystemEvent`, `SETurnEvents`, `SNMGenericEvent` |
| S17 | **Spy reports** | `SPY_*`, `SPYSUM_*` (13), `SPYINFO_*`, `SPY_TRADE_BTN`/`SPY_DEFENSE_BTN` sprites | Spy Network (Spies / Spy Reports; statuses Enroute/Active/Detected/Completed/Extracted); Spy Report: Trade Routes / Events / Research / Defenses | `SpyReport`, `SpyReportTrade/Events/TechTree/Defences`, `SpyReportTradeRoute`, `TradeSpyReport`, `EventsSpyReport`, `TechTreeSpyReport`, `DefencesSpyReport` | `SpyCraft`, `ClientSpyManager`/`ServerSpyManager` |
| S18 | **Modal turn dialogs** | `ELIMINATEDDLG_*`, `ENDGAMESPLASH_*`, `PROCESSING_TITLE`, `TIMERSDLG_*`, `AIPOLICY_*`, `SPECPROJECT_CONFIRM_*`, `SCENARIO_PROGRESSIONWARS_DLG_*`, `UPSTARTOBJ_*`/`*OBJ_*` scenario objectives | "You have been ELIMINATED!", "You are VICTORIOUS!", "Game ends in a DRAW", Processing…, Game Time Limits, Choose AI Policy (Maintain/Defend/Expand), Generational Convoy | `EndGameDialog`, `EndGameMoviePanel`, `AIProcessingDialog`, `AIRebellionDialog`, `SetTimersDialog`, `AIPolicyDialog`, `ProgressDialog::StrategyHost/Join`, `AdvanceStageFleetQueryDialog`, `SEPostDialog` | `EndCondition`/`IEndConditionFunctor`, `*VictoryFunctor` (12), `AIRebellion` |
### 2.3 Combat layer
| # | Screen | Evidence | Key labels | `Game::` UI classes | Subsystem |
|---|---|---|---|---|---|
| C1 | **Combat setup / encounter query** | `GUI/CombatSetup/*` (15: `CombatElements(_MouseOver)`, `CombatStates(_2)`, 11 `combatcard_*.tga`); sprites `ENCACTION_{OBSERVE,IGNORE,FIGHT,AUTO,FIGHTIF,AUTOPEACE,SURRENDER,SURRENDERAUTO,SURRENDERFIGHT}`, `COMBATSETUP_CARD_*`, 24 `COMBATSETUP_CARD_SCENARIO_*` (one per encounter type: VonNeumann, SlaversRefuel, Pirate, Monitor, Meteor, Derelict, Swarm, PuppetMaster, SystemKiller, TradeRaiders, LarvaQueen, SwarmQueen, Locust, Berserker, CrowRuins, Refugees, Ortgay, VNHome, VNFinsol, GasCloud, TheHerald, Unknown, RebelAI); `COMBATSETUP_*` (23), `ENCOUNTERNAME_*` (24), `COMBATLAUNCH_*`; globals `COMBATSETUP_SYSTEMSUMMARY_TOP`; `UI_COMBAT_STING/WILL_FIGHT/WONT_FIGHT` | "Encounter at %s / in Deep Space / in Nodespace", "Raiders in %s"; per-player choice: Fight Manually · Fight Manually If Opponent Does · Auto Resolve Peacefully · Auto Resolve · Observe · Demand Surrender (Auto/Fight) · Surrender; query timer | `CombatSetupScreen` (+`Overlay`), `CombatSetupDialog` (+`TimerOverlay`), `CardPanel`, `EncounterInfoPanel` (+`Overlay`), `EncounterActionControl`, `EncounterList` (+`Item`), `CombatPlayerList/Item`, `CombatPlayerInvariant` | `EncounterQuery`, `EncounterParams`, `CombatEncounterParams`, `SNMDoEncounterQuery`/`SNMEncounterQueryResults`, `SNMRequestRandomEncounter`, `CombatMissions/Encounter/{DeepSpace,InSystem,NodeSpace}.combat` |
| C2 | **Combat loading** | `GUI/Combat/CL_*.tga` (33 faction/encounter loading backdrops), `CL_Elements.tga` (`COMBATLOAD_SCREENHAZE`, `COMBATLOAD_VERSUS`), `GUI/SplashArt/Loading/*` (37 splashes), `LoadScreen_Anim00-03.tga`, `loadbar.tga`; `COMBATLOAD_LOADING`, `COMBAT_WAITINGFORPLAYER/SERVER` | "Loading…", "Waiting for player: %s" | `CombatLoaderPainter`, `CombatLobbyClient` | `CombatLaunchParams`, `SNMHostCombat/JoinCombat/LaunchCombat`, `CombatNetworkServer/Client`, `CNM*` (combat net msgs) |
| C3 | **Combat screen (tactical HUD)** — Battle view ⇄ Sensors view | `GUI/Combat/CombatElements.tga` (81 sprites: `COMBATHUD_WEAPONS_*`, `GROUPCON_*`, `RESERVESSURROUND_*`, `BOMBARD*`, `STANCEICON_{PURSUE,AGGRESSIVE,STANDOFF,BREAKOFF,RETREAT}`, `CLOAKBUTTON`, `AEAUTOFIREBUTTON`, `ONLYMYTARGET`, `HOLDFIRE_ALL`, `FACINGICON_{TARGET,BROADSIDE,NAV}`, `PLAYERLIST_{FIGHTING,CEASECOMBAT}_ICON`), `ShipOverlay.tga`, `Models/CombatHud/*.X` (ShipSelectRing, EnemyRing, combat_arrow/Sprint_Arrow waypoints, MissileTargetDrop/point, MouseTargetPoint), `GUI/Mouse/mouse_{default,addselection,forcefire,invalid,moveplane,rotateformation}.tga`; `COMBATHUD_*`, `UICSTR_TAC_*` (45 hotkeys), `TOOLTIP_COMBATBTN_*`, `TOOLTIP_STANCE_*`, `TOOLTIP_FACING_*`, `TOOLTIP_COMBAT_*`, `TOOLTIP_*_CAPACITY` (drones, shuttles, bio/node missiles, hunters), `COMBATOPTIONS_*`; globals `COMBATHUD_*`; exe refs `GUI/Combat/CombatHUD.script`, `SensorHUD.script`, `NoHUD.script` (not shipped) | Battle / Sensors main buttons; Fleet Commands; weapons panel (per-bank toggle/fire/launch, groups 0-2, Select All, Hold Fire); Reserves list; stances (Normal, Pursue, Close to Attack, Stand Off, Break Off to Back Line, Retreat), facing (Face Target / Turn Broadside / Face Heading) for Selection vs Fleet; Cloak/Intangibility, AE Autofire, Fire Only At My Target, Bombard Colony (Population / Civilian / Imperial), Cease Combat; hotkeys Pause, Single-Step, Speed Up/Slow Down Time, Toggle Sensors/HUD/Reserves/Weapon Panel/Ship Overlay/Framerate, Next/Prev Ship/Enemy, Focus, Focus On Reinforcements, All Stop, Clear Targets/Selection, Roll Left/Right, Release Grapple; Select Command Fleet | `CombatScreen` (+`BandboxEventTarget`), `CombatView` (+`Focus/SelectionEventTarget`), `BattleView` (+`CameraCtl`, `DebugOverlay`), `SensorsView` (+`CameraCtl`), `CombatOverlay` (+`SelectionEventTarget`), `CombatOverlay_{BombardButton,FacingButton,PlanetStats,Reserves,StanceButton,Weapons}`, `CombatPeaceButton`, `StanceButtonBase`, `CombatSelection`, `CombatSelectionRing`, `CombatFocus`, `Bandbox`, `GunBankSelection`, `ShipWeapons` (+`GunEventTarget`), `WeaponGroupControls`, `AllGroupControls`, `OneGroupControls`, `ReservesList`, `CombatTitle`, `CombatPlayerList`, `CombatOptionsDialog`, `BombardDialog`, `RequestAsylumDialog`, `ChatControl` | 31 `CombatCommand*` types (ship attack/maneuver/waypoint/facing/stance/hold-fire/cloak/intang/bank toggle/fire once/grapple; fleet stance/facing/hold-fire; reserves pick/move; bombard mode; AE autofire; set player AI; want-end-combat; asylum) → `GameCombatSim` / `Mars::CombatSim`; `Actor`/`Ship`/`ShipBase`/`Station`/`Planet` entities; `TacAI*`; `CombatSim` lockstep (`@SYNC ERROR`) |
| C4 | **Combat end & report** | `COMBAT_*` (19: victory/defeat/draw/ceasefire/derelict/VN-mom/asteroids/refugees), `COMBATREPORT_*` (10); `Events/*_Victory.tga` | "You are victorious!", "Round draw.", ceasefire query/success/failure, "Data transmission terminated." (observer); report: Class Name / Total / Lost / Inflicted / Taken, Allies / Enemies, Overall Weapons Damage | `CombatDoneDialog`, `CombatReportPanel`, `CombatReportPanelEx`, `CombatReportPlayerCard`, `CombatReportWeaponItem`, `CombatPlayerStats` | `CombatReport`, `CombatPlayerReport`, `CombatShipReport`, `CombatWeaponReport`, `CombatDamageReport`, `TacReport(Events)`, `EncounterResult(s)` → 20 `*EncounterResult` types, `ClientEncounterResults`, `SNMEncounterResults`, `SNMAllCombatDone` |
---
## 3. Flow
```mermaid
flowchart TD
Splash[F1 Splash / intro movie] --> Menu[F2 Main menu]
Menu --> Profiles[F3 Profile manager]
Menu --> Options[F4 Options / Key bindings]
Menu --> Credits[F5 Credits]
Menu --> Tutorial[F6 Tutorial pages + videos]
Menu --> Movies[F7 Cinematics]
Menu -->|Single Player / Host MP| Mode[F8 Custom or Scenario]
Mode --> Setup[F9 Game setup]
Mode --> Scen[F10 Scenario setup]
Menu -->|Load Game| Load[F11 Load game]
Menu -->|Join MP| Browser[F12 Game browser: LAN / Internet / Chat]
Setup --> Lobby[F13 Lobby: slots, player setup, timers, AI policy]
Scen --> Lobby
Load --> Lobby
Browser --> Lobby
Lobby -->|Launch → Initializing Game…| Strat
subgraph TURN[Strategic turn loop]
Strat[S1 Strategy map screen] --> Sys[S2 System panel]
Strat --> Fleet[S3 Fleet panel + action dialogs]
Fleet --> FM[S4 Fleet manager]
Sys --> DM[S5 Defense manager]
Sys --> PM[S6 Population / Slave manager]
Strat --> Build[S7 Build]
Strat --> Design[S8 Design]
Strat --> Research[S9 Research tech tree]
Strat --> Empire[S10 Empire summary tabs]
Strat --> Trade[S11 Trade sectors]
Strat --> Dip[S12 Diplomacy / Alliances / Aid / Intel]
Dip --> Comm[S13 Comm system]
Strat --> Rank[S14 Rankings]
Strat --> Pol[S15 Political map overlay]
Strat --> Ev[S16 Events]
Empire --> Spy[S17 Spy reports]
Strat --> Save[Save game / Quit dialog]
end
Strat -->|End Turn| Wait[Waiting for other players<br/>SETurnEndPending, cancellable]
Wait -->|all done| Proc[Server SEProcessTurn:<br/>move, build, research, events]
Proc -->|no encounters| NewTurn[SETurnResults / SNMResumePlaying<br/>new turn sound]
Proc -->|encounters| Query[C1 Combat setup: encounter query<br/>Fight / Auto / Peace / Observe / Surrender]
Query --> Loading[C2 Combat loading]
Loading --> HUD[C3 Combat screen: Battle ⇄ Sensors]
HUD -->|combat timer or all cease| Done[C4 Combat done + report]
Done -->|SNMAllCombatDone| NewTurn
Query -->|other players' battles| Wait
NewTurn --> Strat
NewTurn -->|eliminated / victory| End[S18 End-game splash / movie]
End --> Menu
Save -->|Quit to Main Menu| Menu
Lobby -.->|MP: between rounds, mid-game join, host migration| Wait
```
### Turn structure (from strings, sound hooks and `SE*`/`SNM*` event names)
1. **Strategic round** (`LOBBYSTATUS_STRATEGY_ROUND`, `PLAYERSTATUS_PLAYING`). All S-screens are reachable from the map bar at any time; commands accumulate in `TurnCommands`. Optional timer (`GAMESETUP_TIME_STRATEGY`, `StrategyTimerParams`, `SETurnTimeExpired`); timers changeable mid-game (`SNMSetTimers`, "take affect the next turn").
2. **End Turn** → `SNMEndTurn`, local state `SETurnEndPending` (status "Done"); can be withdrawn (`SETurnEndCancelled`, `SNMQueryEndTurnDone`). Autosave "(Autosave EndTurn)". In MP the host "collects turn data from other players" for saves (`SAVEGAME_COLLECTING_TURNDATA`).
3. **Processing** (`PROCESSING_TITLE`, `SEProcessTurn`, `SEAIPrepareTurn`, AI `SNMRunAI`): movement (`SEFleetArrived`), builds (`SEBuildCompleted`), research, trade, plague/morale, scenario scripts, then `SETurnResults` + `SETurnEvents`.
4. **Querying round** (`LOBBYSTATUS_QUERYING_ROUND`, `PLAYERSTATUS_QUERYING`): each encounter raises C1 for every involved player (`SNMDoEncounterQuery`); time limit = base + per-additional-round (`GAMESETUP_TIME_QUERYBASE/QUERYEXTRA`). Results `SNMEncounterQueryResults` decide fight vs auto-resolve (`GameCombatSim` headless) vs peace.
5. **Combat round** (`LOBBYSTATUS_COMBAT_ROUND`, `PLAYERSTATUS_FIGHTING`, status column ROUNDS / TIME REMAINING): battles hosted one at a time per host (`SNMHostCombat` → `SNMHostCombatReply` → `SNMLaunchCombat`, clients `SNMJoinCombat`), each bounded by `GAMESETUP_TIME_COMBAT` (`SNMCombatTimeRemaining`). Players not in a battle stay on S1 read-only ("%s battles in progress, %s of %s remaining"). Combat can end early on ceasefire (`CombatCommandSetWantEndCombat`, `CeaseCombatFunctor`) or elimination (`CombatEliminationFunctor`) or expiry (`CombatExpiredFunctor`). Results → C4 → `SNMEncounterResults`.
6. **Resume** (`SNMAllCombatDone` → `SNMResumePlaying`/`SEResumePlaying`, `UI_LAST_PLAYING` = gui_newturn.wav, `SELastPlaying`): new turn number, S16 events appear, loop to 1.
7. **Exit conditions:** `EndCondition` functors per scenario; `ELIMINATEDDLG`, `ENDGAMESPLASH` (win / other player wins / team wins / draw), `EndGameMoviePanel`; bankruptcy elimination after `BANKRUPTCY_ELIMINATION_TURNS 10`.
8. **MP side-paths:** join in progress (`LOBBY_INPROG_*`: joiner parks in F13 until next turn, `SNMSlotInsertClient`), leaver replaced by AI per `AIPOLICY`, host leaves → host migration + `FNM*` file push of the autosave (`HOSTMIG_*`), "(Rejoin)" save.
---
## 4. Sound-hook → screen index (`sound_ui.csv`)
| Event | Screen |
|---|---|
| `UI_KERBEROS_SPLASH` | F1 |
| `UI_GAMESETUP_ROLLOVER/CONFIRM` | F9/F10 |
| `UI_DRAG_START/STOP` (gui_playerslot) | F13 slot drag, S4/S5/S7 drops |
| `UI_CHAT_*` | F12 chat, S1a chat, S13 |
| `UI_RES_*` | S9 |
| `UI_DESIGN_*` | S8 |
| `UI_AUTO_REFUEL/REPAIR` | S3 support panels |
| `UI_POLITICAL_CLOSE` | S15 |
| `UI_NEWS_*` | S16 |
| `UI_TAB_SELECTED` (gui_overview) | S10 |
| `UI_ALLY_*` / `UI_ALLIANCE_*` | S12 (`UI_ALLY_RECEIVE_AID` marked "not in code yet") |
| `UI_COMBAT_STING/WILL_FIGHT/WONT_FIGHT` | C1 |
| `UI_LAST_PLAYING` (gui_newturn) | turn rollover |
| `UI_EXIT_SCREEN`, `UI_DIALOG_*`, `UI_LIST_*`, `UI_TREE_*`, `UI_BUTTON_*` | generic |
---
## 5. Surprises, hidden/debug, cut features
1. **UI is not data-driven.** Only 4 `.script` files exist and none is a layout. The exe nevertheless references `GUI/Combat/CombatHUD.script`, `SensorHUD.script` and `NoHUD.script` (string-intel §3) — absent from both gobs and from the loose install. Since `gobio` has a `NativeFileSystem` fallback, these are most likely optional dev overrides for compiled-in HUD defaults. **Consequence for reimplementation:** screen layouts have to be recovered from code (Ghidra targets: the `*Panel` constructors and `Mars::PanelManager`), not from data.
2. **Debug overlays and dev toggles left in:** `DebugOverlay::StrategyMapScreen`, `DebugOverlay::BattleView`; `Lines.script` `DEBUG_UseSimpleLine / DEBUG_LockDestination / DEBUG_ForceOutOfRange / DEBUG_ReloadOnFleetChange` (hot-reload of the line script); hotkeys `UICSTR_TAC_FRAMERATE` ("Toggle Framerate") and `UICSTR_TAC_SINGLE_STEP`; `DemoApp` and `MutexScreen` classes; `ForceSingleCore` ini key.
3. **Legacy / cut screens:** `OldGameSetupPanel`; sprites `BARBUTTON_OLDTRADE` and `BARBUTTON_OLDALLIANCE` (pre-ANY trade & alliance buttons replaced by S11/S12); `ChatHistoryPanel2`, `WeaponPanel2`, `CombatReportPanelEx` (v2 rewrites kept beside v1); `Scenario_Set_D/E.tga` carry images for **`SCENARIO_KINGOFTHEHILL`** and **`SCENARIO_SLAVEMASTER`** which have no strings and no `Scenarios/*.txt` — cut scenarios; "Upstart Apes" is internally `EARTHVSTARKAS`; `SUPPORT_REPAIR_AVAIL/REQ` are empty strings.
4. **Localized gob carries UI art:** `Scenario_Set_C.tga` (Holy Lands + Tutorial images), `Tutorial/page9-11.tga` and `Data/credits.txt` are only in `sots_local_en.gob` — a loader that only mounts `sots.gob` will miss sprites the table references.
5. ~~**GameSpy is dead and the 2017 build knows it:**~~ **Corrected by lane G2 — see [[multiplayer-gamespy]] §0 and §1.** The `MATCHINGSERVICE_UNSUPPORTED` string ("Online support for Sword of the Stars is no longer available" + "players can still connect manually") is the *GameSpy kill-switch* message, fired only when a server answers the availability check with the unavailable bit set; the SDK **fails open** on DNS failure, so the 2017 build does not detect the shutdown on its own. F12 does degrade to LAN/manual IP, and that path is fully GameSpy-free. There are **no CD-key strings in this binary at all** — no `CDKEY` substring anywhere, no `STARTUPERROR_*` family, and all 13 `NETERROR_*` entries are connection/version/password errors.
6. **Standalone dedicated server** ships (`sots_server.exe`, `Dedicated Server Launchpad.exe`) with its own error vocabulary `SERVERERROR_*` (ini-section driven: map file, allowed species, defaults) — the strategy server is separable from the client UI, which is good news for a reimplementation split.
7. **Achievement/badge system predates Steam:** 56 `GUI/Achievements/*.tga`, `PlayerBadgeSet`, `PROFILEMAN_BADGES_*`, badge sprites `BADGE_*_GW100` — stored in the local profile.
8. **Sticky-note system:** per-system player notes (`PlayerNotePanel`, `StickyNoteElements.tga`, "Added by: %s, Turn %s") that can be *sent to other players* via `CommDeclareShareSystemNotes`.
9. **Alien-language chat translation:** `ChatTranslation` + `Locale/EN/ChatTrans.txt`; diplomacy is gated on translator tech (`DIPSCREEN_NEEDTRANS`).
10. **Easter eggs:** `MADE_UP_STRING` = "Hang in there, Space Cowboy. You can play the game soon. Finish reading that manual."; `SVSOEasterEgg`/`SVSOSimpleEasterEgg` encounter scripts and an AI task `AITKillEasterEgg`; rebel-AI names Guardian/Chandra/Dillinger/Daystrom/Knight/Singularity/Dyson/Spengler.
11. **Key bindings are display-only** in F4 (`HOTKEYS_DISCLAIMER`); remapping is by editing the profile ini.
12. **The lobby doubles as the MP waiting room** between turns and for mid-game joiners — it is a persistent screen, not just a pre-game one.
---
## 6. Where to dig next (Ghidra hand-off)
- `Game::Screen` / `Game::ScreenBar::ToggleList` — the screen switcher; find the enum behind `BARBUTTON_*` order.
- `Game::StrategyMapScreen` ctor — instantiates most S-panels; cross-ref `STATUSPANEL_MIN_WIDTH` etc. from `globals.txt` to locate layout code.
- `Game::CombatScreen` / `CombatOverlay_*` — check for the `CombatHUD.script` load path to confirm the compiled-default-plus-override theory.
- `SETurnEndPending` → `SNMEndTurn` → `SEProcessTurn` → `SNMDoEncounterQuery` → `SNMAllCombatDone` → `SNMResumePlaying` — the turn state machine, already fully named by RTTI.