Puyo Puyo Tsu/Game Options Variables
This page discusses Puyo Puyo Tsu game options and settings that are changed via the dedicated menu.
Main Location and structure
The option settings are stored in RAM in a 768-byte chunk starting at 0xFF4800. Only a few bytes seem to be actually used. The chunk has an integrity checksum and tag value. It looks like some variables in that chunk are used to save part of the game state, maybe statistics and counters (rensa counter, etc.).
The following table sums up the structure of the 768-byte chunk:
Base address | Size | Setting | Comment |
---|---|---|---|
0xFF4800 | 2 bytes | 16-bit integrity checksum | Integrity checksum calculated by routine checksum_768b() at 0x00182E, data is summed from 0xFF4802 onwards. |
0xFF4802 | 2 bytes | Margin Time | Ranges from 0x00 (0 seconds) to 0x3E (992 seconds); default: 0x06 |
0xFF4804 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4805 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4806 | 1 byte | Chain Type Angle | Chain type, angle of animation (0-3, default 4) |
0xFF4807 | 1 byte | Zenkeshi Ojama Count | Number of bonus ojama puyos sent by an all-clear (0-255, default 30) |
0xFF4808 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4809 | 2 bytes | Possibly unused | |
0xFF480B | 1 byte | Ojama Points | Points given for clearing an ojama puyo (0-250, default 0, 10 points increments) |
0xFF480C | 1 byte | Sousai | On (1) / Off (0), default: 1 |
0xFF480D | 1 byte | Ojama Needed Points | Needed points to send a single ojama (0-250, default 70 or 120 in custom rules, 10 points increments) |
0xFF480E | 1 byte | Puyos to Clear | Needed puyos to clear a chain (1-72, default 4) |
0xFF480F | 1 byte | Ojama Mode | Ojama puyo mode: standard, hard puyos, top row only (0: standard, 1: hard, 2: hard2, default 0) |
0xFF4810 | 1 byte | 2P character select | Hidden setting: used to set 2P character. Valid values: 0x01 (Wisp) - 0x21 (masked satan). |
0xFF4811 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4812 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4813 | 1 byte | Rule Henka | On (1) / Off (0), default: 0 |
0xFF4814 | 1 byte | Voice Mode | Type A (0) / Type B (1), default: 1 |
0xFF4815 | 1 byte | Pad 1 Type | Type 1 (0) / Type 2 (1), default 1 |
0xFF4816 | 1 byte | Pad 2 Type | Type 1 (0) / Type 2 (1), default 1 |
0xFF4817 | 1 byte | Rensa Sibari | Ranges from "Off" (0) to "Limit 9" (8), default: 0 |
0xFF4818 | 1 byte | 2P Battle Count | Immediate value, default: 3 |
0xFF4819 | 1 byte | VS Com. Level | Easy (0) / Normal (1) / Hard (2) / Hardest (3), default: 1 |
0xFF481A | 7 bytes | Possibly unused | |
0xFF4821 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4822 | 5 bytes | Possibly unused | |
0xFF4827 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4828 | 1 byte | Chain Type Angle (in-menu) | Chain type, angle of animation (0-3, default 4) |
0xFF4829 | 1 byte | Ojama Needed Points (in-menu) | Needed points to send a single ojama (0-250, default 120, 10 points increments) |
0xFF482A | 1 byte | Ojama Points (in-menu) | Points given for clearing an ojama puyo (0-250, default 0, 10 points increments) |
0xFF482B | 1 byte | Puyos to Clear (in-menu) | Needed puyos to clear a chain (1-72, default 4) |
0xFF482C | 1 byte | Ojama Mode (in-menu) | Ojama puyo mode: standard, hard puyos, top row only (0: standard, 1: hard, 2: hard2, default 0) |
0xFF482D | 1 byte | Zenkeshi Ojama Count (in-menu) | Number of bonus ojama puyos sent by an all-clear (0-255, default 30) |
0xFF482E | 2 bytes | Possibly unused | |
0xFF4830 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4831 | 2 bytes | Possibly unused | |
0xFF4833 | 1 byte | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4834 | 700 bytes | Possibly unused | |
0xFF4AF0 | 4 bytes | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4AF4 | 2 bytes | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4AF6 | 2 bytes | yet unknown | Yet unknown, explicitly cross-referenced |
0xFF4AF8 | 8 bytes | Chunk tag | Set to the string "COMPILE!" |
Options have been reverse engineered by locating their ASCII strings and figuring out which routine drew the options menu (sub_2C3E). After identifying the margin time setting in memory, watching the other settings change confirmed the finding.
Initialization
The set_default_settings() routine simply moves default values to the setting location in memory:
sub_217C is an initialization routine that copies data based on a yet unknown value (unk_FF4827).
set_default_settings() is called from 0x002216 (init_load_defaults()), which is a very early game initialization routine, itself called from the last general initialization routine (sub_3C2) called the main game loop (at 0x308, while the main loop begins at 0x310).
Handling
Those options are read from various game routines that have yet to be reverse engineered. However, these read accesses are made from routines that can be traced back to previously identified main game logic, giving hope to properly identify routines involved with various game aspects such as offsetting, score calculation, ojamas, chain resolution, etc.
Checksum routine
The checksum routine is quite simple, and actually sums 383 words of memory into d0:
What's puzzling is the fact that this routine is only used for the game options, maybe as some form of protection against limited cheating devices such as the Game Genie.
Hidden options
The game's option menu is drawn on screen from routine sub_2C3E, which includes references to and actually handles two hidden options, one of which is called Game Mode ("Normal", "Special" or "Futa"), the other being unknown and taking values between either "Sensyu" or "Point".
Here's the section mentioning the Game Mode option:
And the other unknown setting values: