This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a boiler simulator originally written in summer 2003 using Borland C++ with BGI (Borland Graphics Interface) for DOS. The project is being ported to modern C++17 with SDL2.
The simulator is an interactive educational tool for coal/fire boiler operations: users control fire intensity, air/water valves, and monitor temperature, pressure, and water level through animated gauges. The UI is entirely in Chinese (GB2312 encoding), rendered via HZK16 bitmap fonts.
make # Build boiler_sdl (requires SDL2)
make clean # Remove binary and .o filesRequires: g++, SDL2 development libraries (sdl2-config must be in PATH).
The port is split into 8 modules with a strictly acyclic dependency graph:
boiler_globals.h ← bgi_compat.h ← drawing.h ← physics.h ← handlers.h
↑
main.cpp
drawing.h is implemented across 4 source files (drawing.cpp, drawing_boiler.cpp, drawing_controls.cpp, drawing_dialogs.cpp).
| File | Lines | Role |
|---|---|---|
boiler_globals.h |
~96 | Shared constants, types, extern declarations for all globals |
bgi_compat.h/.cpp |
~695 | BGI compatibility layer: drawing primitives, fonts, text, value display, screen save/restore |
drawing.h |
~58 | Declares all draw_* functions |
drawing.cpp |
~62 | Simulation state variable definitions + mian_interface_initialize() |
drawing_boiler.cpp |
~433 | Boiler components: background, thermograph, stove (static), graduation marks, pipes (in/out/steam), boiler tank, barometer |
drawing_controls.cpp |
~409 | Controls: valves (water/air open/close), buttons (+/- and stove), control panel, pressed-state variants, stove door animation |
drawing_dialogs.cpp |
~368 | Dialogs: alarm indicators, ESC/HELP/MANUAL buttons, menus, warning windows, ABOUT, HELP window, ask buttons |
physics.h/.cpp |
~288 | Animation (thermograph, pointer, water level), temperature/pressure physics, fire effect |
handlers.h/.cpp |
~228 | Hit detection (in_rect, is_actionable_region) and all button click handlers |
main.cpp |
~395 | SDL init, event loop, main(). Defines SDL/cursor/app-state globals. |
All globals are declared extern in boiler_globals.h and defined in one .cpp file:
- SDL/cursor/app-state vars →
main.cpp - BGI drawing state vars →
bgi_compat.cpp - Simulation state vars →
drawing.cpp
File-local data (static): font8x8[], lookup tables in bgi_compat.cpp; fire buffer, needle state in physics.cpp.
10 CPP files forming the legacy DOS application. _EXTERN.CPP serves as a shared header with all extern function declarations.
| File | Role |
|---|---|
_PROJECT.CPP |
Main entry point and event loop. Mouse input, button hit-testing, simulation state management. Heavy use of goto for menu/dialog flow. |
_DRAWING.CPP |
All static UI rendering: boiler tank, pipes, valves, barometer, thermometer, stove, control panel, alarm indicators. 40+ drawing functions using hardcoded pixel coordinates. |
_CARTOON.CPP |
Physics engine and animation. Temperature/pressure calculations with two modes (with/without water). Thermometer bar, pressure gauge needle rotation (trig-based), water level with sine-wave ripple. |
_PUT_OUT.CPP |
Numeric display formatting for gauges. Giant switch statements mapping internal values (0-69 temp, 0-48 pressure, 0-22 fire/air %) to display strings. |
_OUTPUTHZ.CPP |
Chinese character rendering from hzk16 bitmap font (GB2312). Supports scaling, bold, and horizontal/vertical text. |
_WINDOWS.CPP |
Modal dialogs: warning windows, control panel layout, ABOUT screen, HELP documentation. |
_VGA12H.CPP |
Low-level VGA: direct memory pixel plotting, fire animation (random red/yellow pattern). |
_SOUND.CPP |
PC speaker control via direct I/O ports (0x43, 0x42, 0x61). |
MYPOINTER.CPP |
Mouse driver wrapper using INT 0x33. Custom cursor shapes (arrow, hand, hourglass). |
_EXTERN.CPP |
Extern declarations for all cross-module functions. |
hzk16— 16x16 bitmap font file for GB2312 Chinese characters (required at runtime, must be in working directory)project/resources/— Standalone reference implementations of individual components (fire effects, barometer, thermometer, control panel, mouse tests, color utilities).project/resources/chinese/— Header-based 256-color graphics library with Chinese font rendering, BMP loading, and mouse support.project/flowcharts/— Visio diagrams of the boiler, barometer, thermometer, and project flow.
- Fire intensity: 0-22% in integer steps, mapped to 5 heating tiers
- Temperature: 0-69 internal units mapped to 0-160 degrees C display; caps at 43 when water present (steam point)
- Pressure: 0-48 internal units mapped to 0.10-1.00 mPa; gauge needle sweeps 150-340 degrees
- Water level: sine-wave distortion for ripple effect; boiler tank modeled as curved top/bottom (r=38) + straight middle
- Alarms: water level, pressure, and temperature each have independent alarm states
When porting from BGI to SDL2:
- BGI
line(),bar(),arc(),circle(),pieslice(),floodfill()need SDL2 equivalents (SDL_RenderDrawLine, SDL_RenderFillRect, custom arc/circle functions) - BGI uses a 16-color palette (0-15); map to RGB values
- Mouse handling replaces INT 0x33 with SDL_Event polling
- Sound replaces direct port I/O with SDL_Audio or can be stubbed out
- Chinese text rendering reads from
hzk16file — the bitmap-to-pixel logic ports directly, just swapputpixelfor SDL pixel drawing - All coordinates are hardcoded to 640x480 resolution
- floodfill leaks: SDL2 midpoint-circle/arc algorithms produce pixel gaps that BGI's implementations don't.
floodfill()leaks through these gaps and paints the entire screen. Replace dangerous floodfills with direct scanline fills orbar()calls wherever possible. Remaining floodfills (alarm indicators, gauge center) are safe because they fill small enclosed regions. - Font scaling: BGI font 2 (SMALL_FONT) has smaller glyphs than our 8x8 bitmap font.
outtextxy()applies a conditional base scale of 0.6 wheng_text_font == 2andsetusercharsizemultiplier >= 1.0; multipliers < 1.0 use no base reduction. This keeps boxed numeric displays small enough to fit while keeping gauge labels readable. - Pipe water indicators: The original uses
floodfill()to color pipe indication windows between ellipse pairs. The SDL2 port usesfillellipse()+bar()to fill the same regions without leak risk. - Pressure gauge colors: The gauge face is filled with scanline loops using screen-coordinate
atan2angles. Green (121-211°), yellow (211-331°), red (331-61° wrapping), gray dead zone (61-121°). The annulus between r=40-50 is light gray; colored zones are in the ring r=34-40. - Alarm functions:
draw_alarm_of_water/air/temperaturetake anrgparameter: 4=red alarm (flashing indicator + sound), 10=alarm cleared (reset to green), 0/default=normal green state. - Fire animation replacement: The original
Fire()in_VGA12H.CPPuses direct VGA memory writes (0xA0000000) to scatter random red (4) / yellow (14) dots across 4 offset columns with different step sizes. Each pixel has a 1-in-8 chance of color change; no temporal coherence between frames. The SDL2 port inphysics.cpp:248-301replaces this with a cellular automata "doom fire" algorithm: a 48x50 heat buffer (fire_buf) seeded with high values at the bottom row, propagated upward with random horizontal drift (+-1 pixel) and random decay (0-3 per cell per frame). Heat maps to color viafire_heat_to_color(): >30=yellow (14), >24=brown (6), >16=red (4), else invisible.noFire()clears the buffer and fills the region withbar(). The fire region is positioned at (120, 355) to align with the stove opening.
g_language(LANG_CN / LANG_EN) controls UI language; toggled via button at (575,216).- All translatable strings go through
get_string(StringID)instrings.h/strings.cpp. - ASCII advance in English mode is compact:
outhzxy3()andout_en16()advance ASCII characters bysize*8 + space*2(vssize*16 + space*8for CJK). The 16x16 font glyphs only occupy ~8 columns, so the advance matches actual glyph width. When adding new English strings, calculate max chars as:available_width / (size*8 + space*2). - The
outtextxy()8x8 font is never localized — it handles numeric displays, keyboard shortcuts, and ASCII labels that are language-independent. mian_interface_initialize()redraws the entire UI but resets dynamic visual state (valves, stove door) to default. After calling it mid-session, restore dynamic state explicitly.