User:TimoVM/RAM Writer setups: Difference between revisions
Line 890: | Line 890: | ||
Alongside these actions, the mail writer will now request user input: |
Alongside these actions, the mail writer will now request user input: |
||
* '''Press |
* '''Press SELECT''' together to open a new mail and continue writing data. |
||
⚫ | |||
* '''Press |
* '''Press any other button''' to go back one byte at a time to correct errors. '''If the printed checksum doesn't match the expected checksum, press DOWN 16 times to retry the last mail.''' This will also overwrite the printed checksum with the value at the currently selected address, giving you a method to check how far back you're going. |
||
⚫ | |||
{| class="wikitable" |
{| class="wikitable" |
Revision as of 14:58, 24 June 2023
This page serves as a repository for various RAM writer setups, written and developed by TimoVM, intended for gen 1 or gen 2. the RAM writers used are inspired by various pre-existing RAM writers, especially ZZAZZGlitch's memory writer.
Introduction: What is a RAM writer?
In simple terms, a RAM writer is a program that allows you to visualize and edit values that are stored in memory. In effect, this allows you to easily manipulate stuff like adding/modifying items, changing pokémon data such as making them shiny, triggering instant encounters etc.. This is usually combined with a graphical user interface (GUI) for better readability.
In a sense, you can regard RAM writers as a general tool to greatly expand what you can do with arbitrary code execution, due to granting the ability to easily modify any memory value in RAM at any time.
An unfortunate drawback of this approach is that RAM writers are quite large, memory-wise. For this reason, this guide was developed to document methods to install these RAM writers in a reasonably efficient way. Due to their size, you will always be required to start with building a smaller, more limited RAM writer. These will then be used to build the larger RAM writer.
The setups included in this guide work both for console and VC version, at the moment of writing, these setups are unfortunately only applicable for EN versions.
Red/Blue/Yellow
General installation overview:
- Assemble 8 items to form a text converter item code.
- Catch 14 pokémon (any species is fine), give 12 of them specific nicknames and store them in the currently loaded box. Use your ACE item.
- Use the nickname writer to write the large RAM writer in memory.
- The RAM Writer will automatically take care of the final setup upon first execution
Due to differences in memory layout, the nicknames and items used in Yellow will differ slightly from those in Red/Blue.
Requirements
In order to install the RAM writer, you need to have an ACE setup that redirects execution to the 3rd item slot ($D322) using a jp hl instruction. The ACE item has to be either 4F or 8F. -gm is not compatible with this guide.
Alongside this ACE setup, you will also need to set up inventory underflow to access item slots beyond the usual 20 slots available.
Install details
- The RAM writer itself will be installed in sram bank 3, at address BA53 onward.
- The setup will automatically add the glitch item 4F to your party, along with the necessary bootstrap to use the RAM writer with 4F.
- Upon using 4F, the RAM writer will be copied over to a specific temporary location in RAM, then executed.
- For Red/Blue, the RAM writer will be buffered from C620 onward.
- For Yellow, the RAM writer will be buffered from C978 onward.
Step 1: Assembling an 8-item code
Head to Celadon city and head to the following spot. Make sure to bring a pokémon with Fly/Teleport.
While standing on this spot, open your item bag and keep scrolling down until you find a Nugget x0 item stack, located at item slot #35. Around item slots #22 through #27 you'll likely encounter glitch items with garbled text. You can scroll past these items by pressing B occasionally while tapping DOWN. Do not select any of these items with the A button, otherwise your game will likely crash.
By walking left or right, you can increment or decrement the item ID in slot #35. By walking up and down we can alternate between an item quantity of x0 and x1. We can safely swap the contents of item slot #35 with other item slots, as long as we use Fly/Teleport afterwards to restore the map back to normal. We can use this to collect all the items we need for the item code.
For every item in the following table, head to the Nugget x0 spot, follow the instructions to obtain an item stack, then Fly back to Celadon and head back to the same spot to obtain the next item stack.
Item ID | Item quantity | How to acquire |
---|---|---|
Thunderstone | x06/x05 | From the Nugget spot, walk 16 steps to the left to get Thunderstone x0. Toss 250 from the stack if you're on Red/Blue or toss 251 if you're on Yellow, then swap with an item from your bag. |
TM22 | x229 | At the Nugget spot, swap the Nugget with the TM23 x64 stack 4 slots below, then toss 63 TM23s. Walk one step left and one step down to get TM22 x0. Toss 27 from the stack, then swap with an item from your bag. |
Helix Fossil | (x135) | At the Nugget spot, toss 121 from the stack to get Nugget x135. Walk 7 steps to the left, then swap with an item from your bag. |
B2F | x48 | At the Nugget spot, swap the Nugget with the TM23 x64 stack 4 slots below, then toss 63 TM23s. Walk leftward (you can use the bicycle two slots above to speed this up) until you've looped through the map twice back to the Nugget spots, then walk 15 steps further to the left to get B2F x0. Toss 208 from the stack, then swap with an item from your bag. |
Poké Ball | x134 | From the Nugget spot, walk 35 steps to the left, 4 steps down and 10 steps left to get Poké Ball x0. Toss 122 from the stack, then swap with an item from your bag. |
Hyper Potion | x28 | From the Nugget spot, walk 30 steps to the left to get Hyper Potion x0. Toss 228 from the stack, then swap with an item from your bag. |
HP UP | x32 | From the Nugget spot, walk 14 steps to the left to get HP UP x0. Toss 224 from the stack, then swap with an item from your bag. |
TM45 | x201 | At the Nugget spot, swap the Nugget with the TM23 x64 stack 4 slots below, then toss 63 TM23s. Every step to the right will increment the TM number by 1. Keep walking rightward until you get TM45 x0. Toss 55 from the stack, then swap with an item from your bag. |
Master Ball | x00 | (Optional for catching later) From the Nugget spot, walk 35 steps to the left, 8 steps down and 13 steps left to get Master Ball x0. Swap with an item from your bag, |
Assemble the items you acquired according to the following list:
Item slot | Item ID | Item Quantity |
---|---|---|
Slot #1 | ACE item (8F or 4F) | any |
Slot #2 | Master Ball | x0 |
Slot #3 | Thunderstone | x06/051 |
Slot #4 | TM22 | x229 |
Slot #5 | Helix Fossil | (x135)2 |
Slot #6 | B2F | x48 |
Slot #7 | Poké Ball | x134 |
Slot #8 | Hyper Potion | x28 |
Slot #9 | HP UP | x32 |
Slot #10 | TM45 | x201 |
1 x06 on Red/Blue, x05 on Yellow 2 The item quantity for Helix Fossil is invisible for the player.
This item code looks at the nicknames of the pokémon in the currently stored box, then uses pairs of text characters to write a new program. After it finishes, it immediately jumps to execute the newly written program.
Step 2: Catching and nicknaming 14 pokémon to build a nickname writer
The item code we have assembled converts nicknames into code, which means we'll have to catch pokémon with the right nicknames to do something useful. The pokémon we'll be catching will be stored in a storage box. Make sure the box you pick fulfils the following requirements:
- The box needs to be set as the active box.
- If on VC, it is recommended to not pick box 1 since that's the box Poké Transporter connects to.
Once that is done, we will fill the box with nicknamed pokémon. We'll be making a list with nicknames using Scottey's nickname converter tool. Simply copy paste the entire code below into the converter, then press the "Run" button to display the list of nicknames. Ignore the checksums for now.
If you'll be manually depositing pokémon, follow the list from top to bottom. If you're catching pokémon and sending them to the PC through a full party, follow the list from bottom to top.
Red/Blue | Yellow |
---|---|
Nickname writer (14 codes) | Nickname writer (14 codes) |
00 00 00 00 00 11 9C D8 D5 D5 06 01 21 5C 65 CD D6 35 0E 80 21 4B CF D1 2A 87 30 09 86 12 13 23 81 12 4F 18 F3 21 29 C4 0E 01 D5 CD DF 15 CD 31 38 D1 F0 B5 A7 28 EE 0F 38 CF 1B 0F 38 E7 0F D0 1B 1B 1B 1B 18 C3 |
00 00 00 00 00 11 9B D8 D5 D5 06 01 21 CD 62 CD 84 3E 0E 80 21 4A CF D1 2A 87 30 09 86 12 13 23 81 12 4F 18 F3 21 29 C4 0E 01 D5 CD BF 13 CD 1E 38 D1 F0 B5 A7 28 EE 0F 38 CF 1B 0F 38 E7 0F D0 1B 1B 1B 1B 18 C3 |
After you've double checked everything, make sure to save. Once you activate the mail writer, you'll need to write up to 40 nicknames to form the full RAM writer. You will not be able to save during this time.
Step 3: Using the nickname writer
Once you activate your ACE item, you should be able to open the nickname writer. Make sure to only use the nickname writer inside a pokémon center to ensure that the checksums are correctly displayed.
The program works as follows:
- The program opens the nickname screen and asks you to input a nickname.
- This nickname then gets converted to a sequence of five bytes.
- All five bytes are written starting from the starting location
- The program displays a checksum (sum of all written byte values) to confirm that you correctly entered the code. If the printed checksum doesn't match the expected checksum, you made a mistake entering a code.
- Afterwards, it waits for the user to decide what to do.
During the input phase, the controls are as follows:
- Press A for the program to ask for a new nickname and convert that to the next five bytes to be written.
- Press SELECT to go back five bytes and ask for a new nickname to correct errors. Use this if the printed checksum does not match the predicted checksum and the last written nickname contained ten characters.
- Press B to go back one byte at a time. The checksum will automatically be overwritten by the value written at the current selected address, giving you a measure of how far back you're going. This function is only needed if you accidentally confirmed a nickname without writing all 10 characters.
- Press any other button (except A) to immediately start executing the newly written program. Only do this when you've finished writing everything.
Write mode | Input mode |
---|---|
Press select to switch between uppercase/lowercase | Checksum is displayed right next to ITEM |
We will be installing the full RAM writer using a series of nickname codes. These nickname codes will be assembled using Scotteh's mail code tool. Simply copy paste the entire code below into the converter, then press the "Run" button to display the list of nicknames. Ensure you are entering the mail codes that are appropriate for the location you're installing the program to. The generated nicknames need to be entered from top to bottom.
Installation for Red/Blue (50 codes) | Installation for Yellow (50 codes) |
---|---|
3E 03 CD 7A D9 21 1E D3 36 59 01 C8 00 11 53 BA 21 BB D8 CD B5 00 11 65 DA D5 0E 13 C3 B5 00 AF 3C E0 B6 E0 B7 21 00 DA CD 74 C6 E5 11 F8 FF 19 54 5D 01 0C 00 CD DD C6 21 A9 C3 CD 65 C6 3E 7C 22 7A CD 65 C6 7B CD 65 C6 3E E3 22 1A CD 65 C6 36 7C 09 13 7D FE 13 20 E5 26 00 74 21 50 C4 36 ED E1 18 C4 F5 CB 37 CD 6C C6 F1 E6 0F C6 F6 F6 80 22 C9 CD BE C6 CB 5F 20 39 CB 57 28 0A 0F 30 01 E9 F0 FE 83 E0 FE C9 0F 30 2A E5 CD DD C6 4E CD BE C6 0F 38 12 0F 30 01 4B 79 83 4F 21 50 C4 36 EC 23 CD 65 C6 18 E8 E1 71 E5 06 1C 21 CE 77 CD D6 35 E1 C9 0F 30 03 53 1E 00 19 C9 CD 31 38 F0 B5 76 11 00 00 F5 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 F1 C9 F0 FE E5 26 0A 74 26 40 77 E1 C9 21 43 0A 74 65 36 03 0E C8 11 20 C6 D5 21 53 BA C3 B5 00 |
21 43 0A 74 65 75 21 1D D3 36 59 01 C8 00 11 53 BA 21 BB D8 CD B1 00 11 64 DA D5 0E 12 C3 B1 00 AF 3C E0 B6 E0 B7 21 00 DA CD CC C9 E5 11 F8 FF 19 54 5D 01 0C 00 CD 35 CA 21 A9 C3 CD BD C9 3E 7C 22 7A CD BD C9 7B CD BD C9 3E E3 22 1A CD BD C9 36 7C 09 13 7D FE 13 20 E5 26 00 74 21 50 C4 36 ED E1 18 C4 F5 CB 37 CD C4 C9 F1 E6 0F C6 F6 F6 80 22 C9 CD 16 CA CB 5F 20 39 CB 57 28 0A 0F 30 01 E9 F0 FE 83 E0 FE C9 0F 30 2A E5 CD 35 CA 4E CD 16 CA 0F 38 12 0F 30 01 4B 79 83 4F 21 50 C4 36 EC 23 CD BD C9 18 E8 E1 71 E5 06 1C 21 46 7B CD 84 3E E1 C9 0F 30 03 53 1E 00 19 C9 CD 1E 38 F0 B5 76 11 00 00 F5 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 F1 C9 E5 F0 FE 26 0A 74 26 40 77 E1 C9 21 43 0A 74 65 75 0E C8 11 78 C9 D5 21 53 BA C3 B1 00 |
Once all codes have been entered and verified, you can press any button (with the exception of A, B and DOWN) during input mode to start up the full RAM writer.
Step 4: Using the full RAM writer
Assuming the program was entered correctly, the game should open up one of the screens as seen in the below screenshots. The RAM writer will draw various values on the screen. The leftmost 4 columns describe the addresses that are currently in view. The rightmost two columns describe the values at each of these addresses. All values on screen are represented in hexadecimal format.
For example: DA01>05 means that the address $DA01 is currently holding the value of $05.
Make sure to save the game after you've confirmed that the RAM writer is fully functional.
The RAM writer can also be used during battle. Opening and closing the RAM writer in battle will pass your turn to the enemy and cause the battle to continue as usual.
Due to the location the RAM writer is buffered, upon closing the RAM writer in battle in Red/Blue, you will see a slight graphical corruption at the bottom of the screen that will immediately be overwritten by the battle text box. This corruption is purely cosmetic and temporary, meaning that it will not cause any harm to your game.
Full Writer Controls
The RAM writer uses two modes of operation. In Read mode you are able to navigate memory and view the values at specific addresses. in Write mode you'll lock in a single address and manipulate the value at that address. By default, the RAM writer will open in Read mode.
RAM writer in Read mode | RAM writer in Write mode. |
Read mode controls
up: address -1 down: address +1 left: address -10 right: address +10 B + up: address -1 B + down: address +1 B + left: address -10 B + right: address +10 start: exit program A: toggle write mode select + up: sram bank -1 select + down: sram bank +1 select + left: sram bank -10 select + right: sram bank +10 select + A: start executing code from current address onwards (use with caution!)
Write mode controls
up: value -1 down: value +1 left: value -10 right: value +10 B: set current value to 0 A: exit write mode and load final value into the address
Asm translation of included programs/codes
Note: these are not yet up to date
7-item code nickname converter
Hex values | Opcodes | Labels/notes |
---|---|---|
26 DE | ld h, $DE | |
2A | ldi a, (hl) | .loop |
87 | add a | |
44 | ld b, h | |
30 04 | jr nc, .notChar | |
86 | add (hl) | |
02 | ld (bc), a | |
2C | inc l | |
03 | inc bc | |
20 F5 | jr nz, .loop | .notChar |
E9 | jp hl |
Transcript |
---|
26 DE 2A 87 44 30 04 86 02 2C 03 20 F5 E9 |
Nickname writer
Hex values | Opcodes | Labels/notes |
---|---|---|
11 96 DA / 11 53 BA | ld de, $DA96 / ld de, $BA53 | ;defines the address to write to |
D5 | push de | |
D5 | push de | .loop |
AF | xor a | |
47 | ld b, a | |
21 5C 65 | ld hl, DisplayNameRaterScreen | |
CD D6 35 | Call BankSwitch | |
21 4B 0A | ld hl, 0A4B | |
74 | ld (hl), h | |
65 | ld h, l | |
77 | ld (hl), a | |
26 CF | ld h, CF | ; hl now holds the address of wStringBuffer |
D1 | pop de | |
2A | ldi a, (hl) | .not@ |
87 | add a | |
30 09 | jr nc, .@ | |
86 | add (hl) | |
12 | ld (de), a | |
13 | inc de | |
23 | inc hl | |
81 | add c | |
12 | ld (de), a | |
4F | ld c, a | |
18 F3 | jr, .not@ | |
21 00 C4 | ld hl, $C400 | .@ |
0E 01 | ld c, $01 | |
D5 | push de | |
CD DF 15 | Call PrintBCDNumber.loop | |
CD 31 38 | Call JoypadLowSensitivity | |
D1 | pop de | |
F0 B5 | ld a, hJoy5 | |
BD | cp l | |
28 CF | jr z, .loop | |
38 EC | jr c, .@ | |
07 | rlca | |
D0 | ret nc | |
1B | dec de | |
18 E7 | jr, .@ |
Transcript |
---|
11 96 DA D5 D5 AF 47 21 5C 65 CD D6 35 21 4B 0A 74 65 77 26 CF D1 2A 87 30 09 86 12 13 23 81 12 4F 18 F3 21 00 C4 0E 01 D5 CD DF 15 CD 31 38 D1 F0 B5 BD 28 CF 38 EC 07 D0 1B 18 E7 |
Full RAM writer (DA96)
setup AF 3C E0 B6 E0 B7 21 00 DA ld hl, DA00 resolveDisplay CD EA DA call resolveInput E5 push hl 11 F8 FF ld de, FFF8 19 add hl, de 54 ld d, h 5D ld e, l 01 0C 00 ld bc, 000C CD 53 DB call openSramBank 21 A9 C3 ld hl, C3A9 CD DB DA call printHex .displayLoop 3E 7C ld a, 7C 22 ldi (hl), a 7A ld a, d CD DB DA call printHex 7B ld a, e CD DB DA call printHex 3E E3 ld a, E3 22 ldi (hl), a 1A ld a, (de) CD DB DA call printHex 36 7C ld a, 7C 09 add hl, bc 13 inc de 7D ld a, l FE 13 cp 13 20 E5 jr nz, .displayLoop 26 00 ld h, 00 74 ld (hl), h 21 50 C4 ld hl, C450 36 ED ld (hl), ED E1 pop hl 18 C4 jr, resolveDisplay printHex F5 push af CB 37 swap a CD E2 DA call .firstHex F1 pop af .firstHex DAE2 E6 0F and 0F C6 F6 add a, F6 F6 60 or a, 60 22 ldi (hl), a C9 ret ResolveInput DAEA CD 34 DB call sampleDpad CB 5F bit 3, a 20 39 jr nz, .noStartButton .noStartButton CB 57 bit 2, a 28 0A jr z, noSelectButton 0F rrca 30 01 jr nc, .changeSramBank E9 jp hl .changeSramBank F0 FE ldh a, (FE) 83 add e E0 FE ldh (FE), a C9 ret .noSelectButton 0F rrca 30 2A jr nc, .noAButton CD 53 DB call openSramBank 4E ld c, (hl) E5 push hl .inputALoop CD 34 DB call sampleDpad 0F rrca 38 12 jr c, .AButtonPressed 0F rrca 30 01 jr nc , .BButtonNotPressed 4B ld c, e .BButtonNotPressed 79 ld a, c 83 add e 4F ld c, a 21 50 C4 ld hl, C450 36 EC ld (hl), EC 23 inc hl CD DB DA call printHex 18 E8 jr, .inputALoop .AButtonPressed E1 pop hl 71 ld (hl), c E5 push hl 3E 1C ld a, 1C 21 CE 77 ld hl, 77CE CD D6 35 Call Bankswitch E1 pop hl C9 ret .noAButton 0F rrca 30 03 jr nc, noBButton 53 ld d, e 1E 00 ld e, 00 19 add hl, de C9 ret sampleDpad CD 31 38 call JoypadLowSensitivity F0 B5 ldh a, (B5) 76 halt 11 00 00 ld de, 0000 F5 push af 07 rlca 30 01 jp nc, .noDown 13 inc de .noDown 07 rlca 30 01 jr nc, .noUp 1B dec de .noUp 07 rlca 30 03 jr nc, .noLeft 11 F0 FF ld de, FFF0 .noLeft 07 rlca 30 02 jr nc, .noRight 1E 10 ld e, 10 .noRight F1 pop af c9 ret opensrambank E5 push hl F0 FE ldh a, (FE) 26 0A ld h, 0A 74 ld (hl), h 26 40 ld h, 40 77 ld (hl), a E1 pop hl c9 ret
Transcript |
---|
3E 01 E0 B6 E0 B7 21 00 DA CD EA DA E5 11 F8 FF 19 54 5D 01 0C 00 CD 53 DB 21 A9 C3 CD DB DA 3E 7C 22 7A CD DB DA 7B CD DB DA 3E E3 22 1A CD DB DA 36 7C 09 13 7D FE 13 20 E5 26 00 74 21 50 C4 36 ED E1 18 C4 F5 CB 37 CD E2 DA F1 E6 0F C6 F6 F6 60 22 C9 CD 34 DB CB 5F 20 39 CB 57 28 0A 0F 30 01 E9 F0 FE 83 E0 FE C9 0F 30 2A E5 CD 53 DB 4E CD 34 DB 0F 38 12 0F 30 01 4B 79 83 4F 21 50 C4 36 EC 23 CD DB DA 18 E8 E1 71 E5 06 1C 21 CE 77 CD D6 35 E1 C9 0F 30 03 53 1E 00 19 C9 CD 31 38 F0 B5 76 11 00 00 F5 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 F1 C9 E5 F0 FE 26 0A 74 26 40 77 E1 C9 |
Full RAM writer (BA53)
setup 3E 01 ld a, 01 E0 B6 ldh (B6), a E0 B7 ldh (B7), a 21 00 DA ld hl, DA00 resolveDisplay CD 9E BA call resolveInput E5 push hl 11 F8 FF ld de, FFF8 19 add hl, de 54 ld d, h 5D ld e, l 01 0C 00 ld bc, 000C 21 AB C3 ld hl, C3AB .displayLoop 3E 7C ld a, 7C 22 ldi (hl), a 7A ld a, d CD 8F BA call printHex 7B ld a, e CD 8F BA call printHex 3E E3 ld a, E3 22 ldi (hl), a 1A ld a, (de) CD 8F BA call printHex 36 7C ld a, 7C 09 add hl, bc 13 inc de 7D ld a, l FE 13 cp 13 20 E5 jr nz, .displayLoop 21 50 C4 ld hl, C450 36 ED ld (hl), ED E1 pop hl 18 CD jr, resolveDisplay printHex F5 push af CB 37 swap a CD 94 ba call .firstHex F1 pop af .firstHex BA96 E6 0F and 0F C6 F6 add a, F6 F6 60 or a, 60 22 ldi (hl), a C9 ret ResolveInput CD D4 BA call sampleDpad CB 5F bit 3, a 28 02 jr z, .noStartButton C1 pop bc C9 ret .noStartButton CB 57 bit 2, a 28 01 jr z, noSelectButton E9 jp hl .noSelectButton 0F rrca 30 1D jr nc, .noAButton 4E ld c, (hl) E5 push hl .inputALoop CD D4 BA call sampleDpad 0F rrca 38 12 jr c, .AButtonPressed 0F rrca 30 01 jr nc , .BButtonNotPressed 4B ld c, e .BButtonNotPressed 79 ld a, c 83 add e 4F ld c, a 21 50 C4 ld hl, C450 36 EC ld (hl), EC 23 inc hl CD 8F BA call printHex 18 E8 jr, .inputALoop .AButtonPressed E1 pop hl 71 ld (hl), c C9 ret .noAButton 0F rrca 30 03 jr nc, noBButton 53 ld d, e 1E 00 ld e, 00 19 add hl, de C9 ret sampleDpad CD 31 38 call JoypadLowSensitivity F0 B5 ldh a, (B5) 76 halt 11 00 00 ld de, 0000 F5 push af 07 rlca 30 01 jp nc, .noDown 13 inc de .noDown 07 rlca 30 01 jr nc, .noUp 1B dec de .noUp 07 rlca 30 03 jr nc, .noLeft 11 F0 FF ld de, FFF0 .noLeft 07 rlca 30 02 jr nc, .noRight 1E 10 ld e, 10 .noRight F1 pop af c9 ret
Transcript |
---|
3E 01 E0 B6 E0 B7 21 00 DA CD 9E BA E5 11 F8 FF 19 54 5D 01 0C 00 21 AB C3 3E 7C 22 7A CD 8F BA 7B CD 8F BA 3E E3 22 1A CD 8F BA 36 7C 09 13 7D FE 13 20 E5 21 50 C4 36 ED E1 18 CD F5 CB 37 CD 96 BA F1 E6 0F C6 F6 F6 60 22 C9 CD D4 BA CB 5F 28 02 C1 C9 CB 57 28 01 E9 0F 30 1D 4E E5 CD D4 BA 0F 38 12 0F 30 01 4B 79 83 4F 21 50 C4 36 EC 23 CD 8F BA 18 E8 E1 71 C9 0F 30 03 53 1E 00 19 C9 CD 31 38 F0 B5 76 11 00 00 F5 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 F1 C9 |
Gold/Silver/Crystal
General installation overview:
- Use a box name code to set every TM quantity to 255.
- Write out a mail writer program by changing TM quantities. Use a box name code to use the mail writer.
- Enter a series of mail codes in order to write the full RAM writer.
- Use the full RAM writer to automatically it to the data of box 14.
Requirements
In order to install the RAM writer, you need to have an ACE setup that redirects execution to the 1st or 2nd character of box name 1. Available options are:
For Gold & Silver:
- Coin Case ACE which uses a pokémon's EVs to redirect to the last read mail, which fixes the stack and then redirects to the start of box names.
- Wrong Pocket TM17 ACE using a Quagsire holding TM01 and with Return as first move.
For Crystal:
- TMless 0x1500 ACE setup which uses a bad clone and a pokémon with specific EVs to redirect to the last read mail, which redirects to the start of box names.
- (TODO: add Zodiac's page and/or LuckyTyphlosion's setup)
Next, make sure to take care of the following:
- Make sure to empty box 14 of any pokémon you wish to keep. We'll be installing the full RAM writer in the data for box 14, meaning everything inside it will have its data overwritten.
- For Crystal, put any item that you can afford to lose in the first slot of your item pack. This item will be changed to a TM15 during the setup.
Step 1: Setting all TM quantities to 255
Enter the following box names, then execute ACE.
Gold & Silver | Crystal |
---|---|
Box 1: A p 'v C é 2 2 5 Box 2: 'v j 'v u é 1 2 5 Box 3: 'v ♂ é 5 2 p 'v 9 Box 4: é 4 2 p é 6 2 5 Box 5: 'v u é 8 2 'v {space} 5 Box 6: é 7 2 'v : é 9 2 Box 7: 0 9 ♀ 5 ♀ 5 5 5 Box 8: 5 5 5 5 5 5 x 'd |
Box 1: p 'v 9 é 'd 5 'v * Box 2: é H 5 'v ♂ é G 5 Box 3: A 4 é m 5 'v 9 5 Box 4: é k 5 F é 'l 5 F Box 5: 0 B 's 'v 5 u 'v c Box 6: é n 5 's k 5 'v B Box 7: 'd 5 5 2 p é 'm 5 Box 8: 'v 'd é 't 5 'v ♂ 5 Box 9: é 's 5 é n 5 v 5 Box 10: 'v L é T 2 0 9 5 Box 11: 5 5 5 5 'm 5 5 ♀ Box 12: 'v F 's k 5 F ? E Box 13: 's k 5 * 'm k 5 5 |
This will set the quantities of all 50 TMs to 255. For Crystal, this will also change the first item to a TM15 and install a bootstrap to redirect execution to the TM/HM pocket. Do not use this TM15 yet.
What to do now you have 255 of every TM
At this moment, there are two main options.
- You can use the quantities in the TM/HM pocket to easily write out simple codes. A list of TM codes can be found on this page. (Currently only supported for Gold/Silver)
- You can continue with the guide and build a RAM writer in order to achieve near-complete ACE control.
Step 2: Selling TMs to form a mail writer
Sell TMs such that you get the following quantities:
TM | Gold & Silver | Crystal | ||
---|---|---|---|---|
Final Quantity | Sell value | Final Quantity | Sell value | |
TM01 DYNAMICPUNCH | x17 | 357000 | x17 | 357000 |
TM02 HEADBUTT | x85 | 170000 | x128 | 127000 |
TM03 CURSE | x221 | 51000 | x210 | 67500 |
TM04 ROLLOUT | x213 | 42000 | x213 | 42000 |
TM05 ROAR | x213 | 21000 | x213 | 21000 |
TM06 TOXIC | x213 | 63000 | x213 | 63000 |
TM07 ZAP CANNON | x62 | 193000 | x33 | 222000 |
TM08 ROCK SMASH | x04 | 125500 | x117 | 69000 |
TM09 PSYCH UP | x33 | 111000 | x94 | 80500 |
TM10 HIDDEN POWER | x66 | 283500 | x207 | 72000 |
TM11 SUNNY DAY | x98 | 157000 | x225 | 30000 |
TM12 SWEET SCENT | x207 | 24000 | x209 | 23000 |
TM13 SNORE | x225 | 15000 | x42 | 106500 |
TM14 BLIZZARD | x209 | 69000 | x254 | 1500 |
TM15 HYPER BEAM | x42 | 319500 | x80 | 262500 |
TM16 ICY WIND | x135 | 180000 | x56 | 298500 |
TM17 PROTECT | x48 | 310500 | x251 | 6000 |
TM18 RAIN DANCE | x07 | 248000 | x40 | 215000 |
TM19 GIGA DRAIN | x134 | 181500 | x10 | 367500 |
TM20 ENDURE | x18 | 355500 | x135 | 180000 |
TM21 FRUSTRATION | x19 | 118000 | x134 | 60500 |
TM22 SOLARBEAM | x129 | 189000 | x18 | 355500 |
TM23 IRON TAIL | x79 | 264000 | x19 | 354000 |
TM24 DRAGONBREATH | x18 | 355500 | x35 | 330000 |
TM25 THUNDER | x42 | 213000 | x129 | 126000 |
TM26 EARTHQUAKE | x39 | 324000 | x79 | 264000 |
TM27 RETURN | x32 | 111500 | x18 | 118500 |
TM28 DIG | x242 | 13000 | x24 | 231000 |
TM29 PSYCHIC | x33 | 222000 | x239 | 16000 |
TM30 SHADOW BALL | x1 | 381000 | x33 | 333000 |
TM31 MUD-SLAP | x196 | 88500 | x1 | 381000 |
TM32 DOUBLE TEAM | x77 | 178000 | x197 | 58000 |
TM33 ICE PUNCH | x205 | 75000 | x77 | 267000 |
TM34 SWAGGER | x240 | 7500 | x205 | 25000 |
TM35 SLEEP TALK | x58 | 98500 | x204 | 25500 |
TM36 SLUDGE BOMB | x27 | 114000 | x56 | 99500 |
TM37 SANDSTORM | x205 | 50000 | x27 | 228000 |
TM38 FIRE BLAST | x144 | 111000 | x205 | 50000 |
TM39 SWIFT | x55 | 200000 | x75 | 180000 |
TM40 DEFENSE CURL | x240 | 7500 | x53 | 101000 |
TM41 THUNDERPUNCH | x171 | 126000 | x189 | 99000 |
TM42 DREAM EATER | x189 | 99000 | x40 | 322500 |
TM43 DETECT | x40 | 107500 | x217 | 19000 |
TM44 REST | x216 | 58500 | x56 | 298500 |
TM45 ATTRACT | x56 | 298500 | x240 | 22500 |
TM46 THIEF | x238 | 25500 | x254 | 1500 |
TM47 STEEL WING | x7 | 372000 | x08 | 370500 |
TM48 FIRE PUNCH | x208 | 70500 | x200 | 82500 |
TM49 FURY CUTTER | x24 | 346500 | x24 | 346500 |
TM50 NIGHTMARE | x241 | 14000 | x242 | 13000 |
What to do now you have sold TMs
Once you've finished selling TMs, set up box names according to the following codes. This code will redirect execution from box names to TMs.
For Crystal, you already have a TM15 that will redirect execution to the TM/HM pocket, meaning you can skip setting up this box code.
Box number | Box name |
---|---|
Box 1 | A p 'v C é 'd 2 5 |
Box 2 | 5 5 5 5 5 5 h 'm |
Box 3 | ♀ |
Other | Can be left as they are |
Step 3: Using the mail writer
Once everything has been double checked, you can use your ACE item (In Crystal, use TM15) in order to start up the mail writer. Make sure to save prior to this step. Once you start the mail writer you'll need to finish writing all mail codes before you have an opportunity to save again.
Controls
The mail writer will open a screen that asks you to write the contents of a mail. This is where you'll need to enter mail codes. Once done, use the "END" option to finish the mail.
This will cause the mail writer to convert the newly written code into assembly. It will also print a checksum (sum of all written values) on the screen just to the right of the lower row. This can be used to verify if a code was entered correctly.
Alongside these actions, the mail writer will now request user input:
- Press SELECT together to open a new mail and continue writing data.
- Press START to immediately jump to and start executing the newly written program. Only use this when you've finished every mail.
- Press any other button to go back one byte at a time to correct errors. If the printed checksum doesn't match the expected checksum, press DOWN 16 times to retry the last mail. This will also overwrite the printed checksum with the value at the currently selected address, giving you a method to check how far back you're going.
Enter your mail code, then press "END". | It prints the checksum and waits for input. |
Building the full RAM writer
We will be installing the full RAM writer using a series of mail codes. These mail codes will be assembled using Scotteh's mail code tool. Copy paste the entire code in the text box on the mail code tool's page, then press "Run".
Gold & Silver (18 codes) | Crystal (18 codes) |
---|---|
3E 03 CD E1 30 0E CE 11 E1 B9 21 7A DD CD 1A 31 0E 2D 11 18 D4 D5 CD 1A 31 21 E1 D5 34 7D 4E 09 22 AF 3D 22 C9 AF 3C E0 D6 21 00 DA CD 21 DF E5 11 F8 FF 19 54 5D 01 0C 00 F0 FE 21 A9 C3 CD E1 30 CD 65 CC 3E 7C 22 7A CD 65 CC 7B CD 65 CC 3E E3 22 1A CD 65 CC 36 7C 09 13 7D FE 13 20 E5 CD F1 30 21 50 C4 36 ED E1 18 C2 F5 CB 37 CD 6C CC F1 E6 0F C6 F6 F6 80 22 C9 CD 90 37 11 00 00 F0 AB 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 07 C9 CD 74 CC 38 41 07 30 0B 07 07 30 01 E9 F0 FE 83 E0 FE C9 07 30 03 53 1E 00 19 07 30 2A E5 F0 FE CD E1 30 46 CD 74 CC 07 07 30 01 43 07 38 0E 78 83 47 21 50 C4 36 EC 23 CD 65 CC 18 E7 E1 70 E5 3E 05 21 FD 4D CF E1 C9 FA AB CE FE E1 C0 FA C2 CE FE 90 C0 3E 0D EA E0 CE C9 C3 01 DF 3E 03 CD E1 30 0E 71 11 20 CC D5 21 E1 B9 CD 1A 31 0E 48 11 21 DF CD 1A 31 0E 12 11 0F DF CD 1A 31 0E 03 11 8A FF CD 1A 31 AF E0 89 C9 |
3E 03 CD CB 2F 0E D0 11 E1 B9 21 A6 D2 CD 26 30 0E 2A 11 47 DA D5 CD 26 30 21 BC D8 34 3E D0 4E 09 22 AF 3D 22 C9 AF 3C E0 D4 21 00 DA CD 21 C0 E5 11 F8 FF 19 54 5D 01 0C 00 F0 FE 21 A9 C4 CD CB 2F CD 65 CD 3E 7C 22 7A CD 65 CD 7B CD 65 CD 3E E3 22 1A CD 65 CD 36 7C 09 13 7D FE 13 20 E5 CD E1 2F 21 50 C5 36 ED E1 18 C2 F5 CB 37 CD 6C CD F1 E6 0F C6 F6 F6 80 22 C9 CD 4B 35 11 00 00 F0 A9 07 30 01 13 07 30 01 1B 07 30 03 11 F0 FF 07 30 02 1E 10 07 C9 FA 74 CF FE D0 C0 FA 8B CF FE 90 C0 3E 0D EA A9 CF C9 CD 74 CD 38 41 07 30 0B 07 07 30 01 E9 F0 FE 83 E0 FE C9 07 30 03 53 1E 00 19 07 30 2A E5 F0 FE CD CB 2F 46 CD 74 CD 07 07 30 01 43 07 38 0E 78 83 47 21 50 C5 36 EC 23 CD 65 CD 18 E7 E1 70 E5 3E 05 21 13 4E CF E1 C9 20 8B C3 00 C0 3E 03 CD CB 2F 0E 71 11 20 CD D5 21 E1 B9 CD 26 30 0E 5A 11 0F C0 CD 26 30 0E 05 11 F9 FF CD 26 30 3E 70 E0 88 3E 18 E0 87 C9 |
After you press run, the tool will generate the mail codes that you need to enter in the mail writer.
After entering every code, a new number will appear to the right of the bottom mail row. This is a checksum and is used to verify that you've correctly entered every mail. If a checksum doesn't match the one given by the tool, that means that a code was incorrectly entered, meaning you will need to redo your mail by pressing DOWN enough times (16 times if you’ve entered a full mail code) to return to the starting byte of the last mail, then entering that same mail again.
After you're finished entering all mail codes, you can press any button outside of A, B or DOWN during the user input phase in order to start up the full RAM writer.
Step 4: Activating the RAM writer
After you're finished and have verified that all checksums were valid, press any button outside of A, B or DOWN during the user input phase in order to start up the full RAM writer.
Doing this will activate the following effects:
- Save the RAM writer to the contents of box 14.
- Add TM33 (G/S) or TM17 (C) to the Key Item pocket.
- Install setup to make sure that using TM33/TM17 from the key item pocket will start the RAM writer.
- Automatically start the RAM writer.
Starting the RAM writer, either automatically or through using wrong pocket TM33/TM17, will activate the following effects:
- Copy the necessary data to memory to activate the RAM writer.
- Deploy setup that will enable the use of TM33/TM17 during battle.
- Start the RAM writer.
After exiting the RAM writer, you can restart the RAM writer by using TM33 from the item pack. In battle, you can activate the RAM writer by using TM33/TM17 and selecting "QUIT". Please note that the setup to enable the use of TM33/TM17 during battle does not persist between resets, you can reenable this function by using the RAM writer outside of battle at least once.
As you can see in the screenshots below, the RAM writer will draw various values on the screen. The leftmost 4 columns describe the addresses that are currently in view. The rightmost two columns describe the values at each of these addresses. All values on screen are represented in hexadecimal format.
For example: DA01>05 means that the address $DA01 is currently holding the value of $05.
Let's go over the controls of the full RAM writer. By default, the RAM writer will open in Read mode.
Full Writer Controls
The RAM writer uses two modes of operation. In Read mode you are able to navigate memory and view the values at specific addresses. in Write mode you'll lock in a single address and manipulate the value at that address.
RAM writer in Read mode | RAM writer in Write mode. Note the arrow pointing at the current address turning white. |
Read mode controls
up: address -1 down: address +1 left: address -10 right: address +10 B + up: address -1 B + down: address +1 B + left: address -10 B + right: address +10 start: exit program A: toggle write mode select + up: sram bank -1 select + down: sram bank +1 select + left: sram bank -10 select + right: sram bank +10 select + A: start executing code from current address onwards (use with caution!)
Write mode controls
up: value -1 down: value +1 left: value -10 right: value +10 B: set current value to 0 A: exit write mode and load final value into the address
Asm translation of included programs/codes
Set all TM quantities to x255
Before first execution | After first execution |
---|---|
80 add b AF xor a D6 82 sub $82 EA F8 F8 ld $f8f8, a FB ei 50 ld d, b D6 A9 sub $A9 D6 B4 sub $B4 EA F7 F8 ld $F8F7, a FB ei 50 ld d, b D6 EF sub $EF EA FB F8 ld $F8FB, a AF xor a D6 FF sub $FF 50 ld d, b EA FA F8 ld $F8FA, a AF xor a EA FC F8 ld $F8FC, a FB ei 50 ld d, b D6 B4 sub $B4 EA FE F8 ld $F8FE, a D6 7F sub $7F FB ei 50 ld d, b EA FD F8 ld $F8FD, a D6 9C sub $9C EA FF F8 ld $F8FF, a 50 ld d, b F6 FF or $FF F5 push af FB ei F5 push af FB ei FB ei FB ei 50 ld d, b FB ei FB ei FB ei FB ei FB ei B7 or a D0 ret nc |
80 add b AF xor a D6 82 sub $82 EA F8 F8 ld $f8f8, a FB ei 50 ld d, b D6 A9 sub $A9 D6 B4 sub $B4 EA F7 F8 ld $F8F7, a FB ei 50 ld d, b D6 EF sub $EF EA FB F8 ld $F8FB, a AF xor a D6 FF sub $FF 50 ld d, b EA FA F8 ld $F8FA, a AF xor a EA FC F8 ld $F8FC, a FB ei 50 ld d, b D6 B4 sub $B4 EA FE F8 ld $F8FE, a D6 7F sub $7F FB ei 50 ld d, b EA FD F8 ld $F8FD, a D6 9C sub $9C EA FF F8 ld $F8FF, a 50 ld d, b F6 FF or $FF 21 7E F5 ld hl, $F57E 01 32 00 ld bc, $0032 CD 4C 31 call ByteFill FB ei FB ei FB ei B7 or a D0 ret nc |
Redirect to TMs
Before first execution | After first execution |
---|---|
80 add b AF xor a D6 82 sub $82 EA D0 F8 ld $F8D0, a FB ei 50 ld d, b FB ei FB ei FB ei FB ei FB ei FB ei A7 and a D2 50 F5 jp nc, $F550 50 ld d, b |
80 add b AF xor a D6 82 sub $82 EA D0 F8 ld $F8D0, a FB ei 50 ld d, b FB ei FB ei FB ei FB ei FB ei FB ei A7 and a D2 7E F5 jp nc, $F57E 50 ld d, b |
Mail writer
11 55 DD ld de, wOTPartyCount; safe to edit outside of battle D5 push de .continue D5 push de D5 push de 3E 04 ld a, 04 21 42 62 ld hl, _ComposeMailMessage CF rst08 E1 pop hl D1 pop de .terminator 2A ldi a, (hl) 87 add a 30 07 jr nc, .notChar 86 add (hl) 12 ld (de), a 13 inc de 81 add c 4F ld c, a 12 ld (de), a 2A ldi a, (hl) .notChar 27 daa 20 F2 jr nc, .terminator .loop 21 01 C4 ld hl, C401 4D ld c, l CD F0 3A call PrintBCDNumber.loop 1B dec DE CD 90 37 call JoyTextDelay_ForcehJoyDown F0 AB ldh a, (hJoyLast) BD cp l 28 D8 jr z, .continue 38 EE jr c, .noloop 07 rlca D0 ret nc 18 F1 jr, .loop
Known limitations:
- The first written byte cannot be $00, otherwise the mail writer will prematurely stop converting characters.
- The first character needs to have a value of $80 or higher.
- The second character cannot be $A0 or $9A
Full RAM writer
Installer located at DD55 3E 03 ld a, 03 CD E1 30 call OpenSRAM ; open sram bank 3 (defined by register a) 0E CE ld c, CE 11 E1 B9 ld de, sBox14Species 21 74 DD ld hl, DD74 CD 1A 31 call CopyBytes ; install payload to SRAM 0E 2D ld c, 08 11 18 D4 ld de, D418 ; entry point of wrong pocket TM33 D5 push de CD 1A 31 call CopyBytes ; install TM33 bootstrap to D418 3E E1 ld a, E1 EA B8 D5 ld (D5B8), a ; change item slot #1 to TM33 C9 ret ; due to earlier push, jump to Deployer RAM writer A Setup stored at B9E1, deployed to CC20 AF xor a 3C inc a E0 D6 ldh (D6),a 21 00 DA ld hl, DA00 resolveDisplay CC27 CD 21 DF call resolveInput E5 push hl 11 F8 FF ld de, FFF8 19 add hl, de 54 ld d, h 5D ld e, l 01 0C 00 ld bc, 000C F0 FE ldh a, (FE) 21 A9 C3 ld hl, C3A9 CD E1 30 call openSramBank CD 65 CC call printHex .displayLoop 3E 7C ld a, 7C 22 ldi (hl), a 7A ld a, d CD 65 CC call printHex 7B ld a, e CD 65 CC call printHex 3E E3 ld a, E3 22 ldi (hl), a 1A ld a, (de) CD 65 CC call printHex 36 7C ld a, 7C 09 add hl, bc 13 inc de 7D ld a, l FE 13 cp 13 20 E5 jr nz, .displayLoop CD F1 30 call closeSramBank 21 50 C4 ld hl, C450 36 ED ld (hl), ED E1 pop hl 18 C2 jr, resolveDisplay printHex CC65 F5 push af CB 37 swap a CD 4C C7 call .firstHex F1 pop af .firstHex CC6C E6 0F and 0F C6 F6 add a, F6 F6 80 or a, 80 22 ldi (hl), a C9 ret sampleDpad CC74 CD 90 37 call JoyTextDelay_ForcehJoyDown F0 AB ldh a, (AB) 11 00 00 ld de, 0000 07 rlca 30 01 jp nc, .noDown 13 inc de .noDown 07 rlca 30 01 jr nc, .noUp 1B dec de .noUp 07 rlca 30 03 jr nc, .noLeft 11 F0 FF ld de, FFF0 .noLeft 07 rlca 30 02 jr nc, .noRight 1E 10 ld e, 10 .noRight 07 rlca C9 ret RAM Writer B ResolveInput deployed to DF21 CD 74 CC call sampleDpad 38 41 jr nc, .startButton 07 rlca 30 0B jr z, noSelectButton 07 rlca 07 rlca 30 01 jr nc, .changeSramBank E9 jp hl .changeSramBank F0 FE ldh a, (FE) 83 add e E0 FE ldh (FE), a C9 ret .noSelectButton 07 rlca 30 03 jr nc, .noBButton 53 ld d, e 1E 00 ld e, 00 19 add hl, de .noBButton 07 rlca 30 2A jr nc, .noAButton E5 push hl F0 FE ldh a, (FE) CD E1 30 call openSramBank 46 ld b, (hl) .inputALoop CD 74 CC call sampleDpad 07 rlca 07 rlca 30 01 jr nc , .BButtonNotPressed 43 ld b, e .BButtonNotPressed 0F rrca 38 0E jr c, .AButtonPressed 78 ld a, b 83 add e 47 ld b, a 21 50 C4 ld hl, C450 36 EC ld (hl), EC 23 inc hl CD 65 CC call printHex 18 E7 jr, .inputALoop .AButtonPressed E1 pop hl 70 ld (hl), b E5 push hl 3E 05 ld a, 5 21 FD 4D ld hl, 4DFD CF rst08h .startButton E1 pop hl .noAButton C9 ret OAM DMA Hijack A FA AB CE ld a, (CEAB) FE E1 cp E1 C0 ret nz ; is current selected item TM33? If yes, continue FA C2 CE ld a, (CEC2) FE 90 cp 90 C0 ret nz ; Is TM33 chosen while in battle? If yes, continue 3E 0D ld a, 0D EA E0 CE ld (CEE0); a ; Force cursor to position #13, enabling use of TM33 C9 ret OAM DMA Hijack B C3 01 DF jp DF01 ; jump to OAM DMA hijack B Deployer located at D418 3E 03 ld a, 03 CD E1 30 call OpenSRAM 0E 71 ld c, 71 11 20 CC ld de, CC20 D5 push de 21 E1 B9 ld hl, sBox14Species CD 1A 31 call CopyBytes ; deploy RAM writer A to CC20 0E 48 ld c, 48 11 21 DF ld de, DF21 CD 1A 31 call CopyBytes ; deploy RAM writer B to DF21 0E 12 ld c, 12 11 0F DF ld de, DF0F CD 1A 31 call CopyBytes ; deploy OAM DMA hijack A to DF0F 0E 03 ld c, 03 11 8A FF ld de, FF8A CD 1A 31 call CopyBytes ; deploy OAM DMA hijack B to FF8A AF xor a E0 89 ld (FF89), a ; enable OAM DMA hijack by removing C9 C9 ret ; due to earlier push, jump to CC20
Old methods for reference
Generation I
Setting up TheZZAZZGlitch's memory editor with coordinates
- Main article: Player coordinates RAM writer
Use the player coordinates RAM writer to set up TheZZAZZGlitch's memory editor at DB01.
Setting up TheZZAZZGlitch's memory editor with an item set up
- Main article: Reusable RAM writer
The reusable RAM writer can be use to write a byte one address at a time.
Fast sequential RAM writer
See https://archives.glitchcity.info/forums/board-115/thread-8725/page-0.html
Full Control: Real-time RAM writing with 8F
See https://archives.glitchcity.info/forums/board-115/thread-7744/page-0.html
Thanks to bbbbbbbbba and the larger GCRI community for suggesting improvements to the code initially written to determine mail codes.
Thanks to TheZZAZZGlitch and offgao, and k(ry for previous memory editors.
Generation II
Thanks to flag3833753 and Epsilon (Couldntthinkofaname) for previous work on RAM writers and inspiring various kinds of optimisations to be used in the RAM writers included in this guide.
Thanks to Scotteh for writing the mail code webapp.
Thanks to Crystal_ for their memory editor.
Thanks to Sanqui for discovering Coin Case arbitrary code execution.
Crystal
TheZZAZZGlitch's memory editor ported to Pokémon Crystal by Kai mirror (pokecrystal memory editor.sav)