- 200
- Posts
- 11
- Years
- He or They
- 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)
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:
Then, in the same file, find
LoadSpriteSetFromMapHeader:
;and alter the first bit of code there
in engine/pikachu_movement, need to alter LoadPikachuSpriteIntoVRAM to something like this:
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):
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:
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:
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
First partymonHP (needed for fainting in the above function)
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.
so, using above, modify the various add/call sprite codes.
VRAM:
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:
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:
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:
it loads the "happiness" (really hp exp) into a.
Then do a more elaborate modification of happiness in pikachu_emotions:
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:
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.
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:
and in main.asm, set the varieties/check for different shines!
You also of course have to do the calling for the shiny check in battle.
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:
text_ids2.asm:
alter this:
and in start_sub_menus:
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
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.
Put this wherever you want, if in same bank then just use call instead of callab:
-----
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.
========================================================
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:
Code:
.loadSpriteSet
ld a, b
ld [wSpriteSetID], a
dec a
ld c, a
ld b, 0
ld a, (wSpriteSetID - wSpriteSet)
ld hl, SpriteSets
call AddNTimes ; get sprite set offset
ld de, wSpriteSet
ld bc, (wSpriteSetID - wSpriteSet)
call CopyData ; copy it to wSpriteSet
;change wSpriteSet here to Raichu if you want a Raichu. but what to check, hmm... how about a new function cloned from IsStarterPikachuInOurParty to check for Raichu instead? Worked for me.
callab IsStarterRaichuInOurParty
jr nc, .nope
ld a, SPRITE_RAICHU
ld [wSpriteSet], a
.nope
call LoadMapSpriteTilePatterns
.skipLoadingSpriteSet
call Func_14150
scf
ret
Then, in the same file, find
LoadSpriteSetFromMapHeader:
;and alter the first bit of code there
Spoiler:
Code:
ld hl, wSpriteSet
ld bc, (wSpriteSetID - wSpriteSet)
xor a
call FillMemory
ld a, SPRITE_RAICHU
ld [wSpriteSet], a
;load raichu on cert flag
callab IsStarterPikachuInOurParty2
jr z, .nope
ld a, SPRITE_PIKACHU ; load Pikachu separately
ld [wSpriteSet], a
.nope
in engine/pikachu_movement, need to alter LoadPikachuSpriteIntoVRAM to something like this:
Spoiler:
Code:
LoadPikachuSpriteIntoVRAM:
callab IsStarterPikachuInOurParty2
jr nz, .Raichu
ld de, PikachuSprite
lb bc, BANK(PikachuSprite), (SandshrewSprite - PikachuSprite) / 32
jr .go
.Raichu
ld de, RaichuSprite
lb bc, BANK(PikachuSprite), (SandshrewSprite - PikachuSprite) / 32
.go
ld hl, vNPCSprites + $c * $10
push bc
call CopyVideoDataAlternate
callab IsStarterRaichuInOurParty
jr z, .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 z, .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
call LoadPikachuShadowIntoVRAM
call LoadPikachuBallIconIntoVRAM
ret
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:
Code:
IsStarterPikachuInOurParty::
call IsStarterPikachuInOurParty2
jr nc, .checkR
ret
.checkR
call IsStarterRaichuInOurParty
ret
IsStarterPikachuInOurParty2::
ld hl, wPartySpecies
ld de, wPartyMon1OTID
ld bc, wPartyMonOT
push hl
.loop
pop hl
ld a, [hli]
push hl
inc a
jr z, .noPlayerPikachu
cp PIKACHU + 1
jr nz, .curMonNotPlayerPikachu
ld h, d
ld l, e
ld a, [wPlayerID]
cp [hl]
jr nz, .curMonNotPlayerPikachu
inc hl
ld a, [wPlayerID+1]
cp [hl]
jr nz, .curMonNotPlayerPikachu
push de
push bc
ld hl, wPlayerName
ld d, $6 ; possible player length - 1
.nameCompareLoop
dec d
jr z, .sameOT
ld a, [bc]
inc bc
cp [hl]
inc hl
jr z, .nameCompareLoop
pop bc
pop de
.curMonNotPlayerPikachu
ld hl, wPartyMon2 - wPartyMon1
add hl, de
ld d, h
ld e, l
ld hl, NAME_LENGTH
add hl, bc
ld b, h
ld c, l
jr .loop
.sameOT
pop bc
pop de
ld h, d
ld l, e
ld bc, -NAME_LENGTH
add hl, bc
ld a, [hli]
or [hl]
jr z, .noPlayerPikachu
pop hl
scf
ret
.noPlayerPikachu
pop hl
and a
ret
IsStarterRaichuInOurParty::
ld hl, wPartySpecies
ld de, wPartyMon1OTID
ld bc, wPartyMonOT
push hl
.loop
pop hl
ld a, [hli]
push hl
inc a
jr z, .noPlayerPikachu
cp RAICHU + 1
jr nz, .curMonNotPlayerPikachu
ld h, d
ld l, e
ld a, [wPlayerID]
cp [hl]
jr nz, .curMonNotPlayerPikachu
inc hl
ld a, [wPlayerID+1]
cp [hl]
jr nz, .curMonNotPlayerPikachu
push de
push bc
ld hl, wPlayerName
ld d, $6 ; possible player length - 1
.nameCompareLoop
dec d
jr z, .sameOT
ld a, [bc]
inc bc
cp [hl]
inc hl
jr z, .nameCompareLoop
pop bc
pop de
.curMonNotPlayerPikachu
ld hl, wPartyMon2 - wPartyMon1
add hl, de
ld d, h
ld e, l
ld hl, NAME_LENGTH
add hl, bc
ld b, h
ld c, l
jr .loop
.sameOT
pop bc
pop de
ld h, d
ld l, e
ld bc, -NAME_LENGTH
add hl, bc
ld a, [hli]
or [hl]
jr z, .noPlayerPikachu
pop hl
scf
ret
.noPlayerPikachu
pop hl
and a
ret
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
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
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
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
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
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.png640 bytes · Views: 546
-
pikachu.zip91 KB · Views: 52
-
cycling.png533 bytes · Views: 488
-
persian.png605 bytes · Views: 484
-
squirtle.png540 bytes · Views: 466
-
ballpoke.png346 bytes · Views: 464
-
bulbasaur.png569 bytes · Views: 462
-
charmander.png608 bytes · Views: 461
-
bug.png570 bytes · Views: 462
-
geodude.png389 bytes · Views: 454
-
gyarados.png529 bytes · Views: 455
-
ghost.png529 bytes · Views: 459
-
fish.png638 bytes · Views: 461
-
meowth.png612 bytes · Views: 460
-
eevee.png517 bytes · Views: 463
-
ditto.png406 bytes · Views: 455
-
sandshrew.png432 bytes · Views: 457
-
zubat.png464 bytes · Views: 456
-
snake.png609 bytes · Views: 455
-
raichu_cry_1.wav78.3 KB
-
raichu_cry_2.wav79.6 KB
-
raichu_cry_3.wav54.5 KB
-
Raichu_unhappy.wav98.2 KB
Last edited: