|
DevelopmentSega Master System / Mark III / Game Gear |
Home - Forums - Games - Scans - Maps - Cheats - Credits |
No Mapping Flat Code in $0000 - $529b [1]
Teddy Boy maintains a master "game state" variable in the low 4 bits of the byte at $c016. The valid values are:
Value | State |
---|---|
0 | Value immediately changed to 1 |
1 | Title Screen |
2 | Demo |
3 | Gameplay |
4 | Round Completed |
5 | Life Lost |
6 | Bonus Game |
7 | Options Screen |
8 | Level Select |
For some states, bit 7 of the same byte is used to distinguish a change of state (bit 7 reset) from a continuation of the current state (bit 7 set).
Scores in Teddy Boy are always multiples of 10. Internally, therefore, the game stores values of score / 10
and simply adds a trailing zero for display. These values are stored as groups of three bytes in (little-endian) BCD format. The highest score attainable is thus 9,999,990.
Player 1's score value is stored in RAM at address $c010 and player 2's at address $c013. The value for the top score is stored at $c00a.
There are 35 ways to gain points during play. Each of these achievements will increase the player's score by a certain amount of points. These amounts are stored (in the same format as the scores) in a lookup table at ROM address $355f.
Teddy Boy uses a single palette for most gameplay, although the colours at indices $00 and $10 are often overwritten in order to change the background. Different palettes are used for the title screen and for the bonus game.
The 32 bytes of data defining the main palette begin at offset $0edd. The colours in the main palette are:
Index | $00 | $01 | $02 | $03 | $04 | $05 | $06 | $07 | $08 | $09 | $0a | $0b | $0c | $0d | $0e | $0f |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Value | $00 | $3f | $00 | $3c | $38 | $20 | $32 | $0f | $3b | $0b | $30 | $2c | $08 | $03 | $3c | $2a |
Index | $10 | $11 | $12 | $13 | $14 | $15 | $16 | $17 | $18 | $19 | $1a | $1b | $1c | $1d | $1e | $1f |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Value | $00 | $03 | $34 | $38 | $3f | $20 | $01 | $0f | $0b | $07 | $00 | $0c | $08 | $2a | $3c | $2a |
These are the other palettes used by Teddy Boy. Palette entries beyond those shown are not explicitly set by the code and thus retain their values from the main palette:
Index | $00 | $01 | $02 | $03 | $04 |
---|---|---|---|---|---|
Value | $00 | $0f | $0b | $03 | $33 |
Index | $00 | $01 | $02 | $03 | $04 | $05 | $06 | $07 | $08 | $09 | $0a | $0b | $0c | $0d | $0e | $0f |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Value | $38 | $22 | $3f | $00 | $04 | $3c | $01 | $0f | $0b | $06 | $30 | $0c | $08 | $03 | $20 | $2a |
The title screen palette data can be found in the Teddy Boy ROM at $0907. The bonus game palette data is at $3986.
The data at offset $0a90 in the Teddy Boy Blues ROM describes the strings on the title screen. The first byte gives the number of strings; this is followed by a data block for each string. Each data block contains the following information:
Although the number of strings is given as 5, there are 6 blocks of data. Changing the number of strings to 6 (ROM[$0a90] = 06) causes a new string, "TM
", to appear on the title screen:
Teddy Boy Blues Title Screen with TM
In the Teddy Boy ROM, the corresponding data is at $0950. The copyright information on the title screen has been simplified, involving the removal of one data block and modification of another. Other than this, the only change to the string data is to update each block's ROM address to point to the correct characters.
In particular, the unused data block is still present, almost untouched. The VRAM address has not been updated to reflect the altered logo size. As before, incrementing the number of strings (ROM[$0950] = 05) causes "TM" to appear:
Teddy Boy Title Screen with TM
After resetting the game, enter the Options Screen. Ensure that the Continue
option is unavailable and select a 2 player game. Then, enable the Level Select and immediately start the game without changing the round. Player 1 will face round 1, as expected, but player 2's game will be heavily corrupted.
This bug arises from the implementation of the level select. When the level select is entered, the Continue
option is (internally) forced to "Yes" and when the round is changed, the number is written to RAM as though that round was reached by both players during the previous game. If the round is never changed, therefore, entering the level select is simply equivalent to enabling the Continue
option. When there is a game to continue, this can give surprising results [2] but is mostly harmless.
However, when there is no game to continue, the memory locations which hold the round reached during the previous game have the value zero on entering the level select. Code to initialize the values is present, but it only does so for player 1. Player 2 can thus "continue" their game from the invalid round 0.
If no buttons are pressed on the title screen, a demo of round 1 will begin. Teddy Boy's movements during the demo are driven by simulated input - the data for this is in "TransBot" format and is located at $403c-$4288 in the Teddy Boy ROM. Each time the demo plays, it uses the same input data. Variety arises from randomness in the movement of monsters.
There are seven monster types in the game:
Internally, the game refers to the monster types using the numbers 1 to 7, as above, but with one exception. When describing monsters within dice, the number 8 is also used. Once released, these monsters become type 7 - the use of 7 or 8 only changes how the release occurs. Specifically, type 7 monsters are released in a group (the same as type 6), while type 8 monsters (and types 1 to 5) are released individually.
An 8-byte descriptor for each of the seven monster types exists within $15d4 - $160b in the Teddy Boy ROM. The contents of each descriptor are as follows:
Offset | Length | Contents |
---|---|---|
$00 | 2 bytes | Pointer to Tiles |
$02 | 1 byte | Number of Tiles |
$03 | 2 bytes | RAM address for copy of tile index data |
$05 | 1 byte | Number of Tile Indices |
$06 | 2 bytes | Pointer to Tile Index Data |
The round layout data is stored at $68dc - $7bb7 in the Teddy Boy ROM. Two tables of pointers into this area exist at $0efd - $0f60 and $0f61 - $0fc4. Each table contains one entry for each round from 1 to 50. The first table gives the address of the round layout itself and the second gives the address of a zero-terminated list of the monster types (1 - 7) used in the round. The background colour for each round is stored in a third table, at $0fc5 - $0ff6.
At runtime, the layout is decompressed to yield tile indices in RAM at $c800 - $cb7f. The code at $0e5c - $0e67 calls four functions to perform the decompression:
After calling these functions, the code at $0e68 - $0e78 converts the tile indices in RAM to name table entries in VRAM.
The bonus game layout is stored in the same way, at $3c96 - $3d09. It is decompressed as above by the code at $38ff - $390a (except that the die data is decompressed by calling $0bf6 rather than $0be4). A call is made to $3d0a to randomize the contents of the dice before the code at $390e - $391e performs the conversion of tile indices to name table entries.
The sound engine and its data are self-contained: they fill $443d - $529b in the Teddy Boy ROM. The engine has two entry points:
The main game code communicates with the engine through a trigger at $c080: writing a sound track number to this address causes the track to begin playing.
The engine manages up to six sound channels at a time, mapping these onto the four hardware channels supported by the PSG. A 32 byte structure is maintained in RAM for each channel - these begin at address $c088. Each structure contains the following:
Offset | Length | Contents |
---|---|---|
$00 | 1 byte | Flags (Bit 7: Enable updates; Bit 6: Unknown; Bit 5: Unknown; Bit 3: Unknown; Bit 2: Disable PSG writes) |
$01 | 1 byte | Bits 7-4: Unknown; Bits 3-0: PSG Channel Number (0 - 3) |
$02 | 1 byte | Note Duration Multiplier |
$03 | 2 bytes | Pointer to current location within track data |
$05 | 1 byte | Key Displacement |
$06 | 1 byte | Unknown |
$07 | 1 byte | Unknown |
$08 | 1 byte | Volume |
$09 | 1 byte | Stack Pointer (Stored as an offset) (Full descending stack) |
$0a | 2 bytes | Current Note Duration |
$0c | 2 bytes | Current Note Duration Counter |
$0e | 1 byte | Unknown |
$0f | 1 byte | Unknown |
$10 | 2 bytes | Current Note Base Tone Value |
$12 | 2 bytes | Current Note Adjusted Tone Value |
$14 | 2 bytes | Unknown |
$16 | 1 byte | Current Note Adjusted Volume Value |
$17 | 9 bytes | Loop Counters and Stack |
The data for each sound track begins with a header: one byte giving the number of channels, followed by nine bytes for each. These are used to initialize the first 9 RAM bytes per channel.
After the header comes the track data itself. This is a list of bytes, interpreted as follows:
$00
- $7f
: Note Duration
$80
- $df
: Note Value
$80
corresponds to a rest
$81
- $c8
correspond to notes A2 - G#8, assuming a zero key displacement for the channel
$e0
- $ff
: Coordination Flag
The valid coordination flags have values $e0
- $f2
. The effects of the coordination flags are:
Flag | Parameters | Effect |
---|---|---|
$e0 | $xx | Set Channel Note Duration Multiplier |
$e1 | $xx | Set Channel Volume |
$e2 | None | End Channel Playback |
$e3 | %0000?aaa | Write %aaa to PSG Noise Register |
$e4 | $xx | Set Channel Structure Byte 7 |
$e5 | $xxxx | Absolute Jump (Set location pointer to $xxxx ) |
$e6 | None | Set Bit 5 of Channel Structure Byte 0 |
$e7 | None | Reset Bit 5 of Channel Structure Byte 0 |
$e8 | None | Set Bit 3 of Channel Structure Byte 0 |
$e9 | None | Reset Bit 3 of Channel Structure Byte 0 |
$ea | $xxxx | Absolute Call (Push current location pointer to stack, then set it to $xxxx ) |
$eb | None | Return From Call (Pop location pointer from stack) |
$ec | $xx $yy $zzzz | Loop ($xx = Loop Counter Index, $yy = Total Repeat Count, Set location pointer to $zzzz ) |
$ed | $xx | Set Channel Structure Byte 6 |
$ee | $xx | Add $xx to Channel Key Displacement |
$ef | $xx | Add $xx to Channel Volume (Result clamped to the range $00 - $0f ) |
$f0 | None | End Channel Playback and (Re-)Enable PSG Writes for (Software) Channel 1 |
$f1 | None | End Channel Playback and (Re-)Enable PSG Writes for (Software) Channel 2 |
$f2 | None | End Channel Playback, Enable PSG Writes for Channels 2 & 3 and Set PSG Ch. 3 to High-Frequency White Noise |
This table details the contents of the Teddy Boy ROM (Size: 32KB; CRC32: 2728faa3):
Address Range | Contents |
---|---|
$0000 - $00c4 | Unknown Code (With a few unused bytes) |
$00c5 - $00d6 | Jump Table (9 entries, indexed by game state) (Jump instruction at $0596 ) |
$00d7 - $01e5 | Unknown Code [3] |
$01e6 - $01ed | Jump Table (4 entries, used for sprite attribute table updates) (Jump instruction at $0596 ) |
$01ee - $0284 | Unknown Code |
$0285 - $0298 | Initial Data for VDP Registers 0-9 |
$0299 - $0629 | Unknown Code |
$062a - $062f | Jump Table (3 entries, used for movement) (Jump instruction at $0596 ) |
$0630 - $0893 | Unknown Code |
$0894 - $08a1 | Initialisers for RAM locations $c010 - $c01d at start of gameplay |
$08a2 - $08f9 | Unknown Code |
$08fa - $0907 | Title Screen Fade-in Colours [4] |
$0907 - $090b | Title Screen Palette |
$090c - $094f | Tile Indices: Teddy Boy Logo |
$0950 - $0969 | Title Screen String Data |
$096a - $0980 | "PUSH 1PLAY START BUTTON " |
$0981 - $0982 | "OR " |
$0983 - $0999 | "PUSH 2PLAY START BUTTON " |
$099a - $09a4 | "© SEGA 1985 " [5] |
$09a5 - $09a6 | "TM " [5] |
$09a7 - $0b76 | 2bpp Tiles: Teddy Boy Logo |
$0b77 - $0c79 | Code: Round Layout Decompression |
$0c7a - $0c81 | Tile Indices: Block and Wall Sides |
$0c82 - $0ced | Code: Round Layout Decompression |
$0cee - $0cfb | Die Face Tile Index Pointers |
$0cfc - $0d36 | Code: Round Layout Decompression |
$0d37 - $0d3a | Tile Indices: Die Sides |
$0d3b - $0d56 | Unknown Code |
$0d57 - $0d67 | Code: Round Layout Decompression |
$0d68 - $0edc | Unknown [6] |
$0edd - $0efc | Main Palette |
$0efd - $0f60 | Round Layout Pointer Table |
$0f61 - $0fc4 | Round Monster List Pointer Table |
$0fc5 - $0ff6 | Round Background Colour Table |
$0ff7 - $1006 | 1bpp Tiles: Minor Impact |
$1007 - $100e | 1bpp Tile: Bullet |
$100f - $124e | 4bpp Tiles: Major Impact, Timer, Eyeball Bug, Small Monsters |
$124f - $13ce | 4bpp Tiles: Teddy Boy |
$13cf - $145e | 1bpp Tiles: Teddy Boy Angel |
$145f - $15d3 | Unknown Code |
$15d4 - $160b | Monster Type Descriptors |
$160c - $1759 | Monster Tile Index Data |
$175a - $1944 | Unknown [7] |
$1945 - $197c | Jump Table (28 entries, used for movement) (Jump instruction at $0596 ) |
$197d - $2015 | Unknown Code [8] |
$2016 - $25cb | Unknown [9] |
$25cc - $25db | Jump Table (8 entries, used for Imorin movement) (Jump instruction at $0596 ) |
$25dc - $28d0 | Unknown [10] |
$28d1 - $28dc | Jump Table (6 entries, used for Denden movement) (Jump instruction at $0596 ) |
$28dd - $2fb2 | Unknown [11] |
$2fb3 - $2fb8 | Jump Table (3 entries, used for fire) (Jump instruction at $0596 ) |
$2fb9 - $342c | Unknown Code |
$342d - $3445 | "TOP ROUND REMAIN " |
$3446 - $3448 | "1UP " |
$3449 - $344b | "2UP " |
$344c - $345d | "PLAYER 1 GAME OVER " |
$345e - $3464 | "TIME UP " |
$3465 - $346e | "TIME BONUS " |
$346f - $3476 | "0 POINTS " |
$3477 - $347b | "START " |
$347c - $3485 | "BONUS GAME " |
$3486 - $3492 | "SPECIAL BONUS " |
$3493 - $349f | "PERFECT BONUS " |
$34a0 - $34af | "CONGRATULATIONS! " |
$34b0 - $34ca | "BUT DON'T TOUCH THE DENDEN! " |
$34cb - $34ce | "PTS. " |
$34cf - $355e | Unknown Code |
$355f - $35c7 | Points Lookup Table |
$35c8 - $3972 | Unknown Code |
$3973 - $3985 | Bonus Game Tile and Palette Data |
$3986 - $3995 | Bonus Game Palette |
$3996 - $3c95 | 4bpp Tiles: Bonus Items |
$3c96 - $3d09 | Bonus Game Layout |
$3d0a - $3d6c | Code: Bonus Game Die Contents Randomization |
$3d6d - $3e3a | Bonus Game Die Contents Randomization Data |
$3e3b - $3f74 | Unknown [12] |
$3f75 - $3f8f | Bonus Game Denden Tile Index Data |
$3f90 - $403b | Unknown Code |
$403c - $4288 | Demo Simulated Input Data |
$4289 - $43d8 | Unknown Code |
$43d9 - $43e4 | Initialisers for Options Screen Sprite Attribute Table |
$43e5 - $43e9 | Initialisers for Options Screen Variables |
$43ea - $440d | Unknown Code |
$440e - $4422 | Options Screen String Data |
$4423 - $442a | "CONTINUE " |
$442b - $442e | "FIRE " |
$442f - $4435 | "YES NO " |
$4436 - $4437 | "1P " |
$4438 - $443c | "ROUND " |
$443d - $44bf | Sound Track $82 Data: Game Over |
$44c0 - $44fd | Sound Track $83 Data: Round Completed |
$44fe - $4531 | Sound Track $84 Data: Life Lost |
$4532 - $454e | Sound Track $85 Data |
$454f - $4565 | Sound Track $86 Data |
$4566 - $4576 | Sound Track $87 Data |
$4577 - $4584 | Sound Track $88 Data |
$4585 - $4591 | Sound Track $89 Data |
$4592 - $45a4 | Sound Track $8a Data |
$45a5 - $45c3 | Sound Track $8b Data |
$45c4 - $45f3 | Sound Track $8c Data |
$45f4 - $4616 | Sound Track $8d Data |
$4617 - $4665 | Sound Track $8e Data |
$4666 - $4692 | Sound Track $8f Data |
$4693 - $46c3 | Sound Track $90 Data: Extra Life |
$46c4 - $46e1 | Sound Track $91 Data |
$46e2 - $476c | Sound Track $92 Data: Bonus Game |
$476d - $47c5 | Sound Track $93 Data: Bonus Game End |
$47c6 - $47d4 | Sound Track $94 Data |
$47d5 - $48d9 | Sound Track $95 Data: Title Screen |
$48da - $48f1 | Sound Track $96 Data |
$48f2 - $49d6 | Sound Engine Data |
$49d7 - $4d39 | Sound Track $81 Data: Gameplay |
$4d3a - $4d7b | Code: Sound Engine |
$4d7c - $4da7 | Sound Track Data Pointers |
$4da8 - $4dd3 | Jump Table (22 entries, indexed by sound track number) (Jump instruction at $4d7b ) |
$4dd4 - $4f97 | Sound Engine [13] |
$4f98 - $50b5 | Code: Sound Engine [14] |
$50b6 - $50db | Jump Table (19 entries, indexed by sound coordination flag) (Jump instruction at $50b1 ) |
$50dc - $51b5 | Code: Sound Coordination Flag Handlers |
$51b6 - $51e6 | Code: Sound Engine [15] |
$51e7 - $51ea | PSG Silencing Data |
$51eb - $527c | PSG Tone Table |
$527d - $5288 | Code: HL = H * E (Unsigned) |
$5289 - $529b | Code: A , H (Quotient, Remainder) = HL / E (Unsigned) |
$529c | Unused? |
$529d - $52db | Tile Indices: Die Faces [16] |
$52dc - $533b | 2bpp Tiles: Block and Wall Sides |
$533c - $53ab | 2bpp Tiles: Die Sides |
$53ac - $53eb | 4bpp Tiles: Fire |
$53ec - $541b | 1bpp Tiles: !'TM. |
$541c - $5473 | 1bpp Tiles: 0123456789: |
$5474 - $556b | 1bpp Tiles: ABCDEFGHIJKLMNOPQRSTUVWXYZ©SEGA |
$556c - $566b | 4bpp Tiles: Wall, Block, Die Face 1 |
$566c - $577b | 2bpp Tiles: Die Faces 2-6 |
$577c - $57fb | 4bpp Tiles: Dharman |
$57fc - $58fb | 4bpp Tiles: Oshishi |
$58fc - $5b7b | 4bpp Tiles: Slow Mover |
$5b7c - $625b | 4bpp Tiles: Denden |
$625c - $665b | 4bpp Tiles: Imorin |
$665c - $675b | 4bpp Tiles: Pyon |
$675c - $68db | 4bpp Tiles: Blue Masked Monster |
$68dc - $7bb7 | Round Layouts and Monster Lists |
$7bb8 - $7fef | Unused |
$7ff0 - $7fff | ROM Header (Product Code: 4003; Version: 0; Region: SMS Export; ROM Size: 32KB) |
This table describes several of the RAM locations used by Teddy Boy:
Address | Length | Contents |
---|---|---|
$c000 | 1 byte | Value of VDP Register 1 |
$c004 | 1 byte | Game Paused ($00/$ff = running/paused) |
$c00a | 3 bytes | Top Score Value |
$c00f | 1 byte | Fire Enable ($00/$01 = disabled/enabled) |
$c010 | 3 bytes | Player 1 Score Value |
$c013 | 3 bytes | Player 2 Score Value |
$c016 | 1 byte | Game State |
$c017 | 1 byte | Player 1 Round Number in BCD |
$c018 | 1 byte | Player 1 Round Number |
$c019 | 1 byte | Player 2 Round Number in BCD |
$c01a | 1 byte | Player 2 Round Number |
$c01b | 1 byte | Player 1 Number of Lives |
$c01c | 1 byte | Player 2 Number of Lives |
$c01f | 1 bit | State of Reset Button ($00/$10 = pressed/released) |
$c020 | 1 byte | X Scroll Adjustment |
$c021 | 1 byte | Y Scroll Adjustment |
$c022 | 1 byte | X Scroll Value |
$c023 | 1 byte | Y Scroll Value |
$c024 | 1 byte | Negated X Scroll Adjustment |
$c025 | 1 byte | Negated Y Scroll Adjustment |
$c034 | 2 bytes | Title Screen Countdown |
$c050 | 1 byte | High byte to use when converting tile indices to name table entries |
$c051 | 4 bits | Foreground palette index to use when outputting 1bpp tiles |
$c052 | 2 bytes | Current Round Number * 2 |
$c054 | 1 byte | Next available tile index for monster tiles |
$c07a | 1 byte | Cursor Location (0 - 3) on Options Screen and Level Select |
$c07b | 1 bit | Options Screen: Continue (%???????0/%???????1 = yes/no) |
$c07c | 1 bit | Options Screen: Fire (%???????0/%???????1 = yes/no) |
$c07d | 1 bit | Options Screen: 1P (%???????0/%???????1 = yes/no) |
$c07e | 1 byte | Number of Presses of on Options Screen |
$c080 | 1 byte | Sound Engine Trigger |
$c088 | $c0 bytes | Sound Channel Structures |
$c600 | $100 bytes | Copy of Sprite Attribute Table |
$c800 | $380 bytes | Current Round Layout (Tile indices) |
$cb80 | 1 byte | Terminator for Round Layout ($45) |
$cb81 | 1 byte | Number of Dice |
$cb82 | $140 bytes | Die Data [17] |
$d100 | $61 bytes | Backup of Number of Dice and Die Data for Player 1 [18] |
$d180 | $61 bytes | Backup of Number of Dice and Die Data for Player 2 |
$d200 | $143 bytes | Monster Tile Index Data |
$e000 | - | Top of Stack |
See Teddy Boy Editor.
$01a9
- $01c4
is unused.$0ebf
- $0edc
.$1854
- $1863
and $1909
- $1944
.$1e72
- $1e7a
and $1e7b
- $1e83
are unused.$2016
- $201f
, $2119
- $2122
, $224c
- $224f
and $23b5
- $23bc
.$27c7
- $2816
.$2b55
- $2b6c
, $2c70
- $2c7b
and $2dbc
- $2dc0
.$3ee0
- $3f00
.$4e89
- $4ea4
and $4f90
- $4f97
.$4ff6
- $4ff8
is unused.$51dd
- $51e1
and $51e2
- $51e6
are unused.Researched by RetroSpark, Guy Brys