All sprite entities in Faxanadu (dropped items, NPCs, enemies, and bosses) have behavior scripts that define how they move. I'll refer to these as "BScripts" for short. This is a simplified scripting language with the following components: * **Ops:** The base operations a script can perform. This can run an action, switch a behavior, go to a script address, and other things. * **Actions:** Simple actions that can be performed, generally related to movement direction, but also spell-casting * **Behaviors:** Broader behavior routines that perform things like hopping, walking, or flying. # Memory Locations There are a few memory locations relevant to BScripts: | Bank | Address Range | Description | | ---- | ------------- | ---------------------- | | 12 | $A5E7 - $A66A | Behaviors lookup table | | 12 | $A6D8 - $A6E7 | Ops lookup table | | 12 | $A794 - $A7A3 | Actions lookup table | # BScripts Structure BScripts have the following structure: | Script Offset | Size (bytes) | Description | | ------------- | ------------ | ----------- | | 0 | 1 | Op ID | | 1+ | N | Parameters | | ... | | | Scripts will end with an End Script (0xFF) or Go To (0x05 + address). # Ops Operations are identified by a number between 0 and 7, and a special value 0xFF. Implementations are all in Bank 12. Here's a quick summary of the ops: | Op ID | Name | Arguments | Implementation Address | | ----- | -------------------------------------------------------------- | ----------- | ---------------------- | | $00 | [[#Op $00 Switch Behavior\|Switch Behavior]] | 2 (2 bytes) | $A6FF | | $01 | [[#Op $01 Maybe Disable and Go To\|Maybe: Disable and Go To]] | | $A72C | | $02 | [[#Op $02 Run Action\|Run Action]] | 1 (1 byte) | $A772 | | $03 | [[#Op $03 Check Distance To Player\|Check Distance to Player]] | 4 (7 bytes) | $A7E5 | | $04 | [[#Op $04 Finish Behavior\|Finish Behavior]] | 0 | $A86E | | $05 | [[#Op $05 Go To\|Go To]] | 1 (2 bytes) | $A74C | | $06 | [[#0p $06 Add Value To Sprite Data\|Add Value To Sprite Data]] | 2 (3 bytes) | $A84F | | $07 | [[#Op $07 Set Phase\|Set Phase]] | 1 (1 byte) | $A6E8 | | $FF | [[#Op $FF End Script\|End Script]] | 0 | None | ## Op $00: Switch Behavior **Function Address:** $A6FF **Arguments:** 1. Behavior ID (1 byte) 2. First unconditional parameter for behavior (1 byte) Switch the sprite to perform a behavior's logic until it ends. Each call always takes at least one argument (which may or may not be used by a behavior), and may also take additional arguments as needed by the behavior implementation. See [[#Behaviors]] for valid values and arguments. ## Op $01: Maybe: Disable and Go To **Function Address:** $A72C **Arguments:** TODO ## Op $02: Run Action **Function Address:** $A772 **Arguments:** 1. Action ID (1 byte) Run an action. Unlike behaviors, actions have no additional arguments. They're used for quick, single-purpose actions. See [[#Actions]]. ## Op $03: Check Distance To Player **Function Address:** $A7E5 **Arguments:** 1. Check direction (0=X, 1=Y) (1 byte) 2. Distance value (1 byte) 3. Address to jump to if distance < value (2 bytes) 4. Address to jump to if distance >= value (2 bytes) Check if the distance between the player and sprite is within or outside the given value. This can check in either the X or Y direction. Depending on the result, this will jump to one of two addresses defined in the arguments. ## Op $04: Finish Behavior **Function Address:** $A86E **Arguments:** None. Immediately finish a behavior. This will unset the behavior ID and continue on with the next operation. ## Op $05: Go To **Function Address:** $A74C **Arguments:** 1. Script jump address (2 bytes) ## 0p $06: Add Value To Sprite Data **Function Address:** $A84F **Arguments:** 1. Sprites data RAM address (2 bytes) 2. Value to set (1 byte) Add a value to the existing value in a Current Sprites data block of RAM, as in: ``` existing_value += new_value ``` This is valid for several collections of Current Sprite data in RAM, including: * `CurrentSprites_Flags` * `CurrentSprites_XPos_Full` * `CurrentSprites_YPos` * `CurrentSprites_Values` * `CurrentSprites_HitCounter` The value will be set for the current sprite in that array. ## Op $07: Set Phase **Function Address:** $A6E8 **Arguments:** 1. Phase value ## Op $FF: End Script **Function Address:** None. **Arguments:** None. Immediately end the script. # Actions Actions are simple movement or attack changes in a sprite that may be invoked in-between behaviors. They do not take any parameters. Implementations are all in Bank 12. Here's a quick summary of the actions: | Action ID | Name | Implementation Address | | --------- | -------------------------------------------------------------------- | ---------------------- | | $00 | [[#Action $00 Face Player (X)\|Face Player (X)]] | $867B | | $01 | [[#Action $01 Flip X Direction\| Flip X Direction]] | $8407 | | $02 | [[#Action $02 Face Player (Y)\|Face Player (Y)]] | $8691 | | $03 | [[#Action $03 Flip Y Direction\|Flip Y Direction]] | $8410 | | $04 | [[#Action $04 Randomly Flip X Direction\|Randomly Flip X Direction]] | $A7AD | | $05 | [[#Action $05 Randomly Flip Y Direction\|Randomly Flip Y Direction]] | $A7C9 | | $06 | [[#Action $06 Rise Upward\|Rise Upward]] | $A7A4 | | $07 | [[#Action $07 Cast Magic\|Cast Magic]] | $9239 | ## Action $00: Face Player (X) **Function Address:** $867B Face the player in the X direction. ## Action $01: Flip X Direction **Function Address:** $8407 Flip the sprite's X direction. This will change the direction the sprite faces/moves. ## Action $02: Face Player (Y) **Function Address:** $8691 Face the player in the Y direction. ## Action $03: Flip Y Direction **Function Address:** $8410 Flip the sprite's Y direction. This will change the direction the sprite falls/rises. ## Action $04: Randomly Flip X Direction **Function Address:** $A7AD Randomly flip the X direction. This will generate a random number. If it's < 128, the sprite will face right. Otherwise it will face left. ## Action $05: Randomly Flip Y Direction **Function Address:** $A7C9 Randomly flip the Y direction. This will generate a random number. If it's < 128, the sprite will fall. Otherwise it will rise. ## Action $06: Rise Upward **Function Address:** $A7A4 This will clear the Falling flag for the sprite, causing it to rise up. ## Action $07: Cast Magic **Function Address:** $9239 # Behaviors Behaviors are more detailed code paths that make up the bulk of most sprites' overall logic. They may take any number of arguments (but always at least 1 — an arbitrary data value), and work with various bits of state in memory. Implementations are all in Bank 12. Here's a quick summary of the behaviors: | Behavior ID | Name | Arguments | | Implementation Address | | ----------- | ------------------------------------------------------------------------------------ | ----------- | --- | ---------------------- | | $00 | [[#Behavior $00 Move Toward Player\|Move Toward Player]] | 3 (3 bytes) | | $A8FC | | $01 | [[#Behavior $01 Wait\|Wait]] | 1 (1 byte) | | $A98B | | $02 | [[#Behavior $02 Bounce and Expire\|Bounce and Expire]] | | | $8D0A | | $03 | | | | $9E6D | | $04 | [[#Behavior $04 Walk Forward\|Walk Forward]] | 3 (3 bytes) | | $A941 | | $05 | _No-op_ | 1 (1 byte) | | $A6AE | | $06 | | | | $9A32 | | $07 | | | | $ABCC | | $08 | | | | $ABCC | | $09 | [[#Behavior $09 Hop\|Hop]] | 4 (4 bytes) | | $A9DE | | $0A | Rapasheiku Boss | | | $9B83 | | $0B | _No-op_ | 1 (1 byte) | | $A6AE | | $0C | | | | $9C89 | | $0D | | | | $9CF2 | | $0E | | | | $9DA9 | | $0F | | | | $9F03 | | $10 | | | | $9FE3 | | $11 | | 5 (5 bytes) | | $A997 | | $12 | | | | $AA86 | | $13 | | | | $AAFA | | $14 | | | | $A8D7 | | $15 | [[#Behavior $15 Fall/Wait\|Fall/Wait]] | 1 (1 byte) | | $A978 | | $16 | | | | $8DA3 | | $17 | | | | $8ECF | | $18 | | | | $8F2E | | $19 | | | | $8FE7 | | $1A | | | | $9060 | | $1B | | | | $A0CB | | $1C | | | | $A11D | | $1D | | | | $A154 | | $1E | | | | $9284 | | $1F | [[#Behavior $1F Flash Screen, Damage Player\|Flash Screen, Damage Player]] | 1 (1 byte) | | $AB26 | | $20 | | | | $92E0 | | $21 | | | | $93E5 | | $22 | | | | $9538 | | $23 | | | | $9632 | | $24 | | | | $95C0 | | $25 | | | | $971D | | $26 | | | | $97AE | | $27 | | | | $9865 | | $28 | | | | $9497 | | $29 | | | | $A246 | | $2A | | | | $A25F | | $2B | | | | $A354 | | $2C | | | | $A384 | | $2D | | | | $A3BF | | $2E | [[#Behavior $2E Mattock Dropped by Ripasheiku\|Mattock Dropped by Ripasheiku]] | 1 (1 byte) | | $A3EF | | $2F | [[#Behavior $2F Wing Boots Dropped by Zorugeriru\|Wing Boots Dropped by Zorugeriru]] | 1 (1 byte) | | $A413 | | $30 | [[#Behavior $30 Black Onyx Dropped by Zoradohna\|Black Onyx Dropped by Zoradohna]] | 1 (1 byte) | | $A437 | | $31 | [[#Behavior $31 Pendant Dropped by Ripasheiku\|Pendant Dropped by Ripasheiku]] | 1 (1 byte) | | $A45B | | $32 | | | | $A48A | | $33 | | | | $A49D | | $34 | | | | $A4B0 | | $35 | | | | $A4C3 | | $36 | | | | $A4D6 | | $37 | | | | $A4FC | | $38 | | | | $A4E9 | | $39 | | | | $A31E | | $3A | | | | $A558 | | $3B | | | | $A56F | | $3C | | | | $A586 | | $3D | | | | $A47F | | $3E | | | | $AB67 | | $3F | | | | $8E77 | | $40 | | | | $9129 | | $41 | | | | $91B3 | ## Behavior $00: Move Toward Player **Function Address:** $A8FC **Arguments:** 1. Number of ticks to walk (1 byte) 2. Per-tick X fractional distance (1 byte) 3. Per-tick X full distance (1 byte) Walks a pre-set distance toward the player. It will also move down toward the player, if above. ## Behavior $01: Wait **Function Address:** $A98B **Arguments:** 1. Number of ticks to wait (1 byte) Waits a specified number of ticks before performing the next op. ## Behavior $02: Bounce and Expire **Function Address:** $8D0A **Arguments:** 1. Unused Bounces down and up repeatedly for 256 ticks, and then disappears. This is used for dropped coins. ## Behavior $04: Walk Forward **Function Address:** $A941 **Arguments:** 1. Duration (1 byte) 2. Fractional movement amount in pixels (1 byte) 3. Full movement amount in blocks (1 byte) Walks forward in the sprite's facing direction by the specified amount for the specified duration. If the sprite hits a wall, its facing/X direction will flip. If the sprite is no longer on a block, it will fall. ## Behavior $09: Hop **Function Address:** $A9DE **Arguments:** 1. Unused 2. X fractional movement for hop (1 byte) 3. X full movement for hop (1 byte) 4. Hop mode (1 byte) Hops up and then down, optionally moving in an X direction at the same time. The following hop modes are supported: | Hop Mode | Jump Strength | Gravity Index | Start Tick Value | Ground Tick Value | | -------- | ------------- | ------------- | ---------------- | ----------------- | | 0 | 4 | 2 | $40 (64) | $C0 (192) | | 1 | 5 | 3 | $20 (32) | $60 (96) | | 2 | 6 | 4 | $10 (16) | $30 (48) | | 3 | 7 | 5 | $08 (8) | $18 (24) | | 4 | 7 | 4 | $10 (16) | $30 (48) | The Gravity Index is used for two things: 1. A gravity calculation for falling 2. A peak tick lookup table, to determine whether it's time to flip the Y direction (from jumping to falling). The peak tick lookup table (not all values are used by this behavior — it's shared with others). | Index | Value | | ----- | ----- | | 0 | $FF | | 1 | $7F | | 2 | $3F | | 3 | $1F | | 4 | $0F | | 5 | $07 | | 6 | $03 | | 7 | $01 | ## Behavior $11: Unused Eyeball Behavior **Function Address:** $A997 **Arguments:** 1. Duration (1 byte) 2. X delta pixels (1 byte) 3. X delta blocks (1 byte) 4. Y delta pixels (1 byte) 5. Y delta blocks (1 byte) ## Behavior $15: Fall/Wait **Function Address:** $A978 **Arguments:** 1. Duration (1 byte) Falls until it's either on top of a block or off the screen. If off the screen, the sprite will be removed. ## Behavior $1F: Flash Screen, Damage Player **Function Address:** $AB26 **Arguments:** 1. Unused (1 byte) Flashes the screen (turns it greyscale for a frame), damaging the player for 10HP. ## Behavior $2E: Mattock Dropped by Ripasheiku **Function Address:** $A3EF **Arguments:** 1. Unused (1 byte) Shows the sprite on screen only if all conditions are met: 1. The player has not retrieved the Mattock from Ripasheiku 2. Ripasheiku is not on the screen ## Behavior $2F: Wing Boots Dropped by Zorugeriru **Function Address:** $A413 **Arguments:** 1. Unused (1 byte) Shows the sprite on screen only if all conditions are met: 1. The player has not retrieved the Wingboots from Zorugeriru 2. Zorugeriru is not on the screen ## Behavior $30: Black Onyx Dropped by Zoradohna **Function Address:** $A437 **Arguments:** 1. Unused (1 byte) Shows the sprite on screen only if all conditions are met: 1. The player does not have the Black Onyx 2. Zoradohna is not on the screen ## Behavior $31: Pendant Dropped by Ripasheiku **Function Address:** $A45B **Arguments:** 1. Unused (1 byte) Shows the sprite on screen only if all conditions are met: 1. The player does not have the Pendant 2. Ripasheiku is not on the screen ## Behavior $3F: Buzz Around **Function Address:** $A45B **Arguments:** 1. Unused (1 byte) Hornet behavior. This sprite will move around horizontally and vertically, oscillating up and down. This behavior does not return. It will continue indefinitely.