You are not logged in.
WARNING: This is a really long tutorial, and while it may not be as complicated for you as it was for me to make it up, it is still a lot more complicated than, say, editing the text or which item is in the PC at the start of the game or any of that jazz. But if you follow the tutorial properly (and assuming I haven't accidentally skipped something, since there was a lot to explain) you should be able to get this working in your game.
To see the finished results of this tutorial, you can check out this youtube video:
Step 1: Get the graphics for the girl player.
For the girl player, you will need the following graphics:
To get the right dimensions for these, you can just copy+paste the ones for Red and edit them. Please note that in my example, I have Danny-E33's larger backsprite routine installed. You can do this without that routine of course, but your backsprite will have to be the normal Red Version size instead of the larger Gold Version size I am using.
Once you have your graphics drawn/found etc. make sure that they use ONLY the colours that other graphics in the project folder use (otherwise they won't convert properly) and save them as .png files with names you can remember. In my example, I kept the same naming scheme as the original files, but I substituted the word "Leaf" everywhere the original file name said "Red" and placed them in the same subfolders as the originals. This was just to make it easier for me to remember the file names later, and to make sure they are converted properly at compile.
So I ended up with files named:
Step 2: Inserting the sprites.
Now that you have the new .png files in the proper subfolders, we have to actually reference them somewhere to get them included. So we will open main.asm in notepad++ and find the references to the player's sprites. Doing a search for RedPicFront will eventually get you to this:
RedPicFront:: INCBIN "pic/trainer/red.pic" ShrinkPic1:: INCBIN "pic/trainer/shrink1.pic" ShrinkPic2:: INCBIN "pic/trainer/shrink2.pic"
Well, let's just add a new line really quick to include our new front sprite for the girl, so we can reference it later. You should have something that looks like this:
RedPicFront:: INCBIN "pic/trainer/red.pic" LeafPicFront:: INCBIN "pic/trainer/leaf.pic" ShrinkPic1:: INCBIN "pic/trainer/shrink1.pic" ShrinkPic2:: INCBIN "pic/trainer/shrink2.pic"
Now if you scroll down a little from that, you should see the lines that include the overworld sprites. So we will just go to the line that says:
RedCyclingSprite: INCBIN "gfx/sprites/cycling.2bpp" RedSprite: INCBIN "gfx/sprites/red.2bpp"
and add a couple of lines under it, so it looks like this:
RedCyclingSprite: INCBIN "gfx/sprites/cycling.2bpp" RedSprite: INCBIN "gfx/sprites/red.2bpp" LeafSprite: INCBIN "gfx/sprites/leaf.2bpp" LeafCyclingSprite: INCBIN "gfx/sprites/leafcycling.2bpp"
Now, at least in my case, adding thew overworlds to this bank caused errors at compile, because we were trying to add too many sprites in this bank. To make life simpler later, we can just take 2 unrelated sprites and move them to another bank. I decided to cut and paste the lines that said:
GiovanniSprite: INCBIN "gfx/sprites/giovanni.2bpp" RocketSprite: INCBIN "gfx/sprites/rocket.2bpp"
to the top of the other bank of overworld sprites. You can find that other bank by searching "SECTION "NPC Sprites 1"" or by scrolling up a bit from the banks we were just editing.
Now, the next thing we should come to is the fishing tiles. We won't have room to include these in the same bank as Red's fishing tiles, so we will have to find another bank to include them in. Which bank they are in is not important, since the routine that calls them can find them in any bank. So I added them in the same bank as the player backsprites.
So to finish inserting the graphics, do a search in main.asm for RedPicBack. You will eventually find something that looks like this:
RedPicBack:: INCBIN "pic/trainer/redb.pic" OldManPic:: INCBIN "pic/trainer/oldman.pic"
So I just went ahead and added some lines to make it look like this:
RedPicBack:: INCBIN "pic/trainer/redb.pic" LeafPicBack:: INCBIN "pic/trainer/leafb.pic" OldManPic:: INCBIN "pic/trainer/oldman.pic" LeafFishingTilesFront: INCBIN "gfx/leaf_fishing_tile_front.2bpp" LeafFishingTilesBack: INCBIN "gfx/leaf_fishing_tile_back.2bpp" LeafFishingTilesSide: INCBIN "gfx/leaf_fishing_tile_side.2bpp"
Now that we have all of the entries for the graphics added, now is a good time to save main.asm and attempt to compile the rom. If all goes well, the rom will compile normally with these extra graphics included (but nothing will call them yet). If you get errors saying that a bank is full, you will have to move something around to make it compile properly. If this happens, the cygwin terminal will tell you which line in main.asm it had a problem with, so you can go right to it and know which bank you need to make room in.
Step 3: Setting up the into.
Ok, so you got everything sorted properly so your rom will compile with the new graphics? Ok, let's start making it so we can use them!
The first thing you will want to do is add the menu that asks if you are a boy or a girl. The way I did this is by making a copy of the YesNoChoice routine, and having it reference the unused "North/West" menu string.
So, let's open up engine/menu/text_box.asm and find the menu strings. So go ahead and search for TwoOptionMenuStrings and eventually you will come to:
TwoOptionMenuStrings: db 4,3,0 dw .YesNoMenu db 6,3,0 dw .NorthWestMenu db 6,3,0 dw .SouthEastMenu db 6,3,0 dw .YesNoMenu db 6,3,0 dw .NorthEastMenu db 7,3,0 dw .TradeCancelMenu db 7,4,1 dw .HealCancelMenu db 4,3,0 dw .NoYesMenu .NoYesMenu db "NO" next "YES@" .YesNoMenu db "YES" next "NO@" .NorthWestMenu db "NORTH" next "WEST@" .SouthEastMenu db "SOUTH" next "EAST@" .NorthEastMenu db "NORTH" next "EAST@" .TradeCancelMenu db "TRADE" next "CANCEL@" .HealCancelMenu db "HEAL" next "CANCEL@"
The only entries we are interested in right now are the ones with NorthWest. So we'll just edit these really quick so we come up with this:
TwoOptionMenuStrings: db 4,3,0 dw .YesNoMenu db 5,3,0 dw .BoyGirlMenu db 6,3,0 dw .SouthEastMenu db 6,3,0 dw .YesNoMenu db 6,3,0 dw .NorthEastMenu db 7,3,0 dw .TradeCancelMenu db 7,4,1 dw .HealCancelMenu db 4,3,0 dw .NoYesMenu .NoYesMenu db "NO" next "YES@" .YesNoMenu db "YES" next "NO@" .BoyGirlMenu db "BOY" next "GIRL@" .SouthEastMenu db "SOUTH" next "EAST@" .NorthEastMenu db "NORTH" next "EAST@" .TradeCancelMenu db "TRADE" next "CANCEL@" .HealCancelMenu db "HEAL" next "CANCEL@"
Notice that I changed not only the text and label names, but I changed the numbers above the NorthWest choice. Those determine how large the box around the words will be, and by changing that value from 6 to 5, we make it so there isn't exta space after the Boy/Girl options.
Next, we'll need to declare a place to store the player's gender. That way when we add the code to call that menu choice, we have somewhere to save the result. So let's open up wram.asm and declare a new address!
If you search for wGameProgressFlagsEnd you'll find this:
wGameProgressFlagsEnd:: ds 56
These bytes that come after those flags are unused, but are still within the block of WRAM that gets stored in the .sav file when you save the game. So here is a good place to declare the new address we'll be making use of in the rest of this tutorial. So, just change the code above to look like this:
wGameProgressFlagsEnd:: wPlayerGender:: ; $00 = male ; $01 = female ds 1 ; unused ds 55
Now that we have these edited, you can save that file and move on to the actual intro. If you look in /engine/oak_speech.asm you will see that this is the main code for the intro. Scroll down to the bottom, and paste this:
; displays boy/girl choice BoyGirlChoice:: call SaveScreenTilesToBuffer1 call InitBoyGirlTextBoxParameters jr DisplayBoyGirlChoice InitBoyGirlTextBoxParameters:: ld a, $1 ; loads the value for the unused North/West choice, that was changed to say Boy/Girl ld [wTwoOptionMenuID], a coord hl, 13, 7 ld bc, $80e ret DisplayBoyGirlChoice:: ld a, $14 ld [wTextBoxID], a call DisplayTextBoxID jp LoadScreenTilesFromBuffer1
This is a copy of the YesNoChoice routine, but modified to call our new Boy/Girl option instead.
Now that we have this subroutine added, we can scroll back up and write some new code to call it.
Near the top, you'll see a label called OakSpeech, and a few lines down, you'll see some code that looks like this:
xor a ld [hTilesetType],a ld a,[wd732] bit 1,a ; possibly a debug mode bit jp nz,.skipChoosingNames
Immediately under that, we'll add our new code for the gender selection. So immediately after the line about skipping the intro, we'll add this:
ld hl,BoyGirlText ; added to the same file as the other oak text call PrintText ; show this text call BoyGirlChoice ; added routine at the end of this file ld a, [wCurrentMenuItem] ld [wPlayerGender], a ; store player's gender. 00 for boy, 01 for girl call ClearScreen ; clear the screen before resuming normal intro
Now if you scroll down a bit you will find something that looks like this:
ld hl,OakSpeechText2 call PrintText call GBFadeOutToWhite call ClearScreen ld de,RedPicFront ld bc,(Bank(RedPicFront) << 8) | $00 call IntroDisplayPicCenteredOrUpperRight
So we'll need to change this up a bit, so it can show the other pic if you are a girl. Make it look like this:
ld hl,OakSpeechText2 call PrintText call GBFadeOutToWhite call ClearScreen ld de,RedPicFront lb bc, Bank(RedPicFront), $00 ld a, [wPlayerGender] ; check gender and a ; check gender jr z, .NotLeaf1 ld de,LeafPicFront lb bc, Bank(LeafPicFront), $00 .NotLeaf1: call IntroDisplayPicCenteredOrUpperRight
Next, we can scroll down a bit more until we see:
.skipChoosingNames call GBFadeOutToWhite call ClearScreen ld de,RedPicFront lb bc, Bank(RedPicFront), $00 call IntroDisplayPicCenteredOrUpperRight
So we'll just change it to say:
.skipChoosingNames call GBFadeOutToWhite call ClearScreen ld de,RedPicFront lb bc, Bank(RedPicFront), $00 ld a, [wPlayerGender] ; check gender and a ; check gender jr z, .NotLeaf2 ld de,LeafPicFront lb bc, Bank(LeafPicFront), $00 .NotLeaf2: call IntroDisplayPicCenteredOrUpperRight
You can see where this is going, really. A lot of checking the gender and just making it load the girl's stuff instead, otherwise keep loading the boy's stuff. We're still not done with this file yet though. So scroll down a bit more until you see:
call DelayFrames ld de,RedSprite ld bc,(BANK(RedSprite) << 8) | $0C ld hl,vSprites call CopyVideoData ld de,ShrinkPic1 ld bc,(BANK(ShrinkPic1) << 8) | $00 call IntroDisplayPicCenteredOrUpperRight
and make it look like this:
call DelayFrames ld de,RedSprite lb bc, BANK(RedSprite), $0C ld a, [wPlayerGender] ; check gender and a ; check gender jr z, .NotLeaf3 ld de,LeafSprite lb bc, BANK(LeafSprite), $0C .NotLeaf3: ld hl,vSprites call CopyVideoData ld de,ShrinkPic1 lb bc, BANK(ShrinkPic1), $00 call IntroDisplayPicCenteredOrUpperRight
Now, we'll scroll down a bit more until we see:
OakSpeechText3: TX_FAR _OakSpeechText3 db "@"
Since we added a text string earlier when asking your gender, we'll need to set this up here so the script can find it. So we'll add:
BoyGirlText: ; This is new so we had to add a reference to get it to compile TX_FAR _BoyGirlText db "@"
under the OakSpeechText3 part. That's all we have to do in this file, but we're not quite done with the intro. (The intro is probably the most complicated part in all honesty).
Now we'll go ahead and save that file, and open /engine/oak_speech2.asm to keep working. At the top you will see:
ChoosePlayerName: call OakSpeechSlidePicRight ld de, DefaultNamesPlayer call DisplayIntroNameTextBox ld a, [wCurrentMenuItem] and a jr z, .customName ld hl, DefaultNamesPlayerList call GetDefaultName ld de, wPlayerName call OakSpeechSlidePicLeft jr .done
and change that to this:
ChoosePlayerName: call OakSpeechSlidePicRight ld a, [wPlayerGender] ; Added gender check and a jr nz, .AreGirl ; Skip to girl names if you are a girl instead ld de, DefaultNamesPlayer call DisplayIntroNameTextBox ld a, [wCurrentMenuItem] and a jr z, .customName ld hl, DefaultNamesPlayerList call GetDefaultName ld de, wPlayerName call OakSpeechSlidePicLeft jr .done .AreGirl ; Copy of the boy naming routine, just with girl's names ld de, DefaultNamesGirl call DisplayIntroNameTextBox ld a, [wCurrentMenuItem] and a jr z, .customName ld hl, DefaultNamesGirlList call GetDefaultName ld de, wPlayerName call OakSpeechSlidePicLeft jr .done ; End of new Girl Names routine
This adds a copy of the name routine that will instead call the girl's default names, which we will add in a minute. But first, we still have a little more to do.
If you will look at where it says:
.customName ld hl, wPlayerName xor a ; NAME_PLAYER_SCREEN ld [wNamingScreenType], a call DisplayNamingScreen ld a, [wcf4b] cp "@" jr z, .customName call ClearScreen call Delay3 ld de, RedPicFront ld b, BANK(RedPicFront) call IntroDisplayPicCenteredOrUpperRight .done ld hl, YourNameIsText jp PrintText
we'll need to change this, so that entering a custom name won't make you look like the boy when you get back to the intro. So we'll make the code look like this:
.customName ld hl, wPlayerName xor a ; NAME_PLAYER_SCREEN ld [wNamingScreenType], a call DisplayNamingScreen ld a, [wcf4b] cp "@" jr z, .customName call ClearScreen call Delay3 ld de, RedPicFront ld b, BANK(RedPicFront) ld a, [wPlayerGender] ; Added gender check and a ; Added gender check jr z, .AreBoy3 ld de, LeafPicFront ld b, BANK(LeafPicFront) .AreBoy3 call IntroDisplayPicCenteredOrUpperRight .done ld hl, YourNameIsText jp PrintText
Now then, we can get around to adding the name list for the girl player. So scroll down until you see:
IF _RED DefaultNamesPlayer: db "NEW NAME" next "RED" next "ASH" next "JACK" db "@" DefaultNamesRival: db "NEW NAME" next "BLUE" next "GARY" next "JOHN" db "@" ENDC
and add a new entry for your girl names. It will look something like this:
IF _RED DefaultNamesPlayer: db "NEW NAME" next "RED" next "ASH" next "JACK" db "@" DefaultNamesGirl: db "NEW NAME" next "SCARLET" next "LEAF" next "NICOLE" db "@" DefaultNamesRival: db "NEW NAME" next "BLUE" next "GARY" next "JOHN" db "@" ENDC
Obviously, you don't have to use the same names I came up with. Just make sure they aren't too long for a player name and you are fine.
So that sounds like we are done with the intro, right? Not quite. We only added the entries for the name menu. We still need to enter the actual list it will reference, because Red Version was weird. So we'll scroll down a little more until we find:
IF DEF(_RED) DefaultNamesPlayerList: db "NEW NAME@" db "RED@" db "ASH@" db "JACK@" DefaultNamesRivalList: db "NEW NAME@" db "BLUE@" db "GARY@" db "JOHN@" ENDC
and add the girl list in there. It should look like this:
IF DEF(_RED) DefaultNamesPlayerList: db "NEW NAME@" db "RED@" db "ASH@" db "JACK@" DefaultNamesGirlList: db "NEW NAME@" db "SCARLET@" db "LEAF@" db "NICOLE@" DefaultNamesRivalList: db "NEW NAME@" db "BLUE@" db "GARY@" db "JOHN@" ENDC
You also need to add those entries for the girl's name lists to the IF_BLUE lists as well, if you plan on compiling as a version other than Red. That is it for the actual ASM on the intro, but we still need to open another file to finish the intro up. Remember that text string we made up to reference earlier in the gender select menu? Yeah, we have to actually put that string into the game.
So let's save that file and open up /text/oakspeech.asm and scroll down to the bottom of the file. There we can add an entry that looks like this:
_BoyGirlText:: text "Play as a boy, or" line "as a girl?" done
Then just save it and you're done with the intro. At this point, I would recommend compiling it again and testing the intro, just to make sure everything worked the way you wanted it to..
Step 4: Setting up the player's overworld sprites.
Ok, so you got the intro working nicely? Great! Time to move on to getting the game to show the proper sprites when you are fishing as the girl.
So let's go ahead and open up /engine/overworld/player_animations.asm and have a look. You'll want to search for FishingAnim: to find what you are looking for. It will look like this:
FishingAnim: ld c, 10 call DelayFrames ld hl, wd736 set 6, [hl] ; reserve the last 4 OAM entries ld de, RedSprite ld hl, vNPCSprites lb bc, BANK(RedSprite), $c call CopyVideoData ld a, $4 ld hl, RedFishingTiles call LoadAnimSpriteGfx
You'll want to replace that with this:
FishingAnim: ld c, 10 call DelayFrames ld hl, wd736 set 6, [hl] ; reserve the last 4 OAM entries ld a, [wPlayerGender] ; added gender check and a ; added gender check jr z, .BoySpriteLoad ld de, LeafSprite ld hl, vNPCSprites ld bc, (BANK(LeafSprite) << 8) + $0c jr .KeepLoadingSpriteStuff .BoySpriteLoad ld de, RedSprite ld hl, vNPCSprites lb bc, BANK(RedSprite), $c .KeepLoadingSpriteStuff call CopyVideoData ld a, [wPlayerGender] ; added gender check and a ; added gender check jr z, .BoyTiles ; skip loading Leaf's stuff if you're Red ld a, $4 ld hl, LeafFishingTiles jr .ContinueRoutine ; go back to main routine after loading Leaf's stuff .BoyTiles ; alternately, load Red's stuff ld a, $4 ld hl, RedFishingTiles .ContinueRoutine call LoadAnimSpriteGfx
Now I know, I know. That looks like a mess. But it's really just more of the same stuff we did in the intro. All we've done is copy part of it to make an alternate version it can load to get the girl's sprite and fishing tiles. Speaking of those fishing tiles, we'll need to add that little table it is referencing.
So let's scroll down a bit until we see:
RedFishingTiles: dw RedFishingTilesFront db 2, BANK(RedFishingTilesFront) dw vNPCSprites + $20 dw RedFishingTilesBack db 2, BANK(RedFishingTilesBack) dw vNPCSprites + $60 dw RedFishingTilesSide db 2, BANK(RedFishingTilesSide) dw vNPCSprites + $a0 dw RedFishingRodTiles db 3, BANK(RedFishingRodTiles) dw vNPCSprites2 + $7d0
We'll want to add a new table under it, so that it will look like this:
RedFishingTiles: dw RedFishingTilesFront db 2, BANK(RedFishingTilesFront) dw vNPCSprites + $20 dw RedFishingTilesBack db 2, BANK(RedFishingTilesBack) dw vNPCSprites + $60 dw RedFishingTilesSide db 2, BANK(RedFishingTilesSide) dw vNPCSprites + $a0 dw RedFishingRodTiles db 3, BANK(RedFishingRodTiles) dw vNPCSprites2 + $7d0 LeafFishingTiles: ; newly added table of Leaf's sprites dw LeafFishingTilesFront db 2, BANK(LeafFishingTilesFront) dw vNPCSprites + $20 dw LeafFishingTilesBack db 2, BANK(LeafFishingTilesBack) dw vNPCSprites + $60 dw LeafFishingTilesSide db 2, BANK(LeafFishingTilesSide) dw vNPCSprites + $a0 dw RedFishingRodTiles db 3, BANK(RedFishingRodTiles) dw vNPCSprites2 + $7d0
You'll notice that leaf's table still calls one of the original graphics that Red used. I don't see a point in making an identical copy of the actual fishing pole tiles, only the part that is the actual player, so her table calls the same fishing rod sprite the boy did.
Now to move on to your walking and cycling sprites. You'll open /home/overworld.asm and take a look at it for this part. You'll want to find the routine called LoadWalkingPlayerSpriteGraphics for this part. You'll eventually find a routine that looks like this:
LoadWalkingPlayerSpriteGraphics:: ld de,RedSprite ld hl,vNPCSprites jr LoadPlayerSpriteGraphicsCommon LoadSurfingPlayerSpriteGraphics:: ld de,SeelSprite ld hl,vNPCSprites jr LoadPlayerSpriteGraphicsCommon LoadBikePlayerSpriteGraphics:: ld de,RedCyclingSprite ld hl,vNPCSprites
And we'll just change this up a little to look like this:
LoadWalkingPlayerSpriteGraphics:: ld de,RedSprite ld a, [wPlayerGender] and a jr z, .AreGuy1 ld de,LeafSprite .AreGuy1 ld hl,vNPCSprites jr LoadPlayerSpriteGraphicsCommon LoadSurfingPlayerSpriteGraphics:: ld de,SurfingLapras ld hl,vNPCSprites jr LoadPlayerSpriteGraphicsCommon LoadBikePlayerSpriteGraphics:: ld de,RedCyclingSprite ld a, [wPlayerGender] and a jr z, .AreGuy2 ld de,LeafCyclingSprite .AreGuy2 ld hl,vNPCSprites
Now you can save this file, because that is all we had to do in here. If you were to scroll down a little more, you would see that we didn't mess with the part of the code that loaded which bank these sprites were in. That is why we kept Red and Leaf in the same bank when we inserted their sprites. It just seemed simpler to do it that way to me. As with all of the other sections, you'll probably want to stop and compile the rom again to make sure everything went ok before moving on.
Step 5: Adding The Girl's Backsprite.
This section will be relatively short compared to the others, because there isn't much to do here. We'll open up engine/battle/core.asm for this part.
Search until you find LoadPlayerBackPic: and see that it looks like this:
LoadPlayerBackPic: ld a, [wBattleType] dec a ; is it the old man tutorial? ld de, RedPicBack jr nz, .next ld de, OldManPic .next
You'll just want to change this to be:
LoadPlayerBackPic: ld a, [wBattleType] dec a ld de, OldManPic jr z, .next ld a, [wPlayerGender] and a jr z, .RedBack ld de, LeafPicBack jr .next .RedBack ld de, RedPicBack .next
This just reorganises that a bit and adds in the check for the girl's backsprite. This also assumes that all 3 backpics are stored in the same bank, so make sure you did that unless you want to mess with the routine more on your own to allow them to be in different banks.
As always, you'll probably want to save and compile to test this before going on.
Step 6: Adding The Girl To The Hall Of Fame.
For this step, you'll want to open /engine/hall_of_fame.asm and search for HoFLoadPlayerPics: to get to the function we need. It should look something like this:
HoFLoadPlayerPics: ld de, RedPicFront ld a, BANK(RedPicFront) call UncompressSpriteFromDE ld hl, sSpriteBuffer1 ld de, sSpriteBuffer0 ld bc, $310 call CopyData ld de, vFrontPic call InterlaceMergeSpriteBuffers ld de, RedPicBack ld a, BANK(RedPicBack) call UncompressSpriteFromDE
We'll want to edit that so it looks like this:
HoFLoadPlayerPics: ld a, [wPlayerGender] ; New gender check and a ; New gender check jr nz, .GirlStuff1 ld de, RedPicFront ld a, BANK(RedPicFront) jr .Routine ; skip the girl stuff and go to main routine .GirlStuff1 ld de, LeafPicFront ld a, BANK(LeafPicFront) .Routine ; resume original routine call UncompressSpriteFromDE ld hl, sSpriteBuffer1 ld de, sSpriteBuffer0 ld bc, $310 call CopyData ld de, vFrontPic call InterlaceMergeSpriteBuffers ld a, [wPlayerGender] ; new gender check and a ; new gender check jr nz, .GirlStuff2 ld de, RedPicBack ld a, BANK(RedPicBack) jr .routine2 ; skip the girl stuff and continue original routine if guy .GirlStuff2 ld de, LeafPicBack ld a, BANK(LeafPicBack) .routine2 ; original routine call UncompressSpriteFromDE
This will change it so it shows the girl's front and back sprites when your team is entered in the hall of fame. Save it and you are done with this step.
Step 7: Adding The Girl To The Trainer Card
This is the final step in the tutorial. You'll want to open up /engine/menu/start_sub_menus.asm for this part. Search for the function DrawTrainerInfo: and you should see something like this:
DrawTrainerInfo: ld de,RedPicFront lb bc, BANK(RedPicFront), $01 predef DisplayPicCenteredOrUpperRight
So we'll just change that to:
DrawTrainerInfo: ld de,RedPicFront lb bc, BANK(RedPicFront), $01 ld a, [wPlayerGender] and a jr z, .AreBoy ld de, LeafPicFront lb bc, BANK(LeafPicFront), $01 .AreBoy predef DisplayPicCenteredOrUpperRight
And you should be all set! Save it, compile it, and give it a test. If everything went as planned (and assuming I didn't accidentally leave anything out when writing this) you should now have a fully functioning gender selection system in place in Pokemon Red. Let me know if you have any problems and I will try my best to help you figure them out.
IIMarckus, Kanzure, comet, Danny-E33, Sanky, and everyone else who contributed to the Pokered disassembly project.
Danny-E33 - Getting me interested in Pokered, and for the Gen II backsprite routine I used in that video
Pia Carrot - Talking about Pokered a lot at PHO and originally asking me to write this tutorial.
ないすべての情報が必要です。- Asking about this on Discord until I updated it.
Last edited by Mateo (2017-08-03 03:07:09)
Wow, this is pretty awesome. Very thorough tutorial. I wonder why the North/West menu ever existed in the first place.
Probably a lot. But it is irrelevant.
I've got a lot of tools, somewhat old but useful, that I'm comfortable with hacking the rom. Getting more comfortable with the ASM directly but, old dogs and new tricks as it were.
Pokemon: Project Neo A Pokemon hack 15 years in the making...
That's all well and good, but...
xor a ld [$FFD7],a ld a,[wd732] bit 1,a ; XXX when is bit 1 set? jp nz,Func_61bc ; easter egg: skip the intro
Wordpad, which I am largely using to edit the ASM code (I've succeeded thus far in using Wordpad to anti-censor that scene early on in Viridian City with the old man who teaches you how to catch Pokémon–originally, he was drunk instead of not having had his coffee), searched the entirety of /engine/oak_speech.asm and couldn't find it. That is where I'm lost. Heck, I even checked the original file on Github and couldn't find it. (And yes, I'm positive I'm following your instructions.)
Sorry for the double post, but whenever I try to compile the ROM after having done everything up to Step 3, I get the following error:
"Unknown symbol 'PlayMusic'"
Am I doing something wrong?
ld hl, wd798 ; load ram address of Gender
This seems to be the only thing not working for me so far. wd798 does not exist in my version. Any ideas what the alternative would be?
EDIT: Worked it out. Just had to change it to $14.
Last edited by megamctaco (2015-10-25 10:22:06)
If you mean that you changed it to ld hl, $14, then that is just so wrong. Replace it with ld hl, $d798 if anything.
All that got me was a bunch of "Expression must be 8-bit" errors.
As it stands, I can compile Red but not Blue, as "GetDefaultName" is having trouble with Blue version only for some reason. EDIT: Female sprite loads when either boy or girl are selected.
I should mention, I am up to step 4 but can't seem to compile after changing player_animations.asm and overworld.asm. Either a ROMX error or ROM0 too large error.
Last edited by megamctaco (2015-10-25 11:22:14)
The romx error means you are trying to put more in a bank than you have room for.
The issue with the name not being found is the problem with me writing this tutorial on an older version of pokered, and label/variable/etc names getting changed over time. I'll look up the proper name and update this after I have my coffee.
EDIT: Ok, I see what is causing so much trouble here. Apparently some time in the past, they stopped declaring event bytes manually, and made up a macro thing for it and just labeled the start of that block of data with an actual label, not each byte. In the original tutorial, we were just using one of the unused bits in the byte that kept up with trainers in one level of Cinnabar Mansion. It isn't the best way to do it, but it was convenient at the time since it was unused and would be saved properly. Now that the save routines have been vastly improved, it would be simpler to just add a new entry in wram.asm for wPlayerGender and reference that. At some point I'll get around to properly updating this tutorial to use the current label names, and to use a custom ram address instead of trying into that trainer byte (because what if you wanted to add more trainers to that map?)
Also, I noticed that for some reason I was still using the hard coded address $cc26 instead of wCurrentMenuItem like I should be when checking what your answer was in the intro. That's probably why it was always setting you as the girl when you tried it. If you shifted data around in ram it's probably you moved stuff so labels worked fine but the hardcoded address was probably pointing to the wrong thing or something.
As a quick fix version of how to fix some of this:
In engine/oak_speech.asm the block of code you are looking for now looks like:
xor a ld [hTilesetType],a ld a,[wd732] bit 1,a ; possibly a debug mode bit jp nz,.skipChoosingNames
so you would put the code for choosing the gender between that and the part about loading oak's pic.
And where you see:
ld a, [$cc26]
you would change it to:
ld a, [wCurrentMenuItem]
Then you would replace any instance of:
and then you would need to go into wram.asm, and somewhere between "wMainDataStart::" and "wMainDataEnd::" you would need to add
wPlayerGender:: ds 1
And that aught to take care of that. As for issues with running out of space in rom banks, does it give you any information about which bank is full? You shouldn't have issues with any of the code, so it's probably an issue with graphics somewhere, but hard to say without knowing what all is going on.
Last edited by Mateo (2015-10-25 15:17:46)
OK, I'm doing this step by step, and when I added Leaf's overworld walking and cycling sprites, I expected errors and got "Unable to load fixed ROMX section into bank $05". When I then moved two sets of overworld sprites into a different bank to compensate, I got–guess what–"Unknown symbol 'PlayMusic'". Any idea what's causing this?
If you are following the tutorial correctly, I can think of absolutely no reason why it would claim to be unable to find "PlayMusic" because that doesn't even begin to make sense in this situation o.O Are you sure all you did was move the INCLUDE lines for a couple of overworld sprites to cause that to happen?
No, I'm pretty sure all I did was cut and paste the lines for the Giovanni and Rocket sprites to NPC Sprites 1, following the example in the tutorial, and suddenly Cygwin's all "Unknown symbol 'PlayMusic'" for reasons I can't explain either.
Moving those sprites should have absolutely zero impact on the PlayMusic routine, so something has to be up. Does it give any clue as to which file is throwing that error? PlayMusic is called all over the place. I'm guessing that maybe you accientally added a linebreak somewhere so it has a line starting with PlayMusic instead of "call PlayMusic" so it is saying "whoa, PlayMusic isn't a command or a macro, idk what to do with this". I could be wrong, but that's the only thing coming to my mind as making sense at the moment.
EDIT: Also, which text editor are you using to edit the .asm files? I ask because regular notepad tends to have difficulty behaving properly when working with these .asm files, and notepad++ is greatly preferred since it doesn't do weird things like try to change linebreaks and stuff the way normal Notepad does.
Last edited by Mateo (2015-10-26 02:40:44)
When I enter:
cd pokered make
I get this:
rgblink -n pokered.sym -o pokered.gbc red/audio.o red/main.o red/text.o red/wram.o C:\cygwin64\usr\local]bin\rgblink.exe: Unknown symbol 'PlayMusic' Makefile:79: recipe for target 'pokered.gbc' failed make: *** [pokered.gbc] Error 1
There's the problem: it didn't give me any obvious clues, and I couldn't find PlayMusic anywhere in the main.asm file.
Can you replicate this error with the current version of Pokered by following each step of your own tutorial, right up to and including the point where the Giovanni and Rocket sprites are moved to NPC Sprites 1? For all I know, I might very well be the first to encounter this error while trying to insert the female player character.
Last edited by Fotomac (2015-10-26 02:47:59)
I'm not really in a place where I can just do that right now. But yeah, that error message is precisely as unhelpful as I was afraid it would be :/
Again, what text editor are you using to edit the .asm files? Because I do remember another user having similarly baffling and unrelated errors when using Notepad instead of Notepad++ because Notepad was screwing up the file's formatting and causing it to feed a bunch of jibberish to the compiler.
I didn't use WordPad this time; I was forced to use Notepad on account of WordPad feeding me the following bull:
You are about to save the document in a Text-Only format, which
will remove all formatting. Are you sure you want to do this?
To save in other format, click No.
After which, should I click No, I get directed to the Save As window, which gives me the option to save this in any of six types of documents none of which are ASM.
Made those changes you suggested and now I'm getting a "Value must be 8-bit" when I changed wd798 to wPlayerGender.
I tried changing that to [wPlayerGender] and got a syntax error.
Problem appears to be solved; it would appear the Notepad save changed the font to MS Mincho (which I am guessing Cygwin or rgblink or whatever stumbled across the error didn't recognize), so I changed it back to Courier New and saved; the "Unknown symbol 'PlayMusic'" error didn't appear after that, so it would appear Notepad was the responsible party.