Skip to content

Rebuild Progress

Edoardo BAROLO edited this page Jul 31, 2026 · 9 revisions

Godot Rebuild Progress

The rebuild uses Godot 4.4 (.NET SDK) with C#. Project in BattleTechCHI/.

Current State: Phase 6 — Combat Mech Panel ANM + Map Cursor ANM (done)

BattleTechCHI/
├── Scripts/
│   ├── Core/       # GameLoop, StateManager, InputHandler, SaveManager
│   ├── Data/       # GameEnums, GameState, DataModels, WeaponData, CipherDecoder
│   ├── Maps/       # MapLoader, RleDecompressor, TileManager, WorldMapView, LocalMapView, DispatchTables
│   ├── BLD/        # BldLoader, BldInterpreter, Fn1CD3Dispatcher
│   ├── Combat/     # CombatManager, CombatResolver, CombatState, CombatTypes, AiController
│   ├── UI/         # EgaPalette, BorderPanel, StartupSequence, ShopScreen, AnmPlayer, ViewportManager, ViewportRegion, ViewportLayout
│   └── Main.cs     # Entry point
├── Scenes/
│   ├── Main.tscn
│   └── UI/
├── Data/           # Game data files
├── Assets/         # Converted PNG assets
└── Tests/          # Unit tests (33/33 passing)

Build & Run

cd BattleTechCHI
dotnet build
bash build.sh      # Build script
bash run.sh        # Run via xvfb-run godot

Completed Phases

Phase 0-1: Core Engine ✅

  • Godot 4 C# project scaffold
  • Data models (weapons, mechs, items, map headers)
  • Asset pipeline (MTP/BLD loaders)
  • Game loop (init → input → update → render)
  • State manager (world/local/combat/text/building modes)
  • Input handler (WASD, space, F-keys)
  • EGA palette (16 colors, swappable per asset)
  • Border compositing (80px left panel + viewport)
  • Save/load (original binary format)

Phase 2: Maps & Navigation ✅

  • Tile system (ICN tileset, 16×16 tiles, EGA palette)
  • MTP map loader (header + tile data)
  • World map (64×64 rendering, viewport)
  • Local maps (MAP1-14, scrollable viewport)
  • Cursor movement (collision, tile cost)
  • Location→BLD mapping (22 entries)
  • World/local/ interior transitions

Phase 3: BLD Interpreter ✅

  • BLD loader with decryption
  • Cipher decoder
  • Opcode dispatch (26 opcodes)
  • Narrative markers
  • Dialogue UI
  • fn1CD3_0004 dispatch (all 47 cases, real implementations)
  • Conditional system (RNG, state, credit checks)
  • Shop system (display/buy/sell/heal)
  • Room handlers (fn11B8 dispatch)
  • All 26 BLD files supported

Phase 4: Combat System ✅

Complete (June 2026):

Core combat (5 files, 540+ lines):

  • CombatTypes.cs: MechState class with full 11-location armour/structure arrays, 10 ammo bins, heat, crit flags; HitLocation enum (11 body parts); AmmoBin struct; CombatInputState enum
  • CombatState.cs: Twin 12×24 fog grids, 24 unit slots, phase tracking, kill chain state management, player input state tracking
  • CombatManager.cs: 12-phase state machine — Init → UnitLoop → Movement → Targeting → ToHit → Fire → PostFire → HeatDissipation → Complete. Features: movement approach toward target, collision/bounds checks, full 2D6 to-hit formula (skill popcount + terrain + heat thresholds + story state), hit location table, armour→structure damage flow, critical hits, cluster weapons (LRM/SRM per-missile via cluster hits table), ammo decrement, kill chain, combat→world transition with story state update. Player input methods: MovePlayerCursor, SelectNextWeapon, SelectWeaponByNumber, ConfirmPlayerAction, CancelPlayerAction
  • CombatResolver.cs: 24-bit LFSR RNG, Bresenham ray-cast LoS, to-hit computation, heat dissipation (pool→penalty→clear), hit location via RNG & 0x0A front table, criticals via 2D6 ≥ 8, ammo explosion, kill chain
  • AiController.cs: AI targeting from story state properties (offsets 0x33-0x55), action code by distance (short ≤3 / medium ≤6 / long ≤10), weapon selection by best range+damage with ammo check

Combat UI (2 files, 400+ lines):

  • CombatView.cs: TileMap-based 24×12 grid renderer with 15×12 viewport, unit sprites (player/enemy/infantry), fog overlay, green cursor box, red target reticle
  • CombatHUD.cs: Left panel (80px) info overlay with unit stats, weapon list (with ammo counts and selection marker), target info, combat message log, input prompts in all states

Input integration:

  • GameLoop._Input() handles arrow/WASD (cursor movement), Space/Enter (confirm), Escape (cancel), 1-9 (weapon select) during combat mode
  • InputHandler defers to GameLoop during combat mode
  • Two-step confirm flow: target select → weapon select → fire
  • BorderPanel shows combat grid coordinates during combat

Entry: BLD SHOP_DISPATCH 0x2DFn1CD3Dispatcher.CombatEncounter()GameMode.CombatGameLoop.StartCombatEncounter()CombatManager.StartCombat()

World map random encounters — EVERY frame while in WorldMap mode, (RNG & EncounterMask) == 0 triggers a combat encounter with 63-frame cooldown (bD335). EncounterMask starts at 0x1F (1/32 frames ≈ 2/sec) and reduces to 0x7F (1/128 ≈ 0.5/sec) after first victory. View visibility properly restored on combat → world transition.

Remaining Gaps (Closed June 2026)

Three blockers to end-to-end playability were fixed in the June 15 session:

Gap Fix
BLD path resolution Replaced ProjectSettings.GlobalizePath("../original/bld/...") with GetBldPath() — resolves res:// to absolute path, then Path.Combine to original/bld/. Works regardless of CWD.
Room interactions (0x21/0x22) Push/pop state: StorySlots[0]RoomStateBackup[125], clear unit slots 1-7, toggle RoomActive. BLD interpreter continues after dispatch (no mode change). Maps to original fn0FDC_1C9B / fn0FDC_1A26.
ENDMECH/WINSCENE dispatch Tile (26,5) map 1 hosts 4 BLDs (TRAINING, CITADEL, ENDMECH, WINSCENE). SelectBldForTile() picks based on game state: Milestone+[0x53]→WINSCENE, TrainingComplete+[0x52]→ENDMECH, TrainingComplete→CITADEL, else TRAINING.

All 26 BLD files are now loadable and the full story flow is wired. The engine is ready for end-to-end playtesting.

Phase 5: ANM Animation & ViewportManager ✅

Completed June 2026:

ANM Runtime Decompression:

  • RleDecompressor.DecompressAnimationFrames() — XOR-delta RLE decompression of raw .ANM files (3872 byte buffer → 88×88 frame)
  • AnmPlayer.LoadRaw() — loads .ANM binary with PNG fallback, timer-based playback at configurable FPS
  • AnmFramesToImage() — converts decompressed nibble frames to PNG Image

Dispatch Tables:

  • DispatchTables.csPositionInteractionTable (33-entry static, from DGROUP:0x21CE) + AnimationDispatchTable (12-entry runtime, from LocationMapper)
  • GameLoop.DispatchCursorMove() — wired for cursor-hover building name display

ViewportManager:

  • ViewportLayout.cs — enum with 6 values (WorldMap, LocalTiles, TextScreen, BuildingName, Combat, Stats)
  • ViewportRegion.csControl wrapper with SetRegionRect(), clipping, background
  • ViewportManager.csNode2D managing 3 regions per layout (LeftPanel 80×200, Viewport 240×192, BottomBar 320×8), layout switching, EGA-style border drawing, content reparenting
  • BorderPanel refactored — content only (AnmPlayer, labels), no layout elements
  • GameLoop wired — creates ViewportManager, assigns views to regions, calls SetLayout() in OnGameModeChanged()

w4FBA Documentation Corrected:

  • 4 docs (AGENTS.md, CONTEXT.md, TECHNICAL_ANALYSIS.md, BLD_BYTECODE.md): corrected from "set once at startup" / "NEVER modified" to describe 3 writes (startup keycode, render toggle 0→1, restore to 0), normalization via -= 0x31 at pseudocode L5961, protection screen as custom pre-loop text I/O, combat using w4FBC=1 not w4FBA

w4FBA Truth:

  • 3 writes total: (1) keycode 0x31-0x34 stored at pseudocode L5922, (2) render toggle to 1 at L6113 (only if w4FBA==0), (3) restore to 0 at L6130
  • Normalized to 0-3 at L5961 (-= 0x31)
  • Values: 0=WorldMap, 1=LocalTiles, 2=Text, 3=BuildingName
  • w4FBC (offset 0x4FBC) is the ACTUAL mechanism for combat/building/menu narrow-panel — NOT w4FBA
  • 3-pass pipeline: fn207F_18EF → fn1F3D_06C3 → fn1E56_03F5 (unchanged by mode)
  • Protection screen is custom pre-loop text I/O via fn1F3D_0259, NOT a viewport mode

Phase 6: Combat Mech Panel ANM & Map Cursor ANM ✅

Completed June 2026:

Map cursor animation — Frame-based spritesheet with RegionRect cycling replaces old Modulate-toggle blink.

Combat mech panel ANM (MechPortrait.cs):

  • Uses MECHSHAP 24×24 Locust/Commando sprites scaled to 48×48
  • Builds runtime spritesheet, cycles frames on timer
  • State mapping: Idle (4fps), Moving (8fps), Firing (yellow overlay 300ms), TakingDamage (red overlay 400ms)
  • Integrated into CombatHUD at top of 80px panel, labels shifted down

StorySlots fix — Corrected array size from 16 to 8 (original game has exactly 8 mech/story slots at 0xC724, stride 0x7D). All evidence: Reko, save format, combat ammo logic, Spice86 MCP tools.

Emulator A: drive fix — Game runs with DOS default drive = A: but only C: was mounted. Fixed by mounting A: and B: drives to same host directory as C: in DosDriveManager.cs. Full startup sequence now completes end-to-end.

MCP screen capture toolsbt_screenshot + bt_read_video_mode let the AI visually orient inside the emulated game:

  • Text modes (0x03 boot prompts) read char/attr pairs from B800:0000 → 80×25 readable text
  • Graphics modes (0x13/0x0D/0x0E) sample A000:0000 pixels 4×4 → 80×50 luminance grid via the standard VGA 16-color palette
  • Validated end-to-end: adapter prompt → drive prompt → mode 13h intro → world map navigation, all guided by screenshots
  • Also fixed DsAddr to use the fixed game data segment 0x1DE9 (runtime DS varies per scene: 0x1DE9=world map, 0x3858=building interiors)

Next: Phase 7 — Polish & Migration

  • ViewportManager refactor to w4FBC-style narrow-flag model
  • TileMapLayer migration (TileMap → TileMapLayer for Godot 4.4 compat)
  • End-to-end playtest & bugfixing