-
Notifications
You must be signed in to change notification settings - Fork 1
Rebuild Progress
The rebuild uses Godot 4.4 (.NET SDK) with C#. Project in BattleTechCHI/.
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)
cd BattleTechCHI
dotnet build
bash build.sh # Build script
bash run.sh # Run via xvfb-run godot- 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)
- 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
- 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
Complete (June 2026):
Core combat (5 files, 540+ lines):
-
CombatTypes.cs:
MechStateclass with full 11-location armour/structure arrays, 10 ammo bins, heat, crit flags;HitLocationenum (11 body parts);AmmoBinstruct;CombatInputStateenum - 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 & 0x0Afront table, criticals via2D6 ≥ 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 -
InputHandlerdefers to GameLoop during combat mode - Two-step confirm flow: target select → weapon select → fire
-
BorderPanelshows combat grid coordinates during combat
Entry: BLD SHOP_DISPATCH 0x2D → Fn1CD3Dispatcher.CombatEncounter() → GameMode.Combat → GameLoop.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.
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.
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.cs—PositionInteractionTable(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.cs—Controlwrapper withSetRegionRect(), clipping, background -
ViewportManager.cs—Node2Dmanaging 3 regions per layout (LeftPanel 80×200, Viewport 240×192, BottomBar 320×8), layout switching, EGA-style border drawing, content reparenting -
BorderPanelrefactored — content only (AnmPlayer, labels), no layout elements -
GameLoopwired — creates ViewportManager, assigns views to regions, callsSetLayout()inOnGameModeChanged()
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
-= 0x31at 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
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 tools — bt_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:0000pixels 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
DsAddrto use the fixed game data segment0x1DE9(runtime DS varies per scene: 0x1DE9=world map, 0x3858=building interiors)
- ViewportManager refactor to w4FBC-style narrow-flag model
- TileMapLayer migration (TileMap → TileMapLayer for Godot 4.4 compat)
- End-to-end playtest & bugfixing
BattleTech: The Crescent Hawk's Inception — Reverse Engineering Project. RE status: 95%. Godot rebuild: Phase 6 (Combat ANM + map cursor ANM + emulator startup fix).