-
Notifications
You must be signed in to change notification settings - Fork 806
Dive
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.
TODO
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.
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
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
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)
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).
- constants/collision_constants.asm
- data/collision_permissions.asm
- engine/overworld/tile_events.asm
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.
- home/map_objects.asm
- data/text/common_2.asm
- wram.asm
- macros/scripts/events.asm
- engine/overworld/scripting.asm
- home/flag.asm
- engine/overworld/warp_connection.asm
- engine/events/overworld.asm
- engine/overworld/events.asm
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.
- constants/wram_constants.asm
- data/sprites/player_sprites.asm
- engine/events/overworld.asm (again)
- engine/overworld/map_setup.asm
- engine/overworld/player_movement.asm
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
- engine/events/overworld.asm (again)
- engine/overworld/overworld.asm
- home/map.asm
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
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
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)
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
RSE Dive by TriteHexagon TODO: Actually inserting and assigning the song