Me and other members who are investigating the inner workings of Kya DL (mainly in the KDL speedrunning Discord server) use Cheat engine to find variables and save the findings in a cheat table file, because it's a very powerful and flexible program.
I'll be uploading my cheat tables (which also include contributions from other members of the server) in a separate repo, which includes instructions on how to use CE with PCSX2 1.7 .
All addresses and offsets are always hexadecimal.
When talking about a pointer address, this page uses a terminology similar to CE: to get to the desired address, take the 4-byte number stored at the pointer base address, add the offset to that number, and the result is the actual memory address storing that particular variable.
(eg: pointer base address 10
& offset +2
= take value stored at 10
(X), add +2
to it, actual address is X+2
)
When talking about a "normal" address (like with the controller readings), you simply take the beginning address and add the offset to it to get the actual address.
(eg: beginning address 20
& offset 6
= actual address 26
)
Variables and RAM
Game disc files
Save files
Important! The addresses refer to the final NTSC build of the game.
The PAL version has different values, which will eventually be documented.
0495B30
/0495B9C
/0495C1C
Type: 2 byte "integer"
Offset: +00
Joker commands are addresses that contain the button reading from the controller, stored with 2 bytes.
In Kya DL, the buttons have these base values:
Button | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Hex value |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Square | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7FFF |
Cross | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | BFFF |
Circle | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DFFF |
Triangle | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | EFFF |
R1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | F7FF |
L1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | FBFF |
R2 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | FDFF |
L2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | FEFF |
D-pad Left | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | FF7F |
D-pad Down | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | FFBF |
D-pad Right | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | FFDF |
D-pad Up | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | FFEF |
Start | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | FFF7 |
R3 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | FFFB |
L3 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | FFFD |
Select | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | FFFE |
When multiple buttons are pressed, the value gets set to [Button 1] AND [Button 2] AND ... [Button N]; for example when pressing R2 + Triangle + Circle the value gets set to FDFF
AND EFFF
AND DFFF
== CDFF (1100 1101 1111 1111)
Other PS1/PS2 games may store the value in a different way. More info here
FFFF (NOT = 0000)
Type: 1 byte unsigned integers
Length: 4 * 1 byte = 4 bytes total
Offset | Analog stick | Axis |
---|---|---|
+02 |
Right | X |
+03 |
Right | Y |
+04 |
Left | X |
+05 |
Left | Y |
On the X axis, 00
is left and FF
is right.
On the Y axis, 00
is up and FF
is down.
A stick resting in the neutral position has both set to 7F
(127).
Controller readings | ||
---|---|---|
Address: 0495B30 /0495B9C /0495C1C |
||
Size: 12 (currently known!) |
||
Offset | Length (bytes) | Content |
+00 |
02 |
Joker command |
+02 |
01 |
Right analog X axis |
+03 |
01 |
Right analog Y axis |
+04 |
01 |
Left analog X axis |
+05 |
01 |
Left analog Y axis |
+06 |
01 |
pressure |
+07 |
01 |
pressure |
+08 |
01 |
pressure |
+09 |
01 |
pressure |
+0A |
01 |
pressure |
+0B |
01 |
pressure |
+0C |
01 |
pressure |
+0D |
01 |
pressure |
+0E |
01 |
pressure |
+0F |
01 |
pressure |
+10 |
01 |
pressure |
+11 |
01 |
pressure |
Address: 0495CB0
/0495D1C
/0495D9C
The order and way in which things are stored are the same as for player one.
Note that the game also requires a DualShock 2 for player two, if you try plugging in an original DualShock in port 2 and try to control P2 in the secret level nothing will happen.
All currenty known variables of this category are stored with pointers.
Type: float
Pointer base value: 06F2D90
Offset (X): 0000030
Offset (Y): 0000034
Offset (Z): 0000038
To give a sense of scale, when Kya jumps by pressing she peaks at around +1.71 Y.
(it's actually currently unknown which value the game considers to be the X and which one to be the Z, the nomenclature has been chosen based on their order in memory).
Some settings are stored in the file BWITCH.ini in the root of the game DVD.
It's possible (and easier) to change these by editing the variables where they're stored after being read from the disc.
The level the game should load when starting a new game (no idea why it's called AddLevel).
Removing the setting completely from the ini file causes it to default to NATIV (even though the ini file itself states otherwise).
The folder is set by SetPath, which is set to "CdEuro/Level/" in the final game (on both the NTSC and PAL releases).
Level folder in the table below omits the above mentioned root directory.
If set to a value different from the default value of The Roots, when starting a new game, the intro movie will be skipped, the lines "Hey, look at this"..."Is it dead?" will be played, and then the player will be immediately thrown in the level.
06DA5B4
Value | Level folder | Level | Info |
---|---|---|---|
00 |
NATIV | Nativ City | |
01 |
LEVEL_1 | The Roots | Default value |
02 |
LEVEL_2 | Flying Forest | |
03 |
LEVEL_3 | Hunter's Domain | |
04 |
LEVEL_4 | Nativ City when first visiting with Aton | |
05 |
LEVEL_5 | The Quarry | |
06 |
LEVEL_6 | Destroyed Nativ City | |
07 |
LEVEL_7 | The Air Post | |
08 |
LEVEL_8 | Forgotten Island | |
09 |
LEVEL_9 | Brazul Lab (Forgotten Island) | |
0A |
LEVEL_10 | Wolfun City | |
0B |
LEVEL_11 | The Quarry Brazul miniboss | |
0C |
LEVEL_12 | The Fortress | |
0D |
LEVEL_13 | Level Test (secret level) | |
0E |
PREINTRO | Main menu | If choosing this, the intro movie will play first, and then the opening lines will play, before kicking back to the main menu |
0F |
CREDITS | Ending credits | |
Values after 15 make the game try to load levels that don't exist, causing different sorts of weird behaviours Usually the save file gets set to "UNKNOWN LEVEL (number of level as signed integer)" Below are some examples |
|||
10 |
Game returns to the new game save selector and deletes the save that was selected (resetting to EMPTY) | ||
11 |
Game immediately freezes after starting new game, without playing lines and without showing any signs of trying to actually load anything from the PCSX2 logs |
||
12 |
Causes the selected save file to be set to an empty level name |
Strings pertaining to this menu have been found in the final game, but it's currently unknown if and how that can be accessed in the final build.
However, it is known that it's possible to enable the flying cheat and the invincibility cheat by manually writing to the variables pertaining to them in RAM (the cheat options menu is coded weirdly, as there are two separate variables for these two cheats: the first technically only controls if the cheat is displayed as enabled or disabled in the menu, and the second (the "enable" variable) is what the code actually checks to see if the cheat effect should apply (for example, checking the value of the flying cheat enable when + is pressed), and the former gets copied to the latter any moment the cheat options menu is being viewed).
With the aid of the PCSX2 debugger and the September 29 prototype, the code that handles checking the enable variables was found in the final game, and it was confirmed that changing those is enough to restore the functionality.
(Keep in mind that the locations in RAM vary from build to build and version to version, so the values in this page won't work for the September 29 prototype).
These are stored next to each other and are accessed via a pointer.
Pointer base address: 00448AA0
Offset (flying): 0000AA0
Offset (invincibility): 0000AA4
Once flying is enabled, it can be toggled by pressing +
Another dormant debug menu is documented at tcrfFolder | Level | Name | No. of SECTx.bin files | Info |
---|---|---|---|---|
NATIV | Nativ City | NATIV CITY | 26 | SECT3.bnk doesn't exist |
LEVEL_1 | The Roots | THE ROOTS | 13 | |
LEVEL_2 | Flying Forest | FLYING FOREST | 11 | SECT11.bnk doesn't exist |
LEVEL_3 | Hunter's Domain | HUNTER'S DOMAIN | 19 | SECT9.bnk, SECT19.bnk and SECT20.bnk don't exist |
LEVEL_4 | "Nativ City" the first time you visit with Aton | NATIV CITY | 11 | SECTs 2-4, 8-12 don't exist (the whole upper Nativ City doesn't exist in this version, along with minigames) Doesn't have any shops, elevators etc shown on the L1 map The game silently loads in the real NATIV map during the cutscene where Atea tells Kya to follow the signs to the Boomy shop |
LEVEL_5 | The Quarry | THE QUARRY | 14 | |
LEVEL_6 | Destroyed Nativ City | NATIV CITY | 3 | |
LEVEL_7 | The Air Post | THE AIR POST | 19 | |
LEVEL_8 | Forgotten Island | FORGOTTEN ISLAND | 9 | |
LEVEL_9 | Brazul's laboratory (Frank boss fight) | FORGOTTEN ISLAND | 1 | Pretends to be LEVEL_8 in the areas preview in the pause menu |
LEVEL_10 | Wolfun City | WOLFUN CITY | 7 | |
LEVEL_11 | Brazul miniboss (The Quarry) | THE QUARRY | 1 | Pretends to be LEVEL_5 in the areas preview in the pause menu It being so distant from it's parent LEVEL_5 may suggest the decision to separate it was taken late in the development? |
LEVEL_12 | The Fortress | THE FORTRES | 3 | |
LEVEL_13 | Secret level | LEVEL TEST | 5 | More info |
PREINTRO | Main menu | START MENU | 1 | |
CREDITS | End game credits | CREDITS | 1 |
Important! Data (numerical values, checksums etc) is saved as little endian (LE).
So for example an int32 value of 9 will be saved as 09 00 00 00
inside the file.
Note: files that are standard for all PS2 saves (icon.sys, *.ico) won't be discussed
All KDL .dat save files start with a header containing at least two checksums.
Even though the header has a size field inside it, due to the fact that the number of data sections it can contain info for is hardcoded to two in the game code, it's believed to have a fixed size in practice
Save file header | |||
---|---|---|---|
In theory variable size In practice always 1C bytes |
|||
Offset | Size (bytes) | Type | Content |
+00 |
04 |
String | "NEDE" ("EDEN" in reverse(?)) |
+04 |
04 |
Unsigned int32 | Header checksum (Starting from 08 , as to exclude NEDE and the checksum itself, to the address stored in the header size) |
+08 |
04 |
Unsigned? int32 | Header size (in practice always 1C ) |
+0C |
04 |
Unsigned int32 | First data block checksum |
+10 |
04 |
Unsigned? int32 | First data block size |
+14 |
04 |
Unsigned int32 | Second data block checksum All zeroes if there's no second data block |
+18 |
04 |
Unsigned? int32 | Second data block size |
Reverse engineered checksum code can be found here
Offset starts from after header (so at 1C
).
Settings (settings.dat) | |||
---|---|---|---|
Offset | Size (bytes) | Type | Info |
+00 |
04 |
String | "STGS" |
+04 |
04 |
Unknown | Unknown Set to 03 by game |
+08 |
04 |
Signed? int32 | Language setting (PAL version)00 - 04 In order: English, French, German, Spanish, Italian NTSC version completely ignores this setting |
+0C |
04 |
Signed? int32 | Audio (00 = mono, 01 = stereo, 02 = surround) |
+10 |
04 |
Signed? int32 | Music volume (00 - 0C ) |
+14 |
04 |
Signed? int32 | SFX volume (00 - 0C ) |
+1C |
04 |
Signed int32 | X axis screen adjust |
+20 |
04 |
Signed int32 | Y axis screen adjust Stored in negative - in-game negative values stored as positive value and vice versa |
+24 |
01 |
Boolean | Enable vibration |
+25 |
01 |
Boolean | Enable subtitles |
+26 |
01 |
Boolean? | Unknown |
+27 |
01 |
Boolean | Aspect ratio00 = 4:3, 01 = 16:9 |
+28 |
D8 |
Unknown Won't affect game if filled with garbage, won't even get reset to a default value |
|
+110 |
1C |
Unknown Outside the data block size set in the header, thus doesn't affect checksum Won't affect game if filled with garbage or even completely removed |