• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Yellow Hacking Tutorial (Evolve/Replace Pikachu and more) + Pokemon Sprites

200
Posts
10
Years
  • Age 30
  • Seen Jun 19, 2022
Yellow Hacking Tutorial (Evolve/Replace Pikachu and more)
========================================================

Yellow is very similar to RGB, so you'll definitely want to review other guides. This will mooooostly focus on Yellow-specific things - evolving Pikachu,Making All Pokemon Follow or replacing with a different pokemon, but there will also be other things like biking, shinies and an uber uber basic item system.

First off - you will want to grab Yellow Disassembly and a program like Cygwin to make it compile.
You'll want Dannye-33's Gen 2 Sprites Base, because it's got more features than vanilla yellow, better graphics, and makes it a breeze to add in extra new gen pokemon. If you are nostalgic for any of the old yellow sprites, it's very easy to just copypaste from a vanilla yellow disassembly into the appropriate folder: I did that for Pikachu myself (revamping the image while I was at it) and left the others alone.

Altering Our Starter
===========================


Evolve Pikachu into Raichu
---

Alright! The bulk of this tutorial is devoted to Pikachu (specifically, replacing it). As appropriate of a Yellow tutorial. Even if you aren't interested in Raichu specifically and just came here to turn Pikachu into Meowth or something, you'll still learn a lot here that will enable us to do things like that, or evolve said Meowth, so let's start:


The method I prefer is 'evolve by happiness'. This ensures that you get to have Raichu emotion sprites at the appropriate times without too much fuss, although there will still probably be times when the player gets the wrong emotion sprite, the vast majority of the time they will get the right one.

Figure out what happiness level you want Pikachu to evolve at, and alter all the images of that happiness up accordingly in gfx/pikachu. For your convenience I have included a folder where this has already been done for you!

Next: Go to Pikachu's evo_moves.asm data, and change her evolution method to 'Level Up'. You probably want to choose a nice minimum level like 16 to discourage potion or turbo-run hax for early game Raichu. If you really want, though, you can set it to 1.

Then, go into the engine/evos_moves.asm and alter the level up function to check if the pokemon is pikachu, and for that happiness, and if so to skip straight to evolving.

code example: (search for .checkLevel and .doEvolution, and fix to look like this)

Code:
.checkLevel
  ld [hl], c
  ld a, [wEvoOldSpecies]
	cp PIKACHU
  jr nz, .CheckL
  ;160 is happiness level you have when you get to arms raised pikachu. I think?
  ld a, [wPikachuHappiness]
  cp 160
  jp c, .nextEvoEntry2
  jp c, .doEvolution
.CheckL
	ld a, [hli] ; level requirement
	ld b, a
	ld a, [wLoadedMonLevel]
	cp b ; is the mon's level less than the evolution requirement?
	jp c, .nextEvoEntry2 ; if so, go the next evolution entry
.doEvolution

Making Raichu Follow
---
This is the most interesting and painstaking part. You will need to go to each place that loads pikachu's sprite - there's one buffer that is used to reload the sprite after emotions, and two loading functions depending on if you are indoors or outdoors. Add a check if Raichu or Pikachu is in the party, then load the correct sprite depending.

go to engine/overworld/map_sprites.asm

First, InitOutsideMapSprites:

change .loadSpriteSet to something like this:
Spoiler:


Then, in the same file, find
LoadSpriteSetFromMapHeader:
;and alter the first bit of code there
Spoiler:


in engine/pikachu_movement, need to alter LoadPikachuSpriteIntoVRAM to something like this:

Spoiler:


Second, you will need to go in for any place that checks for Pikachu in your party, and add a second check for Raichu, so that Raichu's happiness can grow, you can have appropriate Raichu emotion sprites, and you can get Bulbasaur if you have a Raichu.

engine/pikachu_status is the place to alter here (this is a bit long, and there may be a more efficient way of coding this, buuut I'm still a novice so it's what you get):

Spoiler:


And, less important but still good to do, is altering in the same file IsThisPartymonStarterPikachu_Party, and the IsThisSurfpikachu check , where it CPs for Pikachu, do something like this:

Code:
cp RAICHU
	jr nz, .isPika
	jr .yes
.isPika
	cp PIKACHU
	jr nz, .notPlayerPikachu
.yes

edit: I forgot in pikachu_emotions there is a check for sleeping, too.

If the original does cp +1, +1 as well.
Now your Raichu can let you play the surfing minigame! Nice, huh? It'll still have a Pikachu sprite, but you could always replace that with a Raichu if you want.

You also need to create a sprite for Raichu if you haven't yet.
data/sprite_sets.asm, and in engine/bank3f just duplicate the PikachuSprite(s) there and include your image! This is quite important, as obviously you won't get a following Raichu otherwise!


Altering Pikachu's Voice / Changing voice on evolve
---

It is very simple, it involves replacing pikachu voice .wav files with other .wav files, or finding where they are called and choosing to play a different cry.

If some voices are only played at a certain happiness level, then one can just replace those with Raichu/evolved form without having to do any extra special checks.
You will also want to go to engine/battle/core.asm and to status_screen.asm to go put in a quick check for Raichu/Pikachu and load the right cry.
Like so:
Code:
.playPikachuSoundClip
  callab IsStarterRaichuInOurParty ;really should make one to check box too...
  jr nc, .Pikachu
  ld e,4 ;load voice '5', which I changed to Raichu. Note e starts on 0 to load PikachuCry1.
  jr .cry
.Pikachu
	ld e, 16 ;pikachu's original cry for this one.
.cry
	callab PlayPikachuSoundClip
	jr .continue

For your convenience I have included several Raichu voices that I went to the trouble of cropping from the anime and putting into wav format.

Different Starter (Replace Pikachu and Raichu)
----
Having just Pikachu as your only option is boring, right? Let's change that up.

First, start with the 'Evolve Pikachu' and 'Make Raichu Follow' code above so your new starter can evolve and still follow you around. (skip if you don't want any evolutions) Hypothetically you can do this with multiple evolutions, not just two, just choose another happiness level to evolve at for that 3rd evolution to make your final starter follower and duplicate Raichu check codes again.

There are two different routes you can take: you can replace Pikachu and Raichu with fakemon, or you can simply leave Pikachu and Raichu in the game and switch all the places that check for Pikachu (same ones as in the Raichu code above!) with a different pokemon, so:

cp PIKACHU

becomes

cp MEOWTH

or something like that.
It's not strictly necessary to rename PikachuSprite - no one in game will see the code, so it's just sufficient to change the image to your new pokemon. Duplicate for Raichu with any evolutions.

If you are replacing your entire Pokedex with Fakemon (or next gen pokemon), chances are you will still have to do the above, since I imagine you'll be wanting to rename your constants.

Here's a quick list of places you need to alter (or add stuff on to) for new pokemon:

/pics folder, both the backsprites (/monback) and frontsprites (/ymon)
main.asm (need to include said pics so the game knows where to find them)
pokemon and pokedex constants
everywhere in /data that talks about pokemunz, such as evos_moves and base_stats.
/data/wildPokemon the wild pokemon,
/data/baseStats individual pokemon.asms such as pikachu.asm. (Update base_stats to include any new asm.)
data/ cries, mon_party_sprites, mon_palettes
alter monster names and pokedex entries in /text

You might want to consider altering pikachu's voice too. (Edit: On analysis I found you can just easily edit out calls to pikachu's voice in pikachu_emotions)

Of course, last part needed for a new following starter is to, once again, change the pikachu emotion sprites! If you enjoy image crafting, this is the most fun and easy part, just open up in an image editor (edit: that accepts indexing) and save!
If you hate image drawing, on the other hand, perhaps consider some generic emotion sprites instead, like a ! mark. Your image should only use 4 colors - the image itself can be black, gray and white, since the game will load colors based on palette.



All Pokemon Follow (Now a simple version is complete!)
-----

The coding has been done for making any pokemon follow. It basically replaces the CheckForRaichu and makes a new happiness checker for any pokemon that isn't Pikachu. I split the old CheckforRaichu into two different functions; one to dynamically load the right sprite, and one to check if you have a pokemun in your party's first row.

You may want to replace the pikachu happiness images with generic emotion symbols / smiley faces like SoulSilver and HeartGold does and create some other method for dealing with happiness or allow pokemon happynuzz to all be tied together.
However, I present an alternative system of keeping Pikachu happiness as-is and having other pokemon have happiness based on HP stat exp. You can just comment out the pikachu picture anims and use the game's exclamation, hate and heart symbols.




Check Any Pokemon
Code:
IsaPokemonInOurParty::
	ld hl, wPartySpecies
	push hl
.loop
	pop hl
	ld a, [hli]
	push hl
	inc a
	jr z, .noPlayerPoke
;	cp WHATEVERPOKE + 1, if want all, just leave like this~
;	jr nz, .curMonNotPlayerPikachu
  call FirstPartymonHP
	cp 0
	jr z, .noPlayerPoke
	pop hl
	scf
	ret
.noPlayerPoke
	pop hl
	and a
	ret

First partymonHP (needed for fainting in the above function)
Code:
FirstPartymonHP::
  ld hl, wPartyMon1
  ld bc,(wPartyMon1HP + 1) - wPartyMon1 ;check hp
	add hl,bc
	ld a,[hl]
	ret


I put both of these code in pikachu_status, and called them from the map sprite loader functions I talked about earlier. In this code, I chose to check against either species or type, and basically went with what I had sprites for. If your sprite doesn't have full walk animations, it WILL glitch and look terrible, so make sure it matches pikachu's sprite image set size.
Note that unlike the original full code that checks for OT id and such, this one doesn't care if the pokemon is traded.
If you want to use Pikachu's happiness/status function, you still have to modify IsPikachuParty, instead of IsPikachuInOurParty, to accept all mons, as that's the function that checks status I think. Without it, only Pikachu/Raichu will get happiness updates when you do things with them. Personally I prefer the idea of developing a separate happiness function for the rest of them (see further below).

note: By default, the bird sprite, surf/seel sprite, and the slowbro sprite should have full walking sprites.

Here's the Loading Sprites function, you'll want to modify it to match your own game; for instance, mine has an eevee sprite so I added code for eevee. It got bloated pretty quickly :P.
Just like we did in the Raichu tutorial above, you'll want to put calls to this in engine/overworld/map_sprites.asm so both of the map sprite loading functions there will know what sprite to use.
Code:
LoadPokeFollowSprite::
  ld hl, wPartySpecies
	push hl
	pop hl
	ld a, [hli]
	push hl
	inc a
	jp z, .noPlayerPoke
	CP PIKACHU +1
	jr nz, .curMonNotThis0
	ld a, SPRITE_PIKACHU
.end
  pop hl
	scf
	ld [wSpriteSet], a
	ret
.noPlayerPoke
	pop hl
	and a
	ret	
.curMonNotThis0
	CP RAICHU +1
	jr nz, .curMonNotThis1
	ld a, SPRITE_RAICHU
	jr .end
.curMonNotThis1
	cp PERSIAN + 1
	jr nz, .curMonNotThis2
	ld a, SPRITE_PERSIAN
	jr .end
.curMonNotThis2
	cp BULBASAUR + 1
	jr nz, .curMonNotThis3b
	ld a, SPRITE_BULBASAUR
	jr .end
.curMonNotThis3b
	cp IVYSAUR + 1
	jr nz, .curMonNotThis3c
	ld a, SPRITE_BULBASAUR
	jr .end
.curMonNotThis3c
	cp VENUSAUR + 1
	jr nz, .curMonNotThis3
	ld a, SPRITE_BULBASAUR
	jr .end
.curMonNotThis3
	cp EEVEE + 1
	jr nz, .curMonNotThis4a
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4a
  cp SYLVEON + 1
	jr nz, .curMonNotThis4b
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4b
	cp UMBREON + 1
	jr nz, .curMonNotThis4c
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4c
	cp ESPEON + 1
	jr nz, .curMonNotThis4d
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4d
	cp FLAREON + 1
	jr nz, .curMonNotThis4e
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4e
	cp GLACEON + 1
	jr nz, .curMonNotThis4f
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4f
	cp JOLTEON + 1
	jr nz, .curMonNotThis4g
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4g
	cp VAPOREON + 1
	jr nz, .curMonNotThisEon
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThisEon
	cp LEAFEON + 1
	jr nz, .curMonNotThis4
	ld a, SPRITE_EEVEE
	jr .end
.curMonNotThis4
	cp DITTO + 1
	jr nz, .curMonNotThisDitto
	ld a, SPRITE_DITTO
	jr .end2
.curMonNotThisDitto
	cp SQUIRTLE + 1
	jr nz, .curMonNotThis5a
	ld a, SPRITE_SQUIRTLE
	jr .end2
.curMonNotThis5a
	cp WARTORTLE + 1
	jr nz, .curMonNotThis5b
	ld a, SPRITE_SQUIRTLE
	jr .end2 
.curMonNotThis5b
	cp LAPRAS + 1
	jr nz, .curMonNotThisM
	ld a, SPRITE_LAPRAS
	jr .end2
.curMonNotThisM
	cp GYARADOS + 1
	jr nz, .curMonNotThisFish
	ld a, SPRITE_GYARADOS
	jr .end2 
.curMonNotThisFish
	cp SEEL + 1
	jr nz, .curMonNotThisFishy
	ld a, SPRITE_SEEL
	jr .end2 
.curMonNotThisFishy
	cp DEWGONG + 1
	jr nz, .curMonNotThisFishfood
	ld a, SPRITE_SEEL
	jr .end2 
.curMonNotThisFishfood
	cp SANDSHREW + 1
	jr nz, .curMonNotThisShrew
	ld a, SPRITE_SANDSHREW
	jr .end2;relative value must be 8 bit
.curMonNotThisShrew
	cp SANDSLASH + 1
	jr nz, .curMonNotThisS
	ld a, SPRITE_SANDSHREW
.end2;so, we have multiple different endings here
  pop hl
	scf
	ld [wSpriteSet], a
	ret
.curMonNotThisS
	cp BLASTOISE + 1
	jr nz, .curMonNotThis5
	ld a, SPRITE_SQUIRTLE
	jr .end2
.curMonNotThis5
	cp CHARIZARD + 1
	jr nz, .curMonNotThis6a
	ld a, SPRITE_DRAGON
	jr .end2
.curMonNotThis6a
	cp CHARMELEON + 1
	jr nz, .curMonNotThis6b
	ld a, SPRITE_CHARMANDER
	jr .end2
.curMonNotThis6b
	cp CHARMANDER + 1
	jr nz, .curMonNotThisStarter
	ld a, SPRITE_CHARMANDER
	jr .end2
.curMonNotThisStarter
	cp DRAGONITE + 1
	jr nz, .curMonNotThisG
	ld a, SPRITE_DRAGON
	jr .end2
.curMonNotThisG
	cp ONIX + 1
	jr nz, .curMonNotThisMon
	ld a, SPRITE_SNAKE2
	jr .end2
.curMonNotThisMon
	cp EKANS + 1
	jr nz, .curMonNotThisMon2
	ld a, SPRITE_SNAKE2
	jr .end2
.curMonNotThisMon2
	cp ARBOK + 1
	jr nz, .curMonNotThisMon3
	ld a, SPRITE_SNAKE2
	jr .end2
.curMonNotThisMon3
	cp VOLTORB + 1
	jr nz, .curMonNotThisMon4
	ld a, SPRITE_BALL
	jr .end2
.curMonNotThisMon4
	cp ELECTRODE + 1
	jr nz, .curMonNotThisMon5
	ld a, SPRITE_BALL
	jr .end2
.curMonNotThisMon5
	cp MAGNEMITE + 1
	jr nz, .curMonNotThisMon6
	ld a, SPRITE_BALL
	jr .end2
.curMonNotThisMon6
	cp MAGNETON + 1
	jr nz, .curMonNotThisMon7
	ld a, SPRITE_BALL
	jr .resume
.curMonNotThisMon7
	cp MAGNEZONE + 1
	jr nz, .curMonNotThisMon8
	ld a, SPRITE_BALL
	jr .resume
.curMonNotThisMon8
	cp GLIGAR + 1
	jr nz, .curMonNotThisMon9
	ld a, SPRITE_ZUBAT
	jr .resume
.curMonNotThisMon9
	cp GLISCOR + 1
	jr nz, .curMonNotThisMon10
	ld a, SPRITE_ZUBAT
	jr .resume
.curMonNotThisMon10
	ld a,[wPartyMon1Type1]
 ; callab GetPartyMonSpriteID I didn't have much luck with this, also don't have enough sprites for all of them; they have to have full walksprites.
  ;cp SPRITE_MON              ; $0
	;cp SPRITE_BALL_M           ; $1
	;cp SPRITE_HELIX            ; $2
	cp FAIRY            
	jr nz, .curMonNotThisFairy
	ld a, SPRITE_CLEFAIRY
	jr .resume
.curMonNotThisFairy
	cp WATER           
	jr nz, .curMonNotThisWater
	ld a, SPRITE_FISH
	jr .resume
.curMonNotThisWater
  cp FIRE
	jr nz, .curMonNotThis6
	ld a, SPRITE_DOG
	jr .resume
.curMonNotThis6
	cp BUG              
	jr nz, .curMonNotThisBug
	ld a, SPRITE_BUTTERFREE
	jr .resume
.curMonNotThisBug
	cp GRASS       
	jr nz, .curMonNotThisGrass
	ld a, SPRITE_ODDISH
	jr .resume
.curMonNotThisGrass
  cp DRAGON       
	jr nz, .curMonNotThisDragony
	ld a, SPRITE_SNAKE2
	jr .resume
.curMonNotThisDragony
  cp ROCK        
	jr nz, .curMonNotThis
	ld a, SPRITE_GEODUDE
	jr .resume
.curMonNotThis
  cp GHOST       
	jr nz, .curMonNotThisGhost
	ld a, SPRITE_GHOST
	jr .resume
.curMonNotThisGhost
  cp POISON       
	jr nz, .curMonNotThisPoison
	ld a, SPRITE_ZUBAT
	jr .resume
.curMonNotThisPoison
  ld a,[wPartyMon1Type2]
	cp FLYING
	jr nz, .curMonNotThisBird
	ld a, SPRITE_BIRD
	jr .resume
.curMonNotThisBird
	cp DARK        
	jr nz, .curMonNotThisredux
	ld a, SPRITE_MEOWTH
	jr .resume
.curMonNotThisredux
  ld a, SPRITE_SLOWBRO
  jr .resume
.resume
	ld [wSpriteSet], a
  pop hl
	scf
	ret
so, using above, modify the various add/call sprite codes.

VRAM:
Code:
LoadPikachuSpriteIntoVRAM:
  call IsPikachuFirst
  cp 25 ;rather arbitrary value I asked pikachufirst to load...
  ld a,0
  jr nz, .load2
  call IsStarterPikachuInOurParty2
  jr nc, .Raichu
  ld de, PikachuSprite
	;lb bc, BANK(PikachuSprite), (SandshrewSprite - PikachuSprite) / 32
	jr .go
.Raichu
	ld de, RaichuSprite
.go
  lb bc, BANK(PikachuSprite), (SandshrewSprite - PikachuSprite) / 32
	ld hl, vNPCSprites + $c * $10
	push bc
	call CopyVideoDataAlternate
	call IsStarterRaichuInOurParty
	jr nc, .Pikachu2
	ld de, RaichuSprite + $c * $10
  jr .goo
.Pikachu2
	ld de, PikachuSprite + $c * $10
.goo
	ld hl, vNPCSprites2 + $c * $10
	ld a, [h_0xFFFC]
	and a
	jr z, .load
	callab IsStarterRaichuInOurParty
	jr nc, .Pikachu3
	ld de, RaichuSprite + $c * $10
  jr .goo2
.Pikachu3
	ld de, PikachuSprite + $c * $10
.goo2
	ld hl, vNPCSprites2 + $4c * $10
.load
	pop bc
	call CopyVideoDataAlternate
.load2
	call LoadPikachuShadowIntoVRAM
	call LoadPikachuBallIconIntoVRAM
	ret


Here's a quick example of modifying what emotion sprites come up for non-pikachu mons:
in pikachu_emotions, you'll find .check_pikachu_status, alter the start of it:
Code:
.check_pikachu_status
  call IsPikachuFirst
  cp 25
  jr z, .Pika
  ldpikaemotion a, PikachuEmotion24;PikachuEmotion5 unhappy,28 status,29 heart 8 happy, 1 content, 32 confused, 27 shocked, 26 zz wakeup, 25 used attack, 24 exclaim.
	jr c, .play_emotion
.Pika

I went in and disabled all the animation except the ! point for anim 24; it's for pikachu refusing to evolve and I don't really need it much. You can find PikachuEmotion24 in the other pikachu_emotions file, if you comment out:
;pikaemotion_pikapic PikaPicAnimScript24
then that'll do it. Only the exclamation point will play, and you won't get Pikachu sprites for the other pokemon anymore.
You could also try making your own emotion scripts. I'll show that shortly.

Remember to put in some function for just pikachu/raichu detection, if you want to treat them specially:
Code:
IsPikachuFirst::
	ld hl, wPartySpecies
	push hl
.loop
	pop hl
	ld a, [hli]
	push hl
	inc a
	jr z, .noPlayerPoke	
	cp PIKACHU + 1
	jr z, .curMonPlayerPikachu
	cp RAICHU + 1
	jr nz, .noPlayerPoke
.curMonPlayerPikachu
  ld a,25 ;completely arbitrary value to check for, as long as it ain't zero. >_>
  pop hl
  ret
.noPlayerPoke
  ld a,0
	pop hl
	ret

You can alter sprite_sets and sprite_constants to add on new sprites like I did, or you can just replace old ones.

Here's a function for alternative happiness:

Code:
FirstPartymonHappy::
	ld hl, wPartyMon1
	ld bc,wPartyMon1HPExp - wPartyMon1 ;decided to base it off HP exp
	add hl,bc
	ld a,[hl]
	ret

it loads the "happiness" (really hp exp) into a.

Then do a more elaborate modification of happiness in pikachu_emotions:

Code:
.check_pikachu_status
  call IsPikachuFirst
  cp 25
  jr z, .Pika
  call FirstPartymonHappy
  cp 1
  jr nc, .content ;bigger than
  ldpikaemotion a, PikachuEmotionSkull
  jr .play_emotion
.content
  cp 10
  jr nc, .happy
  ldpikaemotion a, PikachuEmotion24;PikachuEmotion5 unhappy,28 status,29 exuberant heart 8 happy, 1 content, 32 confused, 27 shocked, 26 zz wakeup, 25 used attack, 24 exclaim.
  jr .justlilhappy
.happy
  cp 30
  jr nc, .happy2
  ldpikaemotion a, PikachuEmotionSmile;PikachuEmotion5 unhappy,28 status,29 exuberant heart 8 happy, 1 content, 32 confused, 27 shocked, 26 zz wakeup, 25 used attack, 24 exclaim.
  jr .justlilhappy
.happy2
  ldpikaemotion a, PikachuEmotionHeart
.justlilhappy
	jr .play_emotion
.Pika
small edit: prev happiness standards were way too high. :P

Here's some generic replacement emotions you might like, remember to modify both pikachu_emotions (data and engine), one to add these and another has a little table listing all the emotes:

Code:
PikachuEmotionSmile:
	pikaemotion_dummy2
	pikaemotion_emotebubble SMILE_BUBBLE
	db $ff
	
PikachuEmotionHeart:
	pikaemotion_dummy2
	pikaemotion_emotebubble HEART_BUBBLE
	db $ff
	
PikachuEmotionSkull:
	pikaemotion_dummy2
	pikaemotion_emotebubble SKULL_BUBBLE
	db $ff

Running in Yellow
===
Running can be done the exact same way as in Red, but it will cause Pikachu to lag behind. Provided you don't mind this, it works just fine. Pikachu will eventually catch up. Credit goes to Red++ Matteo.

Code:
ld a, [hJoyHeld] ; Check what buttons are being pressed for Shoes
	and B_BUTTON ; Are you holding B?
	jr z, .notRunning ; If you aren't holding B, skip ahead to step normally.
	jp .goFaster ; Needs to link or call to your method of going faster. Make you go faster if you were holding B
.notRunning ; Normal code resumes here


I just stuck this in overworld.asm in dobikespeedup, and it worked fine. You'll want to speed up the normal bike, which brings me to....

Altered Biking in Yellow
===
This can be a pain if you are adding a girl or extra selectable character (there's a tutorial floating around somewhere on it - it just requires going in to all the places that call a boy image and adding a girl flag check, plus option to choose gender in the intro -), because you'll likely immediately run into BANK0 TOO FULL error when you try to add the extra bike image checks.

As such, I opted for Pokemon Riding instead, since it just requires changing the bike image to a pokemon. (I also sped up my bike - now a pokemon - with an extra call AdvancePlayerSprite in the BikeSpeedUp function in overworld.asm)
You don't have to do the same, but it may be less hassle for you.

New, Multiple SHINIES
===
(This is just a quick tut on how to do multiple shinies, not shinies in general; the full code there is in Red++)

I altered status_screen, super_palettes (just to add one more palette is all, add as many shiny palettes as you want)
engine/palettes.asm:

Code:
	ld hl, MonsterPalettes
	;shiny
	ld e, a
	ld d, $00
	add hl, de
	ld a, [hl]
	push bc
	ld d, a
	ld a, e
	and a
	ld a, d
	jr z, .done
	ld b, a
	ld a, [wShinyMonFlag]
	bit 0, a ; is mon supposed to be shiny?
	ld a, b
	jr z, .done
	ld b, a
	ld a,[wTemp]
;Shinybit 1	
	cp 1
	jr nz, .nextcolor
	;ld a,b
	;add (3) ;
	ld a, PAL_MEWTWO ;the best pokemon? >_>
	jr .done
.nextcolor
	ld a,[wTemp]
	cp 2
	jr nz, .nextcolor2
	ld a,PAL_BLUEMON ; or maybe do PAL_NIDORINA 
	;add (3)
	jr .done
.nextcolor2
	ld a,[wTemp]
	cp 3
	jr nz, .nextcolor3
	ld a,PAL_YELLOWMON
	;add (4)
	jr .done
.nextcolor3
	cp 5
	jr nz, .nextcolor4
	ld a,PAL_GREENMON ;
	jr .done
.nextcolor4
	cp 6
	jr nz, .nextcolor5
	ld a,PAL_SHINY ;blackmon
	jr .done
.nextcolor5
	ld a,[wTemp]
	cp 4
	jr nz, .nope
	ld a,PAL_PINKMON
	;ld a,b
	;add (5) ;older version just shifted palettes forward.
	jr .done
.nope
 ld a,b
.done
	pop bc
	ret

and in main.asm, set the varieties/check for different shines!

Code:
IsMonShiny:
; Input: de = address in RAM for DVs
; Reset zero flag if mon is shiny
; Mon is shiny if Defense/Speed/Special are 10, and Attack is 2, 3, 6, 7, 10, 11, 14, or 15
	ld h, d
	ld l, e
	;Attack must be even2,odd1 (1, 3, 5, 7, 9, 11, 13, or 15) (1 in 2)
	ld a, [hl]
	and 2 << 4
	jr z, .NotShiny
	ld a,0
	ld [wTemp], a
	ld a, [hli]
	and $f
	cp 9
	jr z, .MaybeShiny1
	cp 8
	jr z, .MaybeShiny2
	cp 7
	jr z, .MaybeShiny3
	cp 2
	jr z, .MaybeShiny4
	cp 11
	jr nz, .NotShiny
.MaybeShiny1 ;color1
	ld a, 1
	ld [wTemp], a
	ld a, [hl]
	jr .Shiny
.MaybeShiny2;color2
	ld a, 2
	ld [wTemp], a
	ld a, [hl]
	jr .Shiny
.MaybeShiny4;color2
	ld a, 4
	ld [wTemp], a
	ld a, [hl]
	jr .Shiny
.MaybeShiny3;color3
	ld a, 3
	ld [wTemp], a
	ld a, [hl]
		;ol' speed check if we want to reduce values even more, would have to alter the maybe shinies above to go here instead of shiny. could also introduce even moar varieties of pokemonz.
;.shinyspeedcheck
	;and $f << 4
	;cp 5 << 4
	;jr z, .Shiny
	;cp 13 << 4
	;jr nz, .NotShiny
.Shiny
	; set zero flag
	and a ; a cannot be 0, so zero flag is set with thing command
	ret
.NotShiny
	; reset zero flag
	xor a
	ret

You also of course have to do the calling for the shiny check in battle.
Code:
		; is mon shiny?
	ld b, Bank(IsMonShiny)
	ld hl, IsMonShiny
	ld de, wEnemyMonDVs
	call Bankswitch
	ld hl, wShinyMonFlag
	jr nz, .shiny
	res 0, [hl]
	jr .setPAL
.shiny
	set 0, [hl]
.setPAL
	ld b, SET_PAL_BATTLE
	call RunPaletteCommand 
	call HideSprites
	jpab PrintBeginningBattleText;search for this line
This is just my example of modifying the shiny code, the original version you can check out in Red++; the only thing you have to worry about when porting it over to yellow is some variable names change slightly.

NEW, ADDING HOLD ITEMS!
==============================

Edit Note: There's a part of it that is bizarrely finicky. One version of my game only accepts value 20 (or super potion) another, more recent one wanted value 21 set to the item id var on party screen load and map screen load. So be careful with this or it will crash your game, and double check it on any changes you make to the game that it's still working. I suspect this is an indicator I'm doing something wrong.


Alter items.asm, start_sub_menus, battle/core.asm, engine/menu/status_screen.asm and text_ids2. ^_^ I also altered all of the pokemon's catch rates so they would either be above my item range or valid items within that range. If you want you can personally over-ride so all caught pokemon will have catch rate of the same item, in Yellow just search for where it alters Kadabra's catch rate.

This is a _very_ basic item system, I encourage you to develop it further than this.


first ,items.asm:
Code:
	GivePokeHoldItem:
	ld a, 1
	ld [wActionResultOrTookBattleTurn], a ; initialise to success value
	ld a,[wWhichPokemon]
	ld [wTempLevel],a ; remember which item slot was used
	
	ld a, [wcf91]	;contains item_ID?
	ld [wTemp],a
	cp 20
	jr z, .works
	ld a, 20
	ld [wcf91],a
	;party menu isn't working right for anything EXCEPT super potion, equal to 20, bizarrely? probably because trying to load some value in same spot it originally saves item. so let's save the nonsuperpotion and then over-write... >_> meh.
.works
	ld a, [wPartyCount]
	and a
	jp z, .canceledItemUse
	ld a, [wWhichPokemon]
	push af
	ld a, [wcf91]
	push af
	ld a, USE_ITEM_PARTY_MENU
	ld [wPartyMenuTypeOrMessageID], a
	ld a, $ff
	ld [wUpdateSpritesEnabled], a
	call DisplayPartyMenu
	
.getPartyMonDataAddress
	jp c, .canceledItemUse
	ld hl, wPartyMons
	ld bc, wPartyMon2 - wPartyMon1
	ld a, [wWhichPokemon]
	call AddNTimes
	ld a, [wWhichPokemon]
	ld [wUsedItemOnWhichPokemon], a
	ld d, a
	
	ld [wd0b5], a
	call GetMonHeader
	ld bc,wPartyMon1CatchRate - wPartyMon1
	add hl,bc ; hl now points to catch, now item
	ld a, [hl] ;Let's do a check for what the item is
	cp 70 ; you need to put your max valid item count here
	jr c, .cnt ;less than than...
	ld a, 20
	 ;overwrite with potion if the catch rate of Mon is nonexistent item.
	;ld [hl],a ;not necessary to actually do it yet since we overwrite shortly anyway
.cnt 
  ld [wTempCoins1], a ;hold bag id for laters
  ;Now give pokemon the new hold item.
	;xor a ;remove catch, unnecessary but useful if we want no items by default.
	ld a, [wTemp];item
	ld [hl], a ;ld into CatchRate,a
	ld [wd11e],a ; store item ID for GetItemName
	call GetItemName
	call CopyStringToCF4B ; copy name to wcf4b
	ld hl, HoldItemText
	Call PrintText
	
	;take away the old item held and give it to bag
	ld a, [wTempCoins1]
  ld [wcf91],a ;item id
  ld [wd11e],a ;fo item name
  ld hl, wNumBagItems ;put the address of bag in hl
  ld a,1
  ld [wItemQuantity],a ;how many to add
  call AddItemToInventory
  call GetItemName
	call CopyStringToCF4B ; copy name to wcf4b
	ld hl, TookItemText
	Call PrintText
	
  ld a, 20
	ld [wcf91],a ;overwrite fix fo map again...
	
.nope
  ld a,[wTempLevel]
  ld [wWhichPokemon],a
  ld a, 1
  ld [wItemQuantity],a
  ld hl, wNumBagItems
  call RemoveItemFromInventory ;needs wWhichPokemon to have itemslot in it.
.canceledItemUse
	call GBPalWhiteOut
	call z, RunDefaultPaletteCommand
	ld a, [wIsInBattle]
	and a
	ret nz
	jp ReloadMapData

HoldItemText::
 text "Gave the item"
 line "@"
 TX_RAM wcf4b ;some variable goes here
 text "."
 prompt
TookItemText::
 text "Took away the item"
 line "@"
 TX_RAM wcf4b ;some variable goes here
 text "."
 prompt


text_ids2.asm:
alter this:
Code:
UseTossText:
	db   "USE"
	next "GIVE"
	next "TOSS@"

and in start_sub_menus:

Code:
.notBicycle2
	ld a,[wCurrentMenuItem]
	;and a
	cp a, 2
	jr z, .tossItem
	cp a, 1
	jr z, .giveItem1
; use item
  jr .useitem
.giveItem1
  ld b,a
  ld a,8
  ld [wTemp],a
  ld a,b
.useitem
	ld [wPseudoItemID],a ; a must be 0 due to above conditional jump
	ld a,[wcf91]
	cp a,HM_01
	jr nc,.useItem_partyMenu
	ld hl,UsableItems_CloseMenu
	ld de,1
	call IsInArray
	jr c,.useItem_closeMenu
	ld a,[wcf91]
	ld hl,UsableItems_PartyMenu
	ld de,1
	call IsInArray
	jr c,.useItem_partyMenu
	call UseItem
	jp ItemMenuLoop
.useItem_closeMenu
  ;ld a,[wTemp]
	;cp a, 8
	;jr z, .giveItem
	;don't want this one
	xor a
	ld [wPseudoItemID],a
	call UseItem
	ld a,[wActionResultOrTookBattleTurn]
	and a
	jp z,ItemMenuLoop
	jp CloseStartMenu
.useItem_partyMenu
  ld a,[wTemp]
	cp a, 8
	jr z, .giveItem
	;hopefully works
	ld a,[wUpdateSpritesEnabled]
	push af
	call UseItem
	ld a,[wActionResultOrTookBattleTurn]
	cp a,$02
	jp z,.partyMenuNotDisplayed
	call GBPalWhiteOutWithDelay3
	call RestoreScreenTilesAndReloadTilePatterns
	pop af
	ld [wUpdateSpritesEnabled],a
	jp StartMenu_Item
.partyMenuNotDisplayed
	pop af
	ld [wUpdateSpritesEnabled],a
	jp ItemMenuLoop
.tossItem
	call IsKeyItem
	ld a,[wIsKeyItem]
	and a
	jr nz,.skipAskingQuantity
	ld a,[wcf91]
	call IsItemHM
	jr c,.skipAskingQuantity
	call DisplayChooseQuantityMenu
	inc a
	jr z,.tossZeroItems
.skipAskingQuantity
	ld hl,wNumBagItems
	call TossItem
.tossZeroItems
	jp ItemMenuLoop
.giveItem
  ld a,[wUpdateSpritesEnabled]
	push af
	callab GivePokeHoldItem
	ld a,[wActionResultOrTookBattleTurn]
	cp a,$02
	jp z,.partyMenuNotDisplayed
	call GBPalWhiteOutWithDelay3
	call RestoreScreenTilesAndReloadTilePatterns
	pop af
	ld [wUpdateSpritesEnabled],a
	jp StartMenu_Item

status_screen.asm:
[/code]
.StatusWritten
coord hl, 9, 6
;ld de, StatusText;old status text, which just says 'status'
;call PlaceString ; "STATUS/"
ld a, [wLoadedMonCatchRate]
cp 100
jr c, .cnt ;replace 100 above with whatever your max item is, a guard against invalid values
ld a, 20
ld [wLoadedMonCatchRate],a
.cnt
ld [wd11e],a ; store item ID for GetItemName
call GetItemName
ld de,wcd6d;PokeHoldItemText;
call PlaceString
[/code]

In core.asm, to have it actually happen in battle, also alter
Code:
	ApplyAttackToEnemyPokemonDone:
	;######HOLD ITEM SCRIPT! @@@####;
  ld a, [wBattleMonCatchRate]
  cp FULL_HEAL ;is it potionz?
  jr c, .IsItOther
  ld a,0
  ld [wBattleMonStatus],a
  jr .NoUseBerry
.IsItOther
  cp POTION ;is it potionz
  jr c, .IsItOther2
  ld b,10 
  jr .UseHealBerry
.IsItOther2
  cp SUPER_POTION ;is it potionz?
  jr c, .NoUseBerry
  ld b,20
.UseHealBerry
  ld a, [wBattleMonHP + 1]
	cp 15;less than 15 health, use a held item.
  jr nc, .NoUseBerry ;if bigger than above, don't use
  ld a,[wBattleMonHP + 1]
  ;ld b, 10
  add b
  ld b,a 
  ld a,[wBattleMonMaxHP +1]
  cp b
  jr nc, .ContUseItem ;if maxhp bigger than b, continue
	ld a,[wBattleMonMaxHP +1] ; full restore
	ld b,a
.ContUseItem
  ld a, b
	ld [wBattleMonHP + 1],a
	ld [wHPBarNewHP],a
  ld a,FULL_RESTORE
  ld [wBattleMonCatchRate], a ;replace with diff item after use...doesn't seem to work permanently
	callab PrintHoldItemText
.NoUseBerry 
	jp DrawHUDsAndHPBars
Do same thing to Apply Damage to Player Done for items, but with different vars.
I commented out a lot of mine because right now I just want enemies to heal up, my bank was running out of space, and didn't feel like moving around stuff just yet to free up space.
The biggest problem with this code is making an enemy pokemon potentially easier to catch when you alter their item, since catchrate is same as item. Also, items are infinitely reusable after the battle ends, since there is no code for 'no item held' yet nor any permanent replacement mechanism here. However, if you're developing perma-held items like Mega Evolution Stones, that works great.
Code:
	ApplyAttackToPlayerPokemonDone:
;######HOLD ITEM SCRIPT! @@@####;
  ld a, [wEnemyMonCatchRate]
  cp 99 ;Enemies with catch rate lower than that should use items.
  jr nc, .NoUseBerry
 
  ld a, [wEnemyMonHP + 1]
	cp 10;less than 10 health, use a held item.
  jr nc, .NoUseBerry ;if bigger than, don't use
  ;ld b,10 ;better heal. you can uncomment this stuff if you want
  ;ld a,[wEnemyMonHP + 1]
  ;add b
  ;ld b,a 
  ;ld a,[wEnemyMonMaxHP +1]
  ;cp b
  ;jr nc, .ContUseItem ;if maxhp bigger than b, continue
	;ld a,[wEnemyMonMaxHP +1] ; full restore instead of letting HP overflow
	;ld b,a
;.ContUseItem
  ld a, 15 ;originally load b, to be more dynamic, but no point to that here. not enough bank space atm, would have to move stuff around
	ld [wEnemyMonHP + 1],a
  ld a,100
  ld [wEnemyMonCatchRate], a ;replace with diff item after use...doesn't seem to work permanently. anyway, may make a poke easier to catch. >_>
	callab PrintHoldItemText
.NoUseBerry
	jp DrawHUDsAndHPBars
Put this wherever you want, if in same bank then just use call instead of callab:
Code:
UseHoldItemText::
 text "The PKMN ate a little!"
 ;line "@"
 ;TX_RAM wcf4b ;some variable goes here if we want, could put in the item name.
 ;text "."
 prompt

PrintHoldItemText:
 ld hl,UseHoldItemText
 Call PrintText
 ret


-----

Common Bugs -

BANK TOO FULL.

Yellow has less room in a lot of its banks, so you'll run into this very quickly. Some stuff can be shifted to a different bank with no problem, some code is superfluous and can be edited out (For instance, functions with a comment next to them saying 'Unused'.) but sometimes you have to be more careful. Things in banks often call in other things in that bank - I've switched from call to callab with no problems in these instances in the case of functions.
You also need to be careful with images; if something calls a set of images from one bank, and you moved one of those, you'll need to update that code to tell it the new bank to use. In the case of adding new pokemon, I highly recommend Dannye-33's Yellow Gen 2 Sprites Base instead of vanilla pokemon yellow disassembly. All you have to do there for new pokemon images having different banks is to go into their main datafile (such as pikachu.asm) and add the bank on the end! Viola! No more bank troubles.

My Added New Species Turned Into a Trainer!

If you add over 201 species, those over that number will turn into trainers in the wild. Annoying, I know. I believe there is a 'expand past 255 pokemon' project that fixes this and does all the hard work of adding pokemon for ya -wink-, it's for pokered but Yellow is similar so a lot of code, maybe even all, should be portable over. I haven't done this myself though.

My new pokemon turned into an ugly blob! / My pikachu emotion sprite is messed up!

You need to be careful that your image isn't too big or contains too many colors. I recommend a program like gale that can reduce colors to a small palette and then draw with them. What I like to do is duplicate an existing game-friendly image and then just blank it out and draw over that.

-------------

If you want to see some results of this code in action, check out my Yellow hack's screenshots in my hack's thread. Or play the game yourself - it's the first and currently the only hack with an evolving following pokemon, but hopefully with this tutorial that won't stay true for long!


UPDATE:
I've added some extra walking sprites that you can replace pikachu and raichu with. If you are lazy, you can just rename the sprite in question 'pikachu' and put it in the proper folder and it'll work like a charm. Partial credit goes to Dannye-33 for the Persian, Meowth, Eevee, Butterfree, Ghost, Ditto, Zubat, Dratini, Geodude, Fish.
Gyarados's partial credit goes to emimonserrate, who made the sprite I based the walkset on.

There is now a Github that contains the changes I speak of if you want to see it.
 

Attachments

  • raichu.png
    raichu.png
    640 bytes · Views: 538
  • pikachu.zip
    91 KB · Views: 37
  • cycling.png
    cycling.png
    533 bytes · Views: 481
  • persian.png
    persian.png
    605 bytes · Views: 479
  • squirtle.png
    squirtle.png
    540 bytes · Views: 463
  • ballpoke.png
    ballpoke.png
    346 bytes · Views: 461
  • bulbasaur.png
    bulbasaur.png
    569 bytes · Views: 459
  • charmander.png
    charmander.png
    608 bytes · Views: 458
  • bug.png
    bug.png
    570 bytes · Views: 459
  • geodude.png
    geodude.png
    389 bytes · Views: 452
  • gyarados.png
    gyarados.png
    529 bytes · Views: 453
  • ghost.png
    ghost.png
    529 bytes · Views: 456
  • fish.png
    fish.png
    638 bytes · Views: 458
  • meowth.png
    meowth.png
    612 bytes · Views: 455
  • eevee.png
    eevee.png
    517 bytes · Views: 459
  • ditto.png
    ditto.png
    406 bytes · Views: 450
  • sandshrew.png
    sandshrew.png
    432 bytes · Views: 453
  • zubat.png
    zubat.png
    464 bytes · Views: 452
  • snake.png
    snake.png
    609 bytes · Views: 449
  • raichu_cry_1.wav
    78.3 KB
  • raichu_cry_2.wav
    79.6 KB
  • raichu_cry_3.wav
    54.5 KB
  • Raichu_unhappy.wav
    98.2 KB
Last edited:
Back
Top