0% found this document useful (0 votes)
37 views13 pages

BruceLeeRevisited EN v190120

Bruce Lee's game code was analyzed using Ghidra to understand its functions and structures. The game uses 16 colors represented by ink values. Rooms are defined by tile maps, overlays and events. Fireballs and other elements are initialized in events and animated in the game loop to control gameplay. Understanding the game's structures enables modifying and extending it to create new versions like Bruce Lee 2.

Uploaded by

real.mml
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views13 pages

BruceLeeRevisited EN v190120

Bruce Lee's game code was analyzed using Ghidra to understand its functions and structures. The game uses 16 colors represented by ink values. Rooms are defined by tile maps, overlays and events. Fireballs and other elements are initialized in events and animated in the game loop to control gameplay. Understanding the game's structures enables modifying and extending it to create new versions like Bruce Lee 2.

Uploaded by

real.mml
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Bruce Lee Revisited

Hacking Guide

Foreword

This document was created to facilitate the hacking of Bruce Lee and to allow modifications a la
Bruce Lee 2 or Return of Fury.
Using Ghidra, the binary code was reassembled and the source code was largely reconstructed in
order to break down the functions to recognize the possibilities and the restrictions.
In parallel to the document, an Editor for GNU Linux / Windows is created to make it easier to
modify Bruce Lee.
Structures
Tiles
The graphic are made up of 256 tiles, which internally are stored as 4x8 mode 0 pixels and are
scaled to 4x16 pixels at Runtime. There are some restrictions to consider in the design, since the
INKs in the engine have special meanings for the collision query.

Inks
INK Meaning
0 Background, passable
1 Obstacle, unpassable but walkable
2 Background, passable
3 Deadly Objects (Spikes, Fireballs, Missiles, Traps...)
4 Elevator, climbable, first ink for colorcycle
5 Trigger for the Traps, passable
6 Elevator, climbable, second ink for colorcycle
7 Spritecolor (Yamo) green
8 Background, passable
9 Floor, walkable
10 Static Climbable Object
11 Color for collectible Objekts (Lamp / Bonuslives)
12 Elevator, climbable, fourth ink for colorcycle
13 Spritecolor Ninja, Bruce (black)
14 Elevator, climbable, third ink for colorcycle
15 Spritecolor Bruce (yellow)

Four INKs are used for the “Elevators” because they are animated by color rotation.

Pen 5 seems to be able for dual-use because the mines / bottom traps are a feature that you have to
activate in the program flow. You can use the color for tiles that can be used for Tiles to design
rooms without Mines / floor Traps.
Bitmasks of the INKs
The following table shows what the bit masks of the INKs in graphics memory look like in mode 0.
A byte in the graphics memory contains two Mode 0 pixels.

INK Left Pixel Rigth Pixel


0 00000000 00000000
1 01000000 10000000
2 00000100 00001000
3 01000100 10001000
4 00010000 00100000
5 01010000 10100000
6 00010100 00101000
7 01010100 10101000
8 00000001 00000010
9 01000001 10000010
10 00000101 00001010
11 01000101 10001010
12 00010001 00100010
13 01010001 10100010
14 00010101 00101010
15 01010101 10101010

The programmers have taken advantage of the property of INKs 4, 6, 12 and 14 that the top nibble
is identical for these four colors. It is no coincidence that these four colors are used for the
"Elevators".

INK Left Pixel Right Pixel


4 00010000 00100000
6 00010100 00101000
12 00010001 00100010
14 00010101 00101010
Rooms
The management information for the rooms is stored in an array of 64 bytes and is saved for the 20
rooms in quick succession. Only then are the RLE-encoded data and the overlay tables stored (in
the order RLE, OVL, RLE, OVL, ...)
When the game is initialized or a room is entered, the RLE-encoded data of the room is extracted
into an array of 440 bytes (a Room has the Dimension of 40x11 Tiles), of which a copy of an
identical size is made. The overlays (lamps / obstacles) are then placed in the "active" array. The
copy is used to restore the active room to its original state when an overlay is removed.

Stucture:
0..16 Bytes 0..16 Colordefinitions: Border, INKs 0..15
17, 18 Word Pointer to RLE encoded Mapdata
19, 20 Word Pointer to Overlay-Table of the Room
21 Byte Room-visited-Flag for Player 1
22 Byte Room-visited-Flag for Player 2
23, 24 Word Pointer to EVENT1 – triggered at first visit of the Room
25, 26 Word Pointer to EVENT2 – will be called in regular Gameloop
27, 28 Word Pointer to EVENT3 – unused on the CPC
29, 30 Word Pointer to EVENT4 – triggered after collecting an Object
31, 32 Bytes Coordinates Enemy Spawnzone 1
33, 34 Bytes Coordinates Enemy Spawnzone 2
35..37 Bytes Define Exit/Entry to next Room (top left),
38..40 Bytes Define Exit/Entry to next Room (top middle)
41..43 Bytes Define Exit/Entry to next Room (top right)
44..46 Bytes Define Exit/Entry to next Room (middle left)
47..49 Bytes Define Exit/Entry to next Room (middle middle)
50..52 Bytes Define Exit/Entry to next Room (mitte right)
53..55 Bytes Define Exit/Entry to next Room (bottom left)
56..58 Bytes Define Exit/Entry to next Room (bottom middle)
59..61 Bytes Define Exit/Entry to next Room (bottom rigth)
62..63 Bytes Two X-Offsets for the Tablecolums for calculating the correct Entry

Spawnzones:
If you dont want Enemys to Spawn you have to set both Zoneentrys to &ff,00.
Room Exits/Entrypoints
The rooms are linked together with each other using table entrys which are stored in a 3x3 matrix.
An entry consists of to which room the exit of the current map leads and at which coordinate the
connected room is entered. If an tableentry is not used, the first byte must be set to &ff and the
coordinates left blank.
The X coordinates are calculated in bytes, the Y coordinate in pixels. The last two bytes of the
management structure control the two offsets in order to correctly determine the address of the
entry.

Axis 0..Offset 1 -1 Offset 1..Offset 2-1 Offset 2..80


Y 0..3a Entry 1 Entry 2 Entry 3
Y 3b..69 Entry 4 Entry 5 Entry 6
Y 6a.. Entry 7 Entry 8 Entry 9

A Special treatment for room numbers 12 to 15 is encoded in the engine. Reason is unkown and
requires further investigation.
EVENTs
The events are used to control / operate room-dependent gameplay elements. Events that you do not
want to use should be linked to a routine with immediate RET.
From the gameloop, the events are called up with JP (HL)
In-game, the four events for the 20 rooms are stored in an array and the table entries are copied into
the headers of the rooms when the program starts.
EVENT1: Is called up at the first visit of a player of a room and can be used to initialize variables
etc.
EVENT2: Is called in the regular game loop. It is used to animate Features of the Rooms (Traps,
Elevators, Missiles, Fireballs)
EVENT3: Is not used on the CPC and is not jumped to.
EVENT4: Called up after collecting an object. This controls whether you want to remove overlay
elements from the Room or which ones you want to insert into the Room.

Since you can create your own scripts depending on the room, you should prefix the function names
in order not to lose the overview, and that you do not come into conflict with the symbols of the
restored source code, especially in cases where you want to cache your own local variables.
Overlays
The overlays are used to record the map elements that can / should change at runtime.
Here, among other things where lamps or obstacles or other things are to be placed or removed, as
required.
Elements can be grouped by Sequences, and a coherent coordinate sequence must be marked using
a status byte. The End of list is completed with &ff. A list must exist for each room, an empty List
contains only the end mark &ff.
Bits of the Statusbyte:

7 6 5 4 3 2 1 0
SequenceMark - - - - - Player 1 Player 0

Bit 7 marks the list entry as a sequence marker, bits 0 and 1 are influenced by the respective player.
The respective bit controls whether the following list entries are to be shown or hidden for the
respective player.
Otherwise, an overlay list entry consists only of the X and Y coordinates and the tile number for this
coordinate.
From the game, the function for displaying / hiding a sequence is controlled via a room number and
the coordinate of the first sequence entry, which means that elements in other rooms can also be
influenced.

Register: M9_BridgeSeq2
LD A,9
B:Y-Coordinate LD BC,&0415
CALL removeOVLatXY
C:X-Coordinate LD A,9
LD BC,&040a
A: Roomnumber
CALL placeOVLatXY
Gameplay-Elements
Fireballs
Fireballs are initialized in EVENT1 in a room and used in EVENT2. EVENT1 can be used for
fine-tuning the table entries.
Initialization: LD IX,M17_Fireballs
JP InitFireballTab

The fireballs are just as easy to use by addressing the list with IX and calling the AnimateFireball
function within EVENT2.
A list entry consists of 11 bytes and a list can contain several entries. You shouldn't define too many
fireballs per room, otherwise the performance of the game will drop noticeably. The list ends with a
zero byte.

0 byte Tilenummer
1 byte Direction (0 right, 1 left)
2 byte Startposition X (Tilepos 0..39)
3 byte Endposition X (Tilepos 0..39)
4 byte Y-Position (Tilepos 0..10)
5 byte Initvalue Delay (Speed) of Animation
6 byte Workvalue Countdown to next Fireball
7 byte Workvalue actual X-Position
8 byte Workvalue Countdown Delay (Speed) of Animation
9 byte Initvalue Countdown to next Fireball
10 byte Offset to Tilenumber for fading in/fine Animation
11 byte End of List/Begin of next Entry

Missiles
In contrast to the fireballs, the missiles do not need to be initialized in EVENT1. They are
called in EVENT2 by addressing the table in register IX and calling the "AnimateMissiles"
function. The list structure is much simpler here, since screen memory addresses are used here. A
list must be closed with 0xff.
The tile in the background has no meaning for the function. It only serves the player to see in which
areas missiles are traveling.

1 byte Direction (0 right, 1 left)


2 word Initaddress Screenmemory Startposition
3 word Workaddress Screenmemory actual Position
4 word Targetaddress Screenmemory Targetposition
Traps
Traps use hard-coded structures and a maximum of six traps can be placed in one room. You
simply place them on the map and call them up in EVENT2 with JP or Call Handletrap.
There are two types of Traps in the Game:
Firethrowers and Mines.
While Firethrowers only affect the Tile above the Thrower, Mines will have an Explosion-Range
and affect multiple Tiles in Range.
They are handled via 6x4 Table-Entrys. The Duration of each Phase is hardcoded.

Size Description
byte Status/Phase
byte x-coordinate
byte y-coordinate
byte Tilenumber

Elevators
The elevator is animated in EVENT2 of a room by calling the routine "JP
AnimateElevator" as the last command of the EVENT routine.
They are animated using color animation of Inks 4, 6, 12 and 14.

Design guide: One of the Inks is used for highlightning, while the other three Inks should share the
same color.
For upward animation, the color is rotated through the inks 4 → 14 → 6 → 12.
For downward animation the other way around 4 ← 14 ← 6 ← 12.

The up / down movement of the sprites on the elevator is synchronized with the color animation.
Sprites
The Spritegraphics are addressed via a pointer table. While Sprites can have a variable width, the
height is fixed to 23 Pixels.
The first byte of the sprite data specifies the sprite width in bytes. This is followed by the graphics
data in Mode 0 resolution. Unfortunately, only three colors can be used for the sprites (Inks 7,13
and 15).

In the engine, the three sprites are drawn in 384byte offscreen buffers, which are then transferred to
the screenmemory, followed by the management information for the sprite, which is addressed in
the engine via the index register IX / IY.

Spriteheader:

Byte 0 Status On Ground


In Air (Jumping)
Byte 1 Collect-Flag Sets Flag if an Object is collected because
Removing the Graphics of a collectible takes some
time to prevent get multiple points or lifes for the
same object.
Byte 2 Action/Phase Number of the Routine for this Action/Phase and
the corresponding Sprite
Byte 3 Mirrorflag Controls the mirroring of the Spritegfx
Byte 4 Actual X-Position Bytes (0..79)
Byte 5 Actual Y-Position Pixel (0..199)
Byte 6 X-Position previous Gametick
Byte 7 Y-Position previous Gametick
Byte 8 Command Inputvalue from Joystick/Keyboard/AI
Byte 9 Width of Sprite In Bytes. (Height is fixed to 23 Pixel)
Word 0xA, Pointer Spritedata Pointer to the Graphicsdata of the Sprite
0xB
Byte 0xC Counter Countdown to next Action/Phase
Offset for Jumpheight
Byte 0xD Kind of Background Free Background
on Climbable Object
on „Elevator“
Byte 0xE HP Hitpoints
Directly behind the spriteheader is a pointer table with the possible actions that a sprite can perform
as well as a pointer to the sprite that is to be displayed during the action. The pointer to the sprite is
in front of the pointer to the action.
dw PTR1_BruceStand ; 0
dw AC0_Spawn
dw PTR1_BruceStand ; 1
dw AC1_CountDowntoSpawn
dw PTR1_BruceStand ; 2
dw AC2_getinput_for_posiblActions
dw PTR2_BruceRun1 ; 3
dw AC3_RunAnim1
dw PTR3_BruceRun2 ; 4
dw AC4_RunAnim3
dw PTR4_BruceFallorJump ; 5
dw AC5_Falldown
dw PTR6_BruceJumpRight1 ; 6
dw AC6_Jumpright1
dw PTR7_BruceJumpRight2 ; 7
dw AC7_Jumpright2
dw PTR10_BrucePunchRight ; 8
dw AC8_Punch
dw PTR5_BruceJumpUp ; 9
dw AC9_Landed
dw PTR5_BruceJumpUp ; a
dw ACA_UpPhase2
dw PTR4_BruceFallorJump ; b
dw ACB_UpPhase3
dw PTR14_BruceClimbing ; c
dw ACC_Climb
dw PTR8_BruceFlyKick1 ; d
dw ACD_InitFlykick1
dw PTR8_BruceFlyKick1 ; e
dw ACE_FlykickEnds
dw PTR9_BruceFlykick2 ; f
dw ACFspr_Flykick
dw PTR11_BruceDuck ; 10
dw AC10_duck
dw PTR34_BruceFlying ; 11
dw AC11_Bruce_RunAnim2
dw 0000h ; 12
dw 0000h
dw PTR10_BrucePunchRight ; 13
dw AC13_PunchEnding
dw PTR13_BruceGotHit ; 14
dw AC14_gothit
dw PTR12_BruceLyingonGround ; 15
dw AC14_gothit

In (IX + 02) it is determined which action is to be carried out. The routines are started and returns in
register A what action is to be carried out next. This could be used to expand the engine to teach
Bruce new skills.
Memorymap of unmodified Game
Adresse von bis Bedeutung
0x1500 0x16ff Tiles für Scoreline
0x1800 0x27ff 256 Tiles a 16 Bytes
0x2800 0x2cff 20 x 64bytes Roomheader
0x2d00 0x2d01 Default „RET“-Routine
0x2d02 0x47ff RLE- und OVL-Data of the 20 Rooms
0x4800 0x484d Pointerlist to Spritegraphics
0x484c 0x57ff Spritegraphics
0x5800 0x5803 Entrypoint of the BRUCE.N02: -> JP Main
0x5804 0x58a3 20 x 4 words Addresstable of EVENTs of the 20 Rooms
0x5923 0x5ada Uncompressed Mapdata active Room with OVLs
0x5adb 0x5c92 Uncompressed Mapdata without OVLs
0x5c93 0x5e12 384bytes OffscreenBuffer for Ninja
0x5e13 0x5e21 Header for Ninja
0x5e22 0x5e79 Pointertable to Sprites and Actions for Ninja
0x5e7a 0x5ff9 384bytes OffscreenBuffer for Yamo
0x5ffa 0x6008 Header for Yamo
0x6009 0x6064 Pointertable to Sprites and Actions for Ninja
0x6065 0x61e4 384bytes OffscreenBuffer for Bruce
0x61e5 0x61f3 Header Bruce/Player 1
0x61f4 0x624b Pointertable to Sprites and Actions for Bruce
0x624c 0x625a Header Player 2
Reserved Tiles
Tile Description
0x4b Fireball (Full Tile)
0x4c Fireball (left half)
0x4d Fireball (right half)
0x45 Mine (Placing in Room)
0x53 Mine-Explosion Phase 1
0x54 Mine-Explosion Phase 2
0x55, 0x56, 0x57 Mine-Explosion Phase 3
0x50 Flamethrower Phase 1
0x51 Flamethrower Phase 2
0x52 Flamethrower Fires
0x5f Flamethrower Inactivated
0x6f Flamethrower Armed (Placing in Room)

The Tiles have been EQUated in the Source for greater Flexibility at Tiledesign.

You might also like