Text Palette Changing [FE6] [FE7] [FE8]

Have you ever wanted to be able to use a different color for your text aside from dark grey and dark red? Maybe that off-white background is driving you bonkers? Are the limitations of [ToggleColorInvert] getting you down? Well, here’s an edit that allows you to change those things. WARNING: I am new to assembly; therefore, this may be messy and error-prone. I’m going into excruciating detail to explain what I did, just in case it breaks horribly and I have no idea how to fix it. Or if one of the wizards thinks there’s a more efficient way of doing things.


First, the text palette and text box background palette are loaded into palette RAM (500 series).
Next, the text in question is copied into WRAM (200 series).
Finally, the functions that actually put text on the screen are called. If you have [ToggleColorInvert], that loads a different text and background palette in the same space in palette RAM as the normal palettes. [ToggleRed] actually uses the same text palette, albeit a different part of it. NOTE: In case you didn’t know, you CAN combine both toggles, but they won’t look great (unless you change the inverted palette). The game reads through each byte in WRAM, goes to a jump table (basically a table of pointers), and executes code depending on the byte it read. Bytes 08-0F (which is the Open Speech Bubble class) go through this same process in a different jump table to determine how long the text box has to be.

This modification basically does the same thing as the [ToggleColorInvert] command: it overwrites the current palette, using the unused FEditor code 0x1E. The syntax is [0x1E][0xXX][0xYY], where XX is the background palette byte and YY is the text palette byte. Here’s a look at the assembly code for FE7/8:

ldr     r0,BackgroundTable
ldrb    r3,[r4,#0x1]     @load background palette byte
sub     r3,r3,#0x26
lsl     r3,r3,#0x5
add     r0,r0,r3         @new background palette location now in r0
ldr     r1,TextTable
ldrb    r3,[r4,#0x2]     @load text palette byte
sub     r3,r3,#0x26
lsl     r3,r3,#0x5
add     r1,r1,r3         @new text palette location now in r1
add     r4,r4,#0x3       @increment wram pointer to next instruction
ldr     r2,[r7]          @r7 has iram pointer to wram pointer
str     r4,[r2]          @store new wram pointer
push    {r4-r7}
ldr     r2,PaletteOffset
ldmia   r1!, {r4-r7}
stmia   r2!, {r4-r7}
ldmia   r1!, {r4-r7}
stmia   r2!, {r4-r7}     @finish loading new text palette
ldmia   r0!, {r4-r7}
stmia   r2!, {r4-r7}
ldmia   r0!, {r4-r7}
stmia   r2!, {r4-r7}     @finish loading new bg palette
pop     {r4-r7}
ldr     r1, ReadNextCommand
bx      r1

    .long 0x08B2B200
    .long 0x08B2B600
    .long 0x05000040
    .long 0x08007015

BackgroundTable and Textable are where you, the person using this, pastes the new palette tables in free space. PaletteOffset is the same in all 3 games, while ReadNextCommand varies (don’t worry, I’ll include the hex further down in this post, along with detailed instructions on what to change).

What does this do? We find the palettes that were called for both background and text. Next, we increment the wram pointer by 2 (this makes it so that the parameters themselves aren’t read as text to be displayed). Finally, we store the new palettes in palette RAM and branch back to the instructions leading to the first jump table.

Now hold on, I hear you say. What’s that sub r3,r3,#0x26 doing there? Good catch! At this time, your palette parameters have to range from 26-FF. Why? FEditor acts funny if you use the reserved opcodes. I am looking for someone to update FEditor so that it will display, for instance, [0x1E][0x26][0x26], rather than changing the parameters to their respective ASCII codes. Similar to the way [LoadFace] works, basically. However, even if this is implemented, you’ll still be stuck with a maximum of FE palettes, because [0x00] is read as “End of text” when the text is being put in WRAM, so everything afterward isn’t going to show up. I could probably do something about it, but I’m not going to, because 1) who is honestly going to use DA (218) palettes, and 2) if, by some freaky chance you do need more, it’s quite easy to make the parameters halfwords instead of bytes, letting you use something like 65000 palettes.

Is that all? Not quite. Remember I mentioned earlier that a different jump table is used when the Open Speech Bubble functions are called? Gotta add something here, too. Fortunately, it’s a lot shorter.

.org 0x2

add     r4,r4,#0x3
ldr     r0,NextValue
bx      r0

    .long 0x08008B67

This just increments that same pointer to WRAM by 3, again bypassing the parameters. If you don’t, and you do too many palette changes in one box, you’ll get something like this:

Aaaand that’s pretty much it! So…here’s the part you actually want: adding this to your hack!

Adding this to your hack

FE7 and FE8:

00 00 0D 48 63 78 26 3B 5B 01 C0 18 0B 49 A3 78 26 3B 5B 01 C9 18 03 34 3A 68 14 60 F0 B4 08 4A F0 C9 F0 C2 F0 C9 F0 C2 F0 C8 F0 C2 F0 C8 F0 C2 F0 BC 04 49 08 47 C0 46 00 B2 B2 08 00 B6 B2 08 40 00 00 05 15 70 00 08

This is part that does the palette overwriting. You’re going to paste this in free space, and you’re going to change the pointer at (FE7: 8694, FE8: 70A8) to the offset that you pasted this to. Next, in the last 2 rows, you can see 4 pointers: 8B2B200, 8B2B600, 5000040, 8007015. If you’re in FE8 (which is where I wrote this), ignore the last pointer. If you’re in FE7, change it to 8008601. The first two pointers are to your background palette table and your text palette table, respectively, which you will also have somewhere in free space. The areas I wrote are free space in FE8, but you might not want them there, so just repoint accordingly. Each palette is 0x20 bytes long, so a full table will be 0xDA*0x20 = 0x1B40 bytes long, so make sure you have enough space. And always remember to reverse your pointers!

00 00 03 34 00 48 00 47 67 8B 00 08

This is the part that prevents the text box from being too large. Similar to above, you paste this in free space, then change the pointer at (FE7: A1D0, FE8: 8BF8) to the offset you pasted this to. At the very end of this function there’s also a pointer; if you’re in FE7, change this to 800A13F (otherwise, you’re good).


I did this pretty much for Omni, but I’ll post it here anyway. The basic premise is exactly the same, but there’s a few modifications.

F0 B4 0D 48 0D 4D 2C 68 A3 78 26 3B 5B 01 C0 18 0B 49 23 79 26 3B 5B 01 C9 18 05 34 2C 60 09 4A F0 C9 F0 C2 F0 C9 F0 C2 F0 C8 F0 C2 F0 C8 F0 C2 F0 BC 05 49 08 47 C0 46 80 00 A3 08 38 00 00 03 E0 00 A3 80 40 00 00 05 E9 99 00 08

Paste this in free space, then write the pointer to this location at 9A84. In the bottom tow, there’s 5 pointers: 8A30080, 3000038, 8A300E0, 5000040, 800999E. You’ll want to change the first and third to your background and text palette tables, respectively (see FE7/8 section for more details).

38 68 05 30 38 60 01 48 00 47 C0 46 B7 C5 00 08

Paste this in free space, then write the pointer to this location at C648.

NOTE: This function will most likely have to be updated if I get that FEditor edit I talked about. Characters in FE6 are written into the ROM as 0x82 0xZZ (where ZZ has some relation to the normal ASCII characters), which means the parameters are also saved as 82 XX 82 YY. So the incrementing function adds 5 instead of 3.


Alright, you’ve implemented the code. Now you’ve got 2 tables full of 00s and no idea what to fill it with. What to do? First, let’s look at what part of the palette is actually used where.

NOTE: All my testing has been done in FE8. I think it’s reasonable to assume that it’s the same in the other two (or at the very least, FE7), but it’s not assured. Please let me know if you discover anything wrong.


If you open up the palette editor in your editor of choice and look at 5000060 (fourth palette in the Background section), you should see this (the colors aren’t exactly the same between games, but fairly similar):

The first color is, as usual, transparent. Colors 2-4 are used in the border. Color #5 is the main fill, ie, the important one. Generally speaking, you can probably copy and paste the basic palette (located at 9E84D4 in FE8, no idea in the others) and only change #5 to whatever you want and leave the rest alone. I have no idea what 6-16 do; if someone finds out, let me know, and I’ll add it to this post and give credit.


Same thing as background, but look at the one before (5000040). Should look something like this:

This is a bit different. Zahlman believes that there’s 4 groups of 4, with each group having 1 transparent color and the others actually being useful. As far as I can tell, this isn’t the case. Here’s what I’ve discovered:

1 is transparent. 3 and 4 are used for the world map text in FE8. 6 and 7 are the normal text box colors; these are the ones you’ll be changing most of the time. 15 and 16 are called with [ToggleRed]. I have no idea what the other ones are used for; again, if you find out, let me know. In all of these cases, the first one of the two is the anti-aliasing color, and the second is the main color. If you look at the example at the end of this post, I just changed color 7 and left color 6 alone. Again, you can probably get away with copying the basic palette and modifying only specific bytes; in FE8, it’s located at 59EF20.

Calculating palette values

If you have a color’s RGB value, you can change it into the hex value required for GBA fairly easily.
First, divide and floor each value by 8. Each pigment will range from 0-31. Change this number to hex (0x00-0x1F).
For red: Leave it alone.
For green: Multiply by 0x20 (lsl 0x5)
For blue: Multiply by 0x400 (lsl 0x10)
Add everything together. Voila!

Here is the hex calculator I use, if you need one.

Confused? Here’s an example. White is (255,255,255). We divide by 8 and floor, netting us (31,31,31), or (1F,1F,1F).
0x1F0x20 = 0x3E0.
0x400 = 0x7C00.
0x7C00+0x3E0+0x1F = 0x7FFFF

Go wild! And if you find a really nice palette, perhaps share it with the rest of us! Just remember to make it legible; pretty colors are all well and good, but if we can’t read your text then it’s kinda useless.

What if I want to change other text boxes?

Originally, I wanted to make something that could change the palette of any kind of text box, but that kinda proved impossible because they’re in different locations or loaded at different times. That being said, you can use code similar to mine and just change the palette offsets. Fiddle around with it! Here is a summary of my notes for FE8; at the very least, you got some palette offsets to look at.


  1. Add the palette overriding function to free space. Update pointers as needed.
  2. Add the parameter skipping function to free space. Update pointers as needed.
  3. Add actual palettes to your background and text palette tables.
  4. When you want to change palettes, call it in FEditor with [0x1E][0xXX][0xYY], where XX is the (background palette + 0x26) and YY is the (text palette + 0x26) (THE 26 IS REALLY IMPORTANT, GUYS).

As far as testing goes, I did some slightly more rigorous testing in FE8, and then the bare minimum in FE7/6 (just enough to verify it works). It’s possible, nay, probable, that there’s glitches; please let me know so I can hang my head in shame (and maybe fix them).

If your FEditor text looks like this, don’t panic! For now, it’s supposed to.

Because, the end result is this:

C’mon, you gotta admit that looks cool!

CREDIT: Zahlman helped alot with analyzing code and bouncing ideas, and Crazycolorz corrected some broken code.


Well done Tequilla, as always you do mind boggling things.

Oh man, those are some sweet effects.

Man, part of the idea behind that patching format I was talking about with Cam was to make exactly this kind of thing not require a bunch of manual steps. But for now I guess we make do with what we have. It was fun working this stuff out with you (and I’m definitely not done examining it yet :smile_cat: )

I think your code dumps didn’t format quite the way you wanted/expected, m8 :confused:

I think I explained that one badly to you. It’s more like, 5 groups of 3, and then they also use index 0 as a common transparent colour. I managed to get far enough into understanding the text rendering to be confident that I found the actual font data, and it’s pretty clearly 2bpp. So you could use up to 3 colours + a transparent one, but the GBAFE fonts only ever use two + transparency AFAICT. But yeah if you look at the colours in the palette they seem pretty naturally grouped: “inverted”, “normal”, “blue”, “yellow”, “red” text. My best guess is that a bunch of this code is left over from Advance Wars (which does at least use blue as well as red), and quite possibly from even earlier in IS’ history. Anyway, they aren’t “useful” as is, but only because there isn’t a command that causes them to be used. I’m hoping to fix that (among other things) :smiling_imp:

Can’t, like, GBAGE make raw dumps of palette bytes? Or maybe one of @BwdYeti’s tools?

The palettes are all uncompressed, right? So it should be fairly easy to find the corresponding ones in the other games… do you have a similar list of “types of text” for 6 and 7? (Eh n/m I guess I’ll just read the EA docs or something, lol)


No idea.

Yes, they’re uncompressed; no, I don’t have a similiar list for other games. Sorry.

Eh I’m sure I’ll figure it out. BTW did you get any further with the 0x80 0x00…0x03 codes? Actually, did you test 0x80 0x00 specifically? Like, it seems to be provided for in the code, but I’m not sure that it doesn’t just read the 0x00 as an end-of-text anyway.

Pretty… complicated, but I have to admit it looks cool.
And it’d be pretty damn perfect for that scene at the end of ch.8 of MS.

1 Like