Creating Mods/Cheat Codes
The Sonic Adventure DX and Sonic Adventure 2: Battle Mod Loaders allow you to edit the game's code and memory without resorting to a DLL mod. The syntax is similar to cheat code for consoles, such as Action Replay code. This is useful for simple modifications where a DLL would be overkill.
Creating a cheat code
Using the SA Mod Manager
First edit your mod by right clicking it and clicking on Edit mod, or by selecting it and pressing Ctrl + E.

Then go in the "Codes" tab and click on "New code".

You are now in the cheat code editor :

Fields are:
- Name*: short name for the cheat code.
- Author: author(s) of the cheat code.
- Type*: "Code" will make your cheat code run every frame, "Patch" will make it run once at start up.
- Is Required: if checked, the cheat code will be forced on and won't appear in the Mod Manager "Codes" tab.
- Description: description of the cheat code.
To write the code, see Writing a cheat code.
When finished, save the cheat code, enable the mod and click "Save" to compile the cheat codes.
Using notepad or another editor
In your mod folder, create an empty text file, preferably called "Codes.lst".
Then open your mod.ini to add the following line:
Codes=Codes.lst
Save your mod.ini, then open Codes.lst with the editor of your choice.
Here is the structure of a cheat code:
[Type] [Name] (Required) [Code] Author [Author] Category [Category] Description [Description]
Fields are:
- Type*: "Code" will make your cheat code run every frame, "Patch" will make it run once at start up.
- Name*: short name for the cheat code.
- Required: the cheat code will be forced on and won't appear in the Mod Manager "Codes" tab.
- Code: the actual code, see Writing a cheat code.
- Author, Category and Description are optional.
Once finished, save the Codes.lst file, open the Mod Manager, enable the mod if not already and click "Save" to compile the cheat codes.
Writing a cheat code
See the full documentation.
Memory operations
Each line follows the following format:
[opcode] [address] [value] (repeat count)
The memory operations you can use are:
| Operation | Opcodes | Description | C equivalent |
|---|---|---|---|
| Write | write8
write16 write32 writefloat |
Write value at address | *address = value; |
| Add | add8
add16 add32 addfloat |
Add value at address | *address += value; |
| Subtract | sub8
sub16 sub32 subfloat |
Subtract value at address | *address -= value; |
| Multiply | mulu8
mulu16 mulu32 muls8 muls16 muls32 mulfloat |
Multiply value at address | *address *= value; |
| Divide | divu8
divu16 divu32 divs8 divs16 divs32 divfloat |
Divide value at address | *address /= value; |
Bitwise operations
These are more advanced operations as they operate on the bit level.
[opcode] [address] [value] (repeat count)
| Operation | Opcodes | Description | C equivalent |
|---|---|---|---|
| Shift left | shl8
shl16 shl32 |
Shift bits at address to the left | *address <<= value; |
| Shift right | shrs8
shrs16 shrs32 shru8 shru16 shru32 |
Shift bits at address to the right | *address >>= value; |
| AND | and8
and16 and32 |
AND bits at address
Often used to remove flags |
*address &= value; |
| OR | or8
or16 or32 |
OR bits at address
Often used to add flags |
*address |= value; |
| XOR | xor8
xor16 xor32 |
XOR bits at address | *address ^= value; |
| Rotate left | rol8
rol16 rol32 |
Rotate bits left | |
| Rotate right | ror8
ror16 ror32 |
Rotate bits right |
Special operations
[opcode] [address] [value]
| Operation | Opcodes | Description | C equivalent |
|---|---|---|---|
| Write NOP | writenop | Write NOP opcode at address N times
Often used to remove a call (writenop address 5) |
WriteData<value>((void*)address, 0x90); |
| Write JUMP | writejump | Write a JUMP opcode at address followed by rel jump address
Often used to redirect a function to another |
WriteJump((void*)address, (void*)value); |
| Write CALL | writecall | Write a CALL opcode at address followed by rel call address
Often used to replace a call to a function with another |
WriteCall((void*)address, (void*)value); |
Conditions
The cheat code system supports conditions and branching.
[condition opcode] [address] [compared value] (repeat count) ... else ... endif
Here are the conditions available:
| Operation | Opcodes | Description | C equivalent |
|---|---|---|---|
| If equal | ifeq8
ifeq16 ifeq32 ifeqfloat |
Check if value at address is equal | if (*address == value) |
| If not equal | ifne8
ifne16 ifne32 ifnefloat |
Check if value at address is different | if (*address != value) |
| If lower | ifltu8
ifltu16 ifltu32 iflts8 iflts16 iflts32 ifltfloat |
Check if value at address is lower | if (*address < value) |
| If lower or equal | ifltequ8
ifltequ16 ifltequ32 iflteqs8 iflteqs16 iflteqs32 iflteqfloat |
Check if value at address is lower or equal | if (*address <= value) |
| If greater | ifgtu8
ifgtu16 ifgtu32 ifgts8 ifgts16 ifgts32 ifgtfloat |
Check if value at address is greater | if (*address > value) |
| If greater or equal | ifgtequ8
ifgtequ16 ifgtequ32 ifgteqs8 ifgteqs16 ifgteqs32 ifgteqfloat |
Check if value at address is greater or equal | if (*address >= value) |
| If mask | ifmask8
ifmask16 ifmask32 |
Check if value at address has specific bits
Often used to check flags |
if ((*address & value) == value) |
| If key pressed | ifkbkey [keycode] | Check if keyboard key is pressed
See Windows virtual key codes. |
if (GetAsyncKeyState(value)) |
Registers
The cheat code system has 16 registers available, you can use them as variables.
Most opcodes have a register equivalent, simply add "reg" before the type (writereg8, divregu8, ifmaskreg8...)
[opcode] [address] [value] (repeat count)
| Operation | Opcodes | Description | C equivalent |
|---|---|---|---|
| Read | readreg8
readreg16 readreg32 |
Read value at address into register | reg[value] = *address; |
Values format
Values can be in decimal, hexadecimal, or float format.
| Type | Example |
|---|---|
| Decimal | 10 |
| Hexadecimal | 0xA |
| Float | 10.0 |
Repeat count should be preceded with x.
Addresses can be in hexadecimal or pointer chain format.
| Type | Example |
|---|---|
| Hexadecimal | 03B0F0FC |
| Pointer chain | p03B42E30|20|C0|6 |
Examples
These examples use Sonic Adventure DX (2004) addresses.
Write to memory
write16 03B0F0E4 999
This forces the ring count to 999 every frame.
write16means that it will write to 2 bytes. This is because the Rings variable in SADX is a 2 bytes (a "short" or "Sint16" in c++).03B0F0E4is the hexadecimal address of the Rings variable999is the 2-byte values that is going to be written at the provided address.
writefloat 03B0F0FC 1.0
This forces the gravity to be upside down.
writefloatmeans that the edited value is a (single precision) floating point value.03B0F0FCis the hexadecimal address of the up gravity direction.1.0is a float value that we will be writing, 1.0 for up gravity means upward.
Conditions
ifltu32 03B0F14C 9999 add32 03B0F14C 1 endif
This increased the score counter every frame until it reaches 9999.
ifltu32means "if value is inferior to3 (9999 here)03B0F14Cis the level score.
ifmask32 03B0E9D0 0x10 mulfloat 03B0F0FC 1.05 endif
This increases the gravity when you press d-pad up.
ifmask32means we are checking if the value at address has specific bits03B0E9D0is the hexadecimal address of the pressed buttons variable, each bit corresponds to a button.0x10is the bit mask for d-pad up.
More examples
Check the SADX Mod Loader cheat codes and SA2 Mod Loader cheat codes for more examples.
Resources
To get addresses: