-
Notifications
You must be signed in to change notification settings - Fork 1k
Attack animation tiles
The aim of this tutorial is to use additional tiles for the attack animations in battle.
There are 2 ways to do that : moving black tiles from both attack tilesets to the font tileset, and/or add a new tileset.
The 1st method lets you add up to 22 tiles, the 2nd method lets you add 32 tiles more or less but it puts some limitations.
You can use both methods to have a total of 54 new tiles. Before starting the tutorial, I strongly recommend to know how animations work in pokered. You need to know at least what are frameblocks and subanimations, especially for the first method.
This is the best way if you only need few tiles. Don't worry, you will not need to replace any existing tile, you will understand what this is about in a second.
First you need to know that the font tileset (in gfx/font/font.png) is used in battle just like the 2 attack animation tilesets.
If you look at this font tileset, you will notice a white empty space (enough for 32 tiles) right after the 64 characters, BUT this space can't be used for the tiles that use 4 colors. The font tileset is coded in 1 bit per pixel (1bpp), which means that it only uses black (and white for the transparency of course). No gray.
Now the interesting thing is that many tiles in the attack tilesets (22 in total) only use black. So, as you probably want to add 4-color tiles, you can just move the black tiles from the attack tilesets to the unused space in the font tileset, and then replace these black tiles by your custom tiles.
From this point, it's a bit complicated to explain but I will do my best, the example in the third part should make it clear anyway.
So, after moving your tiles, change the tile IDs in the frameblocks so that the animations find the new location of the moved tiles. Otherwise, the attacks using these tiles will not find them (they would use the new replaced tiles and that's not what we want). Just change data/battle_anims/frame_blocks.asm.
You need to do a little bit of investigation for that, I mean you need to find which specific frameblock(s) use the tile. Make sure the tile ID in the frameblock matches the place of the tile in the tileset, and make sure that the animation using the frameblock uses the good tileset too. Then set the tile ID in the frameblock to the new ID (in the font tileset).
Important to know: the font tileset can be used along with attack_anim_1 or attack_anim_2 (and even attack_anim_3 if you add a 3rd tileset).
The tile IDs in the free slots of the font tileset go from 0x8F to 0xAE.
Let's make all this clear with an example. The question mark tiles in attack_anim_1 are fully black, then you can move them to the font tileset. Now, put your new custom tiles where the question mark is in attack_anim_1.
Now you need to change the ID of the question mark tiles in the frameblocks. Start with the first tile.
Go to frame_blocks.asm and look for the frameblock(s) that use the 1st tile of the question mark. The ID of this tile is 0x2a, we know it because we can see that it's the 42nd in the tileset (counting from 0!). Do ctrl+F and search for $2a. You will find the frameblocks 35 and 52. Be careful here, this doesn't mean these two frameblocks use the tile, because they might use the tile 0x2a of the other tileset (attack_anim_2). To figure this out, you have to investigate a bit.
In subanimations.asm, search for the subanimations that use frameblocks 35 and 52, you will see that 35 is used by subanim 15, and 52 is used by subanims 25 and 26.
Now, what animation(s) does use these subanims? Search in data/moves/animations.asm, you'll find Roar, Sonicboom, Amnesia, ConfusedPlayerAnim and ConfusedEnemyAnim. From here you can guess that only Amnesia and confusion animations use the question mark tile, or you can check in-game, or just by checking the tileset ID (in animations.asm. 0 is attack_anim_1 and 1 is attack_anim_2).
Now, you know which frameblock you have to change: 52. Because Amnesia and confusion animations use the subanims 25 and 26, which use the frameblock 52. Set the tile IDs to something from 0x90 to 0xAF.
That's it, you just replaced the question mark tiles without messing with Amnesia's animation. You can use your new tiles now.
Using this method, you will be able to add only one tileset of 32 tiles. When creating the tileset image, choose a size that can fit 32 8 by 8 tiles. This tutorial uses a 128*16 image. Of course, the tileset must be indexed in 4 colors (black, white, light grey and dark grey).
A few limits to this method:
- You might be restricted to 16 tiles if you add many attack animations (subanimations, frameblocks...).
Indeed the tilesets and files using them must be in the same bank, which puts some limits in terms of rom space.
If you manage to keep a bank with few data in it, you can think of adding more tiles but this requires further modification and knowledge not included in this tutorial. Anyway, 32 tiles is the recommended quantity for this tutorial. - Another limit of adding a tileset is that you will have to remove 5 special effect animations. There are 3 already unused in the code so you'll need to choose 2 more to remove, you'll understand why later.
This method can be improved, you are welcome to share anything useful.
In engine/battle/animations.asm, add these lines under the tileset declarations:
...
MoveAnimationTiles0:
MoveAnimationTiles2:
INCBIN "gfx/battle/move_anim_0.2bpp"
MoveAnimationTiles1:
INCBIN "gfx/battle/move_anim_1.2bpp"
+MoveAnimationTiles3:
+ INCBIN "gfx/battle/move_anim_2.2bpp" ; the path must match the name of your directory and tileset of course
...
Then add this line under the 3 anim_tileset lines:
...
MoveAnimationTilesPointers:
; number of tiles, gfx pointer
anim_tileset 79, MoveAnimationTiles0
anim_tileset 79, MoveAnimationTiles1
anim_tileset 64, MoveAnimationTiles2
+ anim_tileset x, MoveAnimationTiles3
...
Replace the "x" with the number of tiles you have in your tileset. As mentioned before, this tutorial will be adding 32.
Adding a tileset will probably make the bank space overflow. By default, these scripts are kept in bank1E. You need to move some data from this bank to another bank. To do this, move some scripts from bank1E to a more open bank, such as Itemfinder 2. To do this, make these changes in main.asm:
...
SECTION "Itemfinder 2", ROMX
INCLUDE "engine/menus/league_pc.asm"
INCLUDE "engine/events/hidden_items.asm"
+INCLUDE "engine/movie/evolution.asm"
+INCLUDE "engine/overworld/elevator.asm"
+INCLUDE "engine/items/tm_prices.asm"
+INCLUDE "gfx/fishing.asm"
SECTION "bank1E", ROMX
INCLUDE "engine/battle/animations.asm"
INCLUDE "engine/overworld/cut2.asm"
INCLUDE "engine/overworld/dust_smoke.asm"
-INCLUDE "gfx/fishing.asm"
INCLUDE "data/moves/animations.asm"
INCLUDE "data/battle_anims/subanimations.asm"
INCLUDE "data/battle_anims/frame_blocks.asm"
-INCLUDE "engine/movie/evolution.asm"
-INCLUDE "engine/overworld/elevator.asm"
-INCLUDE "engine/items/tm_prices.asm"
...
You could, of course, move these scripts to any bank that they will fit. I chose Itemfinder 2 since it is very empty.
When you are moving scripts, make sure to keep these scripts in the same bank:
- engine/battle/animations.asm
- data/moves/animations.asm
- data/battle_anims/subanimations.asm
- data/battle_anims/frame_blocks.asm
- engine/overworld/cut2.asm
- engine/overworld/dust_smoke.asm
These files need each other in some way, don't put them in separate banks.
In data/moves/animations.asm, set the 3rd parameter of the animation you want to 3. This tells the compiler that the animation uses tileset 3. We do count tilesets from 0 but 0, 1, and 2 are for tilesets 1 and 2. So, 3 is for tileset 3.
In constants/move_animation_constants.asm, replace $C0 with $C5.
; special effects that are part of move animations
; SpecialEffectPointers associates them with effect routines (see data/battle_anims/special_effect_pointers.asm)
- const_def $C0
+ const_def $C5
DEF FIRST_SE_ID EQU const_value
const_skip $18
const SE_WAVY_SCREEN ; $D8 used in Psywave/Night Shade/Psychic etc.
const SE_SUBSTITUTE_MON ; $D9 used in Substitute (turns the pokemon into a mini sprite)
const SE_SHAKE_BACK_AND_FORTH ; $DA used in Double Team
const SE_SLIDE_ENEMY_MON_OFF ; $DB used in Whirlwind
...
The ones beginning with "SE" are special effect animations. We have to remove 5 of them total. By "remove" I mean delete the whole line of the constant.
since 3 of the animations are already unused, we can remove them first:
- SE_FLASH_ENEMY_MON_PIC
- SE_SHAKE_ENEMY_HUD_2
- SE_SHOOT_MANY_BALLS_UPWARD
From there, you have 2 more animations left to remove.
Some suggestions include:
- SE_BOUNCE_UP_AND_DOWN since this is exclusive to Splash
- SE_LEAVES_FALLING since it is very similar to SE_PETALS_FALLING
- SE_SLIDE_MON_DOWN_AND_HIDE since it is only used in Acid Armor and can be replicated using a combination of SE_SLIDE_MON_DOWN and SE_SLIDE_MON_UP
any other single move animation would be a good removal as well, like SE_MINIMIZE_MON or SE_SLIDE_ENEMY_MON_OFF (which are only used by Minimize and Whirlwind respectively).
You can try to make a generic animation to combine 2 animations into one (in engine/battle/animations.asm) but that sounds pretty hard. I hope this tutorial will be updated with more information in the future.
After you removed those 5 constants, remove the references to them in data/battle_anims/special_effect_pointers.asm and data/moves/animations.asm.
In data/moves/animations.asm, after removing a reference to a removed constant, you may want to replace it with an equivalent special effect animations or subanimation.
Example: if you chose to remove SE_LEAVES_FALLING to replace it with SE_PETALS_FALLING, you may want to do the following under RazorLeafAnim
...
RazorLeafAnim:
- battle_anim RAZOR_LEAF, SE_LEAVES_FALLING
+ battle_anim NO_MOVE, SE_PETALS_FALLING
battle_anim SWIFT, SUBANIM_1_LEAVES_TOSS, 1, 1
battle_anim RAZOR_WIND, SUBANIM_0_SLICE, 0, 1
db -1 ; end
...
Now you can use your new tileset.
This part is not necessary for the tutorial but it's meant to explain what happens in the code.
When you set the tileset ID of an animation to 3, this causes a bug as soon as you use your new tileset (if FIRST_SE_ID is left to 0xC0). The bug comes from the PlayAnimation routine in engine/battle/animations.asm.
The value pointed by the animation pointer is 0xC4 when the animation uses the tileset 3, this pointer is at AttackAnimationPointers + (AnimationID*2) if I'm not wrong.
0xC4 is loaded into register a, then a is compared with FIRST_SE_ID (which has 0xC0). As a is greater than FIRST_SE_ID, the routine doesn't jump to .playSubanimation. The routine "thinks" the animation contains a special effect whereas it contains subanimation(s) instead.
It loops in searchSpecialEffectTableLoop and it obviously doesn't find any matching special effect. This is the cause of the bug and the reason why we set FIRST_SE_ID to 0xC5, we make it greater than 0xC4 to force the jump.
I hope that I was clear in the explanations, I did my best to make this tutorial enjoyable to read but I might improve it in the future.
I made many tests and didn't find any bug with both methods, you can be quiet. I didn't make a full playthrough however, you're welcome to report any bug or detail that I should mention on this page.
By the way I thank 33dannye for providing me some information about the source code in pokered.