-
Notifications
You must be signed in to change notification settings - Fork 10
WIP Dev Tips Code Notes En Masse
When RAM digging, you may find yourself wishing for a way to do code notes en masse. Unfortunately, there's not a convenient or simple way to do this, but it is possible and can save a ton of time if you are patient enough to learn how.
First, we'll look at how local code notes work:
- Open the Memory Inspector and the Code Notes windows.
- Go to a random address and type something in as a note, but do not publish it.
- Check that address in the Code Notes window. You'll notice that your note is red.
- Go to the emulator's RACache directory and open the
GameID-User.txt
file of the game you have running.
- Lines that start with
N0:
are local code notes. Once you publish a note, it will disappear from theGameID-User.txt
file.
N0:address of the note:"text of the code note"
-
N0:
is how the server knows this is a code note.
-
address of the note
the memory address, obviously. This will be in hex, not decimal.
-
:
it's just a separator
-
"text of the code note"
- the contents of the code note, and yes, the quotes are required. Line breaks can be used with\r\n
and quotes within the note can be used with\"
Now, the next part requires some general know-how with spreadsheets. It will vary per game, so you'll need to figure out the formula for a lot of things yourself. We will use an example, though.
Let's say we want to have notes for all character stats. You will need the following:
- Character 1's stat addresses.
- An offset for Character 1 and Character 2's first stats.
We will use Trails in the Sky SC as an example.
Character 1 is Estelle, and her stat addresses are as followed:
Address | "Character and Stat" |
---|---|
0xc5bbcc | "[16-bit] Estelle - Current Level" |
0xc5bbd0 | "[16-bit] Estelle - Max HP" |
0xc5bbd4 | "[16-bit] Estelle - Current HP" |
0xc5bbd8 | "[16-bit] Estelle - Max EP" |
0xc5bbda | "[16-bit] Estelle - Current EP" |
0xc5bbdc | "[16-bit] Estelle - Current CP" |
0xc5bbe0 | "[32-bit] Estelle - Current EXP" |
0xc5bbe4 | "[16-bit] Estelle - STR Stat" |
0xc5bbe6 | "[16-bit] Estelle - DEF Stat" |
0xc5bbe8 | "[16-bit] Estelle - ATS Stat" |
0xc5bbea | "[16-bit] Estelle - ADF Stat" |
0xc5bbec | "[16-bit] Estelle - DEX Stat" |
0xc5bbee | "[16-bit] Estelle - AGL Stat" |
0xc5bbf0 | "[16-bit] Estelle - MOV Stat" |
0xc5bbf2 | "[16-bit] Estelle - SPD Stat" |
0xc5bbfa | "[16-bit] Estelle - RNG Stat" |
Character 2 is Joshua. His first stat (Current Level) is at the address 0xc5bc08.
0xc5bc08 minus 0xc5bbcc is 0x3c, or 60 in decimal. We can confirm this by checking his last stat (RNG), which is 0xc5bc36, also 0x3c/60 from Estelle's last stat.
We'll start by putting Estelle's stats into a spreadsheet and adding a column between the addresses and stats. It will look like this (column numbers in parenthesis):
Address (A) | Blank Column (B) | "Character and Stat" (C) |
---|---|---|
0xc5bbcc | "[16-bit] Estelle - Current Level" | |
0xc5bbd0 | "[16-bit] Estelle - Max HP" | |
0xc5bbd4 | "[16-bit] Estelle - Current HP" | |
0xc5bbd8 | "[16-bit] Estelle - Max EP" | |
0xc5bbda | "[16-bit] Estelle - Current EP" | |
0xc5bbdc | "[16-bit] Estelle - Current CP" | |
0xc5bbe0 | "[32-bit] Estelle - Current EXP" | |
0xc5bbe4 | "[16-bit] Estelle - STR Stat" | |
0xc5bbe6 | "[16-bit] Estelle - DEF Stat" | |
0xc5bbe8 | "[16-bit] Estelle - ATS Stat" | |
0xc5bbea | "[16-bit] Estelle - ADF Stat" | |
0xc5bbec | "[16-bit] Estelle - DEX Stat" | |
0xc5bbee | "[16-bit] Estelle - AGL Stat" | |
0xc5bbf0 | "[16-bit] Estelle - MOV Stat" | |
0xc5bbf2 | "[16-bit] Estelle - SPD Stat" | |
0xc5bbfa | "[16-bit] Estelle - RNG Stat" |
In cell B1, we'll use the following formula: =hex2dec(A1)
to turn the address to decimal. Then we'll drag it down to populate the other cells. It should now look like this (also, added the row column since we'll need it):
Row | Address (A) | Address in Decimal (B) | "Character and Stat" (C) |
---|---|---|---|
01 | 0xc5bbcc | 12958668 | "[16-bit] Estelle - Current Level" |
02 | 0xc5bbd0 | 12958672 | "[16-bit] Estelle - Max HP" |
03 | 0xc5bbd4 | 12958676 | "[16-bit] Estelle - Current HP" |
04 | 0xc5bbd8 | 12958680 | "[16-bit] Estelle - Max EP" |
05 | 0xc5bbda | 12958682 | "[16-bit] Estelle - Current EP" |
06 | 0xc5bbdc | 12958684 | "[16-bit] Estelle - Current CP" |
07 | 0xc5bbe0 | 12958688 | "[32-bit] Estelle - Current EXP" |
08 | 0xc5bbe4 | 12958692 | "[16-bit] Estelle - STR Stat" |
09 | 0xc5bbe6 | 12958694 | "[16-bit] Estelle - DEF Stat" |
10 | 0xc5bbe8 | 12958696 | "[16-bit] Estelle - ATS Stat" |
11 | 0xc5bbea | 12958698 | "[16-bit] Estelle - ADF Stat" |
12 | 0xc5bbec | 12958700 | "[16-bit] Estelle - DEX Stat" |
13 | 0xc5bbee | 12958702 | "[16-bit] Estelle - AGL Stat" |
14 | 0xc5bbf0 | 12958704 | "[16-bit] Estelle - MOV Stat" |
15 | 0xc5bbf2 | 12958706 | "[16-bit] Estelle - SPD Stat" |
16 | 0xc5bbfa | 12958714 | "[16-bit] Estelle - RNG Stat" |
Now, we'll populate the cells with Joshua's stats using the offset. In cell B17, we will use the formula =B1+60
, which will give us 12958728
. Drag cell B17 to B32. In cell A17, use the formula =dec2hex
and drag that down to A32. It should now look like this:
Row | Address (A) | Address in Decimal (B) | "Character and Stat" (C) |
---|---|---|---|
01 | 0xc5bbcc | 12958668 | "[16-bit] Estelle - Current Level" |
02 | 0xc5bbd0 | 12958672 | "[16-bit] Estelle - Max HP" |
03 | 0xc5bbd4 | 12958676 | "[16-bit] Estelle - Current HP" |
04 | 0xc5bbd8 | 12958680 | "[16-bit] Estelle - Max EP" |
05 | 0xc5bbda | 12958682 | "[16-bit] Estelle - Current EP" |
06 | 0xc5bbdc | 12958684 | "[16-bit] Estelle - Current CP" |
07 | 0xc5bbe0 | 12958688 | "[32-bit] Estelle - Current EXP" |
08 | 0xc5bbe4 | 12958692 | "[16-bit] Estelle - STR Stat" |
09 | 0xc5bbe6 | 12958694 | "[16-bit] Estelle - DEF Stat" |
10 | 0xc5bbe8 | 12958696 | "[16-bit] Estelle - ATS Stat" |
11 | 0xc5bbea | 12958698 | "[16-bit] Estelle - ADF Stat" |
12 | 0xc5bbec | 12958700 | "[16-bit] Estelle - DEX Stat" |
13 | 0xc5bbee | 12958702 | "[16-bit] Estelle - AGL Stat" |
14 | 0xc5bbf0 | 12958704 | "[16-bit] Estelle - MOV Stat" |
15 | 0xc5bbf2 | 12958706 | "[16-bit] Estelle - SPD Stat" |
16 | 0xc5bbfa | 12958714 | "[16-bit] Estelle - RNG Stat" |
17 | 0xc5bc08 | 12958728 | |
18 | 0xc5bc0c | 12958732 | |
19 | 0xc5bc10 | 12958736 | |
20 | 0xc5bc14 | 12958740 | |
21 | 0xc5bc16 | 12958742 | |
22 | 0xc5bc18 | 12958744 | |
23 | 0xc5bc1c | 12958748 | |
24 | 0xc5bc20 | 12958752 | |
25 | 0xc5bc22 | 12958754 | |
26 | 0xc5bc24 | 12958756 | |
27 | 0xc5bc26 | 12958758 | |
28 | 0xc5bc28 | 12958760 | |
29 | 0xc5bc2a | 12958762 | |
30 | 0xc5bc2c | 12958764 | |
31 | 0xc5bc2e | 12958766 | |
32 | 0xc5bc36 | 12958774 |
Now, we'll copy cells C1:C16 and paste them to cells C17:C32. We'll highlight C17:C32 and use the Find & Replace tool (CTRL+H for Google Sheets) to change instances of Estelle
to Joshua
, but only for that cell range. It will look like this:
Row | Address (A) | Address in Decimal (B) | "Character and Stat" (C) |
---|---|---|---|
01 | 0xc5bbcc | 12958668 | "[16-bit] Estelle - Current Level" |
02 | 0xc5bbd0 | 12958672 | "[16-bit] Estelle - Max HP" |
03 | 0xc5bbd4 | 12958676 | "[16-bit] Estelle - Current HP" |
04 | 0xc5bbd8 | 12958680 | "[16-bit] Estelle - Max EP" |
05 | 0xc5bbda | 12958682 | "[16-bit] Estelle - Current EP" |
06 | 0xc5bbdc | 12958684 | "[16-bit] Estelle - Current CP" |
07 | 0xc5bbe0 | 12958688 | "[32-bit] Estelle - Current EXP" |
08 | 0xc5bbe4 | 12958692 | "[16-bit] Estelle - STR Stat" |
09 | 0xc5bbe6 | 12958694 | "[16-bit] Estelle - DEF Stat" |
10 | 0xc5bbe8 | 12958696 | "[16-bit] Estelle - ATS Stat" |
11 | 0xc5bbea | 12958698 | "[16-bit] Estelle - ADF Stat" |
12 | 0xc5bbec | 12958700 | "[16-bit] Estelle - DEX Stat" |
13 | 0xc5bbee | 12958702 | "[16-bit] Estelle - AGL Stat" |
14 | 0xc5bbf0 | 12958704 | "[16-bit] Estelle - MOV Stat" |
15 | 0xc5bbf2 | 12958706 | "[16-bit] Estelle - SPD Stat" |
16 | 0xc5bbfa | 12958714 | "[16-bit] Estelle - RNG Stat" |
17 | 0xc5bc08 | 12958728 | "[16-bit] Joshua - Current Level" |
18 | 0xc5bc0c | 12958732 | "[16-bit] Joshua - Max HP" |
19 | 0xc5bc10 | 12958736 | "[16-bit] Joshua - Current HP" |
20 | 0xc5bc14 | 12958740 | "[16-bit] Joshua - Max EP" |
21 | 0xc5bc16 | 12958742 | "[16-bit] Joshua - Current EP" |
22 | 0xc5bc18 | 12958744 | "[16-bit] Joshua - Current CP" |
23 | 0xc5bc1c | 12958748 | "[32-bit] Joshua - Current EXP" |
24 | 0xc5bc20 | 12958752 | "[16-bit] Joshua - STR Stat" |
25 | 0xc5bc22 | 12958754 | "[16-bit] Joshua - DEF Stat" |
26 | 0xc5bc24 | 12958756 | "[16-bit] Joshua - ATS Stat" |
27 | 0xc5bc26 | 12958758 | "[16-bit] Joshua - ADF Stat" |
28 | 0xc5bc28 | 12958760 | "[16-bit] Joshua - DEX Stat" |
29 | 0xc5bc2a | 12958762 | "[16-bit] Joshua - AGL Stat" |
30 | 0xc5bc2c | 12958764 | "[16-bit] Joshua - MOV Stat" |
31 | 0xc5bc2e | 12958766 | "[16-bit] Joshua - SPD Stat" |
32 | 0xc5bc36 | 12958774 | "[16-bit] Joshua - RNG Stat" |
We can repeat this for the remaining characters, but we'll leave it as is to keep it simple.
Remember the syntax: N0:address of the note:"text of the code note"
. This is how we'll set up the spreadsheet:
- Add a column to the left of column A and fill that column with
N0:
.
- Copy cells B1:B32 (which are now the hex addresses).
- Right-click on B1 and go to Paste Special -> Values only, or simply press CTRL+SHIFT+V. If you don't do this, the next step will mess everything up.
- Clear Column C (which were the decimal addresses) and fill C1:C32 with
:
.
- The sheet should now look like this:
Row | N0: (A) | Address (B) | : (C) | "Character and Stat" (D) |
---|---|---|---|---|
01 | N0: | 0xc5bbcc | : | "[16-bit] Estelle - Current Level" |
02 | N0: | 0xc5bbd0 | : | "[16-bit] Estelle - Max HP" |
03 | N0: | 0xc5bbd4 | : | "[16-bit] Estelle - Current HP" |
04 | N0: | 0xc5bbd8 | : | "[16-bit] Estelle - Max EP" |
05 | N0: | 0xc5bbda | : | "[16-bit] Estelle - Current EP" |
06 | N0: | 0xc5bbdc | : | "[16-bit] Estelle - Current CP" |
07 | N0: | 0xc5bbe0 | : | "[32-bit] Estelle - Current EXP" |
08 | N0: | 0xc5bbe4 | : | "[16-bit] Estelle - STR Stat" |
09 | N0: | 0xc5bbe6 | : | "[16-bit] Estelle - DEF Stat" |
10 | N0: | 0xc5bbe8 | : | "[16-bit] Estelle - ATS Stat" |
11 | N0: | 0xc5bbea | : | "[16-bit] Estelle - ADF Stat" |
12 | N0: | 0xc5bbec | : | "[16-bit] Estelle - DEX Stat" |
13 | N0: | 0xc5bbee | : | "[16-bit] Estelle - AGL Stat" |
14 | N0: | 0xc5bbf0 | : | "[16-bit] Estelle - MOV Stat" |
15 | N0: | 0xc5bbf2 | : | "[16-bit] Estelle - SPD Stat" |
16 | N0: | 0xc5bbfa | : | "[16-bit] Estelle - RNG Stat" |
17 | N0: | 0xc5bc08 | : | "[16-bit] Joshua - Current Level" |
18 | N0: | 0xc5bc0c | : | "[16-bit] Joshua - Max HP" |
19 | N0: | 0xc5bc10 | : | "[16-bit] Joshua - Current HP" |
20 | N0: | 0xc5bc14 | : | "[16-bit] Joshua - Max EP" |
21 | N0: | 0xc5bc16 | : | "[16-bit] Joshua - Current EP" |
22 | N0: | 0xc5bc18 | : | "[16-bit] Joshua - Current CP" |
23 | N0: | 0xc5bc1c | : | "[32-bit] Joshua - Current EXP" |
24 | N0: | 0xc5bc20 | : | "[16-bit] Joshua - STR Stat" |
25 | N0: | 0xc5bc22 | : | "[16-bit] Joshua - DEF Stat" |
26 | N0: | 0xc5bc24 | : | "[16-bit] Joshua - ATS Stat" |
27 | N0: | 0xc5bc26 | : | "[16-bit] Joshua - ADF Stat" |
28 | N0: | 0xc5bc28 | : | "[16-bit] Joshua - DEX Stat" |
29 | N0: | 0xc5bc2a | : | "[16-bit] Joshua - AGL Stat" |
30 | N0: | 0xc5bc2c | : | "[16-bit] Joshua - MOV Stat" |
31 | N0: | 0xc5bc2e | : | "[16-bit] Joshua - SPD Stat" |
32 | N0: | 0xc5bc36 | : | "[16-bit] Joshua - RNG Stat" |
- Copy cells A1:D32 and paste them into the
GameID-User.txt
file.
- Use Find and Replace to change tabs to an empty space/nothing/blank.
The GameID-User.txt
contents now look like this:
#.#.#.#
Trails in the Sky SC
N0:0xc5bbcc:"[16-bit] Estelle - Current Level"
N0:0xc5bbd0:"[16-bit] Estelle - Max HP"
N0:0xc5bbd4:"[16-bit] Estelle - Current HP"
N0:0xc5bbd8:"[16-bit] Estelle - Max EP"
N0:0xc5bbda:"[16-bit] Estelle - Current EP"
N0:0xc5bbdc:"[16-bit] Estelle - Current CP"
N0:0xc5bbe0:"[32-bit] Estelle - Current EXP"
N0:0xc5bbe4:"[16-bit] Estelle - STR Stat"
N0:0xc5bbe6:"[16-bit] Estelle - DEF Stat"
N0:0xc5bbe8:"[16-bit] Estelle - ATS Stat"
N0:0xc5bbea:"[16-bit] Estelle - ADF Stat"
N0:0xc5bbec:"[16-bit] Estelle - DEX Stat"
N0:0xc5bbee:"[16-bit] Estelle - AGL Stat"
N0:0xc5bbf0:"[16-bit] Estelle - MOV Stat"
N0:0xc5bbf2:"[16-bit] Estelle - SPD Stat"
N0:0xc5bbfa:"[16-bit] Estelle - RNG Stat"
N0:0xc5bc08:"[16-bit] Joshua - Current Level"
N0:0xc5bc0c:"[16-bit] Joshua - Max HP"
N0:0xc5bc10:"[16-bit] Joshua - Current HP"
N0:0xc5bc14:"[16-bit] Joshua - Max EP"
N0:0xc5bc16:"[16-bit] Joshua - Current EP"
N0:0xc5bc18:"[16-bit] Joshua - Current CP"
N0:0xc5bc1c:"[32-bit] Joshua - Current EXP"
N0:0xc5bc20:"[16-bit] Joshua - STR Stat"
N0:0xc5bc22:"[16-bit] Joshua - DEF Stat"
N0:0xc5bc24:"[16-bit] Joshua - ATS Stat"
N0:0xc5bc26:"[16-bit] Joshua - ADF Stat"
N0:0xc5bc28:"[16-bit] Joshua - DEX Stat"
N0:0xc5bc2a:"[16-bit] Joshua - AGL Stat"
N0:0xc5bc2c:"[16-bit] Joshua - MOV Stat"
N0:0xc5bc2e:"[16-bit] Joshua - SPD Stat"
N0:0xc5bc36:"[16-bit] Joshua - RNG Stat"
- Save it.
- Next time the game is loaded and the Code Notes window is opened, all of those notes will appear in red.
- If we click Publish at the bottom of the Code Notes window, all of the notes will publish at once.
That's all, folks. Learn some spreadsheet formulas and Regular Expressions and you will become a Code Note guru. Please use responsibly and don't actually save over my Trails in the Sky SC notes. Always spot-check addresses here and there to make sure your formulas stay consistent. I added over 500 code notes to the wrong game using an older method, which was much easier to make mistakes. <3 - tele.
- User Guidelines
- Developer Guidelines
- Content Guidelines
- FAQ
- Setup Guide
- Emulator Support and Issues
- Ways to Contribute
- RABot, the RA Discord Robot
- Events
- Overlay Themes
- Useful Links
- Contributing with the docs
- About Us
- Tutorials
- Developer Docs
- How to Become an Achievement Developer
- Getting Started as an Achievement Developer
- Game Identification
- Achievement Design
- Achievement Scoring
- Difficulty Scale and Balance
- Progression and Win Condition Typing
- Badge and Icon Creation
- Achievement Development Overview
- Flags
- BitCount Size
- Alt Groups
- Hit Counts
- Delta Values
- Prior Values
- Value Definition
- Condition Syntax
- Minimum Required Versions for Logic Features
- Memory Inspector
- Real Examples
- Set Development Roadmap
- Achievement Templates
- Tips and Tricks
- Leaderboards
- Rich Presence
- RATools
- Console Specific Tips
- Emulator Hotkeys for Developers
- libretro core support
- Docs To Do List
- WIP User Code of Conduct
- WIP CoC FAQ
- WIP Content Guidelines
- WIP-Jr
- WIP---Dev-Tips---Code-Notes-En-Masse
- WIP-‐-Reauthorship-Policy
- Manifesto RetroAchievements
- Código de Conduta do Usuário
- FAQ - Perguntas Frequentes
- Como contribuir se você não é um desenvolvedor
- Tutorial para Jogos Multi-Discos
- Introdução
- Primeiros Passos como um Desenvolvedor de Conquistas
- Recursos de Lógica para Achievements
- Exemplos Reais
- Dicas e Truques
- Dicas Específicas de Console
- Modelos de Achievement
- Escala de Dificuldade e Equilíbrio
- Roteiro de Desenvolvimento de um Set de Conquistas
- Criação de Ícones e Emblemas
- Leaderboards
- Rich Presence
- Design de Conquistas
- Manifesto RetroAchievements
- Código de Conducta del Usuario
- FAQ - Preguntas Frecuentes
- Tablas Globales y Reglas para la Casería de Logros
- Mi juego no esta cargando los logros
- Como contribuir si no eres un desarrollador
- Por que no deberías utilizar la función de cargar estado
- Contribuyendo con los documentos
- Como funciona la Documentación de RA
- Descargas
- Intro
- Código de Conducta del Desarrollador
- Como convertirme en un Desarrollador de Logros
- Primeros pasos como un Desarrollador de Logros
- Un vistazo al Inspector de Memoria
- Características en la Logica de un Logro
- Ejemplos Reales
- Intro
- Utilizando Hit Counts como un Temporizador
- Utilizando Valores Delta y Hit Counts para Detectar un Incremento
- Un Ejemplo Simple en como evitar el Abuso de Estados de Guardado
- Evitar el Problema de que un Contador se Incremente Dos Veces en el Mismo Frame
- Creando un Temporizador con un ResetIf Hits basándote en la Velocidad de un Juego
- Plantillas para Logros
- Tips y Trucos
- Escala de Dificultad y Balance
- Diseño de Logros
- Mapa de Desarrollo de Set
- Revisiones en Set de Logros
- Creación de Iconos y Badges
- Tablas de Clasificación
- Rich Presence
- Trabajando con el ROM apropiado
- Identificación del Juego
- Guía para Sets Bonus
- Logros para ROM hacks
- Tips Específicos por Consola