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 | Parameters | Implementation Address |
| ----- | --------------------- | ----------- | ---------------------- |
| $00 | Switch Behavior | 2 (2 bytes) | $A6FF |
| $01 | | | $A72C |
| $02 | Run Action | 1 (1 byte) | $A772 |
| $03 | If Distance to Player | 4 (7 bytes) | $A7E5 |
| $04 | Finish Behavior | 0 | $A86E |
| $05 | Go To | 1 (2 bytes) | $A74C |
| $06 | Set Sprite Data | 2 (3 bytes) | $A84F |
| $07 | | | $A6E8 |
| $FF | End Script | 0 | N/A |
# 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 | Face player (X) | $867B |
| $01 | Flip X direction | $8407 |
| $02 | Face player (Y) | $8691 |
| $03 | Flip Y direction | $8410 |
| $04 | Randomly flip X direction | $A7AD |
| $05 | Randomly flip Y direction | $A7C9 |
| $06 | Fly upward | $A7A4 |
| $07 | Cast magic | $9239 |
# Behaviors
Behaviors are more detailed code paths that make up the bulk of most sprites' overall logic.
They may take any number of parameters (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 | Parameters | 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 | Walk Forward | 3 (3 bytes) | $A941 |
| $05 | _No-op_ | 1 (1 byte) | $A6AE |
| $06 | | | |
| $07 | | | |
| $08 | | | |
| $09 | [[#Behavior $09 Hop\|Hop]] | 4 (4 bytes) | $A9DE |
| $0A | | | |
| $0B | _No-op_ | 1 (1 byte) | $A6AE |
| $0C | | | |
| $0D | | | |
| $0E | | | |
| $0F | | | |
| $10 | | | |
| $11 | | | |
| $12 | | | |
| $13 | | | |
| $14 | | | |
| $15 | | | |
| $16 | | | |
| $17 | | | |
| $18 | | | |
| $19 | | | |
| $1A | | | |
| $1B | | | |
| $1C | | | |
| $1D | | | |
| $1E | | | |
| $1F | | | |
| $20 | | | |
| $21 | | | |
| $22 | | | |
| $23 | | | |
| $24 | | | |
| $25 | | | |
| $26 | | | |
| $27 | | | |
| $28 | | | |
| $29 | | | |
| $2A | | | |
| $2B | | | |
| $2C | | | |
| $2D | | | |
| $2E | | | |
| $2F | | | |
| $30 | | | |
| $31 | | | |
| $32 | | | |
| $33 | | | |
| $34 | | | |
| $35 | | | |
| $36 | | | |
| $38 | | | |
| $39 | | | |
| $3A | | | |
| $3B | | | |
| $3C | | | |
| $3D | | | |
| $3E | | | |
| $3F | | | |
| $40 | | | |
| $41 | | | |
## Behavior $00: Move Toward Player
**Function Address:** $A8FC
**Arguments:**
1. Number of ticks to walk
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
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 $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 |