- 12
- Posts
- 1
- Years
- Seen Dec 31, 2023
Hello everyone, how are you? First of all, I apologize for my English, I used google translator. If something is not easy to understand, you can comment below.
I recently ported the Costume Menu originally created by Slawter666 (original post) to the RHH Pokemon Expansion. When he developed this in 2018, the decomp was still not 100% which made things a bit difficult for him.
The code can be viewed and pull on my GitHub branch: (link)
As soon as I make the video, I'll add it here. For now, watch the creator's old video.
I managed to resolve 99% of the conflicts and after understanding the logic a little, I made the menu work with the Expansion. The menu is unfinished, missing some things that I don't know how to add, my level of programming in C language is very basic and a lot of the logic used in the decomp and creation of the menu I have no idea.
For this to work, I added the overworld expansion (ghoulslash) and the dynamic palettes (latest: ExpoSeed) to the code, but I also have some errors in this.
After 5 years of its creation, a madman from the other side of the world, with no experience in programming, decided to tinker with this creation, ME.
I'm reviving this project for the community as a way to complete it. The ideas from a Costume Menu are many, here are some suggestions for use:
I managed to finalize some things that the original creator hadn't done yet. Below is a list of the changes I chose to make:
- Slawter666 had added a lot of sprites from other generations, I chose to remove them and leave only the emerald ones and some punctual ones (9 protagonists, team rocket, giovanni, prof Oak);
- The code in "player_field_avatar" modified a lot of original things, to avoid the maximum of conflicts I decided to keep the original of the expansion and make only a few necessary changes;
- The original menu keeps SaveBlock2Ptr->playergender and adds SaveBlock2Ptr->custome, I decided to keep it the same as the menu creator, but I suspect some bugs, if someone manages to change "costume_menu.c" to use SaveBlock2Ptr->playergender and keep gender (male/famale) intact, I would like to revert it to avoid future merge conflicts and bugs that may appear. The more original the codebase is, the better;
- In the "field_move" images it was reducing to 4 frames instead of 5. I also decided to keep the original gen 3 game;
- He had no intention of creating sprites for underwatering, instead he would use bob generation along with the surfing sprite. I intend to create them just like the original game;
- Originally, it had the focus to change all sprites, including walking and running ones for gen 4 (from 16x32 to 32x32), I decided to keep the gen 3 style;
- He still hadn't added the back sprites in battles and the front sprites on the trainer card, corresponding to the clothes you are wearing. I managed to add this too;
- He also hadn't put sprites for decoration, the character's head icons on the map and cable car, I managed to do that.
This Costume Menu is far from finished and has enormous potential, so I'll gladly accept any help. I know that together we will be able to finalize it and make them available to everyone in the community and future members who will use them to create incredible pokemon hacks. I'll leave a video showing the current operation and the bug that I couldn't solve.
Here is the list of what still needs to be done in the base to make the minimum complete possible:
- There is an error loading the skin palette when you select it and close the menu. The colors appear changed, they stay with the color of the previous skin until you update the action in the overworld (open the menu again, enter the bag, the pokemon summary, in battle or change the map). I believe that some code is missing from the creator's original lines, that is, some incompatibility with the indexing of dynamic palettes together with changing the costumeId in the saveblock. I couldn't resolve this;
- It remains to change some codes that may affect the character's behavior, in the frontier battle for example, but I haven't tested it yet and I haven't seen those lines of code;
- The Slawter666 add field_move effect for selected costume, but I couldn't make it work for the 5 frame images. It is a very interesting detail and I would like to activate it. If anyone can fix this. To select the field_move, just go to "src\data\costume_menu\costumes.h" and change the character's ".fieldMove" to the correct one;
- The creation of a base script to release the skins. By test pattern, there is a line of code that Slawter666 left, I enabled it. When you filter by pressing select it releases all clothes. He also left the base lines in the "data\specials.inc" file but I haven't delved into scripts yet and I have no idea what would be needed in that part;
- Draw and add all sprites and code lines for each character. Brendan, May, Red, Leaf, Ethan and Lyra work 100%. Lucas are at 95% (upgrade field_move), and the rest, just have the walking sprite that the game itself provides or that was available in other xD codes. I'm terrible at drawing these images, I have a notion of changing them from the gale program (the back and front images I got from google and edited there) but for their creation, I'm a terrible artist. For example, I have no idea how to make Steven or Professor Birch riding an acro bike (there are 27 frames of 32x32 in this sprite).
This menu has the functionality to receive asymmetrical sprites.
Example Lyra: She only has a bow on her hat on the left side, so there is an image for the left side with the bow and an image for the right side without the bow. This applies to all movements. Tutorial in the comment below, on how to add asymmetric sprites in the game.
Here is the list of all base sprites that are still missing to complete the Costume Menu minimum and a definition of them:
Required Images: All images are in 4bpp - 16 colors. Motion pictures and decor need to share the same palette as sprite walking (underwater as a specific palette "OBJ_EVENT_PAL_TAG_PLAYER_UNDERWATER").
Example brendan: You can find almost all the templates in the "graphics\object_events\pics\people" folder. Back to "graphics\trainers\back_pics", front to "graphics\trainers\front_pics" and icon to "graphics\pokenav\region_map".
Normal Sprite
- walking - 16x32 - 9 frames - 144x32
- running - 16x32 - 9 frames - 144x32
- mach_bike - 32x32 - 9 frames - 288x32
- acro_bike - 32x32 - 27 frames - 864x32
- surfing - 32x32 - 6 frames - 192x32
- underwater - 32x32 - 4 frames - 128x32
- field_move - 32x32 - 9 frames - 160x32
- fishing - 32x32 - 9 frames - 384x32
- watering - 32x32 - 6 frames - 192x32
- decorating - 16x32 - 1 frame - 16x32
- Front - 64x64 - 1 frame - 64x64
- Back - 64x64 - 5 frames - 64x320
- Icon - 16x16 - 1 frame - 16x16
Asymmetric Sprite
- walking - 16x32 - 12 frames - 192x32
- running - 16x32 - 12 frames - 192x32
- mach_bike - 32x32 - 12 frames - 384x32
- acro_bike - 32x32 - 32 frames - 1024x32
- surfing - 32x32 - 8 frames - 256x32
- underwater - 32x32 - 4 frames - 128x32
- field_move - 32x32 - 9 frames - 160x32
- fishing - 32x32 - 16 frames - 512x32
- watering - 32x32 - 8 frames - 256x32
- decorating - 16x32 - 1 frame - 16x32
- Front - 64x64 - 1 frame - 64x64
- Back - 64x64 - 5 frames - 64x320
- Icon - 16x16 - 1 frame - 16x16
List of sprites needed:
Sprites / Status
Protagonists:
- Brendan - Complete;
- May - Complete;
- Red - Complete;
- Leaf - Complete;
- Ethan - Complete;
- Lyra - Complete;
- Krys - Missing: walking, running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
- Lucas - Upgrade field_move;
- Dawn - Missing: walking, running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
Rivals:
- Esteven - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
- Wally - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, and watering;
Teachers:
- Prof Birch - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, back and icon;
- Prof Oak - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, back and icon;
Teams:
- Rocket F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Rocket M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Giovanni - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Aqua F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Aqua M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Archie - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Magma F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Magma M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Maxie - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
Gym Leaders, Elite Four, Frontier Brains and more characters:
Initially I would not add them, but if an artist appears for them, I can create a separate branch with all the playable characters.
This is my first contribution to the community and I want to make it as complete as possible and with as little conflict as possible when merging. If you want to contribute to the project, your help is welcome. I want to make it clear that all credits for the original Menu go to Slawter666 (who knows, maybe one day he'll come back and find his creation finished, that would be awesome). Any sprite sent to contribute to the project will be given due credit to the creator of the art and anyone can use them.
I'll leave below a basic tutorial of what is needed to add new characters if you want to add new players to your projects and a basic sprite editing tutorial in Gale. Let's complete this together.
CHANGELOG
17/09 - Finish Ethan and Lyra Sprites;
15/09 - Add Ethan Sprites and Fix Lyra Sprites;
13/09 - Add Lyra sprite and finalized asymmetric sprites code;
CREDITS
SLAWTER66 - Initial codes of costume menu;
POKABBIE - inspiration from pokemon rogue codes to finish the costume menu and base sprite Ethan;
RichardPT and robloxmaster376 - Sprites base from DevianArt: Lucas, Lyra, Kris, Ethan;
Tutorial add new character with Costume Menu ( Mega Spoiler)
Below are all the files used to add a new character. From the base character, its movement, front and back, trainer card, icon on the map, cable car and decoration. I divided it into 4 categories:
1 - Add new character:
2 - Add front/back sprites;
3 - Bind the character in the custom menu;
4 - Trainer Card, Icon map, Cable Car and Decoration;
Location of images:
This is a base tutorial, you need to remember to replace the corresponding tutorial name with your character's name.
To expand the characters, you will need the overworld expansion.
For example, I'll use the lines of code as if I were adding the complete Wally:
First step, get all the necessary images mentioned above. It's kind of obvious but it doesn't hurt to remember. Put them in their respective folders or wherever you find it most convenient.
With the images in place, let's start by opening "include\constants\event_objects.h" and declaring a new definition for wally and its movements. Don't forget to change "NUM_OBJ_EVENT_GFX" to the last corresponding number in your list. By default there are 9 definitions:
Note: Wally walking already exists because it's part of the base game, it's number 135 in the list, and the race shares the same "OBJ_EVENT" so I won't add it to the list. In your case, don't forget to add and change the numbers for your current sequence. Example: if your "NUM_OBJ_EVENT_GFX" is 300, you add the movements from the number 300 and change "NUM_OBJ_EVENT_GFX" to the last number in the list.
Now in "src\data\object_events\object_event_graphics.h" let's add the 10 calls for the images and the palette:
Remembering that Wally already has the call for the walk, if it is a new character you can add it by copying the model and replacing the corresponding names and the correct path where your image is.
I chose to keep Wally walking in the game's original folder and create a folder called wally for the other sprites, thus avoiding some possible merge conflicts with other branches.
The next edit is in "src\data\object_events\object_event_graphics_info_pointers.h". Let's add the following lines:
Remembering that for my example, Wally is already in the game so I won't add the first line of code because it already exists. For your characters it is absolutely necessary. You already understand, I will not warn more.
and in the function "const struct ObjectEventGraphicsInfo *const gObjectEventGraphicsInfoPointers[NUM_OBJ_EVENT_GFX]" we will link the graphics with the definitions:
The next step is to go to the "src\data\object_events\object_event_pic_tables.h" file and add the animations. I'll leave the example code, but the easiest thing is to copy all of Brendan's or May's animations and then just replace the name with the one corresponding to your character:
Then open "src\event_object_movement.c" and enter wally's palette definition:
Do not change "OBJ_EVENT_PAL_TAG_NONE". Slawter666 used an "enun" function to add varios. both ways are right.
Add in the function "static const struct SpritePalette sObjectEventSpritePalettes[]" the following line:
Now let's go to "src\data\object_events\object_event_graphics_info.h" Where we will put everything together in character building. The game by default writes the information separately. I chose to keep the old way. If you want to change it, just copy the information and replace it in the correct places. Let's add the following code:
Let's now in "spritesheet_rules.mk" declare the direction to create the sprites that have animation. Decorating does not make this list. Add the following:
Note that for the walking and running sprites, you will use 2 and 4, for the others 4 and 4, because these two are 16x32 and the others 32x32.
Ready your new character is in the game ready (minimally) to be playable, being an npc or as a player.
----------------------------
Let's now complement it by adding the remainder. The tutorial character already has front and back images, but I'll exemplify with him.
For the front and back images:
Go to "include\constants\trainers.h" and make your settings in the listings. Always add to the last and don't forget to continue the sequence of numbers:
For the back_pic, I recommend writing it in the order you're going to use it in the custom menu as it affects the selection if it's changed. Ex: In the clothes menu red is 2 and leaf is 3, but the back_pic are numbered inverted, when you enter a battle with red, you will see leaf and the opposite is also valid.
Now let's go to "src\data\graphics\trainers.h" to add the images. The principle is the same as for the sprites we've added above, pay close attention to where you place your image and the name.
If you want to use an image with a different palette for the background, you can add the following line: const u32 gTrainerBackPicPalette_Wally[] = INCBIN_U32("graphics/trainers/back_pics/wally_back_pic.gbapal.lz");
Then, go to "include\graphics.h" and add the calls corresponding to the images:
In case of using a different palette for the background add the line:
extern const u32 gTrainerBackPicPalette_Wally[];
Now in "src\data\trainer_graphics\back_pic_anims.h" Add the background animation:
and in the function "const union AnimCmd *const *const gTrainerBackAnimsPtrTable[]" add the following line:
"sAnim_GeneralFrame" represents the initial image and then it will read the others. In the case of steven back, he has 4 frames of 64x64 and the last frame is the static one, so sAnim_GeneralFrame3 in it. If you use a 5-frame image, I recommend leaving the first frame to be the initial frame and using sAnim_GeneralFrame0 in the function.
"sAnimCmd_Wally_1" is the animation readout, you don't need to create one, unless your background sprite needs it, otherwise you can use it. I recommend "sAnimCmd_Wally_1" for 4 frame images and "sAnimCmd_Red_1" for 5 frame images.
Now in "src\data\trainer_graphics\back_pic_tables.h" we will have 3 additions. The first is the image size in the "const struct MonCoords gTrainerBackPicCoords" function:
use ".y_offset = 4" for 4 frame images and ".y_offset = 5" for 5 frame images.
Then in "const struct CompressedSpriteSheet gTrainerBackPicTable" Add:
And finally in the function "const struct CompressedSpritePalette gTrainerBackPicPaletteTable" put:
Here again, if you are using a separate palette for the back image, switch to the corresponding nomenclature. Example: "TRAINER_BACK_PAL(WALLY, gTrainerBackPicPalette_Wally),"
Now the fronts, go to "src\data\trainer_graphics\front_pic_anims.h" and add:
see that these functions are the same, so if you don't want to add, you can use any other instead in the next code. In the function "gTrainerFrontAnimsPtrTable"
Now in the file "src\data\trainer_graphics\front_pic_tables.h" let's add the size of the front image:
then in the "gTrainerFrontPicTable" function put this:
and finally in the function "gTrainerFrontPicPaletteTable" add:
our next file is "src\pokemon.c". let's add the image back to the battles. Look for the "sTrainerBackSpriteTemplates" function and put:
Now in "src\data.c" add:
If your back image has 5 frames, just add one more line, following the numbering. Ex: "gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 4, TRAINER_PIC_SIZE,".
then we go to "include\data.h" and add:
Done Now we have front and back images for our character.
----------------
Next step is to link our character to the clothing menu and make sure that when selecting it all movements and images come correctly.
Go to "include\constants\costumes.h" and add the new character definition to the costume menu:
Note: Pay close attention to this numbering, it needs to be the same as the back_pic and player_field_avatar that we will edit later.
Now in "src\data\costume_menu\costumes.h" let's add these lines:
Then let's add your name and description in "src\data\costume_menu\costume_descriptions.h" like this:
I used a google description for Wally, you can write whatever you want, just remembering to be a maximum of 3 lines of text and don't forget to use "\n" to skip lines. Also, don't make the text too big per line, otherwise it goes over the screen.
Now in "include\constants\global.h" let's add the character's style next to "PLAYER_STYLE_COUNT". Also change the "PLAYER_STYLE_COUNT" to the total numbering of styles:
mine was:
for:
The next changes are in "src\field_player_avatar.c". In the function "static const u16 sPlayerAvatarGfxIds[][PLAYER_STYLE_COUNT]" Let's add the "OBJ_EVENT_GFX" of each state. Just copy the last one of each and change the name. I'll only give an example of "PLAYER_AVATAR_STATE_NORMAL" but you do this in all states of the function:
Now in the function "static const u16 sPlayerAvatarGfxToStateFlag[PLAYER_STYLE_COUNT][5][2]" let's place the style call we defined:
now let's go to the function "u8 GetPlayerAvatarGenderByGraphicsId(u16 gfxId)" write like this below the last case:
Okay, now you have your character in the menu and can change your clothes for the overworld.
------------------
Small details still need to be resolved, such as the trainer's card, the icon on the map and the decoration sprite.
For the Trainer Card:
Let's go back to "include\constants\trainers.h" and add the lines in Facility:
"0x3b" you change to your current sequence number.
Don't forget to change "#define FACILITY_CLASSES_COUNT" to your last number.
Now in "src\data\pokemon\trainer_class_lookups.h" add in the function "gFacilityClassToPicIndex" the following:
You can also add the following to the "gFacilityClassToTrainerClass" function:
Now in the file "src\trainer_card.c" let's make some changes. The first one is for the function "static const u8 sTrainerPicFacilityClass[PLAYER_STYLE_COUNT]" Add the following below the last one:
Now let's make the game read the correct background color depending on your character. As the menu is varied with characters in sequence, we need to tell him which character is a boy and which is a girl. In the function "static u8 SetCardBgsAndPals(void)" "case2:" the code "if (sData->trainerCard.gender != 0 ) is saying that if the gender of the trainer is different from 0 (this is the number of Style_Brendan, of Costume_brendan and male) it will load the female palette. If you are using Brendan, he will notice that the function is == 0 and will return the blue background card. With this logic, if your character is a girl, no need to add anything. If he is a boy, add an "if (sData->trainerCard.gender != 0 )" and change the number "0" by the number of your character. You have to add it to both parts of case 2. In mine In this case, Wally is 10, so the total function looks like this:
The logic is repeated for the functions "TrainerCard_GenerateCardForPlayer" and "TrainerCard_GenerateCardForLinkPlayer". But here you will only add if your character is a girl. I'll leave the base model here and you can do it in both roles, if your character is a girl. In my case I didn't need to add.
With that the trainer card is working according to your new character.
Now let's go to the map icon. Everything is done in "src\region_map.c"
The first step is to add the call to the icon sprite, add the following in sequence:
in the function "CreateRegionMapPlayerIcon" Activate this in sequence:
Your character's icon will now appear correctly.
For Sprite in cable car, go to "src\cable_car.c", in function "playerGraphicsIds" and add:
Finally, we have to fix the decoration spryte. Go to "src\decoration.c", in the "SetUpPlacingDecorationPlayerAvatar" function and add the following to the else if sequence:
Now in the "SetUpPuttingAwayDecorationPlayerAvatar" function we do the same addition logic by putting the following:
Okay, now your character is complete in the game, just enjoy it.
PS: it's my first oficial post. I don't know how to use the blog tools yet. I promise to edit this post and add more color and functions.
I recently ported the Costume Menu originally created by Slawter666 (original post) to the RHH Pokemon Expansion. When he developed this in 2018, the decomp was still not 100% which made things a bit difficult for him.
The code can be viewed and pull on my GitHub branch: (link)
As soon as I make the video, I'll add it here. For now, watch the creator's old video.
![[PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion [PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion](https://i.imgur.com/9l0UAVd.png)
I managed to resolve 99% of the conflicts and after understanding the logic a little, I made the menu work with the Expansion. The menu is unfinished, missing some things that I don't know how to add, my level of programming in C language is very basic and a lot of the logic used in the decomp and creation of the menu I have no idea.
For this to work, I added the overworld expansion (ghoulslash) and the dynamic palettes (latest: ExpoSeed) to the code, but I also have some errors in this.
After 5 years of its creation, a madman from the other side of the world, with no experience in programming, decided to tinker with this creation, ME.
I'm reviving this project for the community as a way to complete it. The ideas from a Costume Menu are many, here are some suggestions for use:
Spoiler:
- Integrates it with a quest menu to gain the character's skin after completing a specific quest;
- Win the character's skin after defeating him in the game. (Archie and Maxxie for example);
- Place the npcs on the map to activate the quest. (example: Add Ethan to a part of rustboro saying that he is visiting the city looking for some berries for his mother and that he needs 20 orans berries for her. When you deliver, you release your skin and you can play normally with him.)
- Free access to certain places with a specific skin. (QG team aqua with member team aqua clothing);
- Place a lost aqua member on the map that in case you win you release your skin and can now go through the aqua team without battling if you are using the skin;
- Release a higher rate of encounters of pokemons of a certain type with a specific outfit. (this one is pretty complex for me, but it's still an idea);
- And many more ideas that your mind creates;
- Win the character's skin after defeating him in the game. (Archie and Maxxie for example);
- Place the npcs on the map to activate the quest. (example: Add Ethan to a part of rustboro saying that he is visiting the city looking for some berries for his mother and that he needs 20 orans berries for her. When you deliver, you release your skin and you can play normally with him.)
- Free access to certain places with a specific skin. (QG team aqua with member team aqua clothing);
- Place a lost aqua member on the map that in case you win you release your skin and can now go through the aqua team without battling if you are using the skin;
- Release a higher rate of encounters of pokemons of a certain type with a specific outfit. (this one is pretty complex for me, but it's still an idea);
- And many more ideas that your mind creates;
I managed to finalize some things that the original creator hadn't done yet. Below is a list of the changes I chose to make:
Spoiler:
- Slawter666 had added a lot of sprites from other generations, I chose to remove them and leave only the emerald ones and some punctual ones (9 protagonists, team rocket, giovanni, prof Oak);
- The code in "player_field_avatar" modified a lot of original things, to avoid the maximum of conflicts I decided to keep the original of the expansion and make only a few necessary changes;
- The original menu keeps SaveBlock2Ptr->playergender and adds SaveBlock2Ptr->custome, I decided to keep it the same as the menu creator, but I suspect some bugs, if someone manages to change "costume_menu.c" to use SaveBlock2Ptr->playergender and keep gender (male/famale) intact, I would like to revert it to avoid future merge conflicts and bugs that may appear. The more original the codebase is, the better;
- In the "field_move" images it was reducing to 4 frames instead of 5. I also decided to keep the original gen 3 game;
- He had no intention of creating sprites for underwatering, instead he would use bob generation along with the surfing sprite. I intend to create them just like the original game;
- Originally, it had the focus to change all sprites, including walking and running ones for gen 4 (from 16x32 to 32x32), I decided to keep the gen 3 style;
- He still hadn't added the back sprites in battles and the front sprites on the trainer card, corresponding to the clothes you are wearing. I managed to add this too;
- He also hadn't put sprites for decoration, the character's head icons on the map and cable car, I managed to do that.
This Costume Menu is far from finished and has enormous potential, so I'll gladly accept any help. I know that together we will be able to finalize it and make them available to everyone in the community and future members who will use them to create incredible pokemon hacks. I'll leave a video showing the current operation and the bug that I couldn't solve.
Here is the list of what still needs to be done in the base to make the minimum complete possible:
Spoiler:
- There is an error loading the skin palette when you select it and close the menu. The colors appear changed, they stay with the color of the previous skin until you update the action in the overworld (open the menu again, enter the bag, the pokemon summary, in battle or change the map). I believe that some code is missing from the creator's original lines, that is, some incompatibility with the indexing of dynamic palettes together with changing the costumeId in the saveblock. I couldn't resolve this;
- It remains to change some codes that may affect the character's behavior, in the frontier battle for example, but I haven't tested it yet and I haven't seen those lines of code;
- The Slawter666 add field_move effect for selected costume, but I couldn't make it work for the 5 frame images. It is a very interesting detail and I would like to activate it. If anyone can fix this. To select the field_move, just go to "src\data\costume_menu\costumes.h" and change the character's ".fieldMove" to the correct one;
- The creation of a base script to release the skins. By test pattern, there is a line of code that Slawter666 left, I enabled it. When you filter by pressing select it releases all clothes. He also left the base lines in the "data\specials.inc" file but I haven't delved into scripts yet and I have no idea what would be needed in that part;
- Draw and add all sprites and code lines for each character. Brendan, May, Red, Leaf, Ethan and Lyra work 100%. Lucas are at 95% (upgrade field_move), and the rest, just have the walking sprite that the game itself provides or that was available in other xD codes. I'm terrible at drawing these images, I have a notion of changing them from the gale program (the back and front images I got from google and edited there) but for their creation, I'm a terrible artist. For example, I have no idea how to make Steven or Professor Birch riding an acro bike (there are 27 frames of 32x32 in this sprite).
This menu has the functionality to receive asymmetrical sprites.
Example Lyra: She only has a bow on her hat on the left side, so there is an image for the left side with the bow and an image for the right side without the bow. This applies to all movements. Tutorial in the comment below, on how to add asymmetric sprites in the game.
![[PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion [PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion](https://i.imgur.com/OfQALCM.png)
![[PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion [PokeCommunity.com] Costume Menu by Slawter666 in the RHH Pokémon Expansion](https://i.imgur.com/zbxWn86.png)
Here is the list of all base sprites that are still missing to complete the Costume Menu minimum and a definition of them:
Spoiler:
Required Images: All images are in 4bpp - 16 colors. Motion pictures and decor need to share the same palette as sprite walking (underwater as a specific palette "OBJ_EVENT_PAL_TAG_PLAYER_UNDERWATER").
Example brendan: You can find almost all the templates in the "graphics\object_events\pics\people" folder. Back to "graphics\trainers\back_pics", front to "graphics\trainers\front_pics" and icon to "graphics\pokenav\region_map".
Normal Sprite
- walking - 16x32 - 9 frames - 144x32
- running - 16x32 - 9 frames - 144x32
- mach_bike - 32x32 - 9 frames - 288x32
- acro_bike - 32x32 - 27 frames - 864x32
- surfing - 32x32 - 6 frames - 192x32
- underwater - 32x32 - 4 frames - 128x32
- field_move - 32x32 - 9 frames - 160x32
- fishing - 32x32 - 9 frames - 384x32
- watering - 32x32 - 6 frames - 192x32
- decorating - 16x32 - 1 frame - 16x32
- Front - 64x64 - 1 frame - 64x64
- Back - 64x64 - 5 frames - 64x320
- Icon - 16x16 - 1 frame - 16x16
Asymmetric Sprite
- walking - 16x32 - 12 frames - 192x32
- running - 16x32 - 12 frames - 192x32
- mach_bike - 32x32 - 12 frames - 384x32
- acro_bike - 32x32 - 32 frames - 1024x32
- surfing - 32x32 - 8 frames - 256x32
- underwater - 32x32 - 4 frames - 128x32
- field_move - 32x32 - 9 frames - 160x32
- fishing - 32x32 - 16 frames - 512x32
- watering - 32x32 - 8 frames - 256x32
- decorating - 16x32 - 1 frame - 16x32
- Front - 64x64 - 1 frame - 64x64
- Back - 64x64 - 5 frames - 64x320
- Icon - 16x16 - 1 frame - 16x16
List of sprites needed:
Sprites / Status
Protagonists:
- Brendan - Complete;
- May - Complete;
- Red - Complete;
- Leaf - Complete;
- Ethan - Complete;
- Lyra - Complete;
- Krys - Missing: walking, running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
- Lucas - Upgrade field_move;
- Dawn - Missing: walking, running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
Rivals:
- Esteven - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating and icon;
- Wally - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, and watering;
Teachers:
- Prof Birch - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, back and icon;
- Prof Oak - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, back and icon;
Teams:
- Rocket F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Rocket M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Giovanni - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Aqua F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Aqua M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Archie - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Magma F - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Member Magma M - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
- Maxie - Missing: running, mach_bike, acro_bike, surfing, underwater, field_move, fishing, watering, decorating, front, back and icon;
Gym Leaders, Elite Four, Frontier Brains and more characters:
Initially I would not add them, but if an artist appears for them, I can create a separate branch with all the playable characters.
This is my first contribution to the community and I want to make it as complete as possible and with as little conflict as possible when merging. If you want to contribute to the project, your help is welcome. I want to make it clear that all credits for the original Menu go to Slawter666 (who knows, maybe one day he'll come back and find his creation finished, that would be awesome). Any sprite sent to contribute to the project will be given due credit to the creator of the art and anyone can use them.
I'll leave below a basic tutorial of what is needed to add new characters if you want to add new players to your projects and a basic sprite editing tutorial in Gale. Let's complete this together.
CHANGELOG
Spoiler:
17/09 - Finish Ethan and Lyra Sprites;
15/09 - Add Ethan Sprites and Fix Lyra Sprites;
13/09 - Add Lyra sprite and finalized asymmetric sprites code;
CREDITS
Spoiler:
SLAWTER66 - Initial codes of costume menu;
POKABBIE - inspiration from pokemon rogue codes to finish the costume menu and base sprite Ethan;
RichardPT and robloxmaster376 - Sprites base from DevianArt: Lucas, Lyra, Kris, Ethan;
Tutorial add new character with Costume Menu ( Mega Spoiler)
Spoiler:
Below are all the files used to add a new character. From the base character, its movement, front and back, trainer card, icon on the map, cable car and decoration. I divided it into 4 categories:
1 - Add new character:
Spoiler:
- include\constants\event_objects.h
- src\data\object_events\object_event_graphics.h
- src\data\object_events\object_event_graphics_info_pointers.h
- src\data\object_events\object_event_pic_tables.h
- src\data\object_events\object_event_graphics_info.h
- src\event_object_movement.c
- src\data\object_events\object_event_graphics_info.h
- spritesheet_rules.mk
- src\data\object_events\object_event_graphics.h
- src\data\object_events\object_event_graphics_info_pointers.h
- src\data\object_events\object_event_pic_tables.h
- src\data\object_events\object_event_graphics_info.h
- src\event_object_movement.c
- src\data\object_events\object_event_graphics_info.h
- spritesheet_rules.mk
2 - Add front/back sprites;
Spoiler:
- include\constants\trainers.h
- src\data\graphics\trainers.h
- include\graphics.h
- src\data\trainer_graphics\back_pic_anims.h
- src\data\trainer_graphics\back_pic_tables.h
- src\data\trainer_graphics\front_pic_anims.h
- src\data\trainer_graphics\front_pic_tables.h
- src\pokemon.c
- src\data.c
- include\data.h
- src\data\graphics\trainers.h
- include\graphics.h
- src\data\trainer_graphics\back_pic_anims.h
- src\data\trainer_graphics\back_pic_tables.h
- src\data\trainer_graphics\front_pic_anims.h
- src\data\trainer_graphics\front_pic_tables.h
- src\pokemon.c
- src\data.c
- include\data.h
3 - Bind the character in the custom menu;
Spoiler:
- include\constants\costumes.h
- src\data\costume_menu\costumes.h
- src\data\costume_menu\costume_descriptions.h
- include\constants\global.h
- src\field_player_avatar.c
- src\data\costume_menu\costumes.h
- src\data\costume_menu\costume_descriptions.h
- include\constants\global.h
- src\field_player_avatar.c
4 - Trainer Card, Icon map, Cable Car and Decoration;
Spoiler:
- include\constants\trainers.h
- src\data\pokemon\trainer_class_lookups.h
- src\trainer_card.c
- src\region_map.c
-src\cable_car.c
- src\decoration.c
- src\data\pokemon\trainer_class_lookups.h
- src\trainer_card.c
- src\region_map.c
-src\cable_car.c
- src\decoration.c
Location of images:
Spoiler:
Icon: "graphics\pokenav\region_map"
Front: "graphics\trainers\front_pics"
Back: "graphics\trainers\back_pics"
Other Moves: "graphics\object_events\pics\people"
Front: "graphics\trainers\front_pics"
Back: "graphics\trainers\back_pics"
Other Moves: "graphics\object_events\pics\people"
This is a base tutorial, you need to remember to replace the corresponding tutorial name with your character's name.
To expand the characters, you will need the overworld expansion.
For example, I'll use the lines of code as if I were adding the complete Wally:
First step, get all the necessary images mentioned above. It's kind of obvious but it doesn't hurt to remember. Put them in their respective folders or wherever you find it most convenient.
With the images in place, let's start by opening "include\constants\event_objects.h" and declaring a new definition for wally and its movements. Don't forget to change "NUM_OBJ_EVENT_GFX" to the last corresponding number in your list. By default there are 9 definitions:
Spoiler:
Code:
// Wally
#define OBJ_EVENT_GFX_WALLY 299
#define OBJ_EVENT_GFX_WALLY_MACH_BIKE 300
#define OBJ_EVENT_GFX_WALLY_ACRO_BIKE 301
#define OBJ_EVENT_GFX_WALLY_SURFING 302
#define OBJ_EVENT_GFX_WALLY_UNDERWATER 303
#define OBJ_EVENT_GFX_WALLY_FIELD_MOVE 304
#define OBJ_EVENT_GFX_WALLY_FISHING 305
#define OBJ_EVENT_GFX_WALLY_WATERING 306
#define OBJ_EVENT_GFX_WALLY_DECORATING 307
Note: Wally walking already exists because it's part of the base game, it's number 135 in the list, and the race shares the same "OBJ_EVENT" so I won't add it to the list. In your case, don't forget to add and change the numbers for your current sequence. Example: if your "NUM_OBJ_EVENT_GFX" is 300, you add the movements from the number 300 and change "NUM_OBJ_EVENT_GFX" to the last number in the list.
Now in "src\data\object_events\object_event_graphics.h" let's add the 10 calls for the images and the palette:
Spoiler:
//Wally
const u32 gObjectEventPic_Wally[] = INCBIN_U32("graphics/object_events/pics/people/wally.4bpp");
const u32 gObjectEventPic_WallyRunning[] = INCBIN_U32("graphics/object_events/pics/people/wally/running.4bpp");
const u32 gObjectEventPic_WallyMachBike[] = INCBIN_U32("graphics/object_events/pics/people/wally/mach_bike.4bpp");
const u32 gObjectEventPic_WallyAcroBike[] = INCBIN_U32("graphics/object_events/pics/people/wally/acro_bike.4bpp");
const u32 gObjectEventPic_WallySurfing[] = INCBIN_U32("graphics/object_events/pics/people/wally/surfing.4bpp");
const u32 gObjectEventPic_WallyUnderwater[] = INCBIN_U32("graphics/object_events/pics/people/wally/underwater.4bpp");
const u32 gObjectEventPic_WallyFieldMove[] = INCBIN_U32("graphics/object_events/pics/people/wally/field_move.4bpp");
const u32 gObjectEventPic_WallyFishing[] = INCBIN_U32("graphics/object_events/pics/people/wally/fishing.4bpp");
const u32 gObjectEventPic_WallyWatering[] = INCBIN_U32("graphics/object_events/pics/people/wally/watering.4bpp");
const u32 gObjectEventPic_WallyDecorating[] = INCBIN_U32("graphics/object_events/pics/people/wally/decorating.4bpp");
const u16 gObjectEventPal_Wally[] = INCBIN_U16("graphics/object_events/pics/people/wally.gbapal");
const u32 gObjectEventPic_Wally[] = INCBIN_U32("graphics/object_events/pics/people/wally.4bpp");
const u32 gObjectEventPic_WallyRunning[] = INCBIN_U32("graphics/object_events/pics/people/wally/running.4bpp");
const u32 gObjectEventPic_WallyMachBike[] = INCBIN_U32("graphics/object_events/pics/people/wally/mach_bike.4bpp");
const u32 gObjectEventPic_WallyAcroBike[] = INCBIN_U32("graphics/object_events/pics/people/wally/acro_bike.4bpp");
const u32 gObjectEventPic_WallySurfing[] = INCBIN_U32("graphics/object_events/pics/people/wally/surfing.4bpp");
const u32 gObjectEventPic_WallyUnderwater[] = INCBIN_U32("graphics/object_events/pics/people/wally/underwater.4bpp");
const u32 gObjectEventPic_WallyFieldMove[] = INCBIN_U32("graphics/object_events/pics/people/wally/field_move.4bpp");
const u32 gObjectEventPic_WallyFishing[] = INCBIN_U32("graphics/object_events/pics/people/wally/fishing.4bpp");
const u32 gObjectEventPic_WallyWatering[] = INCBIN_U32("graphics/object_events/pics/people/wally/watering.4bpp");
const u32 gObjectEventPic_WallyDecorating[] = INCBIN_U32("graphics/object_events/pics/people/wally/decorating.4bpp");
const u16 gObjectEventPal_Wally[] = INCBIN_U16("graphics/object_events/pics/people/wally.gbapal");
Remembering that Wally already has the call for the walk, if it is a new character you can add it by copying the model and replacing the corresponding names and the correct path where your image is.
I chose to keep Wally walking in the game's original folder and create a folder called wally for the other sprites, thus avoiding some possible merge conflicts with other branches.
The next edit is in "src\data\object_events\object_event_graphics_info_pointers.h". Let's add the following lines:
Spoiler:
// Wally
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Wally;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyMachBike;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyAcroBike;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallySurfing;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyUnderwater;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFieldMove;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFishing;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyWatering;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyDecorating;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Wally;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyMachBike;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyAcroBike;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallySurfing;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyUnderwater;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFieldMove;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFishing;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyWatering;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyDecorating;
Remembering that for my example, Wally is already in the game so I won't add the first line of code because it already exists. For your characters it is absolutely necessary. You already understand, I will not warn more.
and in the function "const struct ObjectEventGraphicsInfo *const gObjectEventGraphicsInfoPointers[NUM_OBJ_EVENT_GFX]" we will link the graphics with the definitions:
Spoiler:
// Wally
[OBJ_EVENT_GFX_WALLY] = &gObjectEventGraphicsInfo_Wally,
[OBJ_EVENT_GFX_WALLY_MACH_BIKE] = &gObjectEventGraphicsInfo_WallyMachBike,
[OBJ_EVENT_GFX_WALLY_ACRO_BIKE] = &gObjectEventGraphicsInfo_WallyAcroBike,
[OBJ_EVENT_GFX_WALLY_SURFING] = &gObjectEventGraphicsInfo_WallySurfing,
[OBJ_EVENT_GFX_WALLY_UNDERWATER] = &gObjectEventGraphicsInfo_WallyUnderwater,
[OBJ_EVENT_GFX_WALLY_FIELD_MOVE] = &gObjectEventGraphicsInfo_WallyFieldMove,
[OBJ_EVENT_GFX_WALLY_FISHING] = &gObjectEventGraphicsInfo_WallyFishing,
[OBJ_EVENT_GFX_WALLY_WATERING] = &gObjectEventGraphicsInfo_WallyWatering,
[OBJ_EVENT_GFX_WALLY_DECORATING] = &gObjectEventGraphicsInfo_WallyDecorating,
[OBJ_EVENT_GFX_WALLY] = &gObjectEventGraphicsInfo_Wally,
[OBJ_EVENT_GFX_WALLY_MACH_BIKE] = &gObjectEventGraphicsInfo_WallyMachBike,
[OBJ_EVENT_GFX_WALLY_ACRO_BIKE] = &gObjectEventGraphicsInfo_WallyAcroBike,
[OBJ_EVENT_GFX_WALLY_SURFING] = &gObjectEventGraphicsInfo_WallySurfing,
[OBJ_EVENT_GFX_WALLY_UNDERWATER] = &gObjectEventGraphicsInfo_WallyUnderwater,
[OBJ_EVENT_GFX_WALLY_FIELD_MOVE] = &gObjectEventGraphicsInfo_WallyFieldMove,
[OBJ_EVENT_GFX_WALLY_FISHING] = &gObjectEventGraphicsInfo_WallyFishing,
[OBJ_EVENT_GFX_WALLY_WATERING] = &gObjectEventGraphicsInfo_WallyWatering,
[OBJ_EVENT_GFX_WALLY_DECORATING] = &gObjectEventGraphicsInfo_WallyDecorating,
The next step is to go to the "src\data\object_events\object_event_pic_tables.h" file and add the animations. I'll leave the example code, but the easiest thing is to copy all of Brendan's or May's animations and then just replace the name with the one corresponding to your character:
Spoiler:
// Wally
static const struct SpriteFrameImage sPicTable_Wally[] = {
overworld_frame(gObjectEventPic_Wally, 2, 4, 0),
overworld_frame(gObjectEventPic_Wally, 2, 4, 1),
overworld_frame(gObjectEventPic_Wally, 2, 4, 2),
overworld_frame(gObjectEventPic_Wally, 2, 4, 3),
overworld_frame(gObjectEventPic_Wally, 2, 4, 4),
overworld_frame(gObjectEventPic_Wally, 2, 4, 5),
overworld_frame(gObjectEventPic_Wally, 2, 4, 6),
overworld_frame(gObjectEventPic_Wally, 2, 4, 7),
overworld_frame(gObjectEventPic_Wally, 2, 4, 8),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 0),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 1),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 2),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 3),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 4),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 5),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 6),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 7),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 8),
};
static const struct SpriteFrameImage sPicTable_WallyMachBike[] = {
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 8),
};
static const struct SpriteFrameImage sPicTable_WallyAcroBike[] = {
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 8),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 9),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 10),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 11),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 12),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 13),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 14),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 15),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 16),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 17),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 18),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 19),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 20),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 21),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 22),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 23),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 24),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 25),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 26),
};
static const struct SpriteFrameImage sPicTable_WallySurfing[] = {
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 1),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 3),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 5),
};
static const struct SpriteFrameImage sPicTable_WallyUnderwater[] = {
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
};
static const struct SpriteFrameImage sPicTable_WallyFieldMove[] = {
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 4),
};
static const struct SpriteFrameImage sPicTable_WallyFishing[] = {
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 8),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 9),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 10),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 11),
};
static const struct SpriteFrameImage sPicTable_WallyWatering[] = {
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 5),
};
static const struct SpriteFrameImage sPicTable_WallyDecorating[] = {
obj_frame_tiles(gObjectEventPic_WallyDecorating),
};
static const struct SpriteFrameImage sPicTable_Wally[] = {
overworld_frame(gObjectEventPic_Wally, 2, 4, 0),
overworld_frame(gObjectEventPic_Wally, 2, 4, 1),
overworld_frame(gObjectEventPic_Wally, 2, 4, 2),
overworld_frame(gObjectEventPic_Wally, 2, 4, 3),
overworld_frame(gObjectEventPic_Wally, 2, 4, 4),
overworld_frame(gObjectEventPic_Wally, 2, 4, 5),
overworld_frame(gObjectEventPic_Wally, 2, 4, 6),
overworld_frame(gObjectEventPic_Wally, 2, 4, 7),
overworld_frame(gObjectEventPic_Wally, 2, 4, 8),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 0),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 1),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 2),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 3),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 4),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 5),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 6),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 7),
overworld_frame(gObjectEventPic_WallyRunning, 2, 4, 8),
};
static const struct SpriteFrameImage sPicTable_WallyMachBike[] = {
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyMachBike, 4, 4, 8),
};
static const struct SpriteFrameImage sPicTable_WallyAcroBike[] = {
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 8),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 9),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 10),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 11),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 12),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 13),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 14),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 15),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 16),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 17),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 18),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 19),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 20),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 21),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 22),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 23),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 24),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 25),
overworld_frame(gObjectEventPic_WallyAcroBike, 4, 4, 26),
};
static const struct SpriteFrameImage sPicTable_WallySurfing[] = {
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 1),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 3),
overworld_frame(gObjectEventPic_WallySurfing, 4, 4, 5),
};
static const struct SpriteFrameImage sPicTable_WallyUnderwater[] = {
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyUnderwater, 4, 4, 2),
};
static const struct SpriteFrameImage sPicTable_WallyFieldMove[] = {
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyFieldMove, 4, 4, 4),
};
static const struct SpriteFrameImage sPicTable_WallyFishing[] = {
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 6),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 7),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 8),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 9),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 10),
overworld_frame(gObjectEventPic_WallyFishing, 4, 4, 11),
};
static const struct SpriteFrameImage sPicTable_WallyWatering[] = {
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 0),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 2),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 4),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 1),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 3),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 5),
overworld_frame(gObjectEventPic_WallyWatering, 4, 4, 5),
};
static const struct SpriteFrameImage sPicTable_WallyDecorating[] = {
obj_frame_tiles(gObjectEventPic_WallyDecorating),
};
Then open "src\event_object_movement.c" and enter wally's palette definition:
Code:
#define OBJ_EVENT_PAL_WALLY 0x1125
Add in the function "static const struct SpritePalette sObjectEventSpritePalettes[]" the following line:
Code:
{gObjectEventPal_Wally, OBJ_EVENT_PAL_WALLY},
Now let's go to "src\data\object_events\object_event_graphics_info.h" Where we will put everything together in character building. The game by default writes the information separately. I chose to keep the old way. If you want to change it, just copy the information and replace it in the correct places. Let's add the following code:
Spoiler:
//Wally
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Wally = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 16, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x32, sOamTables_16x32, sAnimTable_WalkRun, sPicTable_Wally, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyMachBike = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_BIKE_TIRE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyMachBike, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyAcroBike = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_BIKE_TIRE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_AcroBike, sPicTable_WallyAcroBike, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallySurfing = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, TRUE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Surfing, sPicTable_WallySurfing, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyUnderwater = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, TRUE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyUnderwater, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFieldMove = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_FieldMove, sPicTable_WallyFieldMove, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFishing = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Fishing, sPicTable_WallyFishing, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyWatering = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyWatering, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyDecorating = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 256, 16, 32,10, SHADOW_SIZE_M, TRUE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x32, sOamTables_16x32, sAnimTable_Inanimate, sPicTable_WallyDecorating, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Wally = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 16, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x32, sOamTables_16x32, sAnimTable_WalkRun, sPicTable_Wally, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyMachBike = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_BIKE_TIRE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyMachBike, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyAcroBike = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_BIKE_TIRE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_AcroBike, sPicTable_WallyAcroBike, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallySurfing = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, TRUE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Surfing, sPicTable_WallySurfing, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyUnderwater = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, TRUE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyUnderwater, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFieldMove = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_FieldMove, sPicTable_WallyFieldMove, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyFishing = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Fishing, sPicTable_WallyFishing, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyWatering = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 512, 32, 32, 0, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Standard, sPicTable_WallyWatering, gDummySpriteAffineAnimTable};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_WallyDecorating = {TAG_NONE, OBJ_EVENT_PAL_WALLY, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 256, 16, 32,10, SHADOW_SIZE_M, TRUE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x32, sOamTables_16x32, sAnimTable_Inanimate, sPicTable_WallyDecorating, gDummySpriteAffineAnimTable};
Let's now in "spritesheet_rules.mk" declare the direction to create the sprites that have animation. Decorating does not make this list. Add the following:
Spoiler:
# Wally
$(OBJEVENTGFXDIR)/people/wally/walking.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/running.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/mach_bike.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/acro_bike.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/surfing.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/underwater.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/field_move.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/fishing.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/watering.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/walking.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/running.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/mach_bike.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/acro_bike.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/surfing.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/underwater.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/field_move.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/fishing.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/people/wally/watering.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
Note that for the walking and running sprites, you will use 2 and 4, for the others 4 and 4, because these two are 16x32 and the others 32x32.
Ready your new character is in the game ready (minimally) to be playable, being an npc or as a player.
----------------------------
Let's now complement it by adding the remainder. The tutorial character already has front and back images, but I'll exemplify with him.
For the front and back images:
Go to "include\constants\trainers.h" and make your settings in the listings. Always add to the last and don't forget to continue the sequence of numbers:
Code:
#define TRAINER_PIC_WALLY 70
Code:
#define TRAINER_BACK_PIC_WALLY 10
Now let's go to "src\data\graphics\trainers.h" to add the images. The principle is the same as for the sprites we've added above, pay close attention to where you place your image and the name.
Spoiler:
const u32 gTrainerFrontPic_Wally[] = INCBIN_U32 ("graphics/trainers/front_pics/wally.4bpp.lz");
const u32 gTrainerPalette_Wally[] = INCBIN_U32 ("graphics/trainers/front_pics/wally.gbapal.lz");
const u8 gTrainerBackPic_Wally[] = INCBIN_U8 ("graphics/trainers/back_pics/wally.4bpp");
const u32 gTrainerPalette_Wally[] = INCBIN_U32 ("graphics/trainers/front_pics/wally.gbapal.lz");
const u8 gTrainerBackPic_Wally[] = INCBIN_U8 ("graphics/trainers/back_pics/wally.4bpp");
If you want to use an image with a different palette for the background, you can add the following line: const u32 gTrainerBackPicPalette_Wally[] = INCBIN_U32("graphics/trainers/back_pics/wally_back_pic.gbapal.lz");
Then, go to "include\graphics.h" and add the calls corresponding to the images:
Spoiler:
extern const u32 gTrainerFrontPic_Wally[];
extern const u32 gTrainerPalette_Wally[];
extern const u8 gTrainerBackPic_Wally[];
extern const u32 gTrainerPalette_Wally[];
extern const u8 gTrainerBackPic_Wally[];
In case of using a different palette for the background add the line:
extern const u32 gTrainerBackPicPalette_Wally[];
Now in "src\data\trainer_graphics\back_pic_anims.h" Add the background animation:
Code:
static const union AnimCmd *const sBackAnims_Wally[] =
{
sAnim_GeneralFrame3,
sAnimCmd_Wally_1,
};
Code:
[TRAINER_BACK_PIC_WALLY] = sBackAnims_Wally,
"sAnimCmd_Wally_1" is the animation readout, you don't need to create one, unless your background sprite needs it, otherwise you can use it. I recommend "sAnimCmd_Wally_1" for 4 frame images and "sAnimCmd_Red_1" for 5 frame images.
Now in "src\data\trainer_graphics\back_pic_tables.h" we will have 3 additions. The first is the image size in the "const struct MonCoords gTrainerBackPicCoords" function:
Code:
[TRAINER_BACK_PIC_WALLY] = {.size = 8, .y_offset = 4},
Then in "const struct CompressedSpriteSheet gTrainerBackPicTable" Add:
Code:
[TRAINER_BACK_PIC_WALLY] = {
.data = (const u32 *)gTrainerBackPic_Wally,
.size = TRAINER_PIC_SIZE * ARRAY_COUNT(gTrainerBackPicTable_Wally),
.tag = TRAINER_BACK_PIC_WALLY,
And finally in the function "const struct CompressedSpritePalette gTrainerBackPicPaletteTable" put:
Code:
TRAINER_BACK_PAL(WALLY, gTrainerPalette_Wally),
Now the fronts, go to "src\data\trainer_graphics\front_pic_anims.h" and add:
Code:
static const union AnimCmd *const sAnims_Wally[] ={
sAnim_GeneralFrame0,
};
Code:
[TRAINER_PIC_WALLY] = sAnims_Wally,
Code:
[TRAINER_PIC_WALLY] = {.size = 8, .y_offset = 1},
Code:
TRAINER_SPRITE(WALLY, gTrainerFrontPic_Wally, TRAINER_PIC_SIZE),
Code:
TRAINER_PAL(WALLY, gTrainerPalette_Wally),
Spoiler:
[TRAINER_BACK_PIC_WALLY] = {
.tileTag = TAG_NONE,
.paletteTag = 0,
.oam = &gOamData_BattleSpritePlayerSide,
.anims = NULL,
.images = gTrainerBackPicTable_Wally,
.affineAnims = gAffineAnims_BattleSpritePlayerSide,
.callback = SpriteCB_BattleSpriteStartSlideLeft,
},
.tileTag = TAG_NONE,
.paletteTag = 0,
.oam = &gOamData_BattleSpritePlayerSide,
.anims = NULL,
.images = gTrainerBackPicTable_Wally,
.affineAnims = gAffineAnims_BattleSpritePlayerSide,
.callback = SpriteCB_BattleSpriteStartSlideLeft,
},
Now in "src\data.c" add:
Spoiler:
const struct SpriteFrameImage gTrainerBackPicTable_Wally[] =
{
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 0, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 1, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 2, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 3, TRAINER_PIC_SIZE,
};
{
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 0, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 1, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 2, TRAINER_PIC_SIZE,
gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 3, TRAINER_PIC_SIZE,
};
If your back image has 5 frames, just add one more line, following the numbering. Ex: "gTrainerBackPic_Wally + TRAINER_PIC_SIZE * 4, TRAINER_PIC_SIZE,".
then we go to "include\data.h" and add:
Code:
extern const struct SpriteFrameImage gTrainerBackPicTable_Wally[];
----------------
Next step is to link our character to the clothing menu and make sure that when selecting it all movements and images come correctly.
Go to "include\constants\costumes.h" and add the new character definition to the costume menu:
Code:
#define COSTUME_WALLY 10
Now in "src\data\costume_menu\costumes.h" let's add these lines:
Spoiler:
[COSTUME_WALLY] = {
.name = gText_CostumeName_Wally,
.gender = MALE,
.hidden = FALSE,
.description = gText_CostumeDescription_Wally,
.overworld = OBJ_EVENT_GFX_WALLY,
.fieldMove = OBJ_EVENT_GFX_WALLY,
.trainerFront = TRAINER_PIC_WALLY,
.trainerBack = TRAINER_BACK_PIC_WALLY,
},
.name = gText_CostumeName_Wally,
.gender = MALE,
.hidden = FALSE,
.description = gText_CostumeDescription_Wally,
.overworld = OBJ_EVENT_GFX_WALLY,
.fieldMove = OBJ_EVENT_GFX_WALLY,
.trainerFront = TRAINER_PIC_WALLY,
.trainerBack = TRAINER_BACK_PIC_WALLY,
},
Then let's add your name and description in "src\data\costume_menu\costume_descriptions.h" like this:
Code:
const u8 gText_CostumeName_Wally[] = _("Wally");
Code:
const u8 gText_CostumeDescription_Wally[] = _(
"Wally is sickly young boy who first appears\n"
"in Petalburg City, asking Norman, the Pe-\n"
"talburg Gym Leader, to help catch Pokémon.");
Now in "include\constants\global.h" let's add the character's style next to "PLAYER_STYLE_COUNT". Also change the "PLAYER_STYLE_COUNT" to the total numbering of styles:
mine was:
Code:
#define STYLE_STEVEN 9
#define PLAYER_STYLE_COUNT 10
Code:
#define STYLE_STEVEN 9
#define STYLE_WALLY 10
#define PLAYER_STYLE_COUNT 11
Spoiler:
[PLAYER_AVATAR_STATE_NORMAL] =
{
OBJ_EVENT_GFX_BRENDAN_NORMAL,
OBJ_EVENT_GFX_MAY_NORMAL,
OBJ_EVENT_GFX_RED,
OBJ_EVENT_GFX_LEAF,
OBJ_EVENT_GFX_ETHAN,
OBJ_EVENT_GFX_LYRA,
OBJ_EVENT_GFX_LUCAS,
OBJ_EVENT_GFX_DAWN,
OBJ_EVENT_GFX_KRIS,
OBJ_EVENT_GFX_STEVEN,
OBJ_EVENT_GFX_WALLY
},
{
OBJ_EVENT_GFX_BRENDAN_NORMAL,
OBJ_EVENT_GFX_MAY_NORMAL,
OBJ_EVENT_GFX_RED,
OBJ_EVENT_GFX_LEAF,
OBJ_EVENT_GFX_ETHAN,
OBJ_EVENT_GFX_LYRA,
OBJ_EVENT_GFX_LUCAS,
OBJ_EVENT_GFX_DAWN,
OBJ_EVENT_GFX_KRIS,
OBJ_EVENT_GFX_STEVEN,
OBJ_EVENT_GFX_WALLY
},
Now in the function "static const u16 sPlayerAvatarGfxToStateFlag[PLAYER_STYLE_COUNT][5][2]" let's place the style call we defined:
Spoiler:
[STYLE_WALLY] =
{
{OBJ_EVENT_GFX_WALLY, PLAYER_AVATAR_FLAG_ON_FOOT},
{OBJ_EVENT_GFX_WALLY_MACH_BIKE, PLAYER_AVATAR_FLAG_MACH_BIKE},
{OBJ_EVENT_GFX_WALLY_ACRO_BIKE, PLAYER_AVATAR_FLAG_ACRO_BIKE}, //acro
{OBJ_EVENT_GFX_WALLY_SURFING, PLAYER_AVATAR_FLAG_SURFING},
{OBJ_EVENT_GFX_WALLY_UNDERWATER, PLAYER_AVATAR_FLAG_UNDERWATER}, //underwater
},
{
{OBJ_EVENT_GFX_WALLY, PLAYER_AVATAR_FLAG_ON_FOOT},
{OBJ_EVENT_GFX_WALLY_MACH_BIKE, PLAYER_AVATAR_FLAG_MACH_BIKE},
{OBJ_EVENT_GFX_WALLY_ACRO_BIKE, PLAYER_AVATAR_FLAG_ACRO_BIKE}, //acro
{OBJ_EVENT_GFX_WALLY_SURFING, PLAYER_AVATAR_FLAG_SURFING},
{OBJ_EVENT_GFX_WALLY_UNDERWATER, PLAYER_AVATAR_FLAG_UNDERWATER}, //underwater
},
now let's go to the function "u8 GetPlayerAvatarGenderByGraphicsId(u16 gfxId)" write like this below the last case:
Spoiler:
case OBJ_EVENT_GFX_WALLY:
case OBJ_EVENT_GFX_WALLY_MACH_BIKE:
case OBJ_EVENT_GFX_WALLY_ACRO_BIKE:
case OBJ_EVENT_GFX_WALLY_SURFING:
case OBJ_EVENT_GFX_WALLY_FIELD_MOVE:
case OBJ_EVENT_GFX_WALLY_FISHING:
case OBJ_EVENT_GFX_WALLY_WATERING:
return STYLE_WALLY;
case OBJ_EVENT_GFX_WALLY_MACH_BIKE:
case OBJ_EVENT_GFX_WALLY_ACRO_BIKE:
case OBJ_EVENT_GFX_WALLY_SURFING:
case OBJ_EVENT_GFX_WALLY_FIELD_MOVE:
case OBJ_EVENT_GFX_WALLY_FISHING:
case OBJ_EVENT_GFX_WALLY_WATERING:
return STYLE_WALLY;
Okay, now you have your character in the menu and can change your clothes for the overworld.
------------------
Small details still need to be resolved, such as the trainer's card, the icon on the map and the decoration sprite.
For the Trainer Card:
Let's go back to "include\constants\trainers.h" and add the lines in Facility:
Code:
#define FACILITY_CLASS_WALLY 0x3b
Don't forget to change "#define FACILITY_CLASSES_COUNT" to your last number.
Now in "src\data\pokemon\trainer_class_lookups.h" add in the function "gFacilityClassToPicIndex" the following:
Code:
[FACILITY_CLASS_WALLY] = TRAINER_PIC_WALLY,
Code:
[FACILITY_CLASS_WALLY] = TRAINER_CLASS_RIVAL,
Now in the file "src\trainer_card.c" let's make some changes. The first one is for the function "static const u8 sTrainerPicFacilityClass[PLAYER_STYLE_COUNT]" Add the following below the last one:
Code:
[STYLE_WALLY] = FACILITY_CLASS_WALLY,
Spoiler:
case 2:
if (sData->cardType != CARD_TYPE_FRLG)
{
LoadPalette(sHoennTrainerCardPals[sData->trainerCard.stars], BG_PLTT_ID(0), 3 * PLTT_SIZE_4BPP);
LoadPalette(sHoennTrainerCardBadges_Pal, BG_PLTT_ID(3), PLTT_SIZE_4BPP);
if (sData->trainerCard.gender != 0 ) {
if (sData->trainerCard.gender != 2 ) {
if (sData->trainerCard.gender != 4 ) {
if (sData->trainerCard.gender != 6 ) {
if (sData->trainerCard.gender != 9 ) {
if (sData->trainerCard.gender != 10 )
LoadPalette(sHoennTrainerCardFemaleBg_Pal, BG_PLTT_ID(1), PLTT_SIZE_4BPP);
}}}}}
}
else
{
LoadPalette(sKantoTrainerCardPals[sData->trainerCard.stars], BG_PLTT_ID(0), 3 * PLTT_SIZE_4BPP);
LoadPalette(sKantoTrainerCardBadges_Pal, BG_PLTT_ID(3), PLTT_SIZE_4BPP);
if (sData->trainerCard.gender != 0 ) {
if (sData->trainerCard.gender != 2 ) {
if (sData->trainerCard.gender != 4 ) {
if (sData->trainerCard.gender != 6 ) {
if (sData->trainerCard.gender != 9 ) {
if (sData->trainerCard.gender != 10 )
LoadPalette(sHoennTrainerCardFemaleBg_Pal, BG_PLTT_ID(1), PLTT_SIZE_4BPP);
}}}}}
}
if (sData->cardType != CARD_TYPE_FRLG)
{
LoadPalette(sHoennTrainerCardPals[sData->trainerCard.stars], BG_PLTT_ID(0), 3 * PLTT_SIZE_4BPP);
LoadPalette(sHoennTrainerCardBadges_Pal, BG_PLTT_ID(3), PLTT_SIZE_4BPP);
if (sData->trainerCard.gender != 0 ) {
if (sData->trainerCard.gender != 2 ) {
if (sData->trainerCard.gender != 4 ) {
if (sData->trainerCard.gender != 6 ) {
if (sData->trainerCard.gender != 9 ) {
if (sData->trainerCard.gender != 10 )
LoadPalette(sHoennTrainerCardFemaleBg_Pal, BG_PLTT_ID(1), PLTT_SIZE_4BPP);
}}}}}
}
else
{
LoadPalette(sKantoTrainerCardPals[sData->trainerCard.stars], BG_PLTT_ID(0), 3 * PLTT_SIZE_4BPP);
LoadPalette(sKantoTrainerCardBadges_Pal, BG_PLTT_ID(3), PLTT_SIZE_4BPP);
if (sData->trainerCard.gender != 0 ) {
if (sData->trainerCard.gender != 2 ) {
if (sData->trainerCard.gender != 4 ) {
if (sData->trainerCard.gender != 6 ) {
if (sData->trainerCard.gender != 9 ) {
if (sData->trainerCard.gender != 10 )
LoadPalette(sHoennTrainerCardFemaleBg_Pal, BG_PLTT_ID(1), PLTT_SIZE_4BPP);
}}}}}
}
The logic is repeated for the functions "TrainerCard_GenerateCardForPlayer" and "TrainerCard_GenerateCardForLinkPlayer". But here you will only add if your character is a girl. I'll leave the base model here and you can do it in both roles, if your character is a girl. In my case I didn't need to add.
Spoiler:
if (trainerCard->gender == 1) {
if (trainerCard->gender == 3) {
if (trainerCard->gender == 5) {
if (trainerCard->gender == 7) {
if (trainerCard->gender == 8) {
trainerCard->facilityClass = gLinkPlayerFacilityClasses[(trainerCard->trainerId % NUM_FEMALE_LINK_FACILITY_CLASSES) + NUM_MALE_LINK_FACILITY_CLASSES];
}}}}}
if (trainerCard->gender == 3) {
if (trainerCard->gender == 5) {
if (trainerCard->gender == 7) {
if (trainerCard->gender == 8) {
trainerCard->facilityClass = gLinkPlayerFacilityClasses[(trainerCard->trainerId % NUM_FEMALE_LINK_FACILITY_CLASSES) + NUM_MALE_LINK_FACILITY_CLASSES];
}}}}}
With that the trainer card is working according to your new character.
Now let's go to the map icon. Everything is done in "src\region_map.c"
The first step is to add the call to the icon sprite, add the following in sequence:
Code:
static const u16 sRegionMapPlayerIcon_WallyPal[] = INCBIN_U16("graphics/pokenav/region_map/wally_icon.gbapal");
static const u8 sRegionMapPlayerIcon_WallyGfx[] = INCBIN_U8("graphics/pokenav/region_map/wally_icon.4bpp");
in the function "CreateRegionMapPlayerIcon" Activate this in sequence:
Code:
else if (gSaveBlock2Ptr->custom == STYLE_WALLY)
{
sheet.data = sRegionMapPlayerIcon_WallyGfx;
palette.data = sRegionMapPlayerIcon_WallyPal;
}
For Sprite in cable car, go to "src\cable_car.c", in function "playerGraphicsIds" and add:
Code:
[STYLE_WALLY] = OBJ_EVENT_GFX_WALLY
Finally, we have to fix the decoration spryte. Go to "src\decoration.c", in the "SetUpPlacingDecorationPlayerAvatar" function and add the following to the else if sequence:
Code:
else if (gSaveBlock2Ptr->custom == STYLE_WALLY)
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_WALLY_DECORATING, SpriteCallbackDummy, x, 72, 0);
Code:
else if (gSaveBlock2Ptr->custom == STYLE_WALLY)
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_WALLY_DECORATING, SpriteCallbackDummy, 136, 72, 0);
Okay, now your character is complete in the game, just enjoy it.
PS: it's my first oficial post. I don't know how to use the blog tools yet. I promise to edit this post and add more color and functions.
Last edited: