Jump to content

Creating Mods/Cheat Codes

From SA Docs
(Redirected from 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.

  • write16 means 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++).
  • 03B0F0E4 is the hexadecimal address of the Rings variable
  • 999 is 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.

  • writefloat means that the edited value is a (single precision) floating point value.
  • 03B0F0FC is the hexadecimal address of the up gravity direction.
  • 1.0 is 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.

  • ifltu32 means "if value is inferior to3 (9999 here)
  • 03B0F14C is the level score.
ifmask32 03B0E9D0 0x10
	mulfloat 03B0F0FC 1.05
endif

This increases the gravity when you press d-pad up.

  • ifmask32 means we are checking if the value at address has specific bits
  • 03B0E9D0 is the hexadecimal address of the pressed buttons variable, each bit corresponds to a button.
  • 0x10 is 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:

  • Check the RAM editing pages on sonicretro (SADX/SA2PC)
  • Start disassembling the game with IDA Pro or Ghidra
  • Ask us for help on Discord