# 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 |