diff options
-rw-r--r-- | Add-a-new-sprite-movement-behavior.md | 6 | ||||
-rw-r--r-- | Puddles-that-splash-the-way-tall-grass-rustles.md | 540 | ||||
-rw-r--r-- | Tutorials.md | 4 | ||||
-rw-r--r-- | screenshots/gfx-overworld-puddle_splash.png | bin | 0 -> 90 bytes | |||
-rw-r--r-- | screenshots/gfx-tilesets-johto_modern.png | bin | 0 -> 2313 bytes | |||
-rw-r--r-- | screenshots/polished-map-puddle-block.png | bin | 0 -> 6263 bytes | |||
-rw-r--r-- | screenshots/polished-map-puddle-tileset.png | bin | 0 -> 9802 bytes | |||
-rw-r--r-- | screenshots/polished-map-puddles.png | bin | 0 -> 17850 bytes | |||
-rw-r--r-- | screenshots/puddles.png | bin | 0 -> 2742 bytes |
9 files changed, 546 insertions, 4 deletions
diff --git a/Add-a-new-sprite-movement-behavior.md b/Add-a-new-sprite-movement-behavior.md index d0eed91..dc2841d 100644 --- a/Add-a-new-sprite-movement-behavior.md +++ b/Add-a-new-sprite-movement-behavior.md @@ -1,6 +1,8 @@ -This tutorial is for how to add a new sprite movement behavior. +This tutorial is for how to add a new map object movement behavior. -Sprite movement behaviors are what you specify with the `SPRITEMOVEDATA_*` constants for `object_event`s in map event scripts. They control the object's sprite appearance as well as how it interacts with the map. For example, objects with `SPRITEMOVEDATA_WALK_UP_DOWN` appear as a 16x16 pixel sprite that walks up and down within a certain radius; while objects with `SPRITEMOVEDATA_BIGDOLL` appear as a 32x32 pixel sprite that does not move. +Map objects are defined by `object_event`s in map event scripts, and their assigned `SPRITEMOVEDATA_*` constants define their movement behavior. This controls how the objects' sprite appears, how it moves, and how it interacts with the player. For example, objects with `SPRITEMOVEDATA_WALK_UP_DOWN` appear as a 16x16 pixel sprite that walks up and down within a certain radius; while objects with `SPRITEMOVEDATA_BIGDOLL` appear as a 32x32 pixel sprite that does not move. + +(Map objects are *not* the same as sprites. A sprite is an 8x8 pixel entity, of which you can have 40 on-screen at a time. Map objects are composed of sprites—a 16x16 pixel object consists of four sprites, for instance—but sprites are used throughout the game, not just in the overworld map engine.) ## Contents diff --git a/Puddles-that-splash-the-way-tall-grass-rustles.md b/Puddles-that-splash-the-way-tall-grass-rustles.md new file mode 100644 index 0000000..1facb33 --- /dev/null +++ b/Puddles-that-splash-the-way-tall-grass-rustles.md @@ -0,0 +1,540 @@ +Gen 3 introduced all kinds of overworld effects: footprints in sand, rain and lightning, reflections in water, splashing in puddles... Most of those are difficult or impossible with the GameBoy Color hardware, but we can achieve decent splashing puddles, including visible water droplets and a splashing noise. + + +## Contents + +1. [Define a collision type for puddles](#1-define-a-collision-type-for-puddles) +2. [Design a splashing sound effect](#2-design-a-splashing-sound-effect) +3. [Design a graphical emote for splashing](#3-design-a-graphical-emote-for-splashing) +4. [Define a map object for splashing](#4-define-a-map-object-for-splashing) +5. [Load puddle splash graphics when outdoors](#5-load-puddle-splash-graphics-when-outdoors) +6. [Show splash graphics and play sound for puddle tiles](#6-show-splash-graphics-and-play-sound-for-puddle-tiles) +7. [Use the puddle collision type for a map](#7-use-the-puddle-collision-type-for-a-map) + + +## 1. Define a collision type for puddles + +Edit [constants/collision_constants.asm](../blob/master/constants/collision_constants.asm): + +```diff + ; collision data types (see data/tilesets/*_collision.asm) + ; TileCollisionTable indexes (see data/collision_permissions.asm) + COLL_FLOOR EQU $00 + COLL_01 EQU $01 ; garbage ++COLL_PUDDLE EQU $02 + COLL_03 EQU $03 ; garbage + COLL_04 EQU $04 ; garbage + COLL_WALL EQU $07 + ... +``` + +Edit [data/collision_permissions.asm](../blob/master/data/collision_permissions.asm): + +```diff + TileCollisionTable:: + ; entries correspond to COLL_* constants + NONTALKABLE LANDTILE ; COLL_FLOOR + NONTALKABLE LANDTILE ; COLL_01 +- NONTALKABLE LANDTILE ; 02 ++ NONTALKABLE LANDTILE ; COLL_PUDDLE + NONTALKABLE LANDTILE ; COLL_03 + NONTALKABLE LANDTILE ; COLL_04 + NONTALKABLE LANDTILE ; 05 + NONTALKABLE LANDTILE ; 06 + NONTALKABLE WALLTILE ; COLL_WALL + ... +``` + +Puddles don't do anything when "talked" to (unlike Cut trees or whirlpools, for instance), and can be walked on, so they need to be `NONTALKABLE LANDTILE`. + + +## 2. Design a splashing sound effect + +Edit [constants/sfx_constants.asm](../blob/master/constants/sfx_constants.asm): + +```diff + ... + const SFX_4_NOTE_DITTY ; cd + const SFX_TWINKLE ; ce ++ const SFX_PUDDLE +``` + +Edit [audio/sfx_pointers.asm](../blob/master/audio/sfx_pointers.asm): + +```diff + ... + dba Sfx_4NoteDitty + dba Sfx_Twinkle ++ dba Sfx_Puddle +``` + +Edit [audio/sfx_crystal.asm](../blob/master/audio/sfx_crystal.asm): + +```diff ++Sfx_Puddle: ++ musicheader 1, 5, Sfx_Puddle_Ch5 ++ ++Sfx_Puddle_Ch5: ++ dutycycle $1 ++ soundinput $97 ++ sound __, 16, $98, $0700 ++ soundinput $8 ++ endchannel +``` + +This is based off of `Sfx_WaterGun_Ch5`. + + +## 3. Design a graphical emote for splashing + +Create **gfx/overworld/puddle_splash.png**: + + + +Edit [constants/script_constants.asm](../blob/master/constants/script_constants.asm): + +```diff + ; showemote arguments + ; Emotes indexes (see data/sprites/emotes.asm) + const_def + const EMOTE_SHOCK ; 0 + const EMOTE_QUESTION ; 1 + const EMOTE_HAPPY ; 2 + const EMOTE_SAD ; 3 + const EMOTE_HEART ; 4 + const EMOTE_BOLT ; 5 + const EMOTE_SLEEP ; 6 + const EMOTE_FISH ; 7 + const EMOTE_SHADOW ; 8 + const EMOTE_ROD ; 9 + const EMOTE_BOULDER_DUST ; 10 + const EMOTE_GRASS_RUSTLE ; 11 ++ const EMOTE_PUDDLE_SPLASH + EMOTE_MEM EQU -1 +``` + +Edit [data/sprites/emotes.asm](../blob/master/data/sprites/emotes.asm): + +```diff + Emotes: + ; entries correspond to EMOTE_* constants + emote ShockEmote, 4, $78 + emote QuestionEmote, 4, $78 + emote HappyEmote, 4, $78 + emote SadEmote, 4, $78 + emote HeartEmote, 4, $78 + emote BoltEmote, 4, $78 + emote SleepEmote, 4, $78 + emote FishEmote, 4, $78 + emote JumpShadowGFX, 1, $7c + emote FishingRodGFX, 2, $7c + emote BoulderDustGFX, 2, $7e + emote GrassRustleGFX, 1, $7e ++ emote PuddleSplashGFX, 1, $7f +``` + +Edit [gfx/emotes.asm](../blob/master/gfx/emotes.asm): + +```diff + ShockEmote: INCBIN "gfx/emotes/shock.2bpp" + QuestionEmote: INCBIN "gfx/emotes/question.2bpp" + HappyEmote: INCBIN "gfx/emotes/happy.2bpp" + SadEmote: INCBIN "gfx/emotes/sad.2bpp" + HeartEmote: INCBIN "gfx/emotes/heart.2bpp" + BoltEmote: INCBIN "gfx/emotes/bolt.2bpp" + SleepEmote: INCBIN "gfx/emotes/sleep.2bpp" + FishEmote: INCBIN "gfx/emotes/fish.2bpp" + JumpShadowGFX: INCBIN "gfx/overworld/shadow.2bpp" + FishingRodGFX: INCBIN "gfx/overworld/fishing_rod.2bpp" + BoulderDustGFX: INCBIN "gfx/overworld/boulder_dust.2bpp" + GrassRustleGFX: INCBIN "gfx/overworld/grass_rustle.2bpp" ++PuddleSplashGFX: INCBIN "gfx/overworld/puddle_splash.2bpp" +``` + + +## 4. Define a map object for splashing + +Edit [constants/map_object_constants.asm](../blob/master/constants/map_object_constants.asm): + +```diff + ; SpriteMovementData indexes (see data/sprites/map_objects.asm) + const_def + const SPRITEMOVEDATA_00 ; 00 + ... + const SPRITEMOVEDATA_BOULDERDUST ; 22 + const SPRITEMOVEDATA_GRASS ; 23 + const SPRITEMOVEDATA_SWIM_WANDER ; 24 ++ const SPRITEMOVEDATA_PUDDLE + NUM_SPRITEMOVEDATA EQU const_value + + ; MapObjectMovementPattern.Pointers indexes (see engine/overworld/map_objects.asm) + const_def + const SPRITEMOVEFN_00 ; 00 + ... + const SPRITEMOVEFN_BOULDERDUST ; 1a + const SPRITEMOVEFN_GRASS ; 1b ++ const SPRITEMOVEFN_PUDDLE + + ... + + ; ObjectActionPairPointers indexes (see engine/overworld/map_object_action.asm) + const_def + const OBJECT_ACTION_00 ; 00 + ... + const OBJECT_ACTION_BOULDER_DUST ; 0e + const OBJECT_ACTION_GRASS_SHAKE ; 0f + const OBJECT_ACTION_SKYFALL ; 10 ++ const OBJECT_ACTION_PUDDLE_SPLASH + + ; Facings indexes (see data/sprites/facings.asm) + const_def + const FACING_STEP_DOWN_0 ; 00 + ... + const FACING_BOULDER_DUST_1 ; 1c + const FACING_BOULDER_DUST_2 ; 1d + const FACING_GRASS_1 ; 1e + const FACING_GRASS_2 ; 1f ++ const FACING_SPLASH_1 ++ const FACING_SPLASH_2 +``` + +Edit [data/sprites/map_objects.asm](../blob/master/data/sprites/map_objects.asm): + +```diff + ; SPRITEMOVEDATA_BOULDERDUST + db SPRITEMOVEFN_BOULDERDUST ; movement function + db DOWN ; facing + db OBJECT_ACTION_BOULDER_DUST ; action + db WONT_DELETE | FIXED_FACING | SLIDING | EMOTE_OBJECT ; flags1 + db LOW_PRIORITY ; flags2 + db 0 ; palette flags + + ; SPRITEMOVEDATA_GRASS + db SPRITEMOVEFN_GRASS ; movement function + db DOWN ; facing + db OBJECT_ACTION_GRASS_SHAKE ; action + db WONT_DELETE | FIXED_FACING | SLIDING | EMOTE_OBJECT ; flags1 + db HIGH_PRIORITY ; flags2 + db 0 ; palette flags + + ; SPRITEMOVEDATA_SWIM_WANDER + db SPRITEMOVEFN_RANDOM_WALK_XY ; movement function + db DOWN ; facing + db OBJECT_ACTION_STAND ; action + db 0 ; flags1 + db 0 ; flags2 + db SWIMMING ; palette flags + +-; 25 +- db SPRITEMOVEFN_00 ; movement function +- db DOWN ; facing +- db OBJECT_ACTION_STAND ; action +- db 0 ; flags1 +- db 0 ; flags2 +- db 0 ; palette flags ++; SPRITEMOVEDATA_PUDDLE ++ db SPRITEMOVEFN_PUDDLE ; movement function ++ db DOWN ; facing ++ db OBJECT_ACTION_PUDDLE_SPLASH ; action ++ db WONT_DELETE | FIXED_FACING | SLIDING | EMOTE_OBJECT ; flags1 ++ db HIGH_PRIORITY ; flags2 ++ db 0 ; palette flags +``` + +Edit [engine/overworld/map_objects.asm](../blob/master/engine/overworld/map_objects.asm): + +```diff +MapObjectMovementPattern: + ... + +.Pointers: +; entries correspond to SPRITEMOVEFN_* constants + dw .Null_00 ; 00 + ... + dw .MovementBoulderDust ; 1a + dw .MovementShakingGrass ; 1b + dw .MovementSplashingPuddle + +... + + .MovementShakingGrass: + call EndSpriteMovement + call ._MovementShadow_Grass_Emote_BoulderDust + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_GRASS_SHAKE ++._MovementGrass_Puddle_End: + ld hl, OBJECT_STEP_DURATION + add hl, de + ld a, [hl] + add -1 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TRACKING_OBJECT + ret + ++.MovementSplashingPuddle: ++ call EndSpriteMovement ++ call ._MovementShadow_Grass_Emote_BoulderDust ++ ld hl, OBJECT_ACTION ++ add hl, bc ++ ld [hl], OBJECT_ACTION_PUDDLE_SPLASH ++ jr ._MovementGrass_Puddle_End +``` + +Edit [engine/overworld/map_object_action.asm](../blob/master/engine/overworld/map_object_action.asm): + +```diff + ObjectActionPairPointers: + ; entries correspond to OBJECT_ACTION_* constants + dw SetFacingStanding, SetFacingStanding + ... + dw SetFacingBoulderDust, SetFacingStanding + dw SetFacingGrassShake, SetFacingStanding + dw SetFacingSkyfall, SetFacingCurrent ++ dw SetFacingPuddleSplash, SetFacingStanding + +... + + SetFacingGrassShake: + ld hl, OBJECT_STEP_FRAME + add hl, bc + inc [hl] + ld a, [hl] + ld hl, OBJECT_FACING_STEP + add hl, bc + and 4 + ld a, FACING_GRASS_1 + jr z, .ok + inc a ; FACING_GRASS_2 + + .ok + ld [hl], a + ret ++ ++SetFacingPuddleSplash: ++ ld hl, OBJECT_STEP_FRAME ++ add hl, bc ++ inc [hl] ++ ld a, [hl] ++ ld hl, OBJECT_FACING_STEP ++ add hl, bc ++ and 4 ++ ld a, FACING_SPLASH_1 ++ jr z, .ok ++ inc a ; FACING_GRASS_2 ++ ++.ok ++ ld [hl], a ++ ret +``` + +Finally, edit [data/sprites/facings.asm](../blob/master/data/sprites/facings.asm): + +```diff + Facings: + ; entries correspond to FACING_* constants + dw FacingStepDown0 + ... + dw FacingBoulderDust1 + dw FacingBoulderDust2 + dw FacingGrass1 + dw FacingGrass2 ++ dw FacingSplash1 ++ dw FacingSplash2 + .End + dw 0 + + ... + + FacingBoulderDust1: ; boulder dust 1 + db 4 ; # + db 0, 0, ABSOLUTE_TILE_ID, $fe + db 0, 8, ABSOLUTE_TILE_ID, $fe + db 8, 0, ABSOLUTE_TILE_ID, $fe + db 8, 8, ABSOLUTE_TILE_ID, $fe + + FacingBoulderDust2: ; boulder dust 2 + db 4 ; # + db 0, 0, ABSOLUTE_TILE_ID, $ff + db 0, 8, ABSOLUTE_TILE_ID, $ff + db 8, 0, ABSOLUTE_TILE_ID, $ff + db 8, 8, ABSOLUTE_TILE_ID, $ff + + FacingGrass1: + db 2 ; # + db 8, 0, ABSOLUTE_TILE_ID, $fe + db 8, 8, ABSOLUTE_TILE_ID | X_FLIP, $fe + + FacingGrass2: + db 2 ; # + db 9, -1, ABSOLUTE_TILE_ID, $fe + db 9, 9, ABSOLUTE_TILE_ID | X_FLIP, $fe ++ ++FacingSplash1: ++ db 2 ; # ++ db 8, 0, ABSOLUTE_TILE_ID, $ff ++ db 8, 8, ABSOLUTE_TILE_ID | X_FLIP, $ff ++ ++FacingSplash2: ++ db 2 ; # ++ db 9, -1, ABSOLUTE_TILE_ID, $ff ++ db 9, 9, ABSOLUTE_TILE_ID | X_FLIP, $ff +``` + + +## 5. Load puddle splash graphics when outdoors + +Edit [engine/overworld/overworld.asm](../blob/master/engine/overworld/overworld.asm): + +```diff + LoadUsedSpritesGFX: + ... + + ld c, EMOTE_SHADOW + farcall LoadEmote + call GetMapEnvironment + call CheckOutdoorMap +- ld c, EMOTE_GRASS_RUSTLE + jr z, .outdoor + ld c, EMOTE_BOULDER_DUST ++ farcall LoadEmote ++ ret + .outdoor ++ ld c, EMOTE_GRASS_RUSTLE ++ farcall LoadEmote ++ ld c, EMOTE_PUDDLE_SPLASH + farcall LoadEmote + ret +``` + +## 6. Show splash graphics and play sound for puddle tiles + +Edit [home/map_objects.asm](../blob/master/home/map_objects.asm): + +```diff + CheckSuperTallGrassTile:: + cp COLL_LONG_GRASS + ret z + cp COLL_LONG_GRASS_1C + ret ++ ++CheckPuddleTile:: ++ cp COLL_PUDDLE ++ ret +``` + +Edit [engine/overworld/movement.asm](../blob/master/engine/overworld/movement.asm): + +```diff + NormalStep: + call InitStep + call UpdateTallGrassFlags + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STEP + + ld hl, OBJECT_NEXT_TILE + add hl, bc + ld a, [hl] + call CheckSuperTallGrassTile + jr z, .shake_grass ++ call CheckPuddleTile ++ jr z, .splash_puddle + + call CheckGrassTile + jr c, .skip_grass + + .shake_grass + call ShakeGrass ++ jr .skip_grass ++ ++.splash_puddle ++ call SplashPuddle ++ ; fallthrough + + .skip_grass + ld hl, wCenteredObject + ld a, [hMapObjectIndexBuffer] + cp [hl] + jr z, .player + + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_NPC_WALK + ret + + .player + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_PLAYER_WALK + ret +``` + +Edit [engine/overworld/map_objects.asm](../blob/master/engine/overworld/map_objects.asm) again: + +```diff + ShakeGrass: + push bc + ld de, .GrassObject + call CopyTempObjectData + call InitTempObject + pop bc + ret + + .GrassObject + db $00, PAL_OW_TREE, SPRITEMOVEDATA_GRASS ++ ++SplashPuddle: ++ push bc ++ ld de, .PuddleObject ++ call CopyTempObjectData ++ call InitTempObject ++ pop bc ++ ld de, SFX_PUDDLE ++ call PlaySFX ++ ret ++ ++.PuddleObject ++ db $00, PAL_OW_BLUE, SPRITEMOVEDATA_PUDDLE +``` + + +## 7. Use the puddle collision type for a map + +For example, let's copy HG/SS and add puddles to Route 34. + +Open [maps/Route34.blk](../blob/master/maps/Route34.blk) with [Polished Map](https://github.com/Rangi42/polished-map) and design some puddle tiles: + + + +Then assemble a block using those tiles: + + + +And use the block somewhere in the map: + + + +Then save the changes. Polished Map will update the relevant tileset and map files: + +- [gfx/tilesets/johto_modern.png](../blob/master/gfx/tilesets/johto_modern.png) +- [gfx/tilesets/johto_modern_palette_map.asm](../blob/master/gfx/tilesets/johto_modern_palette_map.asm) +- [data/tilesets/johto_modern_metatiles.bin](../blob/master/data/tilesets/johto_modern_metatiles.bin) +- [maps/Route34.blk](../blob/master/maps/Route34.blk). + +It will *not* update [data/tilesets/johto_modern_collision.asm](../blob/master/data/tilesets/johto_modern_collision.asm), so we'll edit that separately: + +```diff + tilecoll WALL, FLOOR, FLOOR, FLOOR ; 5e +- tilecoll WALL, WALL, WALL, WALL ; 5f ++ tilecoll PUDDLE, PUDDLE, PUDDLE, PUDDLE ; 5f + tilecoll WATER, WATER, WALL, WALL ; 60 +``` + +Now we can walk around Route 34, and see and hear puddles in action! + + diff --git a/Tutorials.md b/Tutorials.md index e7644c1..fc3cc09 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -24,7 +24,7 @@ Tutorials may use diff syntax to show edits: - [TM (up to 120)](Add-a-new-TM) - [Party menu icon (up to 253)](Add-a-new-party-menu-icon) - [Overworld sprite](Add-a-new-overworld-sprite) -- [Sprite movement behavior](Add-a-new-sprite-movement-behavior) +- [Map object movement behavior](Add-a-new-map-object-movement-behavior) - [Mart](Add-a-new-Mart) - [Music song](Add-a-new-music-song) - [Pack pocket](Add-a-new-Pack-pocket) @@ -48,6 +48,7 @@ Tutorials may use diff syntax to show edits: - [Infinitely reusable TMs](Infinitely-reusable-TMs) - [Automatically reuse Repel](Automatically-reuse-Repel) - [Running Shoes](Running-Shoes) +- [Puddles that splash the way tall grass rustles](Puddles-that-splash-the-way-tall-grass-rustles) **To do:** *(feel free to contribute one of these!)* @@ -78,7 +79,6 @@ Tutorials may use diff syntax to show edits: - Pan the camera for cutscenes by making the player invisible - Gain experience from catching Pokémon - Evolution moves from Gen 7 -- Puddles that splash (from [Polished Crystal](https://github.com/Rangi42/polishedcrystal/commit/14433071fc9d6c9452e964a6d486bc85939244bf)) - A trainer type that has a different party for all 16 badge counts (useful for open world games) ([via](https://hax.iimarckus.org/topic/7137/)) - Nuzlocke mode (an in-game enforced [Nuzlocke Challenge](https://bulbapedia.bulbagarden.net/wiki/Nuzlocke_Challenge)) - Useful unused content (`COLL_CURRENT_*`, `HELD_PREVENT_*`, `ENVIRONMENT_5`, `TRADE_GENDER_MALE`, `GROWTH_SLIGHTLY_*`, `SPRITE_UNUSED_GUY`, `PAL_NPC_PINK`, etc) diff --git a/screenshots/gfx-overworld-puddle_splash.png b/screenshots/gfx-overworld-puddle_splash.png Binary files differnew file mode 100644 index 0000000..cde87d3 --- /dev/null +++ b/screenshots/gfx-overworld-puddle_splash.png diff --git a/screenshots/gfx-tilesets-johto_modern.png b/screenshots/gfx-tilesets-johto_modern.png Binary files differnew file mode 100644 index 0000000..4276169 --- /dev/null +++ b/screenshots/gfx-tilesets-johto_modern.png diff --git a/screenshots/polished-map-puddle-block.png b/screenshots/polished-map-puddle-block.png Binary files differnew file mode 100644 index 0000000..163f0bf --- /dev/null +++ b/screenshots/polished-map-puddle-block.png diff --git a/screenshots/polished-map-puddle-tileset.png b/screenshots/polished-map-puddle-tileset.png Binary files differnew file mode 100644 index 0000000..63980df --- /dev/null +++ b/screenshots/polished-map-puddle-tileset.png diff --git a/screenshots/polished-map-puddles.png b/screenshots/polished-map-puddles.png Binary files differnew file mode 100644 index 0000000..fc64142 --- /dev/null +++ b/screenshots/polished-map-puddles.png diff --git a/screenshots/puddles.png b/screenshots/puddles.png Binary files differnew file mode 100644 index 0000000..f739af8 --- /dev/null +++ b/screenshots/puddles.png |