Addr 0x4C:
High byte of camera position of end of current level?
Addr 0xC7:
Buttons read from joypad 1 (this frame)
Addr 0xC8:
Last frame's buttons. Copied from 0xC7 before 0xC7 is refilled
Addr 0xCA:
Value to write to PPUCTRL (0x2000)
Addr 0xCE:
Y screen position (low?) (pixels)
Addr 0xCC/0xCD:
X screen position (pixels)
Addr 0xEC:
Screen mode?
0x01 = Title screen
0x02 = Title screen idle animation
0x03 = Title screen -> First level
0x04 = Filler/between screens
0x05 = Playable level
Addr 0x617/0x618:
X position of the character on the whole stage (pixels)
Addr 0x84 and 0x87:
Integers indicating the cardinal direction joypad 1's dpad is being held. 0x84 will only show U/D/L/R and 0x87 will only show U/D/L/R/UR/UL/DR/DL.
0x84:
1 = Up
2 = Down
3 = Left
4 = Right
0 = Direction not listed above
0x87:
1 = Up
2 = Down
3 = Left
4 = Right
5 = Up + Left
6 = Up + Right
7 = Down + Left
8 = Down + Right
0 = Direction not listed above
Addr 0x91/0x92:
X position of the character on the screen (sub-pixels)
Addr 0xA9:
Speed gained from riding an enemy/apple
Fetched from [0x583 + enemy_slot_id]
Addr 0x98/0x99:
Speed (sub-pixels)
Addr 0x9A:
Effective speed (pixels). This is the sum of the whole pixel speed and any boost
Addr 0xA9:
Speed boost added to the regular speed.
It looks like speed can be pretty well optimized by keeping a close eye on the effective speed in 0x9A and trying to keep it high.
You have a running speed (holding B) of 2 pixels per frame and can get a boost of 2 more from bomb jumping.
Address 0x53:
For level 1, starts at 0x08, gets changed to 0when screen scroll X becomes 0x0808
Maybe some kind of switch to load other level data?
Address 0xA8:
Seems to be flags
0x80 = Being hit?
0x20 = riding enemy?
0x01 = On ground?
Addr 0x4ED:
Seems to be a counter of how many enemies have been seen? Seems like the high 6 bytes are also used to compare against the high byte for the player position (ish).
Addr 0x4F1:
Enemy slot ID that hit you
Addr 0x4F3-0x4FA (8 slots):
0x00 = Slot empty
0x02 = Enemy is on screen
0x03 = Enemy is off screen
Addr 0x4FB-0x500 (6 slots):
Seems like enemy type ID
Only related to enemies (not apples, range is 0-5)
if value is 0x15 a section of code doesn't run
Other values checked for: 0x13, 0x10, 0x39, 0x3B, 0x3C, 0x3F, 0x44, 0x46, 0x00, 0x16
Addr 0x501-0x508 (8 slots):
? Related to enemies
compared == 0x0D at 0xE8FF
Addr 0x51B-0x520 (6 slots):
An offset into a pointer table for animation data for this specific enemy
Seems to choose what animation this enemy should perform (move vertically upwards, oscillate up and down/left and right, etc)
Used at D507 to get an address in bank 3 (A9B2 + value * 2)
Addr 0x521-0x526 (6 slots):
? Related to enemies
Looks like a counter for this enemy, probably used to determine where in the animation cycle the enemy is
Used as an offset to the address fetched via the above value
[(bank 3)A9B2 + [0x51B + enemy_slot_id * 2]] + [0x521 + enemy_slot_id * 2] * 4 = addr of the start of some data for enemy
Entries in the data are probably 4 bytes, and this value is used to get the data for the current frame.
If the first value in the next entry is 0x80 this counter restarts (and 0x515 + enemy_slot_id is incremented)
Addr 0x527-0x52E (8 slots):
? Related to enemies
Flags
0x40 - might indicate enemy is dying? Seems like you can't be damaged by them if it is set.
0x80 - is often cleared when updating/checking enemies
might indicate player is riding this enemy?
0x08 - ? if set you can't get hit by it? you also can't ride it
0x04 - ? if set you can't get hit by it?
Addr 0x535-0x53C (8 slots):
? Related to enemies
compared < 0x04 at 0xE906
if true, sets 0x40 in flags 0xA8
Addr 0x543-0x54A (8 slots):
Enemy X position (high)
Addr 0x54B-0x552 (8 slots):
Enemy X position (low)
Addr $0563-0x56A (8 slots):
Enemy Y position
Addr 0x573-0x57A (8 slots):
? Related to enemies
Might be hitbox horizontal size
Addr 0x57B-0x582 (8 slots):
? Related to enemies
Might be hitbox vertical size
Function 0xE994
Seems to check player against enemy position.
hitbox_h = [0x573 + enemy_slot_id] + 0x07
hitbox_w = [0x57b + enemy_slot_id] + 0x0F
This function checks if the follow are all true:
player_y < (enemy_y + hitbox_h)
Make sure player is not too low
(enemy_x - hitbox_w) < (screen_scroll_X + player_onscreen_x)
Make sure player is not too far left
(screen_scroll_X + player_onscreen_x) < (enemy_x + hitbox_w)
Make sure player is not too far right
(enemy_y - hitbox_h) < player_y
Make sure player is not too high
(enemy_y - hitbox_h) - player_y is stored to 0x0006
This value must be negative to fit the condition above
If this value -1 to -8 the game considers you as riding the enemy
Bank 3:
Starting at 0xB1AA is an array of addresses
B1CE - level 00 (??)
BB16 - level 01
B1CE - level 02
B648 - level 03
B822 - level 04
B94E - level 05
B32A - level 06
B4AA - level 07
B9F6 - level 08
B744 - level 09
B3E4 - level 10
BA68 - level 11
BBE8 - level 12
B1CE - level 13 (??)
B1CE - level 14 (??)
B1CE - level 15 (??)
B1CE - level 16 (??)
B1CE - level 17 (??)
These addresses point to a data for the powerup boxes in each level.
Each entry in those arrays is 6 bytes long:
[0] - X screen pos (high)
[1] - X screen pos (low)
[2] - ?
[3] - X pos on screen
[4] - Y pos
[5] - Type
Seems like this list of boxes is terminated with 0xFF in [0] and [1]
Known types:
1 -> Extra life
2 -> ?
3 -> Burger
4 -> Heart
5 -> Apple
Function F176:
This function runs level specific code. Using the level ID (address 0x51) it looks up an address:
0xF19B + (level_id * 2)
0xF19A + (level_id * 2)
It then uses the section ID (address 0x52) to get a function address
addr + (section_id * 2)
The value fetched is pushed to the stack, then an RTS instruction is issued. RTS pushes the (16 bit value from stack + 1) to PC, so the addresses stored in the rom are 1 off from the start of the function
Most levels have more than one function pointer in this area. The function is usually to handle moving to the next section or world, or to determine when you have finished the world (usually the last section handler)
(Function addresses in this table have already had 1 added to them)
Section
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Level 00 (???) [F1C0] F23C
Level 01 [F1C2] F243 F287
Level 02 [F1C6] F294 F2AB
Level 03 [F1CA] F2B8 F2D7 F330
Level 04 [F1D0] F337 F362 F3A0
Level 05 [F1D6] F3AC F3DD
Level 06 [F1DA] F40A F40A F40A F433 F458
Level 07 [F1E4] F468 F4D4
Level 08 [F1E8] F4E1 F4F8
Level 09 [F1EC] F505 F505 F505 F505 F505 F521 F540 F576
Level 10 [F1FA] F58B F5B2 F5E8
Level 11 [F200] F5F8 F60F
Level 12 [F204] F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F61C F713 F733
World 1 section 0 (F243):
Handles the "Good luck" guy
When the screen scroll reaches 0x0808 addr 0x53 is changed from 0x08 to 0x00
If Screen scroll X == 0x0BXX, level section is increased (boss is triggered)
World 1 section 1 (F287):
Waits for 0x4F3 (Object enabled) to become 0
World 2 section 0 (F294):
If Screen scroll X == 0x17XX, level section is increased (boss is triggered)
World 2 section 1 (F2AB):
Waits for 0x4F3 (Object enabled) to become 0
World 3 section 0 (F2B8):
If Screen scroll X == 0x16XX, level section is increased (boss is triggered?)
World 3 section 1 (F2D7):
???
if 0xE2 >= 5, move to section 2
World 3 section 2 (F330):
Seems to be hard coded to move to the next world.
World 4 section 0 (F337):
If Screen scroll X == 0x0FXX, level section is increased (boss is triggered?)
World 4 section 1 (F362):
??? Similar to W3S1
World 4 section 2 (F3A0):
??? Similar to W3S2
World 5 section 0 (F3AC):
If block player is in front of (0x615) == 0x79, level section is increased (move to boss room)
World 5 section 1 (F3DD):
???
World 6 section 0-2 (F40A):
If block player is in front of (0x615) == 0x38, level section is increased (causes a screen transition?)
If Screen scroll X == 0x13XX, level section is increased
World 6 section 3 (F433):
???
World 6 section 4 (F458):
Waits for 0x4F3 (Object enabled) to become 0
World 7 section 0 (F468):
?complex stuff?
If Screen scroll X == 0x16XX, level section is increased
World 7 section 1 (F4D4):
Waits for 0x4F3 (Object enabled) to become 0
World 8 section 0 (F4E1):
If Screen scroll X == 0x0BXX, level section is increased
World 8 section 1 (F4F8):
Waits for 0x4F3 (Object enabled) to become 0
World 9 section 0-4 (F505):
If block player is in front of (0x615) == 0x30, level section is increased (causes a screen transition?)
If block player is in front of (0x615) == 0x83, level section is increased (causes a screen transition?)
World 9 section 5 (F521):
If Screen scroll X == 0x20XX, level section is increased
World 9 section 6 (F540):
??? Similar to W3S1
World 9 section 7 (F576):
???
World 10 section 0 (F58B):
If Screen scroll X == 0x0FXX, level section is increased
World 10 section 1 (F5B2):
Monitors 0x4F3 and 0x4F4
???
World 10 section 2 (F5E8):
Waits for 0x4F3 (Object enabled) to become 0
World 11 section 0 (F5F8):
If Screen scroll X == 0x0BXX, level section is increased
World 11 section 1 (F60F):
Waits for 0x4F3 (Object enabled) to become 0
World 12 section 0-20 (F61C):
???
There is a table at 0xF781 used to compare the block the player is in front of, and to decide where to warp the player:
Block ID Map section
BF -- 01
7A -- 0F
C0 -- 00
C1 -- 10
30 -- 11
BD -- 12
BE -- 13
???
World 12 section 21 (F713):
Waits for 0x4F3 (Object enabled) to become 0
World 12 section 22 (F733):
Waits for 0x4F3 (Object enabled) to become 0
Movement when riding an enemy:
Your final movement speed is calculated from a number of different sources
0xA9 is probably the horizontal speed gained from riding an enemy
Skipping shop:
at 0xF7B0 the burger count (0x61E) is compared to 0 which skips a function that likely starts the shop routine.
Title screen:
Address 0x22 is a counter for the start button. It is reset to 4 and counts down when the start button is held. When the counter reaches 0 the game advances to the next screen/into the game.
Level timer length:
There is table at 0xC3D6 which specifies the timer length per level:
Level 00? - 0xC3D6 = 24792 ???
Level 01 - 0xC3D8 = 300
Level 02 - 0xC3D8 = 300
Level 03 - 0xC3D8 = 400
Level 04 - 0xC3D8 = 400
Level 05 - 0xC3D8 = 300
Level 06 - 0xC3D8 = 400
Level 07 - 0xC3D8 = 400
Level 08 - 0xC3D8 = 300
Level 09 - 0xC3D8 = 500
Level 10 - 0xC3D8 = 300
Level 11 - 0xC3D8 = 200
Level 12 - 0xC3D8 = 500
Castle:
Section 0x02 has two doors. The left door warps you to section 00 (entrance to the castle).
The right door warps you to the left side of section 0x10, which looks identical to section 0x02. Going back through the door in section 0x10 brings you to section 0x0F, which is also identical to 0x02 and 0x10.
Seems like 0x02 starts from the elevator down, 0x10 starts from the room on the left, and 0x0F starts from the door on the right.
Ending level 11 on a 0x30 block ID wrong warps you to section 0x11 which looks like a hidden shop. Taking the elevator up takes you to section 0x08 which is identical to 0x0C. This is around halfway through the castle.
Section 0x12 and 0x13 start from falling out of the ceiling on section 0x03.
Section 0x05 is 0x03 coming down from the elevator from section 0x04.
Section 0x07 is 0x03 on the elevator back from 0x06.
Section 0x0D is 0x03 coming down from the elevator from section 0x0C
Section 0x14 is the same as 0x15 (final boss room).
Section 0x16 is a glitched version of 0x00 and 0x01 combined.
Level data ROM bank:
The table at 0xC5AD says what bank each level's data is in:
Level 01 - 3
Level 02 - 3
Level 03 - 0
Level 04 - 0
Level 05 - 1
Level 06 - 2
Level 07 - 0
Level 08 - 1
Level 09 - 3
Level 10 - 1
Level 11 - 2
Level 12 - 3
Address 0x4f-0x50
This address is filled from a table at 0xD102. The address fetched is then incremented by 3 before being stored to 0x4F and 0x50
Level 01 - 8000 + 3 = 8003
Level 02 - 8000 + 3 = 8003
Level 03 - 90b7 + 3 = 90BA
Level 04 - 8000 + 3 = 8003
Level 05 - 8000 + 3 = 8003
Level 06 - a0b4 + 3 = A0B7
Level 07 - 9133 + 3 = 9136
Level 08 - 8953 + 3 = 8956
Level 09 - a0ee + 3 = A0F1
Level 10 - 90d3 + 3 = 90D6
Level 11 - 930c + 3 = 930F
Level 12 - a206 + 3 = A209
Address 0x54-0x55
This address is filled from a table at 0xCD9F.
Level 01 - 9c0a
Level 02 - 800f
Level 03 - 801b
Level 04 - 90d2
Level 05 - 8013
Level 06 - 8013
Level 07 - a0cb
Level 08 - 914e
Level 09 - 8962
Level 10 - a112
Level 11 - 90e6
Level 12 - 931b
Fetching level data:
All accesses are in the bank for thr level. See the table above to find that bank.
The address in 0x54-0x55 is for the level data.
The address in 0x4F-0x50 is for a table of offsets into the level data. Each offset is 208 bytes long.
To fetch level data:
Take the high byte of the position
Use that as an offset into the table from 0x4F-0x50 and fetch a byte value
Take the value, multiple it by 208, and add it to the address in 0x54-0x55
The resulting address is the beginning of that segment of data.
Enemy data
Table in bank 5 at 0xAF63, add level_id * 2
Level 01 - b9d7
Level 02 - af87
Level 03 - b507
Level 04 - b697
Level 05 - baa7
Level 06 - b117
Level 07 - b377
Level 08 - bbb7
Level 09 - b7a7
Level 10 - b267
Level 11 - bc87
Level 12 - bd57
That address points to another table, entries are 4 bytes long. Game fetches 0x4ED, multiplies it by 4, and adds it to get an address. Note: this addition (0xD24F) seems wrong and may have issues with bit overflow if the lower byte would overflow. Might be abusable for something?
[0].b - Enemy position (low byte)
[1].b - Enemy Y position?
[2].b - Enemy type?
[3].b - ???
0x4ED seems to have room for 4 enemies per high position byte. If any of those are unused the data is all 0 in the above table.
Enemy spawn:
Starting at 0xD229
0x4ED seems to hold the next(?) enemy id to load for the level. The following must be true for the enemy to spawn:
Player's position high byte must be <= end of level (0x4C)
(Player's position + 0x90) (high byte) == Enemy high position byte
(Player's position + 0x90) (low byte) < Enemy low position byte
(Player's position + 0x193) (high byte) >= Enemy high position byte
if equal:
(Player's position + 0x193) (low byte) > Enemy low position byte
what this boils down to is that the game checks every half screen (0x80 pixels) and increments the counter if you are in the first 4 pixels.
you can skip the spawns for that half screen by being at 5 speed at a point where you move the screen from 0x7F->0x84 or 0xFF->0x04
World/Section Min/Max:
Table at 0xBC00 (bank 4), indexed by level_id * 2. These are pointers to data for each world:
Level 01 - bc36
Level 02 - bc56
Level 03 - bc76
Level 04 - bca6
Level 05 - bcc6
Level 06 - bce6
Level 07 - bd16
Level 08 - bd36
Level 09 - bd56
Level 10 - bdb6
Level 11 - bdd6
Level 12 - bdf6
Fetch that address and add section_id * 16
Data in that table:
[5].b = Min camera position
[6].b = Max camera position