diff --git a/.github/AS-IS-ANALYSIS.md b/.github/AS-IS-ANALYSIS.md new file mode 100644 index 0000000..42e19f7 --- /dev/null +++ b/.github/AS-IS-ANALYSIS.md @@ -0,0 +1,265 @@ +# DCS-CTLD — As-Is Analysis + +> This document captures the current state of the CTLD codebase prior to +> the v2 modernization effort. It serves as a reference and justification +> for the changes outlined in `MODERNIZATION-PLAN.md`. + +--- + +## 1. Overview + +| Metric | Value | +| ------ | ----- | +| Primary script | `CTLD.lua` | +| Lines of code | ~8 700 | +| i18n script | `CTLD-i18n.lua` | +| Bundled dependency | `mist.lua` (MIST 4.5 build 128-DYNSLOTS-02) | +| Lua version | 5.1 (DCS sandbox) | +| Public functions (`ctld.*`) | 100+ | +| Local / private functions | 0 (everything is public on the `ctld` table) | +| OOP / metatables usage | None — fully procedural | +| Unit tests | None | + +--- + +## 2. File structure + +```text +. +├── CTLD.lua -- Main script (monolith) +├── CTLD-i18n.lua -- Translation tables (FR, ES, KO) +├── mist.lua -- MIST library (stock, not customized) +├── beacon.ogg -- Radio beacon sound +├── beaconsilent.ogg -- Silent beacon sound (FC3) +├── README.md -- User / mission-maker guide +├── demo-mission.miz +├── test-mission.miz +├── test-dev-dynamic.miz +├── test-dev-static.miz +├── test_witchcraft_#131.miz +└── test_witchcraft_#137 et #149.miz +``` + +No `src/`, no `test/`, no `docs/`, no CI configuration. + +--- + +## 3. CTLD.lua section breakdown + +| Section | Lines | Content | +| ------- | ----- | ------- | +| Header + contributors | 1–35 | Credits, links | +| i18n table setup | 36–360 | English reference keys (all `= ""`), `i18n_translate()` | +| USER CONFIGURATION | 403–600 | 50+ tunable parameters | +| Crate configuration | 601–1 200 | `ctld.spawnableCrates`, AA system templates | +| Public API functions | 1 200–1 950 | Functions usable from DO SCRIPT triggers | +| Core gameplay logic | 1 950–4 600 | Troops, vehicles, crates, FOBs, beacons | +| JTAC subsystem | 4 600–7 000 | Targeting, lasing, IR points, F10 menus | +| AI processing + menus | 7 000–8 200 | AI auto-load/unload, F10 menu building | +| `ctld.initialize()` | 8 190–8 400 | State tables init, zone parsing | +| Event handler + tools | 8 400–8 705 | DCS event handler, `ctld.tools` utilities | + +--- + +## 4. State management + +34 global tables inside the `ctld` namespace track runtime state. +Most are duplicated per coalition. + +### 4.1 — Coalition-duplicated tables (RED / BLUE pairs) + +| Table pair | Content | +| ---------- | ------- | +| `ctld.spawnedCratesRED` / `BLUE` | Spawned crate statics | +| `ctld.droppedTroopsRED` / `BLUE` | Deployed infantry groups | +| `ctld.droppedVehiclesRED` / `BLUE` | Deployed vehicles | +| `ctld.droppedFOBCratesRED` / `BLUE` | FOB crates on ground | + +This duplication creates **50+ `if coalition == 1 then … RED … else … BLUE`** branches. + +### 4.2 — Shared tables + +| Table | Content | +| ----- | ------- | +| `ctld.inTransitTroops` | Cargo currently onboard (keyed by unit name) | +| `ctld.inTransitSlingLoadCrates` | Simulated sling-load crates | +| `ctld.builtFOBS` | Completed FOB positions | +| `ctld.completeAASystems` | Assembled AA system groups | +| `ctld.deployedRadioBeacons` | Active beacons | +| `ctld.fobBeacons` | FOB beacon cache (refreshed every 60 s) | +| `ctld.extractZones` | Extract zone definitions | +| `ctld.hoverStatus` | Hover-over-crate tracking | +| `ctld.crateLookupTable` | Crate weight → type lookup | +| `ctld.callbacks` | Registered callback functions | +| `ctld.jtacUnits` | JTAC unit references | +| `ctld.jtacCurrentTargets` | JTAC active targets | +| `ctld.jtacSelectedTarget` | Player-selected JTAC targets | +| `ctld.jtacGeneratedLaserCodes` | Allocated laser codes | +| `ctld.usedUHFFrequencies` / `VHF` / `FM` | Radio frequency pools | + +--- + +## 5. Code duplication patterns + +### 5.1 — RED/BLUE branching (most pervasive) + +```lua +-- This pattern appears 50+ times +if _heli:getCoalition() == 1 then + _list = ctld.droppedTroopsRED +else + _list = ctld.droppedTroopsBLUE +end +``` + +### 5.2 — Troop / Vehicle symmetry + +Many functions have near-identical troop and vehicle variants differentiated +only by a boolean parameter (`true` = troops, `false` = vehicles). + +### 5.3 — Sling load vs simulated load + +Two code paths for crate pickup depending on `ctld.slingLoad`: + +- Real sling load (DCS native, crashy) +- Simulated hover load (custom implementation) + +### 5.4 — Zone handling + +Pickup zones, dropoff zones, and waypoint zones share similar parsing +(smoke color, coalition check, active flag) but are implemented separately. + +--- + +## 6. MIST dependency + +91 calls to `mist.*` functions across the codebase. + +| Category | Functions | Call count | +| -------- | --------- | ---------- | +| Utility | `deepCopy`, `round`, `makeVec2/3` | ~28 | +| Distance / vectors | `get2DDist`, `vec.mag`, `vec.dp`, `vec.sub` | ~15 | +| Heading / bearing | `getHeading` | ~8 | +| Coordinate format | `tostringLL`, `tostringMGRS` | ~4 | +| Spawning | `dynAdd`, `dynAddStatic` | ~8 | +| Route / waypoints | `buildWP`, `getGroupRoute` | ~4 | +| LOS / search | `getUnitsLOS`, `getAvgPos`, `makeUnitTable` | ~4 | +| Database | `mist.DBs.unitsByName` | iterated | +| Scheduling | `mist.scheduleFunction` | ~1 | +| Other | misc | ~19 | + +No functions provide a fallback if MIST is absent — CTLD hard-crashes on +`assert(mist ~= nil)` during initialization. + +--- + +## 7. Scheduling and timers + +20+ `timer.scheduleFunction` calls drive recurring behavior. +All timers reschedule themselves recursively; there are no continuous +polling loops. + +| Timer | Interval | Purpose | +| ----- | -------- | ------- | +| `checkTransportStatus` | 3 s | Monitor transport helicopters | +| `checkHoverStatus` | 1 s | Track hover-over-crate countdown | +| `refreshRadioBeacons` | 60 s | Update beacon battery status | +| `refreshSmoke` | 300 s | Refresh smoke markers | +| `checkAIStatus` | 2 s | AI troop behavior check | +| `timerJTACAutoLase` | variable | JTAC targeting loop | +| `timerLaseUnit` | variable | Single-unit lasing | +| `autoUpdateRepackMenu` | 1 s | Refresh vehicle repacking F10 menu | +| `reconRefreshTargetsInLosOnF10Map` | variable | RECON map markers | + +--- + +## 8. Error handling + +- **pcall usage**: 12 instances, mainly around crate spawning and hover math. +- **Nil checks**: Extensive `if X == nil then return end` before DCS API calls. +- **No structured error propagation**: errors are logged via `env.error()` / + `ctld.logError()` and silently swallowed. +- **No stack traces** or exception chaining. + +--- + +## 9. Internationalization (i18n) + +| Language | Code | `translation_version` | Completeness | +| -------- | ---- | --------------------- | ------------ | +| English | `en` | 1.6 | Reference (keys only, values = `""`) | +| French | `fr` | 1.6 | Partial — many crate/equipment names empty | +| Spanish | `es` | 1.6 | Similar to French | +| Korean | `ko` | **1.1** | Severely outdated, many missing keys | + +Issues: + +- No tooling to detect missing keys or version drift. +- Empty string (`""`) is a valid Lua value, so missing translations silently + fall back to the English key (which is also `""` for reference entries). +- All translations live in a single `CTLD-i18n.lua` file — no per-language + separation. + +--- + +## 10. Documentation + +| Audience | Coverage | Location | +| -------- | -------- | -------- | +| Mission maker | Partial | `README.md` (setup, config, API examples) | +| Player | Minimal | `README.md` (gameplay mechanics mentioned briefly) | +| Developer | None | No architecture doc, no contributing guide | + +README strengths: + +- Good coverage of pickup/dropoff zone configuration. +- Code examples for DO SCRIPT functions. +- Dynamic loading workflow documented. + +README gaps: + +- JTAC advanced features poorly explained. +- No API reference table (signatures, parameters, return values). +- No architecture or data flow diagrams. +- Some examples use different defaults than the current code. + +--- + +## 11. Testing + +- **No automated tests** of any kind. +- **Manual smoke testing** via `.miz` missions in the repository: + - `test-mission.miz` — full feature demonstration + - `test-dev-dynamic.miz` — dynamic script loading for fast iteration + - `test-dev-static.miz` — static loading variant + - `test_witchcraft_#131.miz`, `test_witchcraft_#137 et #149.miz` — bug repro missions +- No test framework, no mocks, no CI. + +--- + +## 12. Dead code and technical debt + +| Item | Location | Detail | +| ---- | -------- | ------ | +| Commented-out blocks | 18+ blocks across file | Old implementations, debug markers, disabled alternatives | +| Unused function | `ctld.tools.getRelativeBearing` | Defined but never called | +| Unused function | `ctld.tools.isValueInIpairTable` | Called once, could be inlined | +| Commented event handler | `ctld.initialize()` | Old `ctld.eventHandler` pattern, replaced but not removed | +| Disabled vehicle types | Crate config tables | Many entries commented out (`-- BUK`, `-- Strela`, etc.) | +| Debug markers | Various | `--ctld.logTrace("FG_ XXXX...")` left in code | +| Alternate coordinate | `ctld.listFOBS()` | MGRS conversion commented out | + +--- + +## 13. Summary of pain points + +1. **Monolithic file**: 8 700 lines, impossible to navigate or review efficiently. +2. **No encapsulation**: 100+ public functions, 0 local functions, all state is global. +3. **RED/BLUE duplication**: 50+ coalition branches + paired tables. +4. **MIST hard dependency**: 91 calls, no fallback, no abstraction layer. +5. **No tests**: zero automated tests, zero mocks, zero CI. +6. **No OOP**: purely procedural, no classes, no metatables. +7. **Dead code**: 18+ commented blocks, unused functions. +8. **i18n drift**: Korean 3 versions behind, many empty translations. +9. **No developer documentation**: new contributors must read 8 700 lines to understand the architecture. +10. **No build system**: the source file IS the deliverable. diff --git a/.github/MODERNIZATION-PLAN.md b/.github/MODERNIZATION-PLAN.md new file mode 100644 index 0000000..3f2ace0 --- /dev/null +++ b/.github/MODERNIZATION-PLAN.md @@ -0,0 +1,364 @@ +# DCS-CTLD Modernization Plan + +> Status: **Draft** +> Branch: `next` (git flow, `main` stays stable) +> Target: CTLD v2.0 + +--- + +## Vision + +Rewrite CTLD as a modern, modular, and testable Lua project while +temporarily preserving backward compatibility with existing missions. +The deliverable remains a single `.lua` file produced by an automated build. + +--- + +## Architectural decisions + +Key decisions made during the planning phase, for reference. + +| # | Topic | Decision | +| - | ----- | -------- | +| 1 | Module split | Separate source files in `src/`, concatenated into a single `dist/CTLD.lua` by a build script (CI) | +| 2 | OOP level | Full OOP Lua 5.1 with metatables and classes — ready to break backward compat when needed | +| 3 | MIST dependency | Middleware layer (`src/mist_compat/`): CTLD never calls `mist.*` directly. Long-term goal: eliminate MIST entirely | +| 4 | API breaking changes | Short/medium term: legacy wrappers with deprecation warnings. Long term (v3): legacy API removed | +| 5 | Lua environment | Lua 5.1 DCS sandbox, desanitized server assumed (`io`, `os`, `lfs` accessible) | +| 6 | Testing | Both: busted + DCS/MIST mocks in CI, and in-game test missions for integration | +| 7 | Documentation | 3 audiences (player, mission maker, developer). Markdown in `docs/`, auto-published to GitHub Pages via MkDocs | +| 8 | i18n | Included in plan: audit missing keys, CI lint for version drift, cleanup empty translations | +| 9 | Priorities | 1-Cleanup, 2-OOP, 3-MIST middleware, 4-Legacy compat, 5-Tests, 6-CI, 7-i18n, 8-Docs | +| 10 | Branching | `next` branch for v2, git flow. `main` stays stable. Feature branches: `feature/-` | + +--- + +## Guiding principles + +- **OOP Lua 5.1**: metatables, classes, state encapsulation. +- **Separate modules** in development, single file in delivery. +- **Zero direct MIST dependency**: all MIST usage goes through a middleware layer. +- **Automated testing**: pure logic tested outside DCS, integration tested in-game. +- **Auto-generated documentation**: from the repo to GitHub Pages. +- **Transitional legacy compatibility**: deprecated wrappers with warnings, removed in v3. + +--- + +## Phases + +### Phase 1 — Dead code cleanup + +**Goal**: Start from a clean, noise-free baseline. + +| Task | Detail | +| ---- | ------ | +| 1.1 | Remove the 18+ identified commented-out code blocks | +| 1.2 | Remove unused functions (`ctld.tools.getRelativeBearing`, etc.) | +| 1.3 | Remove state variables that are never read | +| 1.4 | Clean up obsolete `--TODO`/`--FIXME` markers | +| 1.5 | Validate with existing test missions that nothing breaks | + +**Deliverable**: A lighter CTLD.lua, functionally identical. + +--- + +### Phase 2 — Module split + OOP + +**Goal**: Transform the procedural monolith into a modular, object-oriented architecture. + +#### 2.1 — Lua 5.1 class system + +Define a micro class framework based on metatables: + +```lua +-- src/lib/class.lua +local function class(base) + local cls = {} + cls.__index = cls + if base then setmetatable(cls, { __index = base }) end + function cls:new(...) + local instance = setmetatable({}, cls) + if instance.init then instance:init(...) end + return instance + end + return cls +end +``` + +#### 2.2 — Module layout + +Target structure for the `src/` directory: + +```text +src/ +├── lib/ +│ ├── class.lua -- OOP micro-framework +│ ├── utils.lua -- Utilities (deepCopy, formatText, logging) +│ └── vec.lua -- Vector math (2D/3D distance, bearing) +├── core/ +│ ├── config.lua -- User configuration (USER CONFIGURATION) +│ ├── state.lua -- State manager (replaces 34 global tables) +│ ├── coalition.lua -- Coalition class (eliminates RED/BLUE duplication) +│ ├── i18n.lua -- i18n system +│ └── events.lua -- Event handler + callback system +├── transport/ +│ ├── transport.lua -- Transport class (heli/plane) +│ ├── troops.lua -- Troop management (load/unload/extract) +│ └── vehicles.lua -- Vehicle management +├── logistics/ +│ ├── crate.lua -- Crate class +│ ├── crate_manager.lua -- Spawning, hover, sling load, unpack +│ ├── fob.lua -- FOB construction and management +│ └── beacon.lua -- Radio beacons +├── jtac/ +│ ├── jtac_controller.lua -- JTACController class +│ ├── targeting.lua -- Target acquisition, LOS, priorities +│ ├── lasing.lua -- Laser/IR point, spot corrections +│ └── menu.lua -- F10 JTAC menus +├── ui/ +│ ├── f10_menu.lua -- F10 menu construction +│ ├── messages.lua -- Player messages (displayMessageToGroup) +│ └── smoke.lua -- Smoke markers +├── recon/ +│ └── recon.lua -- Target recognition on F10 map +├── ai/ +│ └── ai_transport.lua -- AI auto-load/unload logic +├── compat/ +│ └── legacy_api.lua -- Deprecated ctld.* wrappers +├── mist_compat/ +│ └── mist_middleware.lua -- MIST middleware (see Phase 3) +└── ctld.lua -- Entry point, initialization, orchestration +``` + +#### 2.3 — Core classes + +| Class | Responsibility | Replaces | +| ----- | -------------- | -------- | +| `Coalition` | Encapsulates side (1/2) and per-coalition state | `ctld.spawnedCratesRED/BLUE`, `ctld.droppedTroopsRED/BLUE`, etc. (34 tables → 2 instances) | +| `Transport` | State of a transport helicopter/plane | `ctld.inTransitTroops[name]`, `ctld.hoverStatus[name]` | +| `Crate` | Represents a logistics crate | Entries from `ctld.spawnableCrates`, `ctld.crateLookupTable` | +| `CrateManager` | Spawn, pickup, drop, unpack crates | `ctld.spawnCrate`, `ctld.unpackCrates`, `ctld.checkHoverStatus` | +| `FOB` | A built Forward Operating Base | `ctld.builtFOBS[name]` | +| `JTACController` | An active JTAC with its lasing state | `ctld.jtacUnits`, `ctld.jtacCurrentTargets`, `ctld.jtacSelectedTarget` | +| `Beacon` | A deployed radio beacon | `ctld.deployedRadioBeacons[name]` | +| `StateManager` | Central registry of all active objects | Replaces 34 global tables | +| `Config` | Typed user configuration | Current USER CONFIGURATION section | + +#### 2.4 — Eliminating RED/BLUE duplication + +Before (50+ branches): + +```lua +if _heli:getCoalition() == 1 then + _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsRED) +else + _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsBLUE) +end +``` + +After: + +```lua +local side = stateManager:getCoalition(heli:getCoalition()) +local extract = side:findNearestDroppedTroop(heli) +``` + +--- + +### Phase 3 — MIST middleware + +**Goal**: Isolate MIST behind a facade. CTLD never references `mist.*` directly. + +| Task | Detail | +| ---- | ------ | +| 3.1 | Inventory the 91 MIST calls and categorize them (trivial / medium / complex) | +| 3.2 | Create `src/mist_compat/mist_middleware.lua` exposing a clean API | +| 3.3 | Rewrite trivial functions: `deepCopy`, `get2DDist`, `round`, `makeVec2/3` | +| 3.4 | Wrap medium functions: `getHeading`, `vec.*`, `tostringLL/MGRS` | +| 3.5 | Delegate complex functions to MIST: `dynAdd`, `dynAddStatic`, `getUnitsLOS` | +| 3.6 | Replace all `mist.*` calls in modules with middleware calls | +| 3.7 | (Long term) Rewrite complex functions to eliminate MIST entirely | + +**Deliverable**: CTLD works with or without MIST (graceful degradation when MIST is absent, eventually). + +--- + +### Phase 4 — Legacy API compatibility layer + +**Goal**: Existing missions continue to work without modification. + +| Task | Detail | +| ---- | ------ | +| 4.1 | List all public `ctld.*` functions documented in the README | +| 4.2 | Create `src/compat/legacy_api.lua` with wrappers that call the new API | +| 4.3 | Each wrapper logs a deprecated warning with the new API name | +| 4.4 | Document old → new migration in `docs/migration-v2.md` | +| 4.5 | Announce the policy: legacy maintained in v2, removed in v3 | + +Example: + +```lua +-- legacy_api.lua +function ctld.spawnCrateAtZone(_side, _weight, _zone) + ctld.logWarning("DEPRECATED: ctld.spawnCrateAtZone() -> use CrateManager:spawnAtZone()") + local side = (_side == "red") and 1 or 2 + return ctld.crateManager:spawnAtZone(side, _weight, _zone) +end +``` + +--- + +### Phase 5 — Unit tests + +**Goal**: Coverage of pure logic outside DCS + in-game smoke tests. + +#### 5.1 — Framework and mocks + +| Task | Detail | +| ---- | ------ | +| 5.1.1 | Set up busted (Lua 5.1) + luarocks in the repo | +| 5.1.2 | Create `test/mocks/dcs_env.lua`: stubs for `trigger`, `Unit`, `Group`, `coalition`, `land`, `timer`, `missionCommands`, `coord`, `world`, `env` | +| 5.1.3 | Create `test/mocks/mist_env.lua`: stubs for MIST functions used | +| 5.1.4 | Configure busted to load mocks before tests | + +#### 5.2 — Unit tests (outside DCS) + +| Module | Priority tests | +| ------ | -------------- | +| `lib/class.lua` | Inheritance, instantiation, override | +| `lib/vec.lua` | 2D/3D distance, bearing, clock direction | +| `lib/utils.lua` | deepCopy, formatText | +| `core/coalition.lua` | Per-coalition state management, lookup | +| `core/i18n.lua` | Translation, fallback, parameters | +| `core/config.lua` | Default values, override | +| `logistics/crate.lua` | Weight uniqueness, lookup | +| `compat/legacy_api.lua` | Wrappers call the correct new API | + +#### 5.3 — In-game tests + +| Task | Detail | +| ---- | ------ | +| 5.3.1 | Create an automated test mission (DO SCRIPT running a test suite) | +| 5.3.2 | Write results to a file via `io.open` (desanitized server) | +| 5.3.3 | Validate: troop load/unload, crate spawn/unpack, JTAC lasing, FOB build, beacons | + +--- + +### Phase 6 — CI infrastructure + +**Goal**: Automate build, tests, and release. + +| Task | Detail | +| ---- | ------ | +| 6.1 | **Build script**: Lua (or Python/Bash) script that concatenates `src/**/*.lua` → `dist/CTLD.lua` in the correct order | +| 6.2 | **GitHub Actions — Tests**: install Lua 5.1 + luarocks + busted, run `busted test/` | +| 6.3 | **GitHub Actions — Build**: generate `dist/CTLD.lua` and `dist/CTLD-i18n.lua` | +| 6.4 | **GitHub Actions — Release**: on tag, publish the `.lua` artifact as a GitHub release | +| 6.5 | **GitHub Actions — Docs**: MkDocs build + deploy to GitHub Pages | +| 6.6 | **i18n lint**: CI script comparing keys across languages and checking `translation_version` | + +--- + +### Phase 7 — i18n cleanup + tooling + +**Goal**: Reliable i18n with automatic drift detection. + +| Task | Detail | +| ---- | ------ | +| 7.1 | Full audit: list EN vs FR vs ES vs KO keys, identify missing ones | +| 7.2 | Fill empty FR keys (crate/equipment names) | +| 7.3 | Update KO (1.1 → 1.6+) or mark it as `incomplete` | +| 7.4 | CI lint script for i18n (see 6.6) | +| 7.5 | Document the process of adding a language in `docs/contributing/i18n.md` | +| 7.6 | Consider extracting i18n into per-language files (`i18n/fr.lua`, `i18n/ko.lua`) | + +--- + +### Phase 8 — Documentation + +**Goal**: 3 guides for 3 audiences, auto-published. + +#### 8.1 — `docs/` structure + +```text +docs/ +├── index.md -- Landing page +├── user-guide/ +│ ├── getting-started.md -- For the player: F10 menus, in-game workflow +│ ├── troops.md -- Troop loading/unloading +│ ├── crates.md -- Crate system +│ ├── jtac.md -- Using JTACs +│ ├── fob.md -- FOB construction +│ └── beacons.md -- Radio beacons +├── mission-maker/ +│ ├── setup.md -- Mission installation +│ ├── configuration.md -- All configurable options +│ ├── api-reference.md -- Public API (DO SCRIPT) +│ ├── zones.md -- Pickup/dropoff/waypoint zones +│ ├── jtac-setup.md -- Advanced JTAC configuration +│ └── examples.md -- Mission examples +├── developer/ +│ ├── architecture.md -- Module, class, and flow diagrams +│ ├── contributing.md -- How to contribute +│ ├── building.md -- Build script, CI +│ ├── testing.md -- Running tests +│ ├── i18n.md -- Adding/maintaining a translation +│ └── migration-v2.md -- v1 → v2 migration guide +└── mkdocs.yml -- MkDocs configuration +``` + +#### 8.2 — Publishing + +- MkDocs Material theme +- GitHub Actions: build + deploy to `gh-pages` on every push to `next` +- Slimmed-down README.md: links to the full documentation site + +--- + +## Indicative timeline + +| Phase | Dependencies | Complexity | +| ----- | ------------ | ---------- | +| 1 — Dead code cleanup | None | Low | +| 2 — Modules + OOP | Phase 1 | **High** | +| 3 — MIST middleware | Phase 2 | Medium | +| 4 — Legacy compat | Phase 2 | Medium | +| 5 — Tests | Phases 2-3 | Medium | +| 6 — CI | Phases 2, 5 | Medium | +| 7 — i18n | Phase 2 | Low | +| 8 — Documentation | Phases 2-4 | Medium | + +> Phases 3 and 4 can be worked on in parallel. +> Phase 6 can start as early as Phase 2 (build script) and grow incrementally. + +--- + +## Branching strategy + +```text +main (stable, v1.x) + └── next (v2 development) + ├── feature/phase1-cleanup + ├── feature/phase2-oop-core + ├── feature/phase2-oop-jtac + ├── feature/phase3-mist-middleware + ├── feature/phase4-legacy-compat + ├── feature/phase5-tests + └── ... +``` + +- `main`: stable v1.x releases, urgent hotfixes only. +- `next`: v2 integration, git flow (feature → next → release). +- Tags: `v2.0-alpha.1`, `v2.0-beta.1`, `v2.0-rc.1`, `v2.0`. + +--- + +## Risks and mitigations + +| Risk | Impact | Mitigation | +| ---- | ------ | ---------- | +| Gameplay regressions after OOP refactoring | High | Unit tests + systematic test missions | +| DCS mock divergence from real API | Medium | In-game tests as complement, versioned mocks | +| Incomplete MIST middleware | Medium | Progressive approach, MIST remains as fallback | +| Mission maker resistance to API changes | Medium | Legacy layer + communication + migration guide | +| Build script complexity (module ordering) | Low | Explicit dependencies, build tested in CI | diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..a364519 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,75 @@ +# Copilot Instructions for DCS-CTLD + +## Working mode / Mode de travail + +- **Communication language**: French (français) for all conversations and commit messages. +- **Documentation language**: English for all technical documentation (code comments, docs/, README). French summaries in docs are acceptable but English is the primary language. +- **Development methodology**: TDD (Test-Driven Development) — write tests before implementation when possible. +- **Programming paradigm**: OOP Lua 5.1 with metatables and classes. No procedural spaghetti. +- **Branching strategy**: Git flow on the `next` branch. Feature branches named `feature/-`. Never commit directly to `main` or `next`. +- **Commit style**: Conventional Commits (`feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`). +- **Build target**: Individual source modules in `src/` are concatenated into a single `dist/CTLD.lua` deliverable by a build script. Never edit the built file directly. +- **MIST dependency**: CTLD code must never call `mist.*` directly. All MIST usage goes through the middleware layer (`src/mist_compat/`). +- **Legacy API**: When refactoring a public `ctld.*` function, always create a deprecated wrapper in `src/compat/legacy_api.lua` that logs a warning and delegates to the new API. +- **Refer to the modernization plan**: See `.github/MODERNIZATION-PLAN.md` for the full roadmap and architectural decisions. + +## Project context +- This repository contains Lua mission scripts for DCS World. +- The primary script is CTLD.lua. +- Internationalization tables are split between CTLD.lua (English reference keys) and CTLD-i18n.lua (translated values). +- Runtime is DCS mission scripting environment (Lua 5.1, metatables available, no LuaJIT, no goto). +- Assumes desanitized server (io, os, lfs accessible). +- MIST is being progressively replaced by an internal middleware layer. + +## Architecture (v2 target) + +- Source modules live in `src/` organized by domain: `lib/`, `core/`, `transport/`, `logistics/`, `jtac/`, `ui/`, `recon/`, `ai/`, `compat/`, `mist_compat/`. +- OOP via a micro class system using metatables (`src/lib/class.lua`). +- State is managed by a `StateManager` singleton and per-coalition `Coalition` instances — no more `ctld.xxxRED`/`ctld.xxxBLUE` table pairs. +- Tests live in `test/` and use busted with DCS/MIST mocks. + +## Compatibility (v1 legacy) +- Preserve existing public ctld.* APIs used by Mission Editor DO SCRIPT triggers. +- Do not rename exported ctld functions or change their parameter semantics unless explicitly requested. +- Keep behavior compatible with existing .miz missions in this repository. +- Keep script load order assumptions intact: MIST first, CTLD-i18n.lua before CTLD.lua. + +## CTLD.lua editing rules +- Keep user-tunable options in the USER CONFIGURATION section with clear comments and safe defaults. +- Keep coalition conventions consistent: + - 1 = red + - 2 = blue + - 0 = both (where applicable) +- Keep pickup/dropoff/waypoint zone tuple formats compatible with current parser logic. +- Keep crate weight values unique in ctld.spawnableCrates. +- Preserve callback behavior and action names used by ctld.processCallback. +- Use defensive nil checks before calling methods on DCS objects (Unit/Group/zone lookups). +- Prefer existing logging patterns (ctld.logInfo, env.info, env.error) over ad-hoc prints. +- Avoid adding heavy polling loops; prefer bounded searches and scheduled checks. + +## I18N rules +- For every new player-visible string, add an English reference key and use ctld.i18n_translate at call sites. +- Do not hardcode new menu or gameplay text without i18n_translate. +- When adding keys, keep translation_version alignment in mind and add placeholders in CTLD-i18n.lua tables. +- Do not remove or rename existing i18n keys unless all language tables are updated. + +## Testing expectations +- Prefer the dynamic loading workflow documented in README for fast iteration. +- After gameplay logic changes, validate at least: + - troop load/unload flows + - crate spawn/load/unpack flows + - JTAC-related flows (if touched) +- Use repository missions for smoke tests when relevant: + - test-dev-dynamic.miz + - test-dev-static.miz + - test-mission.miz +- If user-facing behavior or configuration changes, update README examples in the same change. + +## Code style conventions + +- Follow existing file style and indentation. +- OOP Lua 5.1: use the project class system (`src/lib/class.lua`) for new classes. +- For internal helpers, follow existing naming patterns (local variables often prefixed with _). +- Keep mission-designer guidance comments concise and practical. +- No direct `mist.*` calls — use the middleware. +- Every new public function should have at least one unit test.