Add a new map object movement behavior - pret/pokecrystal GitHub Wiki

This tutorial is for how to add a new map object movement behavior.

Map objects are defined by object_events 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

  1. Define sprite movement constant and data

1. Define sprite movement constant and data

At a minimum, you need to define a new SPRITEMOVEDATA_* constant and its corresponding data. As an example, we'll define SPRITEMOVEDATA_SWIM_UP_DOWN.

Edit constants/map_object_constants.asm:

 ; SpriteMovementData indexes (see data/sprites/map_objects.asm)
 	const_def
 	const SPRITEMOVEDATA_00                   ; 00
 	...
 	const SPRITEMOVEDATA_SWIM_WANDER          ; 24
+	const SPRITEMOVEDATA_SWIM_UP_DOWN
 NUM_SPRITEMOVEDATA EQU const_value

And edit data/sprites/map_objects.asm:

 SpriteMovementData::
 ; entries correspond to SPRITEMOVEDATA_* constants

 ; SPRITEMOVEDATA_00
 	db SPRITEMOVEFN_00 ; movement function
 	db DOWN ; facing
 	db OBJECT_ACTION_STAND ; action
 	db WONT_DELETE ; flags1
 	db 0 ; 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_SWIM_UP_DOWN
+	db SPRITEMOVEFN_RANDOM_WALK_Y ; movement function
+	db DOWN ; facing
+	db OBJECT_ACTION_STAND ; action
+	db 0 ; flags1
+	db 0 ; flags2
+	db SWIMMING ; palette flags

Note that we had to delete some unused data at the bottom which didn't correspond to any SPRITEMOVEDATA_* constant.

Here's what the individual db values mean:

  • movement function: A SPRITEMOVEFN_* constant, as defined in constants/map_object_constants.asm.
  • facing: UP, DOWN, LEFT, or RIGHT.
  • action: An OBJECT_ACTION_* constant, as defined in constants/map_object_constants.asm.
  • flags1: A combination of any of these values, or 0 for none of them:
    • WONT_DELETE: The object won't be deleted if it moves off-screen. Example: SPRITEMOVEDATA_STRENGTH_BOULDER, which needs to stay where it's been pushed.
    • FIXED_FACING: The object doesn't change its facing direction if it moves. Example: SPRITEMOVEDATA_SHADOW, which moves along with the player over a ledge but always looks the same.
    • SLIDING: The object doesn't animate its steps if it moves. Example: SPRITEMOVEDATA_GRASS, which moves along with the player through tall grass but doesn't have a "stepping" animation.
    • MOVE_ANYWHERE: The object isn't limited to moving within a particular radius. Example: SPRITEMOVEDATA_STRENGTH_BOULDER, which can be pushed anywhere.
    • EMOTE_OBJECT: The object is meant to be transient and gets deleted differently. Example: SPRITEMOVEDATA_EMOTE, which pops up briefly above an NPC.
  • flags2: A combination of any of these values, or 0 for none of them:
    • LOW_PRIORITY: The object will appear below other objects, which have normal priority by default. Example: SPRITEMOVEDATA_BOULDERDUST, which appears below Strength boulders when they're pushed.
    • HIGH_PRIORITY: The object will appear above other objects. Do not combine with LOW_PRIORITY. Example: SPRITEMOVEDATA_GRASS, which appears above the player when walking through tall grass.
    • USE_OBP1: The object will use SGB palette #1 instead of #0. This was relevant for Gold and Silver since they could be played on the Super Game Boy, but not Crystal.
  • palette flags: A combination of any of these values, or 0 for none of them:
    • SWIMMING: The object can move over water but is blocked by land, instead of vice-versa. Example: SPRITEMOVEDATA_SWIM_WANDER, which is used for the Lapras in Union Cave.
    • STRENGTH_BOULDER: The object blocks the player if they haven't used Strength. Example: SPRITEMOVEDATA_STRENGTH_BOULDER of course, but also the SPRITEMOVEDATA_BIGDOLL* data for some reason.
    • BIG_OBJECT: The object blocks the spaces below it, to its right, and to its bottom-right, not just the space its coordinates are at. Example: SPRITEMOVEDATA_BIGDOLLSYM, which is used for the Snorlax in Vermilion City.

In the example, we based SPRITEMOVEDATA_SWIM_UP_DOWN off of SPRITEMOVEDATA_SWIM_WANDER but gave it the same movement function as SPRITEMOVEDATA_WALK_UP_DOWN. In particular, it needed the SWIMMING palette flag.

One more thing: there happens to be a bug that affects objects which swim and move randomly; they're not actually limited by their movement radius. So be sure to fix that.

Anyway, that's all! Now you can use SPRITEMOVEDATA_SWIM_UP_DOWN for object_events just like the rest.

Screenshot

TODO: define new SPRITEMOVEFN_*, OBJECT_ACTION_*, and FACING_* data.

TODO: define new STEP_TYPE_* and STEP_* data.