diff --git a/include/z64elf_message.h b/include/z64elf_message.h new file mode 100644 index 0000000000..d6f545b3f0 --- /dev/null +++ b/include/z64elf_message.h @@ -0,0 +1,129 @@ +#ifndef Z64ELF_MESSAGE_H +#define Z64ELF_MESSAGE_H + +#include "ultra64.h" + +// Checks the condition and exits the script if the check passes +#define ELF_MSG_TYPE_CHECK 0 +// ? (unused) +#define ELF_MSG_TYPE_UNK_1 1 +// ? (unused) +#define ELF_MSG_TYPE_UNK_2 2 +// Checks the condition and skips forward by some number of commands if the check passes +#define ELF_MSG_TYPE_SKIP 3 +// Always ends the script, returning the text id for this command +#define ELF_MSG_TYPE_END 7 + +// Check an eventChkInf flag +#define ELF_MSG_CONDITION_FLAG 0 +// Check a dungeon item (map, compass, boss key) +#define ELF_MSG_CONDITION_DUNGEON_ITEM 1 +// Check if an item is in an item slot +#define ELF_MSG_CONDITION_ITEM 2 +// "Other" conditions described below +#define ELF_MSG_CONDITION_OTHER 3 + +// Check what strength upgrade has been obtained so far +#define ELF_MSG_CONDITION_STRENGTH_UPG 0 +// Check if specific boots have been obtained so far +#define ELF_MSG_CONDITION_BOOTS 1 +// Check if a particular song has been obtained +#define ELF_MSG_CONDITION_SONG 2 +// Check if a particular medallion has been obtained +#define ELF_MSG_CONDITION_MEDALLION 3 +// Check if the magic meter has been obtained +#define ELF_MSG_CONDITION_MAGIC 4 + +/* + * Bitpack byte 0 + */ +#define ELF_MSG_B0(type, cond_type, tf) \ + _SHIFTL(ELF_MSG_TYPE_##type, 5, 3) | \ + _SHIFTL(ELF_MSG_CONDITION_##cond_type, 1, 4) | \ + _SHIFTL(tf, 0, 1) + +/* + * Bitpack byte 1 + */ +#define ELF_MSG_B1(cond_type, data) \ + _SHIFTL(ELF_MSG_CONDITION_##cond_type, 4, 4) | \ + _SHIFTL(data, 0, 4) + +/* + * Other bytes + */ +#define ELF_MSG_B(data) \ + _SHIFTL(data, 0, 8) + +/* + * Command macros + */ + +#define ELF_MSG_FLAG(type, textId, tf, flag) \ + { \ + ELF_MSG_B0(type, FLAG, tf), \ + ELF_MSG_B(flag), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(0), \ + } + +#define ELF_MSG_END(textId) \ + ELF_MSG_FLAG(END, textId, false, 0) + +#define ELF_MSG_DUNGEON_ITEM(type, textId, tf, itemId) \ + { \ + ELF_MSG_B0(type, DUNGEON_ITEM, tf), \ + ELF_MSG_B(itemId), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(0), \ + } + +#define ELF_MSG_ITEM(type, textId, tf, slotItemId, itemId) \ + { \ + ELF_MSG_B0(type, ITEM, tf), \ + ELF_MSG_B(slotItemId), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(itemId), \ + } + +#define ELF_MSG_STRENGTH_UPG(type, textId, tf, strUpg) \ + { \ + ELF_MSG_B0(type, OTHER, tf), \ + ELF_MSG_B1(STRENGTH_UPG, strUpg), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(0), \ + } + +#define ELF_MSG_BOOTS(type, textId, tf, itemId) \ + { \ + ELF_MSG_B0(type, OTHER, tf), \ + ELF_MSG_B1(BOOTS, 0), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(itemId), \ + } + +#define ELF_MSG_SONG(type, textId, tf, itemId) \ + { \ + ELF_MSG_B0(type, OTHER, tf), \ + ELF_MSG_B1(SONG, 0), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(itemId), \ + } + +#define ELF_MSG_MEDALLION(type, textId, tf, itemId) \ + { \ + ELF_MSG_B0(type, OTHER, tf), \ + ELF_MSG_B1(MEDALLION, 0), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(itemId), \ + } + +#define ELF_MSG_MAGIC(type, textId, tf) \ + { \ + ELF_MSG_B0(type, OTHER, tf), \ + ELF_MSG_B1(MAGIC, 0), \ + ELF_MSG_B(textId), \ + ELF_MSG_B(0), \ + } + +#endif diff --git a/spec b/spec index 47ed04a15a..d4e901c5c3 100644 --- a/spec +++ b/spec @@ -6796,13 +6796,15 @@ endseg beginseg name "elf_message_field" romalign 0x1000 - include "build/baserom/elf_message_field.o" + include "build/src/elf_message/elf_message_field.o" + number 0 endseg beginseg name "elf_message_ydan" romalign 0x1000 - include "build/baserom/elf_message_ydan.o" + include "build/src/elf_message/elf_message_ydan.o" + number 0 endseg beginseg diff --git a/src/code/z_elf_message.c b/src/code/z_elf_message.c index 7d33b496d7..370fe8d419 100644 --- a/src/code/z_elf_message.c +++ b/src/code/z_elf_message.c @@ -1,16 +1,29 @@ #include "global.h" +#include "z64elf_message.h" -// TODO: use macros to define elf messages once the format is fully documented ElfMessage sChildSariaMsgs[] = { - { 0x66, 0x00, 0x03, 0x00 }, { 0x00, 0x37, 0x61, 0x00 }, { 0xE0, 0x00, 0x64, 0x00 }, { 0x00, 0x25, 0x62, 0x00 }, - { 0x00, 0x37, 0x63, 0x00 }, { 0x00, 0x43, 0x65, 0x00 }, { 0x06, 0x30, 0x66, 0x66 }, { 0x06, 0x30, 0x66, 0x67 }, - { 0x06, 0x30, 0x66, 0x68 }, { 0x06, 0x20, 0x67, 0x65 }, { 0x06, 0x30, 0x68, 0x69 }, { 0x06, 0x30, 0x68, 0x6A }, - { 0xE0, 0x00, 0x69, 0x00 }, + ELF_MSG_STRENGTH_UPG(SKIP, 3, false, 0), + ELF_MSG_FLAG(CHECK, 0x61, false, 0x37), /* eventChkInf[3] & 0x80 */ + ELF_MSG_END(0x64), + ELF_MSG_FLAG(CHECK, 0x62, false, 0x25), /* eventChkInf[2] & 0x20 */ + ELF_MSG_FLAG(CHECK, 0x63, false, 0x37), /* eventChkInf[3] & 0x80 */ + ELF_MSG_FLAG(CHECK, 0x65, false, 0x43), /* eventChkInf[4] & 0x8 */ + ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_FOREST), + ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_FIRE), + ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_WATER), + ELF_MSG_SONG(CHECK, 0x67, false, ITEM_SONG_STORMS), + ELF_MSG_MEDALLION(CHECK, 0x68, false, ITEM_MEDALLION_SPIRIT), + ELF_MSG_MEDALLION(CHECK, 0x68, false, ITEM_MEDALLION_SHADOW), + ELF_MSG_END(0x69), }; ElfMessage sAdultSariaMsgs[] = { - { 0x06, 0x30, 0x6A, 0x66 }, { 0x06, 0x30, 0x6B, 0x67 }, { 0x06, 0x30, 0x6B, 0x68 }, - { 0x06, 0x30, 0x6C, 0x69 }, { 0x06, 0x30, 0x6C, 0x6A }, { 0xE0, 0x00, 0x6D, 0x00 }, + ELF_MSG_MEDALLION(CHECK, 0x6A, false, ITEM_MEDALLION_FOREST), + ELF_MSG_MEDALLION(CHECK, 0x6B, false, ITEM_MEDALLION_FIRE), + ELF_MSG_MEDALLION(CHECK, 0x6B, false, ITEM_MEDALLION_WATER), + ELF_MSG_MEDALLION(CHECK, 0x6C, false, ITEM_MEDALLION_SPIRIT), + ELF_MSG_MEDALLION(CHECK, 0x6C, false, ITEM_MEDALLION_SHADOW), + ELF_MSG_END(0x6D), }; u32 ElfMessage_CheckCondition(ElfMessage* msg) { @@ -18,29 +31,29 @@ u32 ElfMessage_CheckCondition(ElfMessage* msg) { u16 flag; switch (type) { - case 0: + case (ELF_MSG_CONDITION_FLAG << 1): flag = 1 << (msg->byte1 & 0x0F); return ((msg->byte0 & 1) == 1) == ((flag & gSaveContext.eventChkInf[(msg->byte1 & 0xF0) >> 4]) != 0); - case 2: + case (ELF_MSG_CONDITION_DUNGEON_ITEM << 1): return ((msg->byte0 & 1) == 1) == (CHECK_DUNGEON_ITEM(msg->byte1 - ITEM_KEY_BOSS, gSaveContext.mapIndex) != 0); - case 4: + case (ELF_MSG_CONDITION_ITEM << 1): return ((msg->byte0 & 1) == 1) == (msg->byte3 == INV_CONTENT(msg->byte1)); - case 6: + case (ELF_MSG_CONDITION_OTHER << 1): switch (msg->byte1 & 0xF0) { - case 0x00: + case (ELF_MSG_CONDITION_STRENGTH_UPG << 4): return ((msg->byte0 & 1) == 1) == ((msg->byte1 & 0x0F) == CUR_UPG_VALUE(UPG_STRENGTH)); - case 0x10: + case (ELF_MSG_CONDITION_BOOTS << 4): return ((msg->byte0 & 1) == 1) == (((gBitFlags[msg->byte3 - ITEM_BOOTS_KOKIRI] << gEquipShifts[EQUIP_BOOTS]) & gSaveContext.inventory.equipment) != 0); - case 0x20: + case (ELF_MSG_CONDITION_SONG << 4): return ((msg->byte0 & 1) == 1) == (CHECK_QUEST_ITEM(msg->byte3 - ITEM_SONG_MINUET + QUEST_SONG_MINUET) != 0); - case 0x30: + case (ELF_MSG_CONDITION_MEDALLION << 4): return ((msg->byte0 & 1) == 1) == (CHECK_QUEST_ITEM(msg->byte3 - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST) != 0); - case 0x40: + case (ELF_MSG_CONDITION_MAGIC << 4): return ((msg->byte0 & 1) == 1) == (((void)0, gSaveContext.magicAcquired) != 0); } } @@ -54,7 +67,7 @@ u32 ElfMessage_CheckCondition(ElfMessage* msg) { u32 func_8006BE88(ElfMessage** msgp) { u32 temp = true; - while (((*msgp)->byte0 & 0xE0) == 0x20) { + while (((*msgp)->byte0 & 0xE0) == (ELF_MSG_TYPE_UNK_1 << 5)) { if (!ElfMessage_CheckCondition(*msgp)) { temp = false; } @@ -80,7 +93,7 @@ u32 func_8006BF1C(ElfMessage** msgp) { temp1 += sp44[temp2]; temp2++; msg++; - } while ((msg->byte0 & 0xE0) == 0x40); + } while ((msg->byte0 & 0xE0) == (ELF_MSG_TYPE_UNK_2 << 5)); if (temp1 == 0) { return false; @@ -104,28 +117,28 @@ u32 func_8006BF1C(ElfMessage** msgp) { u16 ElfMessage_GetTextFromMsgs(ElfMessage* msg) { while (true) { switch (msg->byte0 & 0xE0) { - case 0x00: + case (ELF_MSG_TYPE_CHECK << 5): if (ElfMessage_CheckCondition(msg)) { return msg->byte2 | 0x100; } break; - case 0x20: + case (ELF_MSG_TYPE_UNK_1 << 5): if (func_8006BE88(&msg)) { return msg->byte2 | 0x100; } break; - case 0x40: + case (ELF_MSG_TYPE_UNK_2 << 5): if (func_8006BF1C(&msg)) { return msg->byte2 | 0x100; } break; - case 0x60: + case (ELF_MSG_TYPE_SKIP << 5): if (ElfMessage_CheckCondition(msg)) { msg += msg->byte2; msg--; } break; - case 0xE0: + case (ELF_MSG_TYPE_END << 5): return msg->byte2 | 0x100; default: LOG_STRING("企画外 条件", "../z_elf_message.c", 281); // "Unplanned conditions" diff --git a/src/elf_message/elf_message_field.c b/src/elf_message/elf_message_field.c new file mode 100644 index 0000000000..fe1e8ee97e --- /dev/null +++ b/src/elf_message/elf_message_field.c @@ -0,0 +1,33 @@ +#include "global.h" +#include "z64elf_message.h" + +ElfMessage gOverworldNaviMsgs[] = { + ELF_MSG_FLAG(CHECK, 0x40, false, 0x05), /* eventChkInf[0] & 0x20 */ + ELF_MSG_FLAG(CHECK, 0x41, false, 0x09), /* eventChkInf[0] & 0x200 */ + ELF_MSG_FLAG(CHECK, 0x42, false, 0x12), /* eventChkInf[1] & 0x4 */ + ELF_MSG_FLAG(CHECK, 0x43, false, 0x14), /* eventChkInf[1] & 0x10 */ + ELF_MSG_FLAG(CHECK, 0x44, false, 0x40), /* eventChkInf[4] & 0x1 */ + ELF_MSG_SONG(CHECK, 0x45, false, ITEM_SONG_SARIA), + ELF_MSG_STRENGTH_UPG(CHECK, 0x46, true, 0), + ELF_MSG_FLAG(CHECK, 0x47, false, 0x25), /* eventChkInf[2] & 0x20 */ + ELF_MSG_MAGIC(CHECK, 0x48, false), + ELF_MSG_FLAG(CHECK, 0x49, false, 0x33), /* eventChkInf[3] & 0x8 */ + ELF_MSG_FLAG(CHECK, 0x4A, false, 0x37), /* eventChkInf[3] & 0x80 */ + ELF_MSG_FLAG(CHECK, 0x4B, false, 0x80), /* eventChkInf[8] & 0x1 */ + ELF_MSG_FLAG(CHECK, 0x4C, false, 0x43), /* eventChkInf[4] & 0x8 */ + ELF_MSG_FLAG(CHECK, 0x4D, false, 0x45), /* eventChkInf[4] & 0x20 */ + ELF_MSG_ITEM(CHECK, 0x4E, true, ITEM_HOOKSHOT, ITEM_NONE), + ELF_MSG_MEDALLION(CHECK, 0x50, false, ITEM_MEDALLION_FOREST), + ELF_MSG_MEDALLION(CHECK, 0x51, false, ITEM_MEDALLION_FIRE), + ELF_MSG_BOOTS(CHECK, 0x52, false, ITEM_BOOTS_IRON), + ELF_MSG_MEDALLION(CHECK, 0x53, false, ITEM_MEDALLION_WATER), + ELF_MSG_FLAG(CHECK, 0x54, false, 0xAA), /* eventChkInf[10] & 0x400 */ + ELF_MSG_ITEM(CHECK, 0x55, true, ITEM_LENS, ITEM_NONE), + ELF_MSG_MEDALLION(CHECK, 0x57, false, ITEM_MEDALLION_SHADOW), + ELF_MSG_SONG(CHECK, 0x58, false, ITEM_SONG_REQUIEM), + ELF_MSG_STRENGTH_UPG(CHECK, 0x56, true, 1), + ELF_MSG_MEDALLION(CHECK, 0x5A, false, ITEM_MEDALLION_SPIRIT), + ELF_MSG_ITEM(CHECK, 0x5B, true, ITEM_ARROW_LIGHT, ITEM_NONE), + ELF_MSG_FLAG(CHECK, 0x5C, false, 0xC3), /* eventChkInf[12] & 0x8 */ + ELF_MSG_END(0x5F), +}; diff --git a/src/elf_message/elf_message_ydan.c b/src/elf_message/elf_message_ydan.c new file mode 100644 index 0000000000..54050e372e --- /dev/null +++ b/src/elf_message/elf_message_ydan.c @@ -0,0 +1,6 @@ +#include "global.h" +#include "z64elf_message.h" + +ElfMessage gDungeonNaviMsgs[] = { + ELF_MSG_END(0x5F), +}; diff --git a/tools/disasm_elf_msg.py b/tools/disasm_elf_msg.py new file mode 100644 index 0000000000..4d58c9d27b --- /dev/null +++ b/tools/disasm_elf_msg.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 + +import struct, sys + +item_ids = { + 0x00 : "ITEM_STICK", + 0x01 : "ITEM_NUT", + 0x02 : "ITEM_BOMB", + 0x03 : "ITEM_BOW", + 0x04 : "ITEM_ARROW_FIRE", + 0x05 : "ITEM_DINS_FIRE", + 0x06 : "ITEM_SLINGSHOT", + 0x07 : "ITEM_OCARINA_FAIRY", + 0x08 : "ITEM_OCARINA_TIME", + 0x09 : "ITEM_BOMBCHU", + 0x0A : "ITEM_HOOKSHOT", + 0x0B : "ITEM_LONGSHOT", + 0x0C : "ITEM_ARROW_ICE", + 0x0D : "ITEM_FARORES_WIND", + 0x0E : "ITEM_BOOMERANG", + 0x0F : "ITEM_LENS", + 0x10 : "ITEM_BEAN", + 0x11 : "ITEM_HAMMER", + 0x12 : "ITEM_ARROW_LIGHT", + 0x13 : "ITEM_NAYRUS_LOVE", + 0x14 : "ITEM_BOTTLE", + 0x15 : "ITEM_POTION_RED", + 0x16 : "ITEM_POTION_GREEN", + 0x17 : "ITEM_POTION_BLUE", + 0x18 : "ITEM_FAIRY", + 0x19 : "ITEM_FISH", + 0x1A : "ITEM_MILK_BOTTLE", + 0x1B : "ITEM_LETTER_RUTO", + 0x1C : "ITEM_BLUE_FIRE", + 0x1D : "ITEM_BUG", + 0x1E : "ITEM_BIG_POE", + 0x1F : "ITEM_MILK_HALF", + 0x20 : "ITEM_POE", + 0x21 : "ITEM_WEIRD_EGG", + 0x22 : "ITEM_CHICKEN", + 0x23 : "ITEM_LETTER_ZELDA", + 0x24 : "ITEM_MASK_KEATON", + 0x25 : "ITEM_MASK_SKULL", + 0x26 : "ITEM_MASK_SPOOKY", + 0x27 : "ITEM_MASK_BUNNY", + 0x28 : "ITEM_MASK_GORON", + 0x29 : "ITEM_MASK_ZORA", + 0x2A : "ITEM_MASK_GERUDO", + 0x2B : "ITEM_MASK_TRUTH", + 0x2C : "ITEM_SOLD_OUT", + 0x2D : "ITEM_POCKET_EGG", + 0x2E : "ITEM_POCKET_CUCCO", + 0x2F : "ITEM_COJIRO", + 0x30 : "ITEM_ODD_MUSHROOM", + 0x31 : "ITEM_ODD_POTION", + 0x32 : "ITEM_SAW", + 0x33 : "ITEM_SWORD_BROKEN", + 0x34 : "ITEM_PRESCRIPTION", + 0x35 : "ITEM_FROG", + 0x36 : "ITEM_EYEDROPS", + 0x37 : "ITEM_CLAIM_CHECK", + 0x38 : "ITEM_BOW_ARROW_FIRE", + 0x39 : "ITEM_BOW_ARROW_ICE", + 0x3A : "ITEM_BOW_ARROW_LIGHT", + 0x3B : "ITEM_SWORD_KOKIRI", + 0x3C : "ITEM_SWORD_MASTER", + 0x3D : "ITEM_SWORD_BGS", + 0x3E : "ITEM_SHIELD_DEKU", + 0x3F : "ITEM_SHIELD_HYLIAN", + 0x40 : "ITEM_SHIELD_MIRROR", + 0x41 : "ITEM_TUNIC_KOKIRI", + 0x42 : "ITEM_TUNIC_GORON", + 0x43 : "ITEM_TUNIC_ZORA", + 0x44 : "ITEM_BOOTS_KOKIRI", + 0x45 : "ITEM_BOOTS_IRON", + 0x46 : "ITEM_BOOTS_HOVER", + 0x47 : "ITEM_BULLET_BAG_30", + 0x48 : "ITEM_BULLET_BAG_40", + 0x49 : "ITEM_BULLET_BAG_50", + 0x4A : "ITEM_QUIVER_30", + 0x4B : "ITEM_QUIVER_40", + 0x4C : "ITEM_QUIVER_50", + 0x4D : "ITEM_BOMB_BAG_20", + 0x4E : "ITEM_BOMB_BAG_30", + 0x4F : "ITEM_BOMB_BAG_40", + 0x50 : "ITEM_BRACELET", + 0x51 : "ITEM_GAUNTLETS_SILVER", + 0x52 : "ITEM_GAUNTLETS_GOLD", + 0x53 : "ITEM_SCALE_SILVER", + 0x54 : "ITEM_SCALE_GOLDEN", + 0x55 : "ITEM_SWORD_KNIFE", + 0x56 : "ITEM_WALLET_ADULT", + 0x57 : "ITEM_WALLET_GIANT", + 0x58 : "ITEM_SEEDS", + 0x59 : "ITEM_FISHING_POLE", + 0x5A : "ITEM_SONG_MINUET", + 0x5B : "ITEM_SONG_BOLERO", + 0x5C : "ITEM_SONG_SERENADE", + 0x5D : "ITEM_SONG_REQUIEM", + 0x5E : "ITEM_SONG_NOCTURNE", + 0x5F : "ITEM_SONG_PRELUDE", + 0x60 : "ITEM_SONG_LULLABY", + 0x61 : "ITEM_SONG_EPONA", + 0x62 : "ITEM_SONG_SARIA", + 0x63 : "ITEM_SONG_SUN", + 0x64 : "ITEM_SONG_TIME", + 0x65 : "ITEM_SONG_STORMS", + 0x66 : "ITEM_MEDALLION_FOREST", + 0x67 : "ITEM_MEDALLION_FIRE", + 0x68 : "ITEM_MEDALLION_WATER", + 0x69 : "ITEM_MEDALLION_SPIRIT", + 0x6A : "ITEM_MEDALLION_SHADOW", + 0x6B : "ITEM_MEDALLION_LIGHT", + 0x6C : "ITEM_KOKIRI_EMERALD", + 0x6D : "ITEM_GORON_RUBY", + 0x6E : "ITEM_ZORA_SAPPHIRE", + 0x6F : "ITEM_STONE_OF_AGONY", + 0x70 : "ITEM_GERUDO_CARD", + 0x71 : "ITEM_SKULL_TOKEN", + 0x72 : "ITEM_HEART_CONTAINER", + 0x73 : "ITEM_HEART_PIECE", + 0x74 : "ITEM_KEY_BOSS", + 0x75 : "ITEM_COMPASS", + 0x76 : "ITEM_DUNGEON_MAP", + 0x77 : "ITEM_KEY_SMALL", + 0x78 : "ITEM_MAGIC_SMALL", + 0x79 : "ITEM_MAGIC_LARGE", + 0x7A : "ITEM_HEART_PIECE_2", + 0x7B : "ITEM_INVALID_1", + 0x7C : "ITEM_INVALID_2", + 0x7D : "ITEM_INVALID_3", + 0x7E : "ITEM_INVALID_4", + 0x7F : "ITEM_INVALID_5", + 0x80 : "ITEM_INVALID_6", + 0x81 : "ITEM_INVALID_7", + 0x82 : "ITEM_MILK", + 0x83 : "ITEM_HEART", + 0x84 : "ITEM_RUPEE_GREEN", + 0x85 : "ITEM_RUPEE_BLUE", + 0x86 : "ITEM_RUPEE_RED", + 0x87 : "ITEM_RUPEE_PURPLE", + 0x88 : "ITEM_RUPEE_GOLD", + 0x89 : "ITEM_INVALID_8", + 0x8A : "ITEM_STICKS_5", + 0x8B : "ITEM_STICKS_10", + 0x8C : "ITEM_NUTS_5", + 0x8D : "ITEM_NUTS_10", + 0x8E : "ITEM_BOMBS_5", + 0x8F : "ITEM_BOMBS_10", + 0x90 : "ITEM_BOMBS_20", + 0x91 : "ITEM_BOMBS_30", + 0x92 : "ITEM_ARROWS_SMALL", + 0x93 : "ITEM_ARROWS_MEDIUM", + 0x94 : "ITEM_ARROWS_LARGE", + 0x95 : "ITEM_SEEDS_30", + 0x96 : "ITEM_BOMBCHUS_5", + 0x97 : "ITEM_BOMBCHUS_20", + 0x98 : "ITEM_STICK_UPGRADE_20", + 0x99 : "ITEM_STICK_UPGRADE_30", + 0x9A : "ITEM_NUT_UPGRADE_30", + 0x9B : "ITEM_NUT_UPGRADE_40", + 0xFC : "ITEM_LAST_USED", + 0xFE : "ITEM_NONE_FE", + 0xFF : "ITEM_NONE", +} + +def disas_elfmsgs(start): + baserom = None + with open("baserom.z64", "rb") as infile: + baserom = bytearray(infile.read()) + + branches = [] + pos = start + + while (True): + print(f"/* {pos - start:04X} {((pos - start) // 4):3} */ ", end="") + + b0, b1, b2, b3 = struct.unpack(">BBBB", baserom[pos:pos+4]) + + elf_message_types = { + 0x00: "CHECK", + 0x20: "UNK_1", + 0x40: "UNK_2", + 0x60: "SKIP", + 0xE0: "END", + } + + cont = True + branch_to = None + + # Get Type + + elf_message_type = b0 & 0xE0 + ARG_0 = elf_message_types[elf_message_type] + + if elf_message_type in [0, 0x20, 0x40, 0xE0]: + if elf_message_type == 0xE0: + cont = False + ARG_1 = f"0x{(b2 & 0xFF):04X}" + elif elf_message_type == 0x60: + branch_to = 4 * (b2 & 0xFF) + ARG_1 = (b2 & 0xFF) + else: + assert False , "Encountered unknown type" + + ARG_2 = f"{bool(b0 & 1)}".lower() + + # Get condition + condition_type = b0 & 0x1E + + if condition_type == 0: + if elf_message_type == 0xE0 and b1 == 0 and not (b0 & 1): + print(f"ELF_MSG_END({ARG_1}),") + else: + print(f"ELF_MSG_FLAG({ARG_0}, {ARG_1}, {ARG_2}, 0x{b1:02X}), /* eventChkInf[{(b1 >> 4) & 0xF}] & 0x{1 << (b1 & 0xF):X} */") + assert b3 == 0 + elif condition_type == 2: + print(f"ELF_MSG_DUNGEON_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}),") + assert b3 == 0 + elif condition_type == 4: + print(f"ELF_MSG_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}, {item_ids[b3]}),") + elif condition_type == 6: + condition_other_type = b1 & 0xF0 + + if condition_other_type == 0: + print(f"ELF_MSG_STRENGTH_UPG({ARG_0}, {ARG_1}, {ARG_2}, {b1 & 0xF}),") + assert b3 == 0 + elif condition_other_type == 0x10: + print(f"ELF_MSG_BOOTS({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),") + assert (b1 & 0xF) == 0 + elif condition_other_type == 0x20: + print(f"ELF_MSG_SONG({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),") + assert (b1 & 0xF) == 0 + elif condition_other_type == 0x30: + print(f"ELF_MSG_MEDALLION({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),") + assert (b1 & 0xF) == 0 + elif condition_other_type == 0x40: + print(f"ELF_MSG_MAGIC({ARG_0}, {ARG_1}, {ARG_2}),") + assert (b1 & 0xF) == 0 + assert b3 == 0 + else: + assert False , "Encountered unknown condition (other) type" + else: + assert False , "Encountered unknown condition type" + + # Control flow + + if branch_to is not None: + branches.append(branch_to) + pos += 4 + if not cont: + print("") + if not cont and all([dst < pos - start for dst in branches]): + break + +disas_elfmsgs(int(sys.argv[1],16))