[Pokeemerald] Editing the Title Screen!
Hello everyone, today I will be explaining some basics on editing the title screen in Pokeemerald. I recently decided to play around with the title screen and decided to share what I have learned. Maybe this will help others in the future.
Please note that as work on Pokeemerald progresses, some of the labels may eventually be outdated in this tutorial. If that happens please let me know.
Also note that while this is not targeted for Pokeruby, everything is most likely very similar and applies to it to.
Credit to Diegoisawesome for pointing me in the right direction for some things.
[spoiler title=”Pre-Reading Material”]
While not required, I recommend reading the following pages from TONC as the knowledge will apply to this. Also some things will be more in depth in TONC compared to how I will explain them.
Sprite and background overview
[/spoiler]
[spoiler title=”Understanding The Files We Will Be Working With”]
For the tittlescreen, the graphic files are located in “graphics\title_screen\”. Any new files should also be placed in this folder to keep this organized.
The bin files are tilemaps used to create the backgrounds displayed on the screen. These can be edited the same way as they’ve always been edited, I will not go into detail on this.
The png files are the images used to display stuff on the screen. Some may look a little weird because of how images need to be formatted for the gba or because some are loaded with the tilemaps. All are index and if you edit any you will need to make sure to keep the indexing.
The pal files are the actual palettes used for the images. I recommend exporting a pal from an editor for your indexed image to make sure everything matches up.
Another file we will be working with is “src\title_screen.c”. This file contains the code for the tittle screen and we will be doing most of our work in it.
I won’t go in depth on all the workings of the file as this document is written so that anyone can follow along and make modifications to the title screen. With experience and building on what is in this document, the rest will make sense over time.
[/spoiler]
[spoiler title=”Removing Things We Don’t Need”]
To start we are going to remove some things from the title screen that I don’t think most people will need. We’ll do this in the “title_screen.c” file.
Let’s take a look at the unedited title screen.
The first thing we’ll remove will be the clouds. There are actually a few ways to do this.
Look for the following bit of code.
LZ77UnCompVram(sTitleScreenCloudsGfx, (void *)(VRAM + 0xC000)); LZ77UnCompVram(gUnknown_08DDE458, (void *)(VRAM + 0xD800));
These are the lines of code that actually load the image and tilemap for the clouds. We can just comment these out but if you are clever it is possible to repurpose this for other effects.
Also look for the following code.
if (gTasks[taskId].tCounter & 1) { gTasks[taskId].data[4]++; gBattle_BG1_Y = gTasks[taskId].data[4] / 2; gBattle_BG1_X = 0; }
This handles the scrolling of the background thus making the clouds move. No need for this if we didn’t load the graphics. Let’s comment it out as well.
There are a few other lines that can be removed if you are not going to use BG1. I won’t go into explaining them but you can search for them by searching for “BG1” in the file.
You should also comment out the following so the tiles and tilemap don’t get included into the ROM since we aren’t using them.
In “src\title_screen.c”
static const u32 sTitleScreenCloudsGfx[] = INCBIN_U32("graphics/title_screen/clouds.4bpp.lz");
In “src\graphics.c”
const u32 gUnknown_08DDE458[] = INCBIN_U32("graphics/title_screen/title_screen1.bin.lz");
In “include\graphics.h”
extern const u32 gUnknown_08DDE458[];
Let’s take a look at the title screen now.
Now let’s remove that yellow glowing effect on Rayquaza. Look for the following line of code.
UpdateLegendaryMarkingColor(gTasks[taskId].tCounter);
Commenting this out should get rid of the effect. You can even remove the function if you want.
Let’s look at the title screen again.
I think that’s all that most people would want to remove.
[/spoiler]
[spoiler title=”Changing The Background”]
I think most people won’t want to keep the Rayquaza background so let’s change that.
You can use any tilemap and tiles that you want for this as long as the dimensions work. I won’t go into editing these as there have been plenty of tutorials on this over the years.
I’m just going to use a tilemap from the intro. Put your files in “graphics\title_screen\” and edit the following lines accordingly.
In “src\title_screen.c”
static const u32 sTitleScreenRayquazaGfx[] = INCBIN_U32("graphics/title_screen/rayquaza.4bpp.lz"); static const u32 sTitleScreenRayquazaTilemap[] = INCBIN_U32("graphics/title_screen/rayquaza.bin.lz");
If you rename things, you should edit the following.
In “src\title_screen.c”
LoadPalette(gTitleScreenBgPalettes, 0, 0x1E0); LZ77UnCompVram(sTitleScreenRayquazaGfx, (void *)(VRAM + 0x8000)); LZ77UnCompVram(sTitleScreenRayquazaTilemap, (void *)(VRAM + 0xD000));
This is the code that that actually loads the graphics. Let’s look at the title screen again.
That looks good. If your colors look different, don’t forget to edit the palette used by your tilemap to use palette E.
[/spoiler]
[spoiler title=”Adding A Sprite To The Screen”]
If you’re like me, you’ll want to display a Pokemon on the title screen. To make things easy, I’ll just one of the Pokemon sprites already in the game.
I’ll add the following to “src\title_screen.c” near the top of the file where the other images are included.
const u32 gTest_Mon[] = INCBIN_U32("graphics/pokemon/anim_front_pics/charizard_front_pic.4bpp.lz"); const u32 gTestPal_Mon[] = INCBIN_U32("graphics/pokemon/palettes/charizard_palette.gbapal.lz");
I’ll also add the following near the top of the file where other things are defined. For me, I’m these things right before the code starts in the file.
static const struct CompressedSpriteSheet sSpriteSheet_Mon[] = { {gTest_Mon, 4096, 777}, {NULL}, }; static const struct CompressedSpritePalette sSpritePal_Mon[] = { {gTestPal_Mon, 777}, {NULL}, };
In this example the number “777” is the tag used for the sprite and pal. It is very important that this is different from the others in the file as the engine will use this tag to refer to these.
Next add the following:
static const struct OamData sMonOamData = { .y = 0, .affineMode = 0, .objMode = 0, .mosaic = 0, .bpp = 0, .shape = 0, .x = 0, .matrixNum = 0, .size = 3, .tileNum = 0, .priority = 0, .paletteNum = 0, .affineParam = 0, }; static const struct SpriteTemplate sMonSpriteTemplate = { .tileTag = 777, .paletteTag = 777, .oam = &sMonOamData, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy, };
For more information on the “OamData” please refer to TONC. These values should be fine for this example.
As for the “SpriteTemplate” we are only concerned with the following for now:
tileTag – The tag used to reference your tiles. Should be the same one used earlier.
paletteTag- The same as the above but for the palette.
oam – Should reference the OamData you declared.
Next we will need to load the data and show it on the screen.
Go to the function “CB2_InitTitleScreen” after the following code:
gReservedSpritePaletteCount = 9; LoadCompressedSpriteSheet(&sSpriteSheet_EmeraldVersion[0]); LoadCompressedSpriteSheet(&sSpriteSheet_PressStart[0]); LoadCompressedSpriteSheet(&sPokemonLogoShineSpriteSheet[0]); LoadPalette(gTitleScreenEmeraldVersionPal, 0x100, 0x20); LoadSpritePalette(&sSpritePalette_PressStart[0]);
Add the following right after that:
LoadCompressedSpriteSheet(sSpriteSheet_Mon); LoadCompressedSpritePalette(sSpritePal_Mon);
This will load the sprite and palette into memory but it still won’t show on the screen.
Look for the following code:
CreatePressStartBanner(START_BANNER_X, 108); CreateCopyrightBanner(START_BANNER_X, 148);
Add the following line right after:
CreateSprite(&sMonSpriteTemplate, 190, 110, 0);
The following are the parameters for CreateSprite:
CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority)
At this point the sprite should show up on the screen. Let’s take a look.
[/spoiler]
[spoiler title=”Adding A Cry”]
One might also want to add a cry to the title screen. I personally want it once you press Start on the title screen.
Look for the following code:
if ((gMain.newKeys & A_BUTTON) || (gMain.newKeys & START_BUTTON)) { FadeOutBGM(4); BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0xFFFF); SetMainCallback2(CB2_GoToMainMenu); }
Add the following before “FadeOutBGM(4);”:
PlayCryInternal(SPECIES_CHARIZARD, 0, 120, 10, 0);
Also, in order to use “SPECIES_CHARIZARD”, you will need to add the following to the top of the file:
#include "constants/species.h"
If you try the ROM now, you should hear the cry on the title screen when you press Start or A.
[/spoiler]
[spoiler title=”Animating The Sprite”]
One of the reasons that I wanted to use the default Charizard sprite is so that I could animate it easily.
Add the following above where you declared your OamData:
static const union AnimCmd smon_Anim1[] = { ANIMCMD_FRAME(0, 30), ANIMCMD_FRAME(64, 30), ANIMCMD_JUMP(0), }; static const union AnimCmd *const smon_AnimTable[] = { smon_Anim1, };
This will animate your sprite by switching between frames. For “ANIMCMD_FRAME” the first parameter is where the sprite frame begins and the second is the duration.
You’ll also want to reference this table in the OamData by updating “anims”.
.anims = smon_AnimTable,
If we look at the title screen, it should now be animated.
[/spoiler]
[spoiler title=”Using a Callback”]
Callbacks can be attached to each sprite to do different things. You can set a function as a callback and it will run every frame. In this example I will make the sprite go invisible every 60 frames to create kind of a weird effect with Charizard. This is not the best example, but should get the point across.
Add the following function in the code:
static void SpriteCB_Mon(struct Sprite *sprite) { sprite->data[2]++; if (sprite->data[2] & 0x3C) { sprite->invisible = FALSE; } else { sprite->invisible = TRUE; } }
Declare the function at the top of the file:
static void SpriteCB_Mon(struct Sprite *sprite);
You’ll also want to reference this function in the OamData by updating “callback”.
.callback = SpriteCB_Mon,
Then if you check your titlescreen, you should see this added effect.
[/spoiler]
Code for this tutorial is available here: https://github.com/Gamer2020/TitleScreenTutorial
Hopefully this will help some people out!