Dive - pret/pokecrystal GitHub Wiki
Gen 3 introduced Dive, a field move that can reach the seafloor, as HM08. Fully implementing Dive is fairly complicated: its in-battle effect is similar to Dig and Fly but not exactly the same, and its field effect requires a lot of changes.
(The code for this feature was adapted from Pokémon Orange.)
Here are all the changes needed to implement Dive, applied to a copy of pokecrystal. You can clone
Rangi42/pokecrystal and checkout
the dive
branch to test it for yourself.
TOC
TODO
1. Start to prepare the Dive move
First, we have to add the move Dive, following this tutorial.
Replace MOVE_OR_ANIM_FC
with DIVE
; give it a name, description, and battle properties (DIVE, EFFECT_FLY, 80, WATER, 100, 10, 0
); and add it to Pokémon learnsets (Seel and Dewgong learn it by level-up).
We still have to implement the move animation, so let's do that next.
2. Create the Dive move animation
Refer to a new tutorial for adding new move animations, including new graphics and objects.
- constants/battle_anim_constants.asm
- data/battle_anims/objects.asm
- data/moves/animations.asm
3. Using Dive hides the Pokémon underwater
Edit constants/battle_constants.asm:
; wPlayerSubStatus4 or wEnemySubStatus4 bit flags
enum_start 7, -1
enum SUBSTATUS_LEECH_SEED
enum SUBSTATUS_RAGE
enum SUBSTATUS_RECHARGE
enum SUBSTATUS_SUBSTITUTE
- enum SUBSTATUS_UNKNOWN_1
+ enum SUBSTATUS_UNDERWATER
enum SUBSTATUS_FOCUS_ENERGY
enum SUBSTATUS_MIST
enum SUBSTATUS_X_ACCURACY
Edit engine/battle/core.asm:
ResidualDamage:
; Return z if the user fainted before
; or as a result of residual damage.
; For Sandstorm damage, see HandleWeather.
...
call SwitchTurnCore
xor a
ld [wNumHits], a
ld de, ANIM_SAP
ld a, BATTLE_VARS_SUBSTATUS3_OPP
call GetBattleVar
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ jr nz, .not_flying_or_underground
+ call Call_PlayBattleAnim_OnlyIfVisible
+ jr .called
+.not_flying_or_underground
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_UNDERWATER
call z, Call_PlayBattleAnim_OnlyIfVisible
+.called
call SwitchTurnCore
HandleWrap:
...
ld a, BATTLE_VARS_SUBSTATUS3
call GetBattleVar
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
jr nz, .skip_anim
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ and 1 << SUBSTATUS_UNDERWATER
+ jr nz, .skip_anim
call SwitchTurnCore
xor a
ld [wNumHits], a
ld [wFXAnimID + 1], a
predef PlayBattleAnim
call SwitchTurnCore
.skip_anim
...
Call_PlayBattleAnim_OnlyIfVisible:
ld a, BATTLE_VARS_SUBSTATUS3
call GetBattleVar
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ and 1 << SUBSTATUS_UNDERWATER
+ ret nz
Call_PlayBattleAnim:
ld a, e
ld [wFXAnimID], a
ld a, d
ld [wFXAnimID + 1], a
call WaitBGMap
predef_jump PlayBattleAnim
Edit engine/battle/effect_commands.asm:
TODO
Edit engine/battle_anims/bg_effects.asm:
BGEffect_CheckFlyDigStatus:
ld hl, BG_EFFECT_STRUCT_BATTLE_TURN
add hl, bc
ldh a, [hBattleTurn]
and $1
xor [hl]
jr nz, .player
ld a, [wEnemySubStatus3] ; EnemySubStatus3
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+ ld a, [wEnemySubStatus4]
+ and 1 << SUBSTATUS_UNDERWATER
ret
.player
ld a, [wPlayerSubStatus3] ; PlayerSubStatus3
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+ ld a, [wPlayerSubStatus4]
+ and 1 << SUBSTATUS_UNDERWATER
ret
Edit engine/battle/ai/scoring.asm:
AI_Smart_Fly:
-; Fly, Dig
+; Fly, Dig, Dive
; Greatly encourage this move if the player is
-; flying or underground, and slower than the enemy.
+; flying, underground, or underwater, and slower than the enemy.
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ jr nz, .player_hidden
+ ld a, [wPlayerSubStatus4]
+ and 1 << SUBSTATUS_UNDERWATER
ret z
+.player_hidden
call AICompareSpeed
ret nc
dec [hl]
dec [hl]
dec [hl]
ret
AI_Smart_PriorityHit:
call AICompareSpeed
ret c
-; Dismiss this move if the player is flying or underground.
+; Dismiss this move if the player is flying, underground, or underwater.
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
jp nz, AIDiscourageMove
+ ld a, [wPlayerSubStatus4]
+ and 1 << SUBSTATUS_UNDERWATER
+ jp nz, AIDiscourageMove
; Greatly encourage this move if it will KO the player.
...
AI_Smart_FutureSight:
; Greatly encourage this move if the player is
-; flying or underground, and slower than the enemy.
+; flying, underground, or underwater, and slower than the enemy.
call AICompareSpeed
ret nc
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ jr nz, .player_hidden
+ ld a, [wPlayerSubStatus4]
+ and 1 << SUBSTATUS_UNDERWATER
ret z
+.player_hidden
dec [hl]
dec [hl]
ret
4. Surf and Whirlpool do double damage to underwater Pokémon
Refer to this tutorial.
- constants/move_effect_constants.asm
- data/moves/moves.asm (again)
- data/moves/effects_pointers.asm
- data/moves/effects.asm
- macros/scripts/battle_commands.asm
- data/battle/effect_command_pointers.asm
- engine/battle/effect_commands.asm (again)
- engine/battle/ai/scoring.asm (again)
5. Prepare the HM08 item
We also have to add the item HM08, following this tutorial.
Add an HM for DIVE
; give it a name and attributes (0, HELD_NONE, 0, CANT_SELECT | CANT_TOSS, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE
); associate it with the move DIVE
; make it unforgettable; and add it to Pokémon base learnsets (50 Pokémon are compatible with it).
6. Define collision types for Dive water
- constants/collision_constants.asm
- data/collision_permissions.asm
- engine/overworld/tile_events.asm
7. Start to prepare the Dive field move effect
Now we can start to add the field move effect, following this tutorial.
Define MONMENUITEM_DIVE
; associate it with the move DIVE
; and implement MonMenu_Dive
for its menu action (in engine/pokemon/mon_menu.asm, or engine/menus/start_menu.asm in older versions of pokecrystal) like this:
+MonMenu_Dive:
+ farcall DiveFunction
+ ld a, [wFieldMoveSucceeded]
+ cp $1
+ jr nz, .Fail
+ ld b, $4
+ ld a, $2
+ ret
+
+.Fail:
+ ld a, $3
+ ret
We still have to implement DiveFunction
; but first, let's define some more components for it.
8. Define a utility function to check for Dive water
- home/map_objects.asm
9. Define text related to using Dive
- data/text/common_2.asm
divemap
and divewarp
event commands
10. Define the - wram.asm
- macros/scripts/events.asm
- engine/overworld/scripting.asm
- home/flag.asm
- engine/overworld/warp_connection.asm
11. Finish the Dive field move effect
- engine/events/overworld.asm
12. Press A on Dive water to use Dive
- engine/overworld/events.asm
13. Design a sprite for swimming underwater
Let's add a unique sprite for the player being underwater, following this tutorial.
Define SPRITE_DIVE
as a regular sprite constant; give it properties (DiveSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BLUE
); and create DiveSpriteGFX
as gfx/sprites/dive.png:
Note that this is the Surfing sprite from Gen 1, which resembles a Seel. It's appropriate for Dive since Seel learns Dive by level-up.
14. Use the sprite for the player when underwater
- constants/wram_constants.asm
- data/sprites/player_sprites.asm
- engine/events/overworld.asm (again)
- engine/overworld/map_setup.asm
- engine/overworld/player_movement.asm
15. Start creating a unique tileset for underwater maps
Refer to this tutorial.
- constants/tileset_constants.asm
- gfx/tilesets/underwater.png
- gfx/tilesets/underwater_palette_map.asm
- data/tilesets/underwater_metatiles.bin
- data/tilesets/underwater_collision.asm
- data/tilesets.asm
- gfx/tileset_palette_maps.asm
- gfx/tilesets.asm
16. Can't Fly while underwater
- engine/events/overworld.asm (again)
17. Fix bugs that affect the Dive features
- engine/overworld/overworld.asm
- home/map.asm
18. Animate underwater seaweed and bubbles
Refer to a new tutorial for adding new animated tiles.
- gfx/tilesets/bubble/1.png
- gfx/tilesets/bubble/2.png
- gfx/tilesets/bubble/3.png
- gfx/tilesets/bubble/4.png
- gfx/tilesets/bubble/5.png
- gfx/tilesets/seaweed/1.png
- gfx/tilesets/seaweed/2.png
- engine/tilesets/tileset_anims.asm
19. Use special palettes for underwater tiles and sprites
Refer to a new tutorial for adding new special palettes, including map (tile) and object (sprite) palettes.
- gfx/tilesets/underwater.pal
- gfx/tilesets/underwater_sprites.pal
- engine/tilesets/tileset_palettes.asm
- engine/gfx/color.asm
20. Add deep water to an overworld tileset
Refer to a new tutorial for adding new animated tiles.
- gfx/tilesets/johto.png
- gfx/tilesets/johto_palette_map.asm
- data/tilesets/johto_collision.asm
- data/tilesets/johto_metatiles.bin
- gfx/tilesets/water/deep-water.png
- engine/tilesets/tileset_anims.asm (again)
21. Add a map with Dive spots
Refer to this tutorial.
- maps/Route41.blk
- maps/Route41.asm
- maps/Route41Underwater.blk
- maps/Route41Underwater.asm
- constants/event_flags.asm (again)
- constants/map_constants.asm
- data/maps/maps.asm
- data/maps/attributes.asm
- data/wild/johto_grass.asm
- data/maps/blocks.asm
- data/maps/scripts.asm
- data/maps/roofs.asm
- data/maps/outdoor_sprites.asm
22. Add a song to use while diving
RSE Dive by TriteHexagon TODO: Actually inserting and assigning the song