The game's own demo puzzle, running as recompiled native code โ Mr. Bolo
rolling balls into the water and parking crates in front of lasers on his way
to the red stairs.
|
|
|
What it took, in short: a DOS memory call QB *expects to fail*, an 8087
emulator the program ships inside itself, QuickBASIC's `ONโฆGOSUB` tables and
self-overlapping instructions, and an EGA card faithful enough for QB's
read-mode and latch tricks. The blow-by-blow is in [`docs/NEXT.md`](docs/NEXT.md).
### How we got here
๐ง **Phase 1 done โ the patient is unpacked and on the table.**
- โ
**Unpacked the PKLITE compression ourselves.** BOLO3.EXE uses PKLITE 1.15 in
its trickiest *large + extra* mode with a *self-decrypting* stub. We reverse-
engineered the stub, wrote a byte-exact static decompressor
([`tools/unpklite.py`](tools/unpklite.py) โ a new reusable toolkit tool), and
recovered the full **136 KB** load image. No emulator required.
- โ
**Analyzed:** 182 functions, ~35K instructions, 833 strings.
- โญ **Identified the language: compiled Microsoft QuickBASIC 4.5.** The runtime
error-message table (`RETURN without GOSUB`, `CASE ELSE expected`, โฆ) gives it
away. That means much of the binary is the *known* QB runtime, and the graphics
are BASIC `SCREEN 9` EGA `PUT`/`GET` sprites โ a big head start on the rest.
- โ
**Classified (Phase 2):** the call graph shows **81% of calls go into the QB
runtime** โ leaving only **~70 functions of actual Bolo game logic** to reverse.
The interrupt/shim surface is small and mapped (DOS, EGA, keyboard, mouse, timer,
FP emulator). See [`docs/CLASSIFY.md`](docs/CLASSIFY.md).
- ๐จ **Lifting (Phase 3):** the game is mechanically lifted to C
([`tools/lift_bolo.py`](tools/lift_bolo.py) โ `src/recomp/gen/`) against the
`recomp16` runtime, with a build skeleton (`CMakeLists.txt`, `src/main.c`).
Segment-aware discovery resolves the call graph: **932 functions, 56.8K
instructions, 70K lines of C**, with **99% of near calls resolved to real
function starts** and only 14 stubs left (all out-of-image BIOS/absolute
targets). The program entry is lifted. Remaining gaps are the classic hard
parts: x87 FPU translation and indirect-dispatch wiring. Compiling needs
MSVC + SDL2 (not available in this environment yet).
| Phase | What | State |
|------:|------|-------|
| 0 | Reconnaissance | โ
[`docs/RECON.md`](docs/RECON.md) |
| 1 | Unpack PKLITE + disassemble | โ
|
| 2 | Classify QB runtime vs game logic | โ
[`docs/CLASSIFY.md`](docs/CLASSIFY.md) |
| 3 | Lift 8086 โ C | โ
932 funcs / 70K lines, call graph resolved |
| 4 | Shim EGA/DOS โ SDL2 | โ
recomp16 runtime wired |
| 5 | Build & debug to playable | โ
**boots to the menu, puzzles load and play** |
| 6 | Ship native + extras | โฌ |
See [`docs/PLAN.md`](docs/PLAN.md) for the full roadmap and milestones.
## Repo layout
```
bolo/
original/ The original 1993 shareware files (the ground truth)
docs/ RECON.md ยท PLAN.md ยท FORMATS.md
tools/ Project-specific tools (PKLITE unpacker, asset extractors)
work/ Scratch / regeneratable analysis output (gitignored)
src/ Recompiled + hand-written runtime code (later phases)
```
## Building & running
With MSYS2 mingw64 (gcc + SDL2) and Python (`unicorn`, `capstone`):
```bash
# 1. post-startup snapshot (PKLITE + QB startup, run once in a Unicorn harness)
python tools/uni_original.py
# 2. lift the program from the snapshot (needs the pcrecomp toolkit: PCRECOMP_HOME)
python tools/lift_bolo.py
# 3. build (parallel, ~10 min)
bash scripts/build.sh
# 4. play
PATH=/c/msys64/mingw64/bin:$PATH ./build/bolo.exe work/snapshot.bin
```
**Controls** are the original game's: `S` select puzzle, arrows + Enter in the
list, arrows to move Mr. Bolo, `T` try again, `Q` quit. The game reads and
writes `BOLO3.SCR` (its solved-puzzle record) next to its data files in
`original/`.
Handy switches: `BOLO_SHOT=N` saves the screen to `work/shot_NNN.bmp` every N
seconds; `BOLO_KEYS="..."` scripts the keyboard for headless runs (`^U/^D/^L/^R`
arrows, `~` = 150 ms pause, trailing `$` = stop); `SDL_VIDEODRIVER=dummy` runs
without a window; `BOLO_TRACE=1` logs every function entry for diffing against
`tools/uni_original.py --enter-trace`.
## About the author
*Bolo Adventures III* is the work of **William Soleau**, who ran Soleau Software
as a one-man shop out of 163 Amsterdam Avenue in New York โ the address is still
on the game's registration form โ and put out
[some 57 DOS games](https://www.classicdosgames.com/company/soleau.html) of
logic puzzles and gentle arcade fare through the 1990s and early 2000s. The
Soleau Software site now reads simply *"Thank-you for 30 years."*
Games were only half of it. By all accounts the same William Soleau โ the
Amherst graduate of the Soleau Software bio โ is a ballet dancer turned
choreographer: a former principal dancer who
[performed in over 30 countries](http://www.balletdances.com/resume.html),
worked with Alvin Ailey, John Butler and Antony Tudor, and has made more than
100 ballets for companies around the world, from the Shanghai Ballet to Ballet
Austin. Since 2018 he has been
[co-artistic director of State Street Ballet](https://statestreetballet.com/william-soleau)
in Santa Barbara. Somewhere between rehearsals, Mr. Bolo got his lasers and his
water. Thank you, Mr. Soleau.
## Credits & legal
Original game ยฉ 1993 **William Soleau / Soleau Software**, distributed as
shareware. This is a personal preservation / reverse-engineering project of a
long-abandoned title; all reverse-engineered code here is original work produced
by analyzing the freely-distributable shareware binary. The unmodified shareware
package is included in [`original/`](original/) โ the game's own terms say it
"may be passed along to your friends or local BBS" โ because it's tiny and it is
the reference for the recompilation. Those files remain ยฉ Soleau Software under
their original shareware terms; the repo's MIT license covers only the code and
tools written here. If you enjoyed Bolo, go say thanks to Soleau Software.
Built with the [pcrecomp toolkit](../tools) and far too much nostalgia.