# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

HC Launcher is a Lazarus/FPC LCL Windows application that provides a GUI for configuring and launching the Harpoon Classic (HC) Game Engine (GE). It builds complex command-line argument strings from UI controls and executes the GE executable via shell.

Published at https://harpgamer.com/harpforum/files/file/445-hc-launcher/ with support topic at https://harpgamer.com/harpforum/topic/6098-file-hc-launcher/. Author: TonyE. First released September 2009, actively maintained since. Current version: 2025.024.

The launcher is described as "early attempts at a launcher program, currently mainly to test command line options" — it is a developer/power-user tool for exercising GE command-line flags, not a polished end-user launcher.

## Development Practices

- **Platform targeting**: Windows-first (HC is Win32) but always include `{$IFDEF MSWINDOWS}`/`{$IFDEF LINUX}` guards for future Linux ports
- **Documentation**: Use XMLDoc format (`/// <summary>`, `/// <param>`, `/// <returns>`) on new/modified code
- **Design**: Use interfaces and generics wherever it makes sense
- **Testing**: Automated tests at unit, integration, and (where feasible) UAT levels. Create and update tests before each check-in. Use FPCUnit for FPC code (see `../shared/pascal/tests/` for patterns).
- **Licensing**: Use libraries that allow a proprietary license (MIT, BSD, Apache 2.0, MPL OK). Discuss with the team before introducing GPL/LGPL dependencies.
- **Version control**: SVN (Git migration planned)

## Build

- **IDE**: Lazarus — open `Launcher.lpi`
- **Command-line (Release)**: `lazbuild Launcher.lpi`
- **Command-line (Debug)**: `lazbuild --build-mode=Debug Launcher.lpi`
- **Target**: Win32 (x86), outputs `Launcher.exe`
- **Tests**: `lazbuild tests/HCLauncherTests.lpi` then `tests/HCLauncherTests.exe --all --format=plain`
- **Server tests** (catalog generator): `php server/tests/test-generator.php` (add `--live` for guest-only checks against harpgamer.com). Needs PHP 8.1+ with curl, zip, openssl and pdo_sqlite, but *not* mysqli (without it, `tests/fake-mysqli.php` runs the database adapter against SQLite). No PHP is installed on this system, so use a portable build from windows.php.net with `-n`, load those extensions with `-d extension=…`, and pass `-d curl.cainfo=` a CA bundle (Git's `mingw64/etc/ssl/certs/ca-bundle.crt` works).
- **IPS database access** (generator, server-side only): `ips_db` in `/safePHP/hcl-config.php` holds a SELECT-only user for the IPS database (`tgpnet_hg_ivbd1`, table prefix `ibf_`). Downloads files are stored on disk at `/IPB/IDM/downloads/` (outside the web root), resolved at runtime from IPS's `filestorage__downloads_Files` setting. IPS is installed at `public_html/harpforum/`.
- **Deploy the catalog generator**: `server\deploy-generator.ps1` (`-DryRun` first; `-Rollback` restores the `.bak`; `-VerifyCatalog` checks the public catalog after the next 4-hourly cron run). It uploads over WebDAV to a cPanel Web Disk (`webdisk.tgp.net`, generator at `/safePHP/`): backup → upload to `.uploading` → hash read-back → MOVE → hash read-back. Settings and credentials live in `.env` in the repo root (svn-ignored; template `.env.example`) and are never printed. Tests: `server\tests\test-deploy.ps1` (local mock WebDAV server, no network). cpdavd quirks: answers COPY/MOVE with 200 rather than 201/204, and sends a quoted charset .NET refuses to parse, so read bodies as bytes.
- **lazbuild location on this system**: `C:\Prog\lazarus\lazarus\lazbuild.exe`
- **HTTPS runtime**: OpenSSL **3.5 LTS**, never 1.1 (end-of-life; house decision in the Lazarus-FPC agent notes, `fpc-openssl-3.md`). FPC 3.2.2 only knows the 1.1 names, so `uHCLOpenSSL.pas` (first in `Launcher.lpr`'s uses, and before `fphttpclient`/`opensslsockets` in `uHCLCatalog`/`uHCLDownloader`) sets `DLLSSLName`/`DLLUtilName` to `libssl-3.dll`/`libcrypto-3.dll` (the `-x64` names on 64-bit) and pulls in the shared `uCICOpenSSL3` for Linux. The 32-bit pair comes from FireDaemon's signed OpenSSL 3.5.8 zip; `vendor/openssl-win32/VENDOR.md` says how to refill it (the DLLs are svn-ignored). They must sit beside `Launcher.exe` (copies in the project root and `tests/`, also ignored) and ship with every release; without them the Downloads tab cannot fetch anything.

> The project was ported from Delphi/RAD Studio to Lazarus/FPC in 2026. This is a one-way migration — Delphi is no longer a build target. Legacy Delphi files (`Launcher.dpr`, `Launcher.dproj`, `uMain1.dfm`, `FmxUtils.pas`) exist in SVN history for reference.

## Source Files

- `Launcher.lpr` — Program entry point (replaces `Launcher.dpr`)
- `Launcher.lpi` — Lazarus project file (replaces `Launcher.dproj`)
- `uMain1.pas` / `uMain1.lfm` — Main form (LCL, replaces TMS VCL `.dfm`): UI logic, settings I/O, coordinates command-line assembly
- `uHCLCmdLineBuilder.pas` — Extracted command-line builder (interface + class, zero UI dependency; independently testable)
- `uHCLFileOrganization.pas` — Managed file organization (interface + class, zero UI dependency; organizes BattleSets, PlatformDBs, ExportDLLs, etc. into a structured directory tree)
- `uHCLProcessUtils.pas` — Process launch utility (clean-room replacement for `FmxUtils.pas`)
- `../shared/pascal/uCICVersionInformation.pas` — Extracts version strings from executables (shared across sibling projects, FPC-compatible)
- `uHCLCatalog.pas` — HarpGamer catalog fetcher/parser (interface + class, multi-source, fpjson; zero UI dependency)
- `uHCLOpenSSL.pas` — Points FPC's HTTPS at OpenSSL 3 (see **HTTPS runtime** under Build); must initialise before any HTTPS unit.
- `uHCLDownloader.pas` — File downloader with direct + IPS-CSRF methods, resume support, progress callbacks
- `uHCLArchive.pas` — Safe ZIP inspection/extraction (interface + class wrapping FPC's `TUnZipper`/paszlib, zero UI dependency); rejects path-traversal ("zip slip") entries
- `uHCLDatabaseMatch.pas` — Scenario-to-database matching: names reduce to family + build date (`HCDB-060103` → HCDB 2006-01-03; `HCDB2` is its own family; exactly six digits). A scenario gets its database exactly when installed (`HCLFindInstalledDatabase`, by identity whatever the folder name) or in the catalog (current or earlier version), else the nearest newer build of the family, which `OfferImport` downloads and installs first (`InstallDatabase`) and places the scenario with.
- `uHCLAutosaves.pas` — Iterative autosave handling (no UI): the GE writes `-S` saves to `<GE folder>\ITER_SAVE_GAMETIME\<base>.<NNNN><ext>` (HC `libge/src/Command.c`; base = `-k` name, else the user scenario's file name, else `BBB-SSS` for a built-in scenario, scenario numbered from 0). The counter restarts every GE run, so newest is by file time. Scan/group, keep-newest-N, older-than-N-days, match a base to an installed scenario, remove (Recycle Bin on Windows via `SHFileOperationW`) and move. `uHCLAutosaveCleanup.pas` is its window (built in code), opened from the Game Engine tab's **Clean up autosaves…**; manual only, every removal confirmed.
- `uHCLBattleSets.pas` — Battleset numbers for `-b` (the GE's `aszBattlesets` table: 1 = GIUK.RES ... 35 = HDSU.RES) with abbreviation and name read from each `.res` in the HC directory (scenario index slot 26 → text slot 27, or the start of the text in the newer BSBuilder format), built-in names as fallback. Uses the shared `uCICHCResContainer`/`uCICHCLzh`.
- `uHCLImport.pas` — Places a downloaded archive into the managed tree (interface + class, zero UI dependency); `PlanImport`/`Execute` split lets the UI confirm before anything is written
- `tests/` — FPCUnit test suite (`test_CmdLineBuilder.pas`, `test_Settings.pas`, `test_FileOrganization.pas`, `test_Catalog.pas`, `test_Archive.pas`, `test_Import.pas`)
- `server/` — PHP server-side scripts for catalog generation and serving (deployed to harpgamer.com)
- `plans/` — Design documents (`PLAN-LAZARUS-PORT.md`, `PLAN-FILEORGANIZATION.md`, `PLAN-HARPGAMER-DOWNLOADS.md`)

## Architecture

Single-form application. All logic lives in `TfrmMain1` (uMain1.pas):

1. **Startup** (`FormCreate`): loads settings from `Launcher.ini`, detects GE directory (INI → registry fallback → app dir), reads GE version via `CICGetAppVersionStr`, shows/hides version-gated UI panels. Initializes `IHCLFileOrganization` for managed file directories; on first run, offers to create the directory tree.
2. **UI → Command Line** (`BuildCommandLineGE`): every control change event calls this procedure, which calls `SnapshotInputs` to populate a `THCGECmdLineInputs` record, then delegates to `IHCLCmdLineBuilder.BuildCommandLine` to assemble the `-f`, `-l`, `-b`, `-c`, `-g`, etc. flags into a preview string. The builder is independently testable with no UI dependency.
3. **File Organization** (`UpdateFileOrganization`): resolves the managed files base directory (custom override or HC dir), creates `IHCLFileOrganization`, and sets file dialog `InitialDir` to category-specific paths with fallback to HC dir.
4. **Launch** (`btnLaunchGEClick`): runs the GE executable with the assembled command line via `uHCLProcessUtils`. `btnLaunchSEClick` runs the Scenario Editor (SE Name, default `Wscenedt32.exe`) with `IHCLCmdLineBuilder.BuildCommandLineSE`: only `-l` (no `perf`), a numeric `-b`, `-d` and `-r`. The SE's getopt is `l:b:c:d:r:t:` (HC `SE/src/winmain.c`) and its `-t` is a working directory, not the GE's save interval, so GE options must never be passed to it.
5. **Downloads** (`tshDownloads` tab): fetches a source-independent JSON catalog from harpgamer.com (or other sources), displays browsable category tree + file list. Downloads files via IPS-CSRF session flow (or direct URL for non-IPS sources) to the `cache\` directory of the category mapped from the file's `artifactType` (`ResolveCacheDir`). Uses `IHCLCatalog` for catalog management and `IHCLDownloader` for file transfer with resume and progress.
   The main button reads **Install** when the selected version is already cached (works from the cached ZIP, no network) and **Download** otherwise; right-click → **Download again** discards the cached copy first. **Play** (and double-click) starts the GE on an installed scenario (`HCLFindInstalledScenario`), taking the Game Engine tab's options but swapping in that scenario (`-c`) with its battleset (`-b`, from the extension's last character: base 36, 1-9 then a=10..z=35, 0=USNI 120, `HCLScenarioBattleSetNumber`; without `-b` the GE stops at its battleset screen even with `-c`) and its PlatformDB folder's `commondb.res`/`commondb.rsr` (`-d`/`-r`), and clearing battleset/saved-game selections. It never passes `-g`, so the GE always asks for side and game options (wanted for now), even when the tab enables them.
6. **Extract and Import** (`OfferImport`, post-download): offers to extract a downloaded ZIP into the managed tree. For a scenario, the platform database comes first from the scenario file itself (`HCLScenarioDatabase`: a versioned `.SC?` has `$FFFF`, a u16 format version, then the NUL-terminated database name at byte 4, e.g. `HCDB-060103`; version-0 battleset scenarios record none), then from the catalog's dependency field. The extension's battleset letter is never used to pick a battleset, since BSBuilder slots (HDSM–HDSU) hold whatever custom battleset a player installed. Scenario ZIPs are cached with their install (`HCLDownloadCategory`: `PlatformDBs\cache` when a database is declared) and moved there if the scenario file reveals one. `IHCLImport.PlanImport` resolves the destination from the artifact type (prompting for a parent BattleSet/PlatformDB when a Scenario declares none, and for GE/SE/both when an ExportDLL archive doesn't lay itself out under `GE/`/`SE/`), then `IHCLImport.Execute` extracts via `IHCLArchive`, which rejects unsafe ("zip slip") entries and strips redundant wrapper directories as each file is written. Never automatic — the cached ZIP stays the authoritative copy.
7. **Shutdown** (`FormDestroy`): nils all event handlers on Downloads tab controls, clears list/tree items, releases interface references in controlled order (including `FArchive`/`FImport`), then persists all control states back to `Launcher.ini`.

## Control Naming Conventions

- `ckb*` — TCheckBox (LCL)
- `cbx*` — TComboBox (LCL)
- `edt*` — TEdit / TSpinEdit (LCL)
- `pnl*` — TPanel (LCL)
- `btn*` — TButton (LCL)
- `lbl*` — TLabel (LCL)
- Suffix `GE` — Game Engine tab controls

## Settings Persistence

INI file (`Launcher.ini`) in the application directory, sections:
- `[Main]` — HC directory, GE executable name (`FileGE`), SE executable name (`FileSE`), managed files base directory override
- `[GECLO]` — Command-line option states (checkboxes, file paths, numeric values)
- `[GECLOGO]` — Game option combobox selections (side, nuke release, weather, etc.)
- `[GECLOLO]` — Logging option states and debug flags

## Managed File Organization

`IHCLFileOrganization` (in `uHCLFileOrganization.pas`) provides a structured directory tree at `<basedir>\HCLauncher\` for organizing downloaded and game-generated artifacts. `<basedir>` defaults to the HC game directory but can be overridden by the user.

Two game-content branches (each nesting `Scenarios\<name>\SavedGames\AutoSaves\`):
- `BattleSets\` — embedded-DB BattleSets (`.res`+`.rsr` pairs, `.HCBS` for BSBuilder-created)
- `PlatformDBs\` — commondb versions (`res\`, `rsr\` subdirs, `.mdb` source files)

Six supporting-asset categories: `ExportDLLs\` (mirrors GE/SE split), `Sounds\` (`.wav`), `Graphics\` (`.bmp`), `Maps\` (`.tif`), `Tools\` (misc./fallback artifact type), `Logs\` (`.log`/`.txt`).

Each category has a `cache\` subdirectory for downloaded ZIPs. One directory per artifact is required to avoid filename collisions (e.g., all BSBuilder BattleSets produce `hdsu.res`/`hdsu.rsr`).

ZIP extraction into this tree is implemented via `uHCLArchive.pas` (safe unzip, zip-slip rejection) and `uHCLImport.pas` (placement policy) — see `plans/PLAN-HARPGAMER-DOWNLOADS.md` Phase 4.

See `plans/PLAN-FILEORGANIZATION.md` for the full layout specification and remaining future work (metadata catalog, deploy-to-GE).

## HC File Formats

- BattleSets: `.res` + `.rsr` pair (e.g., `GIUK.RES`/`GIUK.RSR`; BSBuilder creates `hdsu.res`/`hdsu.rsr` + `.HCBS`)
- Scenarios: `.sc?` (`.scs`, `.scq`, `.sco`, `.scm`, `.SCi`) + `.xml` sidecar + `.BK?` backups + `.BL?`/`.RD?` orders
- Saved games: `.hp?` (`.hpq`, `.hp0`, `.hp1`, `.hpo`, `.hpg`)
- Platform DB: `commondb.res`/`commondb.rsr` is the only `.res`/`.rsr` pair that is a PlatformDB (not a BattleSet)

## Version-Gated UI

UI elements are conditionally shown based on detected GE version:
- `>= 2014.001` — combobox side selector replaces checklist (single side only in newer GE)
- `>= 2022.0.1.5` — debug options panel visible
- `>= 2022.0.2.5` — message log and iterative save filename controls visible

Note: The `-S` iterative save option requires GE >= 2009.074.

## Release History (key milestones)

- **2009.042** — Initial release
- **2010.006** — Settings persistence via INI, improved HC directory detection, file filters
- **2010.011** — Fixed nuclear release options
- **2011.011** — Introduced `-S` iterative saves
- **2013.001** — Fixed spacing bug in `-S` command formatting
- **2014.001** — Limited player side selection to one for newer GE versions
- **2017.001** — Added unit log option
- **2022.016** — Added debugging and logging command-line options
- **2022.027** — Base filename for saves; MessageLog control
- **2025.024** — Added `-h` window hide option; Malacca Strait BS #32 in dropdown
- **2026 (lazport)** — One-way port from Delphi/TMS VCL to Lazarus/LCL. Extracted command-line builder into `IHCLCmdLineBuilder`. 80 FPCUnit tests. High-DPI support. Locale bug fixed in `-t` validation.
- **2026 (fileorg)** — Managed file organization via `IHCLFileOrganization`. Structured directory tree under `<basedir>\HCLauncher\` for BattleSets, PlatformDBs, Scenarios, SavedGames, ExportDLLs, Sounds, Graphics, Maps, Logs. Custom basedir override. 26 FPCUnit tests. Fixed incorrect file dialog filters (`.hcb`→`.res`, `.hcs`→`.sc?`, `.sav`→`.hp?`).
- **2026 (harpgamer)** — HarpGamer catalog integration. Server-side PHP generator uses IPS5 REST API to build source-independent JSON catalog (738 HC files). Launcher Downloads tab with category tree, sorted file list, detail panel with dependency info, search, direct download with IPS-CSRF session flow and progress bar. Multi-source catalog format supports additional community sites. 33 FPCUnit catalog tests (139 total).
- **2026 (extract)** — Extract-and-import into the managed tree via `uHCLArchive.pas` (safe ZIP listing/extraction with zip-slip rejection) and `uHCLImport.pas` (plan/execute placement policy). Closed the artifact-type→category TODO in `uMain1.pas` that previously hard-coded `hclBattleSets` for every download; added the `hclTools` category. ExportDLLs are targeted to `ExportDLLs\`, `GE\` or `SE\`. Wrapper directories are stripped during extraction (a first cut that moved files afterwards could push GE-only DLLs into the shared root). A manual run against the live catalog exposed two Phase 2 bugs that kept extraction from ever being offered — files not inheriting their category's `artifactType`, and every download being saved as `download.part.tmp` — both fixed, with downloaded filenames now sanitised. New FPCUnit suites cover the archive and import layers (300 tests total).
- **2026 (versions)** — The generator reads the IPS database directly (names, sizes, SHA-256 from the stored files, record-specific `r=` download links) and publishes each entry's earlier versions (`versions`, from `downloads_filebackup`; e.g. all 26 HCDB2 builds that scenarios name). The launcher's details panel has a Version dropdown; an earlier version downloads and imports beside the current one (`HCLSelectVersion`, `HCLVersionedName`). 313 FPCUnit tests.

## Porting Lessons (Delphi → Lazarus/FPC)

Gotchas encountered during the 2026 port — relevant if porting other Stratsims projects:

- **`PWideChar` → `PChar`**: FPC's Windows unit declares `GetFileVersionInfoSize` etc. with `PChar`, not `PWideChar`. Delphi uses `PWideChar` in Unicode mode.
- **`TOpenDialog.Options.StrictFiltering`**: Not a valid LFM property in LCL — causes `EReadError` at form load. Remove from any converted `.dfm`→`.lfm`.
- **`CICGetAppVersionStr` on FPC-compiled exe**: FPC does not embed VERSIONINFO by default (unlike Delphi). Wrap calls in try/except or add a `.rc` file with version resource.
- **TMS controls have no LCL equivalent**: Must be replaced one-by-one with standard LCL controls. `.SelectedItemIndex` → `.ItemIndex`, `.FileName` → `.Text`, `OnItemSelected` → `OnChange`. The 8700-line TMS `.dfm` cannot be converted — build `.lfm` from scratch.
- **`{$R *.res}` in `.lpr`**: FPC generates its own `.res` — the Delphi `.res` is replaced automatically. No conflict if using `ResourceType = res` in `.lpi`.
- **SVN tag before deleting Delphi files**: Tag `last-delphi` preserves the final Delphi-compilable state.

## Third-Party Components

Standard LCL controls only. No third-party component dependencies. ZIP extraction uses the `zipper` unit (`TUnZipper`), part of FPC's paszlib package — ships with the compiler under the same modified-LGPL-with-linking-exception as the RTL, compatible with a proprietary license.

## Key Dependencies Outside This Directory

- `../shared/pascal/uCICVersionInformation.pas` — shared unit, changes affect sibling projects (HC, CIC)

## Broader Ecosystem

HC Launcher is part of the Stratsims/StratsimsOSS family of Delphi/Pascal projects for the Harpoon Classic (HC) game. Key sibling projects and shared infrastructure:

### TGlobe5 Component (`C:\Prog\Projects\Stratsims\Delphi\Components\TGlobe5`)

Map rendering component used by HC utilities (e.g., BSBuilder at `C:\Prog\Projects\HC\Util\BSBuilder\`). Supports both Delphi and Lazarus/FPC:

- **Delphi**: Open the appropriate `Packages/TGlobe5_*.dpk` for your Delphi version (D5 through 13)
- **Lazarus**: `lazbuild --build-all Packages/TGlobe5_Lazarus.lpk` (or `--add-package` + `--build-ide=` to install)
- **Linux cross-compile**: `lazbuild --os=linux --cpu=x86_64 --build-all Packages/TGlobe5_Lazarus.lpk`
- **Conditional compilation**: `Source/Globe5.inc` auto-detects FPC vs Delphi, defines `TG_FPC`/`TG_DELPHI*`/`TG_MSWINDOWS`/`TG_LINUX`. All `.pas` files must `{$I Globe5.inc}` before the `unit` keyword (required for FPC `{$MODE DELPHI}`).
- **FPC/Delphi compat notes**: See `TGlobe5/Docs/fpc-lazarus.md` for unit-scoped names, `QueryInterface` signature differences (`constref` vs `const`), `RecreateWnd`, set-to-byte typecasts, pointer dereference patterns.

### General Shared Code (`../shared/pascal/`, prefix `uCIC*`)

MIT-licensed, SVN-managed Pascal units available to all Stratsims projects. Docs in `../shared/pascal/docs/`.

**Cross-compiler (FPC + Delphi) — OSM tile pipeline:**

| Unit | Purpose |
|------|---------|
| `uCICOSMTileCommon` | Constants/types: tile size (256px), lat limit, `TOSMTilePixels` BGRA array. `{$WEAKPACKAGEUNIT}` |
| `uCICOSMTileMath` | Pure functions: lat/lon ↔ Mercator ↔ tile indices, scale→zoom |
| `uCICOSMTileDecode` | PNG→BGRA decode with LCL/VCL platform fixes |
| `uCICOSMTileStore` | LRU tile cache (`TGOSMTileCache`), open-addressing hash, 262KB/slot |
| `uCICTileDownloader` | Async HTTP download queue (`TGTileFetcher`), atomic writes, blacklist, dedup |
| `uCICOSMTileManager` | Coordinator owning cache + downloader; used by TGlobe4/TGlobe5 |

**Cross-compiler — other:**

| Unit | Purpose |
|------|---------|
| `uCICOpenSSL3` | Runtime patch for FPC's openssl.pas to support OpenSSL 3.x on Linux. Must appear in `uses` before `opensslsockets`. No-op on Windows. |

**FPC/Lazarus only — Harpoon Classic files** (extracted from HCPE, relicensed MIT):

| Unit | Purpose |
|------|---------|
| `uCICHCLzh` | LZHUF decoder for LZH bodies in `.RES`/`.RSR` (decode only) |
| `uCICHCResContainer` | `.RES` container read/write: BBFT prefix, offset table, 5/7-byte headers by file name, empty slots |

**FPC/Lazarus only — MQTT:**

| Unit | Purpose |
|------|---------|
| `uCICMQTTProtocol` | Stateless MQTT 5.0/3.1.1 packet builder/parser, pure functions, no I/O |
| `uCICMQTTClient` | Full MQTT 5.0 client (`TCICMQTTClient`) with auto 3.1.1 fallback, TLS, keepalive, QoS 0/1, exponential backoff reconnect. Thread-safe. |
| `uCICG4Presenters` | Custom TGlobe4 point presenter with extended shapes and heading arrows |

**Delphi/VCL only:**

| Unit | Purpose |
|------|---------|
| `uCICVersionInformation` | Extract PE VERSIONINFO → version string (used by HC Launcher). Now FPC-compatible with `{$IFDEF FPC}{$MODE DELPHI}` and `{$IFDEF MSWINDOWS}` guards (returns `''` on Linux). |
| `uCICExecuteProgram` | `TCICExecuteProgram` — ShellExecuteEx wrapper with IsStillRunning polling |

**Tests** (`../shared/pascal/tests/`): FPCUnit suites for MQTT — `test_MQTTPackets` (pure function tests) and `test_MQTTIntegration` (broker tests, Docker localhost or test.mosquitto.org).

**Dependency flow:** `uCICOSMTileCommon` → `TileMath`/`TileDecode` → `TileStore` → `TileManager` ← `TileDownloader`. MQTT: `Protocol` → `Client`.

### TGlobe-Specific Shared Code

- `C:\Prog\Projects\Stratsims\SharedCode\` (prefix `uCICTGlobe*`): OSM tile renderer base class

### HC Project (`C:\Prog\Projects\HC\`)

The main Harpoon Classic game project. Uses TGlobe5 in utilities like BSBuilder for map visualization/editing. HC does not add custom defines to TGlobe5 — it uses the component as-is.

### HC Shared Units (`../HC/shared/pascal/`, prefix `uHC*`)

Shared Pascal units defining HC's data model, used by ExportDLLs and HC utilities:

| Unit | Purpose |
|------|---------|
| `uHCDefines.pas` | Constants — side IDs, marker types (MT_SHIP, MT_SUB, MT_AC...), event types (ATTACK_EVENT, LAUNCH_EVENT...), annex type flags (ANNEX_A1..ANNEX_Z2), sliver/distance/time constants |
| `uHCTypeDefs.pas` | Packed records — THCGroup (group linked list), THCUnit (platform), THCHarpoonEvent (game event), THCPathRec (waypoint), event-specific records (THCAttackEvent, THCSpeedAltEvent, etc.), scenario/victory data |
| `uHCAnnexDefs.pas` | Platform database records — disk and memory variants for each annex type (ships, subs, aircraft, sensors, weapons, torpedoes, missiles, guns, bombs, loadouts, magazines, land installations, satellites, sonobuoys, special weapons, mines) |
| `uHCAnnexHelpers.pas` | Type-safe annex access — IHCAnnexHelper/IHCAnnexMemHelper interfaces, lookup by annex ID, ref-counted lifetime |
| `uHCGCI.pas` | Geographic math — sliver↔degree conversion, great-circle position (HCNewPos), range/bearing (HCGetRangeBearing, HCFindRangeBearing), Vincenty direct, intercept angle, altitude band conversion |
| `uHCEventHelpers.pas` | Event utilities — type-to-string, event-to-JSON serialization, air patrol event lookup |
| `uHCDateTime.pas` | Date/time increment with month/year/leap-year boundary handling |
| `uHCUtils.pas` | Validation (HCIsValidGroup/Unit), marker type tests (HCMTIsAir/Ship/Sub...), display helpers, UUID↔pointer lookups, airborne endurance/bingo calculations |
| `uHCGlobals.pas` | Weather modifier tables (visibility, IR, ESM, radar) |

### HC ExportDLL Interface

Full documentation: `../HC/shared/docs/ExportDLL-Interface-Docs.md`

Win32 DLL plugin interface (cdecl) allowing external DLLs to receive game-state callbacks from the GE and SE. DLLs are loaded from `<HC_DIR>/ExportDLLs/` (common), `ExportDLLs/GE/` (GE-only), or `ExportDLLs/SE/` (SE-only). HC discovers exports by name via `GetProcAddress` — DLLs only export the callbacks they need.

**Target interface version: 45** (versions 4–33 disabled due to THCHarpoonEvent structure change at v34).

Key export categories (68 slots total):
- **Lifecycle**: `DLLInit`, `DLLFree`, `DLLVer`, `DLLDesc`
- **Scenario**: `ScenLoad`, `ScenLoaded`, `DBLoaded`, `SaveGame`, `SaveScen`
- **Game tick**: `GameTime`, `TimeFactor`
- **Group/Unit pointers**: `StartGroup`, `ActGroupPtr`, `ActUnitPtr`, `UnitTop`
- **Unit notifications**: `UnitLatLon`, `UnitShowing`, `UnitCourse`, `UnitSpeed`, `UnitAlt`, `UnitSink`, `UnitFree`, `UnitNew`
- **Events**: `HarpoonEventHead`, `HarpoonEventQueued`
- **Victory**: `VictoryConditionsList`, `VictoryConditionAchieved`, `VictoryConditionLevels`
- **Effects**: `Effect00`–`Effect22` (23 overridable game-logic hooks, GE only)

Best practice: use `QueueHarpoonEvent` callback for game-state changes; direct pointer writes only when no event equivalent exists.

**Coordinate system (slivers)**:
- 1 degree = 372,827 slivers (`SLIVER1`); 90 degrees = 33,554,432 (`SLIVER90`)
- Latitude: 0 = 90°N, SLIVER90 = equator, SLIVER180 = 90°S
- Longitude: 0 = Greenwich, positive = east, negative = west
- Distance: 6,211 distance units per nautical mile (`NM1`)
