# Main Data Locations
* `METATABLE_START`: Starting point for data: `0xC000` (`PRG3_MIRROR`)
* `METATABLE_DATA_START`: Relative offset to start of level pointer: `0xC000` + (value a `0xC000`) == `0xC002`
* Level data offset locations (all containing values relative to `METATABLE_START` — `0xC000`):
* Level 1: `0xC002` + 2 * 2 == `0xC006`
* Value: `0x90`
* Final: `0xC090`
* Level 2: `0xC002` + 2 * 3 == `0xC008`
* Value: `0x1829`
* Final: `0xD829`
* Level 3: `0xC002` + 2 * 1 == `0xC004`
* Value: `0x413`
* Final: `0xC413`
* Level 4: `0xC002` + 2 * 5 == `0xC00C`
* Value: `0xE7B`
* Final: `0xCE7B`
* Level 5: `0xC002` + 2 * 6 == `0xC00E`
* Value: `0x1C7E`
* Final: `0xDC7E`
* Level 6: `0xC002` + 2 * 4 == `0xC00A`
* Value: `0x11AC`
* Final: `0xD1AC`
* Level Data: `0xC000` + above WORD: Meta relative pointers (10 in total)
* At `0xC002`
* Pointers:
* `0x12` — `0cC012`
* `0x413` — `0xC413`
* `0x90` — `0xC090`
* `0x1829` — `0xD829`
* `0x11AC` — `0xD1AC`
* `0xE7B` — `0xCE7B`
* `0x1C7E` — `0xDC7E`
* `0x2049` — `0xE049`
* `0x1C` — `0xC01C`
* `0x2A6` — `0xC2A6`
# Events
Seems to be composed of upper and lower bytes at different ranges.
Upper seems to start at `PRG12: 0xa003 — 0xa021` (maybe longer)
Lower seems to start at `PRG12: 0x9f6b`
That yields:
| Upper Address | Lower Address | Result |
| ------------- | ------------- | ------ |
| 0xA003 | 0x9F6B | 0xA09F |
| 0xA004 | 0x9F6C | 0xA0A3 |
| 0xA005 | 0x9F6D | 0xA0AD |
| 0xA006 | 0x9F6E | 0xA0B1 |
| 0xA007 | 0x9F6F | 0xA0BC |
| 0xA008 | 0x9F70 | 0xA0C9 |
| 0xA009 | 0x9F71 | 0xA0D3 |
| 0xA00A | 0x9F72 | 0xA0DD |
| 0xA00B | 0x9F73 | 0xA350 |
| 0xA00C | 0x9F74 | 0xA0EE |
| 0xA00D | 0x9F75 | 0xA0F8 |
| 0xA00E | 0x9F76 | 0xA4A1 |
| 0xA00F | 0x9F77 | 0xA4FC |
| 0xA010 | 0x9F78 | 0xA37A |
| 0xA011 | 0x9F79 | 0xA35D |
| 0xA012 | 0x9F7A | 0xA102 |
| 0xA013 | 0x9F7B | 0xA10B |
| 0xA014 | 0x9F7C | 0xA116 |
| 0xA015 | 0x9F7D | 0xA121 |
| 0xA016 | 0x9F7E | 0xA12C |
| 0xA017 | 0x9F7F | 0xA137 |
| 0xA018 | 0x9F80 | 0xA5A2 |
| 0xA019 | 0x9F81 | 0xA13B |
| 0xA01A | 0x9F82 | 0xA146 |
| 0xA01B | 0x9F83 | 0xA151 |
| 0xA01C | 0x9F84 | 0xA38C |
| 0xA01D | 0x9F85 | 0xA50E |
| 0xA01E | 0x9F86 | 0xA155 |
| 0xA01F | 0x9F87 | 0xA603 |
| 0xA020 | 0x9F88 | 0xA39E |
| 0xA021 | 0x9F89 | 0xA09F |
| 0xA022 | 0x9F8A | |
| 0xa023 | 0x9f8b | |
| 0xa024 | 0x9f8c | |
| 0xa025 | 0x9f8d | |
| 0xa026 | 0x9f8e | |
| 0xa027 | 0x9f8f | |
| 0xa028 | 0x9f90 | |
| 0xa029 | 0x9f91 | |
| 0xa02a | 0x9f92 | |
| 0xa02b | 0x9f93 | |
| 0xa02c | 0x9f94 | |
| 0xa02d | 0x9f95 | |
| 0xa02e | 0x9f96 | |
| 0xa02f | 0x9f97 | |
| 0xa030 | 0x9f98 | |
| 0xa031 | 0x9f99 | |
| 0xa032 | 0x9f9a | |
| 0xa033 | 0x9f9b | |
| 0xa034 | 0x9f9c | |
| 0xa035 | 0x9f9d | |
| 0xa036 | 0x9f9e | |
| 0xa037 | 0x9f9f | |
| 0xa038 | 0x9fa0 | |
| 0xa039 | 0x9fa1 | |
| 0xa03a | 0x9fa2 | |
| 0xa03b | 0x9fa3 | |
| 0xa03c | 0x9fa4 | |
| 0xa03d | 0x9fa5 | |
| 0xa03e | 0x9fa6 | |
| 0xa03f | 0x9fa7 | |
| 0xa040 | 0x9fa8 | |
| 0xa041 | 0x9fa9 | |
| 0xa042 | 0x9faa | |
| 0xa043 | 0x9fab | |
| 0xa044 | 0x9fac | |
| 0xa045 | 0x9fad | |
| 0xa046 | 0x9fae | |
| 0xa047 | 0x9faf | |
| 0xa048 | 0x9fb0 | |
| 0xa049 | 0x9fb1 | |
| 0xa04a | 0x9fb2 | |
| 0xa04b | 0x9fb3 | |
| 0xa04c | 0x9fb4 | |
| 0xa04d | 0x9fb5 | |
| 0xa04e | 0x9fb6 | |
| 0xa04f | 0x9fb7 | |
| 0xa050 | 0x9fb8 | |
| 0xa051 | 0x9fb9 | |
| 0xa052 | 0x9fba | |
| 0xa053 | 0x9fbb | |
| 0xa054 | 0x9fbc | |
| 0xa055 | 0x9fbd | |
| 0xa056 | 0x9fbe | |
| 0xa057 | 0x9fbf | |
| 0xa058 | 0x9fc0 | |
| 0xa059 | 0x9fc1 | |
| 0xa05a | 0x9fc2 | |
| 0xa05b | 0x9fc3 | |
| 0xa05c | 0x9fc4 | |
| 0xa05d | 0x9fc5 | |
| 0xa05e | 0x9fc6 | |
| 0xa05f | 0x9fc7 | |
| 0xa060 | 0x9fc8 | |
| 0xa061 | 0x9fc9 | |
| 0xa062 | 0x9fca | |
| 0xa063 | 0x9fcb | |
| 0xa064 | 0x9fcc | |
| 0xa065 | 0x9fcd | |
| 0xa066 | 0x9fce | |
| 0xa067 | 0x9fcf | |
| 0xa068 | 0x9fd0 | |
| 0xa069 | 0x9fd1 | |
| 0xa06a | 0x9fd2 | |
| 0xa06b | 0x9fd3 | |
| 0xa06c | 0x9fd4 | |
| 0xa06d | 0x9fd5 | |
| 0xa06e | 0x9fd6 | |
| 0xa06f | 0x9fd7 | |
| 0xa070 | 0x9fd8 | |
| 0xa071 | 0x9fd9 | |
| 0xa072 | 0x9fda | |
| 0xa073 | 0x9fdb | |
| 0xa074 | 0x9fdc | |
| 0xa075 | 0x9fdd | |
| 0xa076 | 0x9fde | |
| 0xa077 | 0x9fdf | |
| 0xa078 | 0x9fe0 | |
| 0xa079 | 0x9fe1 | |
| 0xa07a | 0x9fe2 | |
| 0xa07b | 0x9fe3 | |
| 0xa07c | 0x9fe4 | |
| 0xa07d | 0x9fe5 | |
| 0xa07e | 0x9fe6 | |
| 0xa07f | 0x9fe7 | |
| 0xa080 | 0x9fe8 | |
| 0xa081 | 0x9fe9 | |
| 0xa082 | 0x9fea | |
| 0xa083 | 0x9feb | |
| 0xa084 | 0x9fec | |
| 0xa085 | 0x9fed | |
| 0xa086 | 0x9fee | |
| 0xa087 | 0x9fef | |
| 0xa088 | 0x9ff0 | |
| 0xa089 | 0x9ff1 | |
| 0xa08a | 0x9ff2 | |
| 0xa08b | 0x9ff3 | |
| 0xa08c | 0x9ff4 | |
| 0xa08d | 0x9ff5 | |
| 0xa08e | 0x9ff6 | |
| 0xa08f | 0x9ff7 | |
| 0xa090 | 0x9ff8 | |
| 0xa091 | 0x9ff9 | |
| 0xa092 | 0x9ffa | |
| 0xa093 | 0x9ffb | |
| 0xa094 | 0x9ffc | |
| 0xa095 | 0x9ffd | |
| 0xa096 | 0x9ffe | |
| 0xa097 | 0x9fff | |
| 0xa098 | 0xa000 | |
| 0xa099 | 0xa001 | |
| 0xa09a | 0xa002 | |
Value at each address is 4 bytes. Another address?
# Sprites
Faxanadu keeps state for 8 sprites active at any given time. The following are used for sprite data:
| Address | Purpose | Length | Details |
| ------- | ----------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| 0x02CC | Current sprite IDs | 8 | 1 per sprite |
| 0x02D4 | Sprite Subtypes | 8 | 1 per sprite |
| 0x02DC | Sprite Flags | 8 | 1 per sprite<br><br>Bit 0: ?<br>Bit 1: Visible<br>Bit 2: ?<br>Bit 3: ?<br>Bit 4: ?<br>Bit 5: ?<br>Bit 6: ?<br>Bit 7: MAYBE: Vertical movement? |
| 0x02E4 | Sprites Current Phase | 8 | 1 per sprite |
| 0x02EC | Sprite tick counters | 8 | 1 per sprite |
| 0x032C | Sprite PPU Addresses | 8 | 1 per sprite |
| 0x0334 | Magic type sprite was hit by | 8 | 1 per sprite<br><br>0xFF == Not hit by magic |
| 0x033C | Hit by magic duration | 8 | 1 per sprite<br><br>Invincibility phase? Animation duration?<br> |
| 0x0344 | Sprite hit points | 8 | 1 per sprite |
| 0x034C | Counter used after a sprite was hit | 8 | 1 per sprite |
| 0x0354 | Sprite behaviors (lower nibble) | 8 | 1 per sprite<br><br>TBD |
| 0x035c | Sprite behaviors (upper nibble) | 8 | 1 per sprite<br><br>TBD |
| | | | |
# Block Properties
XXX How do these work?
PRG15_MIRROR: 0xE8C3:
```c
byte LoadBlockProperty(byte param_1)
{
byte bVar1;
bVar1 = *(byte *)(param_1 + 0x600) >> 1;
if ((*(byte *)(param_1 + 0x600) & 1) != 0) {
return (&BlockProperties)[bVar1] >> 4;
}
return (&BlockProperties)[bVar1] & 0xf;
}
```
# Levels
Music lookup table is at PRG15_MIRROR, 0xDF5C
| ID | Level | Music ID |
| --- | -------------------------- | -------- |
| 0 | First town | 0x7 |
| 1 | Between first town and fog | 0x3 |
| 2 | Fog | 0x5 |
| 3 | Town | 0x9 |
| 4 | Building | 0x9 |
| 5 | Tree world | 0x4 |
| 6 | Last world | 0x2 |
| 7 | Final maze | 0x10 |
# Key Requirements
| Key | Index into table |
| ------------- | ---------------- |
| None | 0 |
| "A" | 1 |
| "K" | 2 |
| "Q" | 3 |
| "J" | 4 |
| "Jo" | 5 |
| Ring of Elf | 6 |
| Ring of Dworf | 7 |
| Demon's Ring | 8 |
# Sounds
Seems to be two tables of sounds? One at PRG15_MIRROR 0xF388 (CurrentSoundIndex as key), one at PRG5 0x8590 (NextSoundEffect as key)
CurrentSoundIndex data
| Value | Map Value | Purpose |
| ----- | --------- | --------------------- |
| 0x00 | 0x00 | |
| 0x01 | 0x08 | |
| 0x02 | 0x15 | Hit enemy with weapon |
| 0x03 | 0x14 | |
| 0x04 | 0x04 | |
| 0x05 | 0x19 | Magic (not Death) |
| 0x06 | 0x0B | |
| 0x07 | 0x0D | |
| 0x08 | 0x10 | Pick up item? |
| 0x09 | 0x11 | Touched coin |
| 0x0A | 0x17 | |
| 0x0B | 0x09 | |
| 0x0C | 0x13 | |
| 0x0D | 0x0A | |
| 0x0E | 0x07 | |
| 0x0F | 0x0C | |
| 0x10 | 0x12 | |
| 0x11 | 0x0F | |
| 0x12 | 0x0E | |
| 0x13 | 0x06 | |
| 0x14 | 0x18 | Magic (Death) |
| 0x15 | 0x04 | |
| 0x16 | 0x01 | |
| 0x17 | 0x02 | |
| 0x18 | 0x03 | |
| 0x19 | 0x05 | |
| 0x1A | 0x03 | |
| 0x1B | 0x10 | Touched meat |
| 0x1C | 0x02 | |
| | | |
# Levels
| Level Number | Name |
| ------------ | ------------------------- |
| 0 | First town |
| 1 | Between firsttown and Fog |
| 2 | Fog |
| 3 | Town |
| 4 | Building |
| 5 | Tree World |
| 6 | Last World |
| 7 | Final Maze |
# Weapons
| Selected Index | Name |
| -------------- | ------------- |
| 0 | Hand Dagger |
| 1 | Long Sword |
| 2 | Giant Blade |
| 3 | Dragon Slayer |
# Armors
| Selected Index | Name |
| -------------- | ------------- |
| 0 | Leather Armor |
| 1 | Studded Mail |
| 2 | Full Plate |
| 3 | Battle Suit |
# Shields
| Selected Index | Name |
| -------------- | ------------- |
| 0 | Small Shield |
| 1 | Large Shield |
| 2 | Magic Shield |
| 3 | Battle Helmet |
# Magic
| Selected Index | Name |
| -------------- | -------- |
| 0 | No magic |
| 1 | Deluge |
| 2 | Thunder |
| 3 | Fire |
| 4 | Death |
| 5 | Tilte |
# Items
| Selected Index | Name |
| -------------- | ------------- |
| 0x00 | Ring of Elf |
| 0x01 | Ring of Ruby |
| 0x02 | Ring of Dworf |
| 0x03 | Demon's Ring |
| 0x04 | Key A |
| 0x05 | Key K |
| 0x06 | Key Q |
| 0x07 | Key J |
| 0x08 | Key Jo |
| 0x09 | Mattock |
| 0x0A | Magical Rod |
| 0x0B | Crystal |
| 0x0C | Lamp |
| 0x0D | Hour Glass |
| 0x0E | Book |
| 0x0F | Wing Boots |
| 0x10 | Red Potion |
| 0x11 | Poison |
| 0x12 | Elixir |
| 0x13 | Pendant |
| 0x14 | Black Onyx |
| 0x15 | Fire Crystal |
## Special Items Bitmask
| Bit | Name |
| ---- | ------------- |
| 0x01 | Black Onyx |
| 0x02 | Pendant |
| 0x04 | Magical Rod |
| 0x08 | Elixir |
| 0x10 | Demon's Ring |
| 0x20 | Ring of Dworf |
| 0x40 | Ring of Ruby |
| 0x80 | Ring of Elf |
# Handler functions
Looking for references to some entity handlers.
| Function | Address | Address - 1 | Candidates |
| ----------------- | ------- | ----------- | ------------------------------------------------------------------ |
| PRG14_MIRROR_d033 | d033 | d032 | PRG1::af2c<br>PRG1_MIRROR::ef2c<br>PRG5::9e8f<br>PRG5_MIRROR::de8f |
| PRG14_MIRROR_d044 | d044 | d043 | |
| PRG14_MIRROR_d060 | d060 | d05F | PRG4::a703<br>PRG4_MIRROR::e703 |