B O N E S

The Game of the Haunted Mansion
[ Reverse Engineering Report ]
Version 3.8c • MS-DOS VGA/EGA • 1987-1991
Bruce N. Baker, Science Factor Systems
Decompiled with Ghidra 12.0.1 • January 2026 by Benj Edwards and Claude Opus 4.5
> PLAY HTML5 VERSION <
BONES Screenshot

EXECUTIVE SUMMARY

BONES is a text-based dungeon crawler RPG where players explore a haunted mansion, fight skeletal enemies, collect treasure, and attempt to escape with a magical Transportal Globe. Originally developed in 1981 on a DECSYSTEM 10 using Extended BASIC, then ported to MS-DOS using Microsoft QuickC 2.0 and MASM 5.0.

196
Total Rooms
4
Mansion Levels
7x7
Grid Per Level
7
Skeleton Types
133K
EXE Size
28
String Categories

WIN CONDITION

Find the Transportal Globe and use it to escape the mansion alive.

LOSE CONDITIONS

  • Life Force reaches zero (death)
  • Suffocation in trapped rooms
  • Lethal potion consumption

TECHNICAL STACK

ComponentTechnology
CompilerMicrosoft QuickC 2.0
AssemblerMASM 5.0
Memory ModelLarge
Build DateNovember 25, 1991
Target PlatformMS-DOS (VGA/EGA)

DEVELOPMENT HISTORY

YearEvent
1981Original concept on DECSYSTEM 10 (Extended BASIC)
1987Revived using Desmet C and ASM88
1988Converted to MS QuickC 1.0 + MASM 5.0
1989Upgraded to QuickC 2.0; removed assembly libraries
1990Version 3.0 in large memory model
1991Version 3.8c; mansion mapper; VGA intro

FILE INVENTORY

BONES.EXE
133,120 bytes
Main game binary (MZ Executable)
BONE.D1 / D2 / D3
~18 KB each
String databases (text variants)
BONES.DOC
17,408 bytes
MS Word documentation
ROMAN.FON
11,264 bytes
Windows NE font file
BONEHIGH.DAT
71 bytes
High score table (10 entries)
BONES.CFG
~50 bytes
Configuration settings

MEMORY MAP

The game uses direct memory access throughout. Key addresses identified via Ghidra analysis:

PLAYER POSITION

AddressVariableDescription
0x5330PLAYER_COLUMNCurrent column (1-7)
0xa03aPLAYER_ROWCurrent row (1-7)
0x50d8CURRENT_ROOMRoom number (1-49)
0xd282ROOM_INDEXRoom index (0-48)
0xd214CURRENT_LEVELMansion level (0-3)

PLAYER STATS

AddressVariableDescription
0xd1c6LIFE_FORCEPlayer health
0x57e8ARMOR_VALUEDefense modifier
0xd42aATTACK_FORCEAttack power
0xd63cEXPERIENCEXP points
0xd1c4USER_LEVELPlayer level
0xd446SCORECurrent score (32-bit)
0x5332GOLD_COUNTGold collected
0x50c0JEWEL_COUNTJewels collected

INVENTORY FLAGS

AddressVariableDescription
0x50c4SWORD_FLAGHas sword
0xd27eMACE_FLAGHas mace
0xd41aSHIELD_FLAGHas Warlock's Shield
0xd20eLASER_FLAGHas helium laser
0x50c2UZI_FLAGHas UZI
0xd428GLOBE_FLAGHas Transportal Globe (WIN!)
0xa02aSPELL_FLAGHas spell book
0xd418EXPLOSIVESPlastic explosives count

ROOM DATA ARRAYS

Room data indexed by: level * 0x62 + room * 2

BaseData
0x54d0Room visited flags
0x5348Gold amounts per room
0x57faJewel amounts per room
0x4f38Skeleton counts per room
0x50daEast/West wall blocked
0x565eMist room flags

MANSION GENERATION ALGORITHM

The mansion is procedurally generated using a seeded RNG. The same "mansion number" produces identical layouts, allowing reproducible gameplay.

GRID STRUCTURE

Each level uses a 7x7 coordinate grid (49 rooms):

       Col 0   Col 1   Col 2   Col 3   Col 4   Col 5   Col 6
Row 0  [0]     [1]     [2]     [3]     [4]     [5]     [6]
Row 1  [7]     [8]     [9]     [10]    [11]    [12]    [13]
Row 2  [14]    [15]    [16]    [17]    [18]    [19]    [20]
Row 3  [21]    [22]    [23]    [24]    [25]    [26]    [27]
Row 4  [28]    [29]    [30]    [31]    [32]    [33]    [34]
Row 5  [35]    [36]    [37]    [38]    [39]    [40]    [41]
Row 6  [42]    [43]    [44]    [45]    [46]    [47]    [48]

STARTING POSITION (FUN_1534_0ac0)

; Player starts at random inner grid position
int startRow = rand(6) + 1;      ; 1-6
int startCol = rand(6) + 1;      ; 1-6
int startRoom = (startRow - 1) * 7 + startCol;

GOLD CALCULATION

rand(level^5 + level^2 + 5) * rand(2) * rand(2)

LevelMax GoldFormula
0 (Main)0-4rand(5) * rand(2) * rand(2)
10-7rand(8) * rand(2) * rand(2)
20-40rand(41) * rand(2) * rand(2)
3 (Deep)0-256rand(257) * rand(2) * rand(2)

JEWEL CALCULATION

rand(2) * rand(level^3 + level^2 + 3) * rand(2) * rand(2)

LevelMax Jewels
00-2
10-4
20-14
30-38

HAZARD GENERATION

; Skeleton presence - ~25% chance
skeletonCount = rand(2) * rand(2);

; One-way room - 10% chance (can enter, can't exit)
oneWay = (rand(10) == 1);

; Mist room - MORE COMMON on higher levels!
; Level 0: 1/15 (6.7%),  Level 3: 1/9 (11.1%)
mistChance = 15 - (level * 2);
mist = (rand(mistChance) == 1);

; Wall blocking - 25% per direction
wallBlocked = (rand(4) == 0);

ITEM PLACEMENT

Each level places items in unique rooms (no overlaps):

  • Stairway (level transition)
  • Sword room / Mace room
  • Shield room / UZI room
  • Potion room / Laser room
  • Globe room (win item)
  • Boost room (life force)
  • Spell book room
  • Clip room (UZI ammo)
  • Explosives room

MOVEMENT SYSTEM

DIRECTION CONSTANTS

DirectionValueRoom DeltaCoordinate
West1-1col - 1
East2+1col + 1
North3-7row - 1
South4+7row + 1

MOVEMENT LOGIC (FUN_1000_0c26)

void movePlayer(int direction) {
    int canMove = 0;

    ; WEST: column > 1, wall not blocked
    if (direction == 1 && playerColumn > 1 &&
        wallBlockedEW[currentLevel][roomIndex] == 0)
        canMove = 1;

    ; EAST: column < 7, wall not blocked
    if (direction == 2 && playerColumn < 7 &&
        wallBlockedEW[currentLevel][roomIndex] == 0)
        canMove = 1;

    ; NORTH: row > 1, wall not blocked
    if (direction == 3 && playerRow > 1 &&
        wallBlockedNS[currentLevel][roomIndex] == 0)
        canMove = 1;

    ; SOUTH: row < 7, wall not blocked
    if (direction == 4 && playerRow < 7 &&
        wallBlockedNS[currentLevel][roomIndex] == 0)
        canMove = 1;

    if (canMove) {
        switch(direction) {
            case 1: playerColumn--; currentRoom--; break;
            case 2: playerColumn++; currentRoom++; break;
            case 3: playerRow--; currentRoom -= 7; break;
            case 4: playerRow++; currentRoom += 7; break;
        }
        roomIndex = currentRoom - 1;
    }
}

COMBAT SYSTEM

WEAPON HIERARCHY

Attack strength from weakest to strongest:

Hand < Bones < Sword < Mace < Laser < Spell < UZI

SKELETON TYPES

TypeSpecial AbilityStrategy
WarriorNoneStandard combat
ThiefSteals items/gold, fleesKill quickly
ElectricMULTIPLIES with laser!No laser attacks
MysticBlocks spells easilyUse physical weapons
WarlockCasts spells, steals shieldHigh priority
PhaseImmune to physicalUse magic/laser
VaporImmune to some attacksExperiment

UZI FIRE MODES

60 shots per clip with 4 fire rate options:

ModeShotsEffect
1/4 Clip15Light damage, conserves ammo
1/2 Clip30Moderate damage
3/4 Clip45Heavy damage
Full Clip60Maximum group damage

KEY FUNCTIONS

FUN_1000_0000 1000:0000
Main entry point and game loop

Initializes video, loads strings, runs main menu. Keyboard mapping:

if (*(int *)0x292 == 0x45) ... = 1;  ; 'E' = Exit room
if (*(int *)0x292 == 0x49) ... = 2;  ; 'I' = Investigate
if (*(int *)0x292 == 0x41) ... = 3;  ; 'A' = Attack
if (*(int *)0x292 == 0x43) ... = 4;  ; 'C' = Communicate
if (*(int *)0x292 == 0x53) ... = 5;  ; 'S' = Status
if (*(int *)0x292 == 0x4f) ... = 6;  ; 'O' = Object
if (*(int *)0x292 == 0x47) ... = 7;  ; 'G' = Game mods
if (*(int *)0x292 == 0x52) ... = 8;  ; 'R' = Rest
if (*(int *)0x292 == 0x4d) ... = 9;  ; 'M' = Mapper
FUN_1534_0ac0 1534:0ac0
Mansion generation - creates entire map layout

Seeds RNG with mansion number, generates starting position, places items, creates room contents, configures walls.

FUN_1000_0c26 1000:0c26
Player movement handler

Validates direction against grid boundaries and walls, updates position, triggers room entry.

FUN_1000_0882 1000:0882
Stairway/level transition handler

Manages up/down navigation between levels and random teleport on transfer rooms.

FUN_1dce_0006 1dce:0006
Mansion mapper display

Renders 7x7 grid with visited rooms, current position, special room indicators, wall states.

FUN_190c_23b0 190c:23b0
Random number generator

Core RNG. When seeded with mansion number, produces reproducible results.

STRING DATABASE FORMAT

Text loaded from BONE.D1, BONE.D2, or BONE.D3 files (different variants, same structure).

FILE FORMAT

<count>           ; Number of strings in section
String 1|         ; Each string ends with '|'
String 2|
...
                  ; Blank line separates sections
<count>
String 1|
...
end               ; Literal "end" terminates file

STRING CATEGORIES (28 total)

#CountCategory
1-449 eachRoom descriptions (one per level)
512Blocked exit messages
6-712 eachHand attack hits (single/group)
8-912 eachSkeleton hits player
1012Successful room exit
1112Exit blocked by skeleton
1212Escape past skeleton
1312Gold discovered
1412Skeleton activity noticed
1512Jewels discovered
16-1912 eachSword/Mace hits
20-2110 eachCommunication success
229Thief skeleton warnings
23-2410 eachCommunication rejected
25-2612 eachSkeleton killed
2712Player attack misses
2811Skeleton attack misses

SAMPLE ROOM DESCRIPTIONS

"Your in the study. You see lots of broken furniture."
"It's a torture chamber, you can see a rack."
"Pots and Pans everywhere, your in the kitchen."
"There's blood dripping down the wall."
"Sparks fly from a Tesla Coil."
"A pot is boiling and you see a hand floating in it."
"A note on the wall says 'Prepare to die'."

GAME STATE VARIABLES

COMBAT STATE

AddressVariableDescription
0xd284SKELETONS_SEENSkeletons in room
0xa016SKELETON_WOUNDSkeleton damage
0x4f36SKELETON_ARMORSkeleton defense
0xd200SKELETON_POWERSkeleton attack
0x5334IN_COMBATCombat flag

ITEM ROOM LOCATIONS (per level)

OffsetItem
-0x2bd2Stairway room
-0x5fe6Globe room (WIN)
-0x29ceSword room
-0x2e34Mace room
0x50c8Shield room
0x57f2Potion room
-0x2be4UZI room
-0x2d8cLaser room

ACHIEVEMENT TITLES (Score-based)

  1. Mansion Master - Highest
  2. Bone Tycoon
  3. Bone Master
  4. Mansion Maniac
  5. Bone Buster
  6. Bone Hunter
  7. Apprentice
  8. Common Tramp - Lowest

CONFIG FILE FORMAT (bones.cfg)

Format: %d %d %d %d %d %d %d (7 integers)

  1. Menu text color
  2. Selected text color
  3. Menu box color
  4. Sound on/off
  5. Monitor type
  6. (Unknown)
  7. (Unknown)

DOWNLOADS & RESOURCES

~120 KB
Playable web version based on original game logic and data, not yet fully verified as complete
735 KB
Raw Ghidra output (24,846 lines)
~25 KB
Documented key functions
~25 KB
Full analysis (Markdown)