• 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.

Development: In-Battle Evolutions

metapod23

Hardened Trainer
673
Posts
15
Years
  • Seen Aug 18, 2016
This is another thread from me asking experienced ASMers for help :embarrass

Anyway, I'm curious if it would be possible to add a check in the battle system for when a Pokemon levels up, that would then go to the Evolution Screen if the Pokemon meets the correct level requirements (instead of going to the Evolution Screen only at the end of the battle).

That seems like it would be doable, but I'm not sure if it could be returned to the battle scene easily, and if the battle scene would easily display the newly evolved Pokemon correctly (like its backsprite). And, of course, I've no idea how to begin to do it.

As always, any comments/suggestions or work put into this is appreciated, and credit will of course be given.
 

miksy91

Dark Energy is back in action! ;)
1,480
Posts
15
Years
You should start by looking for the pointer that locates the text for pokemon that's evolving. I believe that leads you to the asm routine that is loaded after a wild pokemon or trainer battle ends (checks for pokemon that might evolve, if not --> load map again with some map loading process code).

Besides, the battle ram data might turn "empty" after the battle ends (happens with G/S/C at least) so in that case you should modify the asm code so that the game temporarily stores the whole battle ram elsewhere (and checks if one of the pokemon evolved and modifies its data while at it...).

What you're asking here sounds pretty much "impossible" to be and I wouldn't be the one to try it but with knowledge and a lot of work, it can be done.
 
Last edited:

TheDarkShark

Metal Headed Hacker
56
Posts
13
Years
I've got another theory: What about looking up the battle ram first, then putting a break on write on your pokemon's level. This should lead you to the routine for level-up the fastest, because you wouldn't need to dig through the routines displaying the text...
 

Full Metal

C(++) Developer.
810
Posts
16
Years
I don't believe that there is a way to just modify the existing system for this. What you would have to do is put a branch in the level-up code, check for an evolution ( by branching, again, to the evolution area -- see Jambo51's threads/posts for this. ) and then return. I believe that's it, but it might be a bit more complicated than that. I'm sure that there's lots of checks and balances, and such. But you would also have to re-copy the sprite info, unless you intend to show the evolution animation.
 
275
Posts
13
Years
  • Seen Oct 9, 2019
Besides, the battle ram data might turn "empty" after the battle ends (happens with G/S/C at least)
I don't know about the actual data for enemy Pokemon, but if it's a trainer battle, the arguments passed to the trainerbattle command remains in RAM after the battle.

(All trainer battles go through that command. The effect where a trainer spots and walks to you is actually a "secret" script.)

So OP would need to copy the data for the enemy team -- six 100-byte (0x64) structures, the first of which is located at 0x0202402C. These structures store the full Pokemon data, including stat, health, and status information (with the possible exceptions of confusion and attraction).

The trainerbattle arguments should still be saved in RAM, so OP need only call a (heavily-modified) version of repeattrainerbattle. Modifications would need to be made to ensure that the Trainer sends out the Pokemon they were actually battling with earlier (since Trainers can switch out). (You'll also need to keep track of how many of their four items the Trainer has used, and restore that information upon initiating the battle.)

EDIT: Just in case anyone plans on analyzing battle ASM by looking at the trainer battle commands... Know that "trainerbattle" only prepares a battle -- and then it runs a script that calls "repeattrainerbattle". "Repeattrainerbattle" actually starts the battle (better name woulda been "dotrainerbattle").
 

Jambo51

Glory To Arstotzka
736
Posts
14
Years
  • Seen Jan 28, 2018
Myself and NintendoBoyDX have actually been researching this, and we came up with a theoretically sound way of doing it.

Our idea was to run the checks in battle right after any level up, and if an evolution trigger was met, basically transform the Pokemon into its evolution. Obviously, we would need to find the stat recalculation routines and make them update the stats, then finally update the stats in the battle ram. As you have no doubt gathered, this will not be a simple process, and indeed, may be improbable as it might make the game lag very badly.

JPAN did research on the evolution animation routines, and found that they only worked when called from exactly where they get called.

Theoretically possible, practically nearly impossible.
 
275
Posts
13
Years
  • Seen Oct 9, 2019
Obviously, we would need to find the stat recalculation routines and make them update the stats, then finally update the stats in the battle ram. As you have no doubt gathered, this will not be a simple process, and indeed, may be improbable as it might make the game lag very badly.
I suspect that the battle ASM just acts directly on the player's Pokemon data -- the six 100-byte data structures stored at 0x02024284. That's the persistent storage area for the player's party, and immediately preceding it is the storage area used by battle ASM to hold up to six enemy Pokemon.

(My reasoning here is that... If you use "setwildbattle", it prepares the six enemy slots appropriately but doesn't start the battle. You can then modify the Pokemon it loads to the first enemy slot and then call "dowildbattle", and your modifications will remain intact (assuming either that you edited the non-protected stat data, or that you repaired the checksum after editing). The game doesn't back up loaded enemy Pokemon to some special location when it processes a battle, so why would the player's Pokemon be any different?)

So you could just modify the Pokemon; no need to move the data elsewhere, though. The stats in "the battle RAM" are the stats. Now, showing the updated data on-screen is another matter.
 

Jambo51

Glory To Arstotzka
736
Posts
14
Years
  • Seen Jan 28, 2018
I suspect that the battle ASM just acts directly on the player's Pokemon data -- the six 100-byte data structures stored at 0x02024284. That's the persistent storage area for the player's party, and immediately preceding it is the storage area used by battle ASM to hold up to six enemy Pokemon.

(My reasoning here is that... If you use "setwildbattle", it prepares the six enemy slots appropriately but doesn't start the battle. You can then modify the Pokemon it loads to the first enemy slot and then call "dowildbattle", and your modifications will remain intact (assuming either that you edited the non-protected stat data, or that you repaired the checksum after editing). The game doesn't back up loaded enemy Pokemon to some special location when it processes a battle, so why would the player's Pokemon be any different?)

So you could just modify the Pokemon; no need to move the data elsewhere, though. The stats in "the battle RAM" are the stats. Now, showing the updated data on-screen is another matter.

Sadly, your suspicions are incorrect. The game relies on seperate battle data, with some of it being copied from the party data, and some of it being calculated and written from the Pokémon base data in the ROM, during battle.

This data is at 0x02023BE4. There are 4 slots, each 0x58 (88) bytes long.
This is a short list of what i've discovered in the battle data:

0x0 - Species (2 bytes)
0x2 - Stats (12 bytes - 2 bytes per stat)
0x18 - Stat raising/falling trackers (6 bytes)
0x20 - Ability (1 byte)
0x21 - Types (2 bytes)
0x24 - Current PP (4 bytes - 1 byte per attack)
0x28 - Current HP (1 byte)
0x2C - Total HP (1 byte)
0x30 - Nickname (13 bytes)
0x3C - OT Name (8 bytes)
0x54 - Personality Value (4 bytes).

The game links battle data slots to party slots by using the following method:

At 0x02023BC4 is a byte which tells the game which battle slot data to use. Further, it is also used to tell the game which party slot is linked to each battle slot.

The even numbered slots are the player's, while the odd numbered slots are the opponent's.

Starting with 0x02023BCE are an array of bytes which link battle data slots to party data slots.

It works out as such:

Party Slot ID = [02023BC4]*2 + 02023BCE

The byte stored in this location is the party slot of the Pokémon represented by the battle data in slot [02023BC4].

Hopefully this helps.
 

Full Metal

C(++) Developer.
810
Posts
16
Years
Correct me if I'm wrong, but if we just wanted to evolve the pokemon ( no evolution )
couldn't we just change the byte @ 0x02023BE4.( via an injected routine on exp checking, of course. ) We wouldn't have to call any outside routines, we could just look and see how the original does it, and clip out the parts we don't need. Then force the game to re-lookup the sprite. Blammo. :o
Or am I way way way over-simplifying this? o.O
 
275
Posts
13
Years
  • Seen Oct 9, 2019
Correct me if I'm wrong, but if we just wanted to evolve the pokemon ( no evolution )
couldn't we just change the byte @ 0x02023BE4.( via an injected routine on exp checking, of course. )
You still need to recalculate the stats...

Then force the game to re-lookup the sprite. Blammo. :o
...and then reshow not just the sprite, but also the HP and EXP bars.
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
There are several big problems while trying to implement this. I've been trying to do do this for some time now, more specifically a temporary evolution during battle.

Mine works something like this:
  • Item is used in battle;
  • Party screen shows up, item gets used;
  • Pokemon evolves (now silently), stats get re-calculated;
  • Evolved pokemon appears on screen if it was the one out at the time.
While the data part wasn't that hard to make, the graphical part with the Evolution screen was the one that was giving me me a headache. After I was willing to abdicate the "X is evolving" screen, things went much smoother.

Any change made to your pokemon in the party screen is carried to the battle data as soon as you quit it, and any change made in the battle screen (that has some impact on the Pokemon 100 bytes) will carry to the Party screen as soon as you enter it, or as soon as the battle ends.
Therefore, items used on the party, such as potions, affect the 100 bytes only, and the game engine carries that change by itself to the battle structure. That is why there is only need for one item coding for both situations (Battle-only items like X Attack are the exception, because they change the battle structure directly, and have no effect outside of it).

I created an item that would access the hacked engine's pokemon decrypt function, changed data in it (in this case, pokemon species, but any other field can be changed), encrypt it, and called the game's stat calculator to fix the last 20 bytes of the data. The menu exited and my pokemon was evolved (a squirtle became a blastoise, although still named squirtle, and at level 13).

The reverting part (my case) was done by having a group of 8 flags in memory (only 6 needed) indicating which had evolved using this method, and 8 bytes (your case, 12 needed) Indicating which pokemon to revert to.

Although this time I cannot provide any code (most functions were tested by using breakpoints in VBA+introducing data by hand), know that evolution during battle is possible, and with some studying of the LV up script, it would be possible to evolve a pokemon without calling the evolution screen.
Denying evolution could be implemented by listening directly to the B key in the Input register, and not evolving if pressed.
Changing the battle sprite if it was the pokemon out could be hard, but best bet would be studying the form-change code for Castform, and use that.

PS: The in-game battle stat recalculator is placed at 0x0803E47C in Fire Red, and given in R0 the pokemon slot address, recalculates the ending 20 bytes of the 100byte structure.
 
94
Posts
13
Years
  • Seen Nov 2, 2016
So I've been working on in battle evolution lately. In the end I want to have it set up so that items like stones can be used to get the pokemon to evolve in battle, and also for them to evolve through level up, and any other means.

So one suggestion was to use castforms script, which is at:
Code:
081D92F8
But the problem with castform is that it, and all its forms, are all 1 single image. So there is no opportunity to change the pointer later on.

So I have what I believe is a better idea. Using the ghost "transformation" sequence when the ghost sprite switches to marowak. Because here, one sprite switches completely to another sprite (so it's better than castform) and its not limited to one single move (like the transform attack).

The load of the pointer of marowak's frontsprite is here:
Code:
0800F1C8

I'm currently looking into how its calculated, and all that. Stat calculations and all that is the easy part. But getting the sprite to switch and a viable animation/sound to play is the hard part. Perhaps by looking at this code, a script can be made and hooked into the castform script, which runs at very good intervals.

EDIT :
Well I believe I've figured out a way. Took a few hours, and also thanks to jambo for a lot of info which was helpful in finding the code!

Code:
081D91A1
081D91A1 unk_081D91A1:   .byte 0x39 @ 9          @ DATA XREF: sub_08013514+30o
081D91A1                                         @ ROM:off_08013564o
081D91A2                 .byte 0x20
081D91A3                 .byte    0
081D91A4                 .byte 0x10
081D91A5                 .byte 0x7C @ |
081D91A6                 .byte    1
081D91A7                 .byte 0x3A @ :
081D91A8                 .byte 0x45 @ E
081D91A9                 .byte  0xC
081D91AA                 .byte 0x19
081D91AB                 .byte    0
081D91AC                 .byte    0
081D91AD                 .byte    0
081D91AE                 .byte    0
081D91AF                 .byte 0x39 @ 9
081D91B0                 .byte 0x20
081D91B1                 .byte    0
081D91B2                 .byte 0x10
081D91B3                 .byte 0x7D @ }
081D91B4                 .byte    1
081D91B5                 .byte 0x12
081D91B6                 .byte 0x40 @ @
081D91B7                 .byte    0
081D91B8                 .byte 0x3E @ >
This is the ghost-marowak battle script.

In this script it calls the transformation battle animation in the following way:
Code:
0x45(playanimation)
0xC(bank)
0x19(transformation animation)
0x00000000(a word that can be used for other stuff, but is unused in this case)

There are 0xC banks to choose from for this command. The bank you choose reflects which side receives the animation. So if we just leave the bank as 0xC, I've found the spot that a routine can be hooked in. 0x1 = opponent, 0x0 = player.

Code:
08016EB8 MOVS R0, #1

This spot needs to be changed so that the script can use either 0x1 or 0x0 depending on whether its the player or the opponents move.

Code:
08034C62 BL get_pokemon_data

This spot is where it pulls marowak's ID number out of pokemon main (not battle) ram. This is where we can hook in routines to read and change the ID # of the pokemon, recalculate stats, and all that good stuff.

I'll probably work it out myself soon, or another person can. I also think there must be a better way of doing things, so I'll keep looking into it for sure.

My plan is to:
Spoiler:
 
Last edited:

Jambo51

Glory To Arstotzka
736
Posts
14
Years
  • Seen Jan 28, 2018
My plan is to:
1. Change the code in those two routines ^ so that the side who receives the animation can be specified, and the pokemon it changes to can be specified.

Not necessary. If you change the 0xC to a different number, you can specify which Pokémon gets it by writing into one of the many choosable buffers. IIRC, 00 uses 0x02023D6C to get which pokémon to use. You could temporarily store the correct byte into that buffer to get the same effect.

Or better yet, use one of the properly temporary buffers. I can't remember exactly which number uses which, but it is possible.
 
Back
Top