From 4489d1ed66ec95fe121c8f58c5025b1c3b0bf6fc Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sat, 20 Dec 2025 00:09:55 -0400 Subject: [PATCH 01/19] Added the option to disable Great Fairy rewards --- include/apcommon.h | 1 + include/yaml_generation.h | 6 ++++++ mod.toml | 1 + src/great_fairy_hooks.c | 5 +++++ src/yaml_generation_menu.c | 8 +++++++- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/apcommon.h b/include/apcommon.h index 2cfe957..819aad8 100644 --- a/include/apcommon.h +++ b/include/apcommon.h @@ -128,6 +128,7 @@ RECOMP_IMPORT(".", u32 rando_get_majora_remains_required()); RECOMP_IMPORT(".", u32 rando_get_random_seed()); RECOMP_IMPORT(".", bool rando_is_magic_trap()); RECOMP_IMPORT(".", bool rando_skulltulas_enabled()); +RECOMP_IMPORT(".", bool rando_great_fairy_rewards_disabled()); RECOMP_IMPORT(".", bool rando_shopsanity_enabled()); RECOMP_IMPORT(".", bool rando_advanced_shops_enabled()); RECOMP_IMPORT(".", bool rando_get_curiostity_shop_trades()); diff --git a/include/yaml_generation.h b/include/yaml_generation.h index 7755bde..c88f453 100644 --- a/include/yaml_generation.h +++ b/include/yaml_generation.h @@ -85,6 +85,12 @@ typedef enum { RANDO_SKULLSANITY_MAX = 0xFFFFFFFF } RandoSkullSanity; +typedef enum { + RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_VANILLA = 0, + RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_ENABLED = 1, + RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_ADVANCED = 2 +} RandoShuffleGreatFairyRewards; + typedef enum { RANDO_SHOP_PRICES_VANILLA = 0, RANDO_SHOP_PRICES_FREE = 1, diff --git a/mod.toml b/mod.toml index 3f98682..ef2e073 100644 --- a/mod.toml +++ b/mod.toml @@ -63,6 +63,7 @@ native_libraries = [ "rando_get_tunic_color", "rando_get_shop_price", "rando_skulltulas_enabled", + "rando_great_fairy_rewards_disabled", "rando_shopsanity_enabled", "rando_advanced_shops_enabled", "rando_scrubs_enabled", diff --git a/src/great_fairy_hooks.c b/src/great_fairy_hooks.c index f99f566..0d77abe 100644 --- a/src/great_fairy_hooks.c +++ b/src/great_fairy_hooks.c @@ -168,6 +168,11 @@ RECOMP_PATCH void EnElfgrp_Init(Actor* thisx, PlayState* play) { void EnElfgrp_OfferLoop(EnElfgrp* this, PlayState* play) { s32 type = ENELFGRP_GET_TYPE(&this->actor); + if (rando_great_fairy_rewards_disabled()) + { + return; + } + bool hasFairies = type == ENELFGRP_TYPE_MAGIC ? rando_has_item(0x01007F) : rando_has_item(0x010000 | (type - 1)) >= rando_get_slotdata_u32("required_stray_fairies"); if (hasFairies && !rando_location_is_checked(LOCATION_GREAT_FAIRY)) { diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index 44de643..452df37 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -389,6 +389,12 @@ static EnumOptionValue rando_skullsanity_options[] = { { "ignore", NULL }, }; +static EnumOptionValue rando_shuffle_great_fairy_rewards_options[] ={ + { "vanilla", NULL }, + { "anything", NULL }, + { "ignore", NULL}, +}; + static EnumOptionValue rando_shopsanity_options[] = { { "vanilla", NULL }, { "enabled", NULL }, @@ -498,7 +504,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "shuffle_spiderhouse_reward", "Shuffle Spiderhouse Rewards:", false); randoCreateIntSliderOption(&yaml_config_menu, "required_skull_tokens", "Required Skulltula Tokens:", 0, 30, 1, 30); randoCreateRadioOption(&yaml_config_menu, "skullsanity", "Skull-Sanity Mode:", rando_skullsanity_options, ARRAY_COUNT(rando_skullsanity_options), RANDO_SKULLSANITY_VANILLA); - randoCreateBoolPropOption(&yaml_config_menu, "shuffle_great_fairy_rewards", "Shuffle Great Fairy Rewards:", false); + randoCreateRadioOption(&yaml_config_menu, "shuffle_great_fairy_rewards", "Shuffle Great Fairy Rewards:", rando_shuffle_great_fairy_rewards_options, ARRAY_COUNT(rando_shuffle_great_fairy_rewards_options), RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_VANILLA); randoCreateIntSliderOption(&yaml_config_menu, "required_stray_fairies", "Required Stray Fairies:", 0, 15, 1, 15); randoCreateBoolPropOption(&yaml_config_menu, "fairysanity", "Fairy-Sanity:", false); randoCreateRadioOption(&yaml_config_menu, "shop_prices", "Shop Prices:", shop_prices_options, ARRAY_COUNT(shop_prices_options), RANDO_SHOP_PRICES_VANILLA); From 2d624d1e05817dd724dc910666e37cf9a710542e Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Mon, 12 Jan 2026 19:59:01 -0400 Subject: [PATCH 02/19] Mod checks slot data for Shuffle Great Fairy Rewards setting instead of glue Also lowered Moon/Majora Remains Required minimum to 0 (was set to 1 for solo non-multiworld seeds) --- include/apcommon.h | 1 - include/yaml_generation.h | 6 ------ mod.toml | 1 - src/great_fairy_hooks.c | 2 +- src/yaml_generation_menu.c | 10 +++++----- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/apcommon.h b/include/apcommon.h index 819aad8..2cfe957 100644 --- a/include/apcommon.h +++ b/include/apcommon.h @@ -128,7 +128,6 @@ RECOMP_IMPORT(".", u32 rando_get_majora_remains_required()); RECOMP_IMPORT(".", u32 rando_get_random_seed()); RECOMP_IMPORT(".", bool rando_is_magic_trap()); RECOMP_IMPORT(".", bool rando_skulltulas_enabled()); -RECOMP_IMPORT(".", bool rando_great_fairy_rewards_disabled()); RECOMP_IMPORT(".", bool rando_shopsanity_enabled()); RECOMP_IMPORT(".", bool rando_advanced_shops_enabled()); RECOMP_IMPORT(".", bool rando_get_curiostity_shop_trades()); diff --git a/include/yaml_generation.h b/include/yaml_generation.h index c88f453..7755bde 100644 --- a/include/yaml_generation.h +++ b/include/yaml_generation.h @@ -85,12 +85,6 @@ typedef enum { RANDO_SKULLSANITY_MAX = 0xFFFFFFFF } RandoSkullSanity; -typedef enum { - RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_VANILLA = 0, - RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_ENABLED = 1, - RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_ADVANCED = 2 -} RandoShuffleGreatFairyRewards; - typedef enum { RANDO_SHOP_PRICES_VANILLA = 0, RANDO_SHOP_PRICES_FREE = 1, diff --git a/mod.toml b/mod.toml index ef2e073..3f98682 100644 --- a/mod.toml +++ b/mod.toml @@ -63,7 +63,6 @@ native_libraries = [ "rando_get_tunic_color", "rando_get_shop_price", "rando_skulltulas_enabled", - "rando_great_fairy_rewards_disabled", "rando_shopsanity_enabled", "rando_advanced_shops_enabled", "rando_scrubs_enabled", diff --git a/src/great_fairy_hooks.c b/src/great_fairy_hooks.c index 0d77abe..c92a250 100644 --- a/src/great_fairy_hooks.c +++ b/src/great_fairy_hooks.c @@ -168,7 +168,7 @@ RECOMP_PATCH void EnElfgrp_Init(Actor* thisx, PlayState* play) { void EnElfgrp_OfferLoop(EnElfgrp* this, PlayState* play) { s32 type = ENELFGRP_GET_TYPE(&this->actor); - if (rando_great_fairy_rewards_disabled()) + if (rando_get_slotdata_u32("shuffle_great_fairy_rewards") == 0) { return; } diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index 452df37..c22f944 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -390,9 +390,9 @@ static EnumOptionValue rando_skullsanity_options[] = { }; static EnumOptionValue rando_shuffle_great_fairy_rewards_options[] ={ + { "disabled", NULL }, { "vanilla", NULL }, - { "anything", NULL }, - { "ignore", NULL}, + { "enabled", NULL}, }; static EnumOptionValue rando_shopsanity_options[] = { @@ -491,8 +491,8 @@ void randoCreateYamlConfigMenu() { yaml_config_menu.num_options = 0; randoCreateRadioOption(&yaml_config_menu, "accessibility", "Accessibility:", rando_accessibility_options, ARRAY_COUNT(rando_accessibility_options), RANDO_ACCESSABILITY_FULL); randoCreateRadioOption(&yaml_config_menu, "logic_difficulty", "Logic Difficulty:", rando_logic_difficulty_options, ARRAY_COUNT(rando_logic_difficulty_options), RANDO_LOGIC_DIFFICULTY_NORMAL); - randoCreateIntSliderOption(&yaml_config_menu, "moon_remains_required", "Moon Boss Remains Required:", 1, 4, 1, 4); - randoCreateIntSliderOption(&yaml_config_menu, "majora_remains_required", "Majora Boss Remains Required:", 1, 4, 1, 4); + randoCreateIntSliderOption(&yaml_config_menu, "moon_remains_required", "Moon Boss Remains Required:", 0, 4, 1, 4); + randoCreateIntSliderOption(&yaml_config_menu, "majora_remains_required", "Majora Boss Remains Required:", 0, 4, 1, 4); randoCreateBoolPropOption(&yaml_config_menu, "camc", "Chests Match Contents:", true); randoCreateBoolPropOption(&yaml_config_menu, "swordless", "Start Swordless:", false); randoCreateBoolPropOption(&yaml_config_menu, "shieldless", "Start Shieldless:", false); @@ -504,7 +504,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "shuffle_spiderhouse_reward", "Shuffle Spiderhouse Rewards:", false); randoCreateIntSliderOption(&yaml_config_menu, "required_skull_tokens", "Required Skulltula Tokens:", 0, 30, 1, 30); randoCreateRadioOption(&yaml_config_menu, "skullsanity", "Skull-Sanity Mode:", rando_skullsanity_options, ARRAY_COUNT(rando_skullsanity_options), RANDO_SKULLSANITY_VANILLA); - randoCreateRadioOption(&yaml_config_menu, "shuffle_great_fairy_rewards", "Shuffle Great Fairy Rewards:", rando_shuffle_great_fairy_rewards_options, ARRAY_COUNT(rando_shuffle_great_fairy_rewards_options), RANDO_SHUFFLE_GREAT_FAIRY_REWARDS_VANILLA); + randoCreateRadioOption(&yaml_config_menu, "shuffle_great_fairy_rewards", "Shuffle Great Fairy Rewards:", rando_shuffle_great_fairy_rewards_options, ARRAY_COUNT(rando_shuffle_great_fairy_rewards_options), 0); randoCreateIntSliderOption(&yaml_config_menu, "required_stray_fairies", "Required Stray Fairies:", 0, 15, 1, 15); randoCreateBoolPropOption(&yaml_config_menu, "fairysanity", "Fairy-Sanity:", false); randoCreateRadioOption(&yaml_config_menu, "shop_prices", "Shop Prices:", shop_prices_options, ARRAY_COUNT(shop_prices_options), RANDO_SHOP_PRICES_VANILLA); From 94ea2b8de78ec3fa2e2566aa21e51edc8d000797 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Wed, 21 Jan 2026 21:52:19 -0400 Subject: [PATCH 03/19] Added the option to disable ShuffleSpiderhouseReward I made sure that the guy in the swamp house doesn't give anything. I also changed his dialog in both forms to indicate that he's not gonna give an item. I also made sure that the guy in the ocean house gives a silver rupee instead of a grey AP item. --- src/item_text.c | 25 +++++++++++++++++++++++++ src/spiderhouse_man_hooks.c | 7 ++++++- src/yaml_generation_menu.c | 8 +++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/item_text.c b/src/item_text.c index 67958ae..8d7a416 100644 --- a/src/item_text.c +++ b/src/item_text.c @@ -102,6 +102,11 @@ static unsigned char p_pirate_bad_msg[128] = "Keep this\x01 bad picture of a pir static unsigned char slow_dog_msg[128] = "Hoo-whine.\x11How can any of us win against...\x10.\x0a.\x0a." "\x03" "blue dog" "\x00" "?\xbf"; static unsigned char fast_dog_msg[128] = "\x0a\x0a\x0a\x0a\x0a\x0a.\x0a.\x0a.\x0a\x0a\x0a\x0a\xbf"; +static unsigned char cursed_spider_msg_1[128] = "I have nothing to give you.\x11Go away.\xbf"; +static unsigned char cursed_spider_msg_2[128] = "Do not bother lifting the curse.\x11The mask is mine!\xbf"; +static unsigned char ssh_guy_msg_1[128] = "Thanks for saving me, I guess.\x11Unfortunately, the mask I had vanished.\x10It was making me infinitely rich! Now, I'll need\x11to go back at waving my arms somewhere...\xbf"; +static unsigned char ssh_guy_msg_2[128] = "I told you to NOT save me! That\x11mask was giving me infinite riches.\x11It's gone now.\x10\x0a\x0a\x0aNow what?\xbf"; + static unsigned char fool_msg[128] = "You are a\x01 FOOL!\xbf"; static unsigned char shop_msg[128]; @@ -343,6 +348,26 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { case 0x74: msg = fool_msg; break; + case 0x910: // Cursed Spider first dialog + if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { + msg = cursed_spider_msg_1; + } + break; + case 0x914: // Cursed Spider recurring dialogs + if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { + msg = cursed_spider_msg_2; + } + break; + case 0x91B: // Cured Spider first dialog + if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { + msg = ssh_guy_msg_1; + } + break; + case 0x918: // Cured Spider recurring dialog + if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { + msg = ssh_guy_msg_2; + } + break; default: break; } diff --git a/src/spiderhouse_man_hooks.c b/src/spiderhouse_man_hooks.c index 3d30349..4a1749b 100644 --- a/src/spiderhouse_man_hooks.c +++ b/src/spiderhouse_man_hooks.c @@ -65,6 +65,11 @@ void OnEnSth_Init(Actor* thisx, PlayState* play) { // fake skull token count for lower requirements Inventory_FakeSkullTokenCount(play->sceneId); + + // If ShuffleSpiderhouseReward is disabled, set the flag that prevent giving the SSH reward + if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { + SET_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_MASK_OF_TRUTH); + } } RECOMP_HOOK_RETURN("EnSth_Init") @@ -125,7 +130,7 @@ RECOMP_PATCH void EnSth_GiveOceansideSpiderHouseReward(EnSth* this, PlayState* p } else { // this could all be moved into a hook? // handle all 3 day checks here as well - if (rando_location_is_checked(GI_WALLET_GIANT)) { + if (rando_location_is_checked(GI_WALLET_GIANT) || (s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { STH_GI_ID(&this->actor) = GI_RUPEE_SILVER; } else { STH_GI_ID(&this->actor) = GI_WALLET_GIANT; diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index c22f944..30620c2 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -383,6 +383,12 @@ static EnumOptionValue shop_prices_options[] = { { "offensive", NULL }, }; +static EnumOptionValue rando_shuffle_spiderhouse_reward_options[] ={ + { "disabled", NULL }, + { "vanilla", NULL }, + { "enabled", NULL}, +}; + static EnumOptionValue rando_skullsanity_options[] = { { "vanilla", NULL }, { "anything", NULL }, @@ -501,7 +507,7 @@ void randoCreateYamlConfigMenu() { randoCreateRadioOption(&yaml_config_menu, "starting_hearts_are_containers_or_pieces", "Unused Starting Hearts are Distributed as:", rando_starting_hearts_type_options, ARRAY_COUNT(rando_starting_hearts_type_options), RANDO_STARTING_HEARTS_ARE_CONTAINERS); randoCreateRadioOption(&yaml_config_menu, "shuffle_regional_maps", "Shuffle Regional Maps:", rando_shuffle_regional_maps_options, ARRAY_COUNT(rando_shuffle_regional_maps_options), RANDO_SHUFFLE_REGIONAL_MAPS_VANILLA); randoCreateRadioOption(&yaml_config_menu, "shuffle_boss_remains", "Shuffle Boss Remains:", rando_shuffle_boss_remains_options, ARRAY_COUNT(rando_shuffle_boss_remains_options), RANDO_SHUFFLE_BOSS_REMAINS_VANILLA); - randoCreateBoolPropOption(&yaml_config_menu, "shuffle_spiderhouse_reward", "Shuffle Spiderhouse Rewards:", false); + randoCreateRadioOption(&yaml_config_menu, "shuffle_spiderhouse_reward", "Shuffle Spiderhouse Rewards:", rando_shuffle_spiderhouse_reward_options, ARRAY_COUNT(rando_shuffle_spiderhouse_reward_options), 0); randoCreateIntSliderOption(&yaml_config_menu, "required_skull_tokens", "Required Skulltula Tokens:", 0, 30, 1, 30); randoCreateRadioOption(&yaml_config_menu, "skullsanity", "Skull-Sanity Mode:", rando_skullsanity_options, ARRAY_COUNT(rando_skullsanity_options), RANDO_SKULLSANITY_VANILLA); randoCreateRadioOption(&yaml_config_menu, "shuffle_great_fairy_rewards", "Shuffle Great Fairy Rewards:", rando_shuffle_great_fairy_rewards_options, ARRAY_COUNT(rando_shuffle_great_fairy_rewards_options), 0); From c88945aaa6ff22f2ae87e37b89b6e0dcf8b9ed9d Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Wed, 21 Jan 2026 22:15:26 -0400 Subject: [PATCH 04/19] Fixed crash when speaking with SSH guy for the first time after being cured The text I wrote was too long, so I shortened it and changed both messages to accomodate. --- src/item_text.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/item_text.c b/src/item_text.c index 8d7a416..815b2a3 100644 --- a/src/item_text.c +++ b/src/item_text.c @@ -104,8 +104,8 @@ static unsigned char fast_dog_msg[128] = "\x0a\x0a\x0a\x0a\x0a\x0a.\x0a.\x0a.\x0 static unsigned char cursed_spider_msg_1[128] = "I have nothing to give you.\x11Go away.\xbf"; static unsigned char cursed_spider_msg_2[128] = "Do not bother lifting the curse.\x11The mask is mine!\xbf"; -static unsigned char ssh_guy_msg_1[128] = "Thanks for saving me, I guess.\x11Unfortunately, the mask I had vanished.\x10It was making me infinitely rich! Now, I'll need\x11to go back at waving my arms somewhere...\xbf"; -static unsigned char ssh_guy_msg_2[128] = "I told you to NOT save me! That\x11mask was giving me infinite riches.\x11It's gone now.\x10\x0a\x0a\x0aNow what?\xbf"; +static unsigned char ssh_guy_msg_1[128] = "I am not giving you my mask.\x11It's mine and mine only!\xbf"; +static unsigned char ssh_guy_msg_2[128] = "Great, now my mask is gone. That\x11mask was giving me infinite riches.\x10Now what?\xbf"; static unsigned char fool_msg[128] = "You are a\x01 FOOL!\xbf"; From 5d928411d094d6af2531e21d2689f7c4398960cc Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Wed, 21 Jan 2026 22:47:51 -0400 Subject: [PATCH 05/19] Changed text box type to the one most NPCs use --- src/item_text.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/item_text.c b/src/item_text.c index 815b2a3..a2e29b9 100644 --- a/src/item_text.c +++ b/src/item_text.c @@ -388,6 +388,10 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { font->msgBuf.schar[0] = 0x06; font->msgBuf.schar[1] = 0x71; } + if (textId == 0x910 || textId == 0x914 || textId == 0x91B || textId == 0x918) { + font->msgBuf.schar[0] = 0x00; + } + if ((textId & 0xFF00) == 0x3600 || (textId & 0xFF00) == 0x3700 || (textId == 0x0880 && rando_shopsanity_enabled() && !rando_location_is_checked_async(0x090002))) { msg = shop_msg; font->msgBuf.schar[0] = 0x06; From 9aa444b3d5a268a9fd1e0c7359667dc19aa4ceb2 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Fri, 23 Jan 2026 00:02:16 -0400 Subject: [PATCH 06/19] Added ShuffleTreasureGameChests option Added new text to hint towards the checks being disabled as well as a way to prevent players from playing the game if the corresponding chests are not shuffled. --- src/item_text.c | 73 +++++++++++++++++++++++++++++++++++++- src/yaml_generation_menu.c | 7 ++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/item_text.c b/src/item_text.c index a2e29b9..ecbf58a 100644 --- a/src/item_text.c +++ b/src/item_text.c @@ -106,6 +106,12 @@ static unsigned char cursed_spider_msg_1[128] = "I have nothing to give you.\x11 static unsigned char cursed_spider_msg_2[128] = "Do not bother lifting the curse.\x11The mask is mine!\xbf"; static unsigned char ssh_guy_msg_1[128] = "I am not giving you my mask.\x11It's mine and mine only!\xbf"; static unsigned char ssh_guy_msg_2[128] = "Great, now my mask is gone. That\x11mask was giving me infinite riches.\x10Now what?\xbf"; +static unsigned char chest_game_not_goron_1[128] = "Sorry, but we only accept\x11\x01strong and burly\x00 individuals.\xbf"; +static unsigned char chest_game_human[128] = "Looks like you're collecting \x01masks\x00!\x11There's \x01one I like\x00, but I don't\x11know if you have it...\xbf"; +static unsigned char chest_game_deku[128] = "Which is unfortunate because\x11you are so cute!!!\xbf"; +static unsigned char chest_game_zora[128] = "It's too bad... You look like my type...\xbf"; +static unsigned char chest_game_disabled_1[128] = "Oh! A customer! Unfortunately,\x11we are under construction.\xbf"; +static unsigned char chest_game_disabled_2[128] = "We'll be opening\x01 after the carnival\x00.\x11It will be the best celebration!\xbf"; static unsigned char fool_msg[128] = "You are a\x01 FOOL!\xbf"; @@ -368,6 +374,69 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { msg = ssh_guy_msg_2; } break; + case 0x76D: // Speaking to Treasure Game lady as human + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_not_goron_1; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) + { + msg = chest_game_disabled_1; + } + break; + case 0x76C: // Speaking to Treasure Game lady as Deku + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_not_goron_1; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) + { + msg = chest_game_disabled_1; + } + break; + case 0x76E: // Speaking to Treasure Game lady as Goron + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { + msg = chest_game_disabled_1; + } + break; + case 0x76F: // Speaking to Treasure Game lady as Zora + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_not_goron_1; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) + { + msg = chest_game_disabled_1; + } + break; + case 0x771: // Accepting or refusing to pay for Treasure Game lady as human + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_human; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) + { + msg = chest_game_disabled_2; + } + break; + case 0x770: // Accepting or refusing to pay for Treasure Game lady as Deku + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_deku; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { + msg = chest_game_disabled_2; + } + break; + case 0x772: // Accepting or refusing to pay for Treasure Game lady as Goron + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { + msg = chest_game_disabled_2; + } + break; + case 0x773: // Accepting or refusing to pay for Treasure Game lady as Zora + if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { + msg = chest_game_zora; + } + else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) + { + msg = chest_game_disabled_2; + } + break; default: break; } @@ -388,7 +457,9 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { font->msgBuf.schar[0] = 0x06; font->msgBuf.schar[1] = 0x71; } - if (textId == 0x910 || textId == 0x914 || textId == 0x91B || textId == 0x918) { + if (textId == 0x910 || textId == 0x914 || textId == 0x91B || textId == 0x918 || + textId == 0x76D || textId == 0x76C || textId == 0x76E || textId == 0x76F || // Speaking to Treasure Game lady + textId == 0x770 || textId == 0x771 || textId == 0x772 || textId == 0x773) { // Choosing to pay for Treasure Game font->msgBuf.schar[0] = 0x00; } diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index 30620c2..ac42cf0 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -407,6 +407,12 @@ static EnumOptionValue rando_shopsanity_options[] = { { "advanced", NULL }, }; +static EnumOptionValue treasure_chest_game_shuffle_options[] = { + { "disabled", NULL }, + { "goron_only", NULL }, + { "everything", NULL }, +}; + static EnumOptionValue rando_damage_multiplier_options[] = { { "half", NULL }, { "normal", NULL }, @@ -521,6 +527,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "bosskeysanity", "Boss-Key-Sanity:", false); randoCreateBoolPropOption(&yaml_config_menu, "curiostity_shop_trades", "Curiosity Shop Trades:", false); randoCreateBoolPropOption(&yaml_config_menu, "intro_checks", "Intro Checks:", false); + randoCreateRadioOption(&yaml_config_menu, "shuffle_treasure_chest_game", "Treasure Chest Game Shuffle:", treasure_chest_game_shuffle_options, ARRAY_COUNT(treasure_chest_game_shuffle_options), 1); randoCreateBoolPropOption(&yaml_config_menu, "start_with_consumables", "Start With Consumables:", true); randoCreateBoolPropOption(&yaml_config_menu, "permanent_chateau_romani", "Permanent Chateau Romani:", true); randoCreateBoolPropOption(&yaml_config_menu, "start_with_inverted_time", "Start With Inverted Time:", true); From b10466c15dc7cc27583f82e4d804ccb3b9010796 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 1 Feb 2026 13:12:16 -0400 Subject: [PATCH 07/19] Preparations for EZTR Trying to change text with EZTR will sometimes crash Recomp after pressing "Start Game". What exactly crashes it doesn't seem to be consistent. --- include/eztr_api.h | 2235 +++++++++++++++++++++++++++++++++++++++ mod.toml | 5 +- src/eztr_replacements.c | 308 ++++++ 3 files changed, 2546 insertions(+), 2 deletions(-) create mode 100644 include/eztr_api.h create mode 100644 src/eztr_replacements.c diff --git a/include/eztr_api.h b/include/eztr_api.h new file mode 100644 index 0000000..3680621 --- /dev/null +++ b/include/eztr_api.h @@ -0,0 +1,2235 @@ +#ifndef __EZTR_API__ +#define __EZTR_API__ + +/*! \file eztr_api.h + \version 2.3.0 + \brief The main header for EZTR + */ + +#include "modding.h" +#include "global.h" + +#ifdef DOXYGEN +#define EZTR_IMPORT(func) func +#define EZTR_PACK_STRUCT + +#else + +#define EZTR_IMPORT(func) RECOMP_IMPORT(EZTR_MOD_ID_STR, func) +#define EZTR_PACK_STRUCT __attribute__((packed)) + +typedef struct { + u16 new_id; + u8 out_success; +} _EZTR_CustomMsgHandleSetter; + +#define __EZTR_CUSTOM_MSG_HANDLE_BODY(name) { \ + static u16 id; \ + static u8 is_set = 0; \ + if (setter != NULL) { \ + if (is_set) { \ + _EZTR_ReportDebugMessage("EZTR_CustomMsgHandle '" #name "', Header Version 2.3.0: The textId has already been set and will not be updated."); \ + setter->out_success = 0; \ + } \ + else { \ + _EZTR_ReportDebugMessage("EZTR_CustomMsgHandle '" #name "', Header Version 2.3.0: Assignment of textId was successful."); \ + id = setter->new_id; \ + is_set = 1; \ + setter->out_success = 1; \ + } \ + } \ + return id; \ +} \ + +#endif + +/** + * \defgroup General + * + * \brief General API information. + * + * @{ + */ + + +/** + * @brief The mod id string for EZTR. + * + * The `eztr_api.h` imports all the functions and events needed for EZTR, + * so you probably won't need to use this directly. + */ +#define EZTR_MOD_ID_STR "MM_EZ_Text_Replacer_API" + +#ifndef DOXYGEN +EZTR_IMPORT( void _EZTR_ReportFatalMessage(char* msg)); +EZTR_IMPORT( void _EZTR_ReportErrorMessage(char* msg)); +EZTR_IMPORT( void _EZTR_ReportWarningMessage(char* msg)); +EZTR_IMPORT( void _EZTR_ReportInfoMessage(char* msg)); +EZTR_IMPORT( void _EZTR_ReportDebugMessage(char* msg)); +EZTR_IMPORT( void _EZTR_ReportVerboseMessage(char* msg)); + +// Typo, Included for backwards compatibility: +EZTR_IMPORT( void _EXTR_ReportErrorMessage(char* msg)); +#endif + +#define EZTR_MSG_HIGHEST_ID 0x354C +/** + * @brief The the full size of message buffer, in bytes. + * + * Also equivalent to maximum length of buffer in single-byte characters (`char`). + */ +#define EZTR_MSG_BUFFER_SIZE 1280 + +/** + * @brief The maximum length of buffer in two-byte characters (`wchar`). + * + * Not really used, but included for parity with the base game. + */ +#define EZTR_MSG_BUFFER_WIDE_SIZE 640 + +/** + * @brief The size of the message buffer's header region, in bytes. + * + * Also servers as the starting index of the message buffer's content region. + * + */ +#define EZTR_MSG_HEADER_SIZE 11 + +/** + * @brief The size of the message buffer's content region, in bytes. + * + * Useful if you need to loop throught a buffer's content. + */ + #define EZTR_MSG_CONTENT_SIZE 1269 // MESSAGE_BUFFER_SIZE - MESSAGE_HEADER_SIZE + +#define EZTR_MSG_ENDING_CHAR '\xBF' +#define EZTR_PIPE_CHAR '|' + +/** @}*/ + +/** + * \defgroup CustomMsgHandle + * + * \brief Macros and types used for working with the handles for custom messages. + * + * This page contains all of the information in custom message handles an how to use them. + * + * It's worth noting that a custom message handle is actually a function, defined through macros. + * In brief, here are the important things to know: + * * The handler's only argument is a pointer that EZTR uses internally. Modders don't need to use it. + * * You can retrieve the handle's textId by calling it with NULL as the argument (`handle(NULL)`) + * * By default, the handle can only have its textId assigned once (See below on how to change this behavior). + * * Handles created using `EZTR_DEFINE_CUSTOM_MSG_HANDLE`, the recommended macro for creating custom message handles, are marked with `RECOMP_EXPORT`. + * + * This implementation was decided on to ensure that the textIds of custom messages are not lost through + * variable reassignments, and to facilitate mods potentially needing to access/modify each other's messages. + * + * For those interested in the technical details: The function's only argument is used by EZTR to set the textId variable + * when a custom message is assigned to it, and to check that the assignment was a success. + * + * The version of the handle function included in this header stores the textId in a static variable, and includes logic that + * will only allow the textId to be set once. If a second attempt to set the ID is made, an error message is printed. Rather than + * change a handle's textId, you should change the stored message at that id. + * + * If you want to change the behavior of the handles, you can write your own custom message handle functions, but + * it's not recommended. + * + * @{ + */ + +/** + * @brief Uses to set/get the actual symbol name for custom message handles + * If you want to add a prefix/suffix to your custom message handles globally, it can be done here. + */ +#ifdef EZTR_NO_HANDLE_PREFIX +#define EZTR_CUSTOM_MSG_HANDLE_NAME(name) name +#else +#define EZTR_CUSTOM_MSG_HANDLE_NAME(name_suffix) EZTR_CustomMsgHandle_##name_suffix +#endif +/** + * @brief Creates a non-exported CustomMsgHandle object + * + * Most mods are not installed in a vacuum. You should consider exporting your custom message handles + * so that other mods can access the messages you define if need be (compatibility patches, addons, etc.) + * + */ +#define EZTR_DEFINE_CUSTOM_MSG_HANDLE_NO_EXPORT(name) \ +u16 EZTR_CUSTOM_MSG_HANDLE_NAME(name)(_EZTR_CustomMsgHandleSetter* setter) \ +__EZTR_CUSTOM_MSG_HANDLE_BODY(name) + +/** + * @brief Creates a CustomMsgHandle object + * + * This is the primary method for creating handles for custom messages. You'll need to use this macro + * inside one of your .c files (outside of any functions) to create the handle itself. Use + * `EZTR_DECLARE_CUSTOM_MSG_HANDLE` to access the handle from other files. + * + * See the `EZTR_CustomMsgHandle` documentation for more information about handles and how they work. + * + */ +#define EZTR_DEFINE_CUSTOM_MSG_HANDLE(name) RECOMP_EXPORT \ +u16 EZTR_CUSTOM_MSG_HANDLE_NAME(name)(_EZTR_CustomMsgHandleSetter* setter) \ +__EZTR_CUSTOM_MSG_HANDLE_BODY(name) + +/** + * @brief Creates a declaration for a CustomMsgHandle object. + * + * Use this reference handles created in other .c files. Also works in headers. + * + */ +#define EZTR_DECLARE_CUSTOM_MSG_HANDLE(name) u16 EZTR_CUSTOM_MSG_HANDLE_NAME(name)(_EZTR_CustomMsgHandleSetter* setter) + +/** + * @brief Creates a declaration for a CustomMsgHandle object. Alternative to `EZTR_DECLARE_CUSTOM_MSG_HANDLE`. + * + * Use this reference handles created in other .c files. Also works in headers. + * + */ +#define EZTR_EXTERN_CUSTOM_MSG_HANDLE(name) EZTR_DECLARE_CUSTOM_MSG_HANDLE(name) + + +/** + * @brief Declares and imports a CustomMsgHandle object from another mod. + * + * This will allow you to use and interact with custom messages from other mods. + */ +#define EZTR_IMPORT_CUSTOM_MSG_HANDLE(mod_str, name_suffix) RECOMP_IMPORT(mod_str, u16 EZTR_CustomMsgHandle_##name_suffix(_EZTR_CustomMsgHandleSetter* setter)) + +/** + * @brief Declares and imports a CustomMsgHandle object from another mod. + * + * This will allow you to use and interact with custom messages from other mods. + */ +#define EZTR_IMPORT_CUSTOM_MSG_HANDLE_NO_PREFIX(mod_str, name) RECOMP_IMPORT(mod_str, u16 name(_EZTR_CustomMsgHandleSetter* setter)) + +/** + * @brief Gets the textId from a custom message handle. + * + * A more readable alternative to `handle(NULL)` + * + */ +#define EZTR_GET_CUSTOM_MSG_ID(handle) handle(NULL) + +// Shorthand: +/** + * @brief Shorthand for `EZTR_CUSTOM_MSG_HANDLE_NAME()` + * + * Useful if you want to use global prefixes. + * + */ +#define EZTR_HNAME(name_suffix) EZTR_CUSTOM_MSG_HANDLE_NAME(name_suffix) + +/** + * @brief Gets the textId from a custom message handle. + * + * A more readable alternative to `handle(NULL)`, and shorthand for `EZTR_GET_CUSTOM_MSG_ID()` + * + * Note that this macro won't apply the global prefix if it's enabled. You'll need to use something like + * `EZTR_GET_CUSTOM_MSG_ID(EZTR_HNAME(my_handle))` or `EZTR_GET_ID(EZTR_HNAME(my_handle))`. + */ +#define EZTR_GET_ID(handle) EZTR_GET_CUSTOM_MSG_ID(handle) + + +/** + * @brief Gets the textId from a custom message handle. + * + * A more readable alternative to `EZTR_CustomMsgHandle_##handle(NULL)`. + * + * This macro WILL apply the global prefix if it's enabled, and can be considered shorthand for + * `EZTR_GET_CUSTOM_MSG_ID(EZTR_HNAME(my_handle))` or `EZTR_GET_ID(EZTR_HNAME(my_handle))`. + */ +#define EZTR_GET_ID_H(handle) EZTR_GET_CUSTOM_MSG_ID(EZTR_CUSTOM_MSG_HANDLE_NAME(handle)) + +/** @}*/ +/** + * @brief A macro to easily create message callback functions. + * + * This macro can be used to create both the function definition and declaration (if one is needed); + * + * * To create the definition, use `EZTR_MSG_CALLBACK(my_callback) {...}` + * * To create the declaration, use `EZTR_MSG_CALLBACK(my_callback);` + * + * `my_callback` can then be passed to any `EZTR_Basic_*` function as the `callback` argument. + * `my_callback` will be run immediately after EZTR loads the message from its internal + * table, allowing you to make changes (or completely regenerate the message from scratch) + * before the message is displayed. + * + * The function generated by this macro has 3 arguments: + * * `EZTR_MsgBuffer* buf` - A message buffer, prepopulated with a copy of whatever message you stored. Write to this buffer the change the message. + * * `u16 textId` - The textId of the message. Useful if you want multiple messages to be controlled by one callback function. + * * `PlayState* play` - The current PlayState for the game. This makes it easy to generate text based on the game's state. + * + */ +#define EZTR_MSG_CALLBACK(fname) void fname(EZTR_MsgBuffer* buf, u16 textId, PlayState* play) + +/** + * @brief Used to declare a function that should run after EZTR has finished initializing. + * + * This is where you should declare all of your text replacements. You don't want to declare them during a + * `recomp_on_init` event, since EZTR may not have initialized itself yet, and attempting to declare text + * replacements before that will cause a crash. Additionally, declaring messaged here will ensure that mod + * priority order is respected when declaring replacements. + * + * As of version 2.1.0, EZTR now enforces that message all calls to `EZTR_Basic_*` functions must be made here. + * + * Example: `EZTR_ON_INIT void declare_my_text() {...}` + * + */ +#define EZTR_ON_INIT RECOMP_CALLBACK("MM_EZ_Text_Replacer_API", EZTR_OnInit) + +/** + * @brief Used to declare a callback function for when EZTR dumps a message. Normally, EZTR only prints that message to the game console, + * but this callback will allow you to do other things with that information. This `EZTR_ON_DUMP_BUFFER` event is only called when EZTR's + * text dump setting is set to `On`. + * + * This is a feature intended for developers, for the creation of EZTR-related tools. It should not be used for gameplay. + * + * The functions parameters are + * * `const char* category`, currently only returns 'Game'. + * * `u16 textId`, the ID of the message being dumped. + * * ` s32 len`, the size of the message in bytes. + * * `EZTR_MsgBuffer* buf`, the message buffer itself. + * + */ +#define EZTR_ON_DUMP_BUFFER(func_name) \ + RECOMP_CALLBACK("MM_EZ_Text_Replacer_API", EZTR_OnDumpBuffer) void func_name(const char* category, u16 textId, s32 len, EZTR_MsgBuffer* buf) + +/** + * @brief Used to declare a callback function for when EZTR dumps the entire message buffer. Normally, EZTR only prints that message to the game console, + * but this callback will allow you to do other things with that information. This `EZTR_ON_DUMP_BUFFER` event is only called when EZTR's + * text dump setting is set to `Full`. + * + * This is a feature intended for developers, for the creation of EZTR-related tools. It should not be used for gameplay. + * + * The functions parameters are + * * `const char* category`, currently only returns 'Game'. + * * `u16 textId`, the ID of the message being dumped. + * * ` s32 len`, the size of the message in bytes. + * * `EZTR_MsgBuffer* buf`, the message buffer itself. + * + */ +#define EZTR_ON_DUMP_BUFFER_FULL(func_name) \ + RECOMP_CALLBACK("MM_EZ_Text_Replacer_API", EZTR_OnDumpBufferFull) void func_name(const char* category, u16 textId, s32 len, EZTR_MsgBuffer* buf) + +/** + * @brief Used by certain members of `EZTR_MsgData` (and the message header generally) to indicate that said member is not in use. + * + * The header members in question are: + * + * * `next_message_id` + * * `first_item_rupees` + * * `second_item_rupees` + * + */ +#define EZTR_NO_VALUE 0xffff + +/** + * \defgroup Types + * + * \brief Type definitions that EZTR uses for Majora's Mask messages. + * + * @{ + */ + +/** + * @brief The message buffers type as defined in the Majora's Mask decompilation. + * + * While you can edit messages by interacting with this struct directly, EZTR + * offers much better ways of editing messages. + */ +typedef union { + char schar[EZTR_MSG_BUFFER_SIZE]; // msgBuf + u16 wchar[EZTR_MSG_BUFFER_WIDE_SIZE]; // msgBufWide + u64 force_structure_alignment_msg; +} EZTR_MsgBuffer_Raw; + + +/** + * @brief The message buffer, but with the header and content regions defined as seperate arrays. + * + * The `content` member can be passed to the `EZTR_MsgSContent_` functions for use in text operations. + * + */ +typedef struct { + char header[EZTR_MSG_HEADER_SIZE]; + char content[EZTR_MSG_CONTENT_SIZE]; +} EZTR_MsgBuffer_Partition; + + +/** + * @brief The message buffer, with the header represented as its individual members. + * + * When compiled, this struct is marked with the `packed` attribute to ensure that it's members align + * to their proper locations within the buffer. + * + * The `padding` member represents a section of the buffer that is unused, and should thus be ignored. + * + * The `content` member can be passed to the `EZTR_MsgSContent_` functions for use in text operations. + * + */ +typedef struct EZTR_PACK_STRUCT { + u8 text_box_type; + u8 text_box_y_pos; + u8 display_icon; + u16 next_message_id; + u16 first_item_rupees; + u16 second_item_rupees; + u16 padding; + char content[EZTR_MSG_CONTENT_SIZE]; +} EZTR_MsgBuffer_Data; + +/** + * @brief A union of the three MsgBuffer structs, and the primary type for interacting with message data. + * + * Each member of the union is a different way of representing the buffer in code. + * + * * `raw` is the buffer as it exists in the Majora's Mask decomp. + * * `partitions` is the buffer, seperated into it's two primary regions (header and content). + * * `data` is the buffer, with it's header and content values listed as individual members. + * + * Do not allocate this on the stack, as you'll likely end up with a StackOverflow. Instead, create a buffer using + * `EZTR_MsgBuffer_Create()` of one of it's sister functions. + */ +typedef union { + EZTR_MsgBuffer_Raw raw; + EZTR_MsgBuffer_Partition partitions; + EZTR_MsgBuffer_Data data; +} EZTR_MsgBuffer; + +/** + * @brief The type declaration for custom message handle. + * + * These are created using either the `EZTR_DEFINE_CUSTOM_MSG_HANDLE()` macro + * or the `EZTR_DEFINE_CUSTOM_MSG_HANDLE_NO_EXPORT()` macro in one of your .c files, + * outside of any functions. + * + * + */ +typedef u16 (*EZTR_CustomMsgHandle)(_EZTR_CustomMsgHandleSetter* setter); + +/** + * @brief The function pointer type for message callbacks. + * + * To easily create functions that match this type, see the `EZTR_MSG_CALLBACK()` macro. + * + */ +typedef void (*EZTR_MsgCallback)(EZTR_MsgBuffer* buf, u16 textId, PlayState* play); + +/** + * @brief Used in the message header to indicate the style of textbox used for the message. + * + * You can set the text box type by assigning to the `text_box_type` member of EZTR_MsgData, + * or by using `EZTR_MsgBuffer_SetTextBoxType()`. + * + */ +typedef enum { + EZTR_STANDARD_TEXT_BOX_I = 0X00, + EZTR_WOODEN_SIGN_BACKGROUND = 0X01, + EZTR_TRANSLUSCENT_BLUE_TEXT_BOX = 0X02, + EZTR_OCARINA_STAFF = 0X03, + EZTR_INVISIBLE_TEXT_BOX_I = 0X04, + EZTR_INVISIBLE_TEXT_BOX_II = 0X05, + EZTR_STANDARD_TEXT_BOX_II = 0X06, + EZTR_INVISIBLE_TEXT_BOX = 0X07, + EZTR_BLUE_TEXT_BOX = 0X08, + EZTR_RED_TEXT_BOX_I = 0X09, + EZTR_INVISIBLE_TEXT_BOX_III = 0X0A, + EZTR_INVISIBLE_TEXT_BOX_IV = 0X0B, + EZTR_INVISIBLE_TEXT_BOX_V = 0X0C, + EZTR_BOMBERS_NOTEBOOK = 0X0D, + EZTR_INVISIBLE_TEXT_BOX_VI = 0X0E, + EZTR_RED_TEXT_BOX_II = 0X0F +} EZTR_TextBoxType; + +/** + * @brief Used in the message header to indicate a display icon for the message. + * + * You can set the display icon by assigning to the `display_icon` member of EZTR_MsgData, + * or by using `EZTR_MsgBuffer_SetTextBoxDIsplayIcon()`. + * + * Note that the value for not displaying an icon is `EZTR_ICON_NO_ICON`, and NOT + * + * `EZTR_ICON_NOTHING` or it's variants. + */ +typedef enum { + EZTR_ICON_NOTHING = 0x00, + EZTR_ICON_GREEN_RUPEE = 0x01, + EZTR_ICON_BLUE_RUPEE = 0x02, + EZTR_ICON_WHITE_RUPEE = 0x03, + EZTR_ICON_RED_RUPEE = 0x04, + EZTR_ICON_PURPLE_RUPEE = 0x05, + EZTR_ICON_WHITE_RUPEE_1 = 0x06, + EZTR_ICON_ORANGE_RUPEE = 0x07, + EZTR_ICON_ADULT_WALLET = 0x08, + EZTR_ICON_GIANTS_WALLET = 0x09, + EZTR_ICON_RECOVERY_HEART = 0x0A, + EZTR_ICON_RECOVERY_HEART_1 = 0x0B, + EZTR_ICON_PIECE_OF_HEART = 0x0C, + EZTR_ICON_HEART_CONTAINER = 0x0D, + EZTR_ICON_SMALL_MAGIC_JAR = 0x0E, + EZTR_ICON_LARGE_MAGIC_JAR = 0x0F, + EZTR_ICON_RECOVERY_HEART_2 = 0x10, + EZTR_ICON_STRAY_FAIRY = 0x11, + EZTR_ICON_RECOVERY_HEART_3 = 0x12, + EZTR_ICON_RECOVERY_HEART_4 = 0x13, + EZTR_ICON_BOMB = 0x14, + EZTR_ICON_BOMB_1 = 0x15, + EZTR_ICON_BOMB_2 = 0x16, + EZTR_ICON_BOMB_3 = 0x17, + EZTR_ICON_BOMB_4 = 0x18, + EZTR_ICON_DEKU_STICK = 0x19, + EZTR_ICON_BOMBCHU = 0x1A, + EZTR_ICON_BOMB_BAG = 0x1B, + EZTR_ICON_BIG_BOMB_BAG = 0x1C, + EZTR_ICON_BIGGER_BOMB_BAG = 0x1D, + EZTR_ICON_HEROS_BOW = 0x1E, + EZTR_ICON_HEROS_BOW_1 = 0x1F, + EZTR_ICON_HEROS_BOW_2 = 0x20, + EZTR_ICON_HEROS_BOW_3 = 0x21, + EZTR_ICON_QUIVER = 0x22, + EZTR_ICON_BIG_QUIVER = 0x23, + EZTR_ICON_BIGGEST_QUIVER = 0x24, + EZTR_ICON_FIRE_ARROW = 0x25, + EZTR_ICON_ICE_ARROW = 0x26, + EZTR_ICON_LIGHT_ARROW = 0x27, + EZTR_ICON_DEKU_NUT = 0x28, + EZTR_ICON_DEKU_NUT_1 = 0x29, + EZTR_ICON_DEKU_NUT_2 = 0x2A, + EZTR_ICON_NOTHING_1 = 0x2B, + EZTR_ICON_NOTHING_2 = 0x2C, + EZTR_ICON_NOTHING_3 = 0x2D, + EZTR_ICON_NOTHING_4 = 0x2E, + EZTR_ICON_NOTHING_5 = 0x2F, + EZTR_ICON_NOTHING_6 = 0x30, + EZTR_ICON_NOTHING_7 = 0x31, + EZTR_ICON_HEROS_SHIELD = 0x32, + EZTR_ICON_MIRROR_SHIELD = 0x33, + EZTR_ICON_POWDER_KEG = 0x34, + EZTR_ICON_MAGIC_BEAN = 0x35, + EZTR_ICON_PICTOGRAPH_BOX = 0x36, + EZTR_ICON_KOKIRI_SWORD = 0x37, + EZTR_ICON_RAZOR_SWORD = 0x38, + EZTR_ICON_GILDED_SWORD = 0x39, + EZTR_ICON_FIERCE_DEITYS_SWORD = 0x3A, + EZTR_ICON_GREAT_FAIRYS_SWORD = 0x3B, + EZTR_ICON_SMALL_KEY = 0x3C, + EZTR_ICON_BOSS_KEY = 0x3D, + EZTR_ICON_DUNGEON_MAP = 0x3E, + EZTR_ICON_COMPASS = 0x3F, + EZTR_ICON_POWDER_KEG_1 = 0x40, + EZTR_ICON_HOOKSHOT = 0x41, + EZTR_ICON_LENS_OF_TRUTH = 0x42, + EZTR_ICON_PICTOGRAPH_BOX_1 = 0x43, + EZTR_ICON_FISHING_ROD = 0x44, + EZTR_ICON_NOTHING_8 = 0x45, + EZTR_ICON_NOTHING_9 = 0x46, + EZTR_ICON_NOTHING_10 = 0x47, + EZTR_ICON_NOTHING_11 = 0x48, + EZTR_ICON_NOTHING_12 = 0x49, + EZTR_ICON_NOTHING_13 = 0x4A, + EZTR_ICON_NOTHING_14 = 0x4B, + EZTR_ICON_OCARINA_OF_TIME = 0x4C, + EZTR_ICON_NOTHING_15 = 0x4D, + EZTR_ICON_NOTHING_16 = 0x4E, + EZTR_ICON_NOTHING_17 = 0x4F, + EZTR_ICON_BOMBERS_NOTEBOOK = 0x50, + EZTR_ICON_NOTHING_18 = 0x51, + EZTR_ICON_GOLD_SKULLTULA_TOKEN = 0x52, + EZTR_ICON_NOTHING_19 = 0x53, + EZTR_ICON_NOTHING_20 = 0x54, + EZTR_ICON_ODOLWAS_REMAINS = 0x55, + EZTR_ICON_GOHTS_REMAINS = 0x56, + EZTR_ICON_GYORGS_REMAINS = 0x57, + EZTR_ICON_TWINMOLDS_REMAINS = 0x58, + EZTR_ICON_RED_POTION = 0x59, + EZTR_ICON_EMPTY_BOTTLE = 0x5A, + EZTR_ICON_RED_POTION_1 = 0x5B, + EZTR_ICON_GREEN_POTION = 0x5C, + EZTR_ICON_BLUE_POTION = 0x5D, + EZTR_ICON_FAIRYS_SPIRIT = 0x5E, + EZTR_ICON_DEKU_PRINCESS = 0x5F, + EZTR_ICON_MILK = 0x60, + EZTR_ICON_MILK_HALF = 0x61, + EZTR_ICON_FISH = 0x62, + EZTR_ICON_BUG = 0x63, + EZTR_ICON_BLUE_FIRE = 0x64, + EZTR_ICON_POE = 0x65, + EZTR_ICON_BIG_POE = 0x66, + EZTR_ICON_SPRING_WATER = 0x67, + EZTR_ICON_HOT_SPRING_WATER = 0x68, + EZTR_ICON_ZORA_EGG = 0x69, + EZTR_ICON_GOLD_DUST = 0x6A, + EZTR_ICON_MUSHROOM = 0x6B, + EZTR_ICON_NOTHING_21 = 0x6C, + EZTR_ICON_NOTHING_22 = 0x6D, + EZTR_ICON_SEAHORSE = 0x6E, + EZTR_ICON_CHATEAU_ROMANI = 0x6F, + EZTR_ICON_HYLIAN_LOACH = 0x70, + EZTR_ICON_NOTHING_23 = 0x71, + EZTR_ICON_NOTHING_24 = 0x72, + EZTR_ICON_NOTHING_25 = 0x73, + EZTR_ICON_NOTHING_26 = 0x74, + EZTR_ICON_NOTHING_27 = 0x75, + EZTR_ICON_NOTHING_28 = 0x76, + EZTR_ICON_NOTHING_29 = 0x77, + EZTR_ICON_DEKU_MASK = 0x78, + EZTR_ICON_GORON_MASK = 0x79, + EZTR_ICON_ZORA_MASK = 0x7A, + EZTR_ICON_FIERCE_DEITY_MASK = 0x7B, + EZTR_ICON_MASK_OF_TRUTH = 0x7C, + EZTR_ICON_KAFEIS_MASK = 0x7D, + EZTR_ICON_ALL_NIGHT_MASK = 0x7E, + EZTR_ICON_BUNNY_HOOD = 0x7F, + EZTR_ICON_KEATON_MASK = 0x80, + EZTR_ICON_GARO_MASK = 0x81, + EZTR_ICON_ROMANI_MASK = 0x82, + EZTR_ICON_CIRCUS_LEADERS_MASK = 0x83, + EZTR_ICON_POSTMANS_HAT = 0x84, + EZTR_ICON_COUPLES_MASK = 0x85, + EZTR_ICON_GREAT_FAIRYS_MASK = 0x86, + EZTR_ICON_GIBDO_MASK = 0x87, + EZTR_ICON_DON_GEROS_MASK = 0x88, + EZTR_ICON_KAMAROS_MASK = 0x89, + EZTR_ICON_CAPTAINS_HAT = 0x8A, + EZTR_ICON_STONE_MASK = 0x8B, + EZTR_ICON_BREMEN_MASK = 0x8C, + EZTR_ICON_BLAST_MASK = 0x8D, + EZTR_ICON_MASK_OF_SCENTS = 0x8E, + EZTR_ICON_GIANTS_MASK = 0x8F, + EZTR_ICON_NOTHING_30 = 0x90, + EZTR_ICON_CHATEAU_ROMANI_1 = 0x91, + EZTR_ICON_MILK_1 = 0x92, + EZTR_ICON_GOLD_DUST_1 = 0x93, + EZTR_ICON_HYLIAN_LOACH_1 = 0x94, + EZTR_ICON_SEAHORSE_1 = 0x95, + EZTR_ICON_MOONS_TEAR = 0x96, + EZTR_ICON_TOWN_TITLE_DEED = 0x97, + EZTR_ICON_SWAMP_TITLE_DEED = 0x98, + EZTR_ICON_MOUNTAIN_TITLE_DEED = 0x99, + EZTR_ICON_OCEAN_TITLE_DEED = 0x9A, + EZTR_ICON_NOTHING_31 = 0x9B, + EZTR_ICON_NOTHING_32 = 0x9C, + EZTR_ICON_NOTHING_33 = 0x9D, + EZTR_ICON_NOTHING_34 = 0x9E, + EZTR_ICON_NOTHING_35 = 0x9F, + EZTR_ICON_ROOM_KEY = 0xA0, + EZTR_ICON_SPECIAL_DELIVERY_TO_MAMA = 0xA1, + EZTR_ICON_NOTHING_36 = 0xA2, + EZTR_ICON_NOTHING_37 = 0xA3, + EZTR_ICON_NOTHING_38 = 0xA4, + EZTR_ICON_NOTHING_39 = 0xA5, + EZTR_ICON_NOTHING_40 = 0xA6, + EZTR_ICON_NOTHING_41 = 0xA7, + EZTR_ICON_NOTHING_42 = 0xA8, + EZTR_ICON_NOTHING_43 = 0xA9, + EZTR_ICON_LETTER_TO_KAFEI = 0xAA, + EZTR_ICON_PENDANT_OF_MEMORIES = 0xAB, + EZTR_ICON_NOTHING_44 = 0xAC, + EZTR_ICON_NOTHING_45 = 0xAD, + EZTR_ICON_NOTHING_46 = 0xAE, + EZTR_ICON_NOTHING_47 = 0xAF, + EZTR_ICON_NOTHING_48 = 0xB0, + EZTR_ICON_NOTHING_49 = 0xB1, + EZTR_ICON_NOTHING_50 = 0xB2, + EZTR_ICON_TINGLES_MAP = 0xB3, + EZTR_ICON_TINGLES_MAP_1 = 0xB4, + EZTR_ICON_TINGLES_MAP_2 = 0xB5, + EZTR_ICON_TINGLES_MAP_3 = 0xB6, + EZTR_ICON_TINGLES_MAP_4 = 0xB7, + EZTR_ICON_TINGLES_MAP_5 = 0xB8, + EZTR_ICON_TINGLES_MAP_6 = 0xB9, + EZTR_ICON_NOTHING_51 = 0xBA, + EZTR_ICON_NOTHING_52 = 0xBB, + EZTR_ICON_NOTHING_53 = 0xBC, + EZTR_ICON_NOTHING_54 = 0xBD, + EZTR_ICON_NOTHING_55 = 0xBE, + EZTR_ICON_NOTHING_56 = 0xBF, + EZTR_ICON_NOTHING_57 = 0xC0, + EZTR_ICON_NOTHING_58 = 0xC1, + EZTR_ICON_NOTHING_59 = 0xC2, + EZTR_ICON_NOTHING_60 = 0xC3, + EZTR_ICON_NOTHING_61 = 0xC4, + EZTR_ICON_NOTHING_62 = 0xC5, + EZTR_ICON_NOTHING_63 = 0xC6, + EZTR_ICON_NOTHING_64 = 0xC7, + EZTR_ICON_NOTHING_65 = 0xC8, + EZTR_ICON_NOTHING_66 = 0xC9, + EZTR_ICON_NOTHING_67 = 0xCA, + EZTR_ICON_NOTHING_68 = 0xCB, + EZTR_ICON_NOTHING_69 = 0xCC, + EZTR_ICON_NOTHING_70 = 0xCD, + EZTR_ICON_NOTHING_71 = 0xCE, + EZTR_ICON_NOTHING_72 = 0xCF, + EZTR_ICON_NOTHING_73 = 0xD0, + EZTR_ICON_NOTHING_74 = 0xD1, + EZTR_ICON_NOTHING_75 = 0xD2, + EZTR_ICON_NOTHING_76 = 0xD3, + EZTR_ICON_NOTHING_77 = 0xD4, + EZTR_ICON_NOTHING_78 = 0xD5, + EZTR_ICON_NOTHING_79 = 0xD6, + EZTR_ICON_NOTHING_80 = 0xD7, + EZTR_ICON_SMALL_BLACK_LINE = 0xD8, + EZTR_ICON_SMALL_BLACK_LINE_1 = 0xD9, + EZTR_ICON_SMALL_BLACK_LINE_2 = 0xDA, + EZTR_ICON_SMALL_BLACK_LINE_3 = 0xDB, + EZTR_ICON_ANJU = 0xDC, + EZTR_ICON_KAFEI = 0xDD, + EZTR_ICON_CURIOSITY_SHOP_OWNER = 0xDE, + EZTR_ICON_BOMB_SHOP_OWNERS_MOTHER = 0xDF, + EZTR_ICON_ROMANI = 0xE0, + EZTR_ICON_CREMIA = 0xE1, + EZTR_ICON_MAYOR_DOTOUR = 0xE2, + EZTR_ICON_MADAME_AROMA = 0xE3, + EZTR_ICON_TOTO = 0xE4, + EZTR_ICON_GORMAN = 0xE5, + EZTR_ICON_POSTMAN = 0xE6, + EZTR_ICON_ROSA_SISTERS = 0xE7, + EZTR_ICON_TOILET_HAND = 0xE8, + EZTR_ICON_GRANNY = 0xE9, + EZTR_ICON_KAMARO = 0xEA, + EZTR_ICON_GROG = 0xEB, + EZTR_ICON_GORMAN_BROTHERS = 0xEC, + EZTR_ICON_SHIRO = 0xED, + EZTR_ICON_GURU_GURU = 0xEE, + EZTR_ICON_BOMBERS = 0xEF, + EZTR_ICON_EXCLAMATION_MARK = 0xF0, + EZTR_ICON_NOTHING_81 = 0xF1, + EZTR_ICON_NOTHING_82 = 0xF2, + EZTR_ICON_NOTHING_83 = 0xF3, + EZTR_ICON_NOTHING_84 = 0xF4, + EZTR_ICON_NOTHING_85 = 0xF5, + EZTR_ICON_NOTHING_86 = 0xF6, + EZTR_ICON_NOTHING_87 = 0xF7, + EZTR_ICON_NOTHING_88 = 0xF8, + EZTR_ICON_NOTHING_89 = 0xF9, + EZTR_ICON_NOTHING_90 = 0xFA, + EZTR_ICON_NOTHING_91 = 0xFB, + EZTR_ICON_NOTHING_92 = 0xFC, + EZTR_ICON_NOTHING_93 = 0xFD, + EZTR_ICON_NO_ICON = 0xFE, + EZTR_ICON_MAX = 0xFE +} EZTR_TextBoxIcon; + +/** @}*/ + + +/** + * \defgroup Control_Code_Macros + * \brief Macros for the various control codes and non-printable bytes used in the Majora's Mask text encoding. + * + * Most of this information was pulled from [the CloudModding wiki](https://wiki.cloudmodding.com/mm/Text_Format). + * + * @{ + */ +/** + * @brief Following Text Color: Default + * + * Default is usually white, but may be black (ie: for notebook updates). + * + */ +#define EZTR_CC_COLOR_DEFAULT "\x00" + +/** + * @brief Following Text Color: Red + */ +#define EZTR_CC_COLOR_RED "\x01" + +/** + * @brief Following Text Color: Green + */ +#define EZTR_CC_COLOR_GREEN "\x02" + +/** + * @brief Following Text Color: Blue + */ +#define EZTR_CC_COLOR_BLUE "\x03" + +/** + * @brief Following Text Color: Yellow + */ +#define EZTR_CC_COLOR_YELLOW "\x04" + +/** + * @brief Following Text Color: Turquoise + */ +#define EZTR_CC_COLOR_LIGHTBLUE "\x05" + +/** + * @brief Following Text Color: Pink + */ +#define EZTR_CC_COLOR_PINK "\x06" + +/** + * @brief Following Text Color: Silver + */ +#define EZTR_CC_COLOR_SILVER "\x07" + +/** + * @brief Following Text Color: Orange + */ +#define EZTR_CC_COLOR_ORANGE "\x08" + +/** + * @brief Slows down text (not used) + * + * Text normally prints 2 letters at a time. 0A acts as a null character. So 0A0A prints nothing not even a space when normally 2 letters are printed. + * + */ +#define EZTR_CC_TEXT_SPEED "\x0a" + +/** + * @brief Print: Hits Required to Win Jungle Cruise Reward + */ +#define EZTR_CC_HS_BOAT_ARCHERY "\x0b" + +/** + * @brief Print: Stray Fairies Collected in Current Dungeon + * + */ +#define EZTR_CC_STRAY_FAIRIES "\x0c" + +/** + * @brief Print: Gold Skulltulas Collected in Current Spider House + */ +#define EZTR_CC_TOKENS "\x0d" + +/** + * @brief Print: 0 + */ +#define EZTR_CC_POINTS_TENS "\x0e" + +/** + * @brief Print: 0 + */ +#define EZTR_CC_POINTS_THOUSANDS "\x0f" + +/** + * @brief Box Break I + * + * Used when four lines of text have been printed, but can technically be used anywhere. More robust than 12/000B? [?] + * + */ +#define EZTR_CC_BOX_BREAK "\x10" + +/** + * @brief Line Break + */ +#define EZTR_CC_NEWLINE "\x11" + +/** + * @brief Box Break II + * + * Used when three lines of text have been printed. Usually preceded by a 13/000C character. + * + */ +#define EZTR_CC_BOX_BREAK2 "\x12" + +/** + * @brief Reset Cursor Position to Start of Current Line + * + * Used as a filler when there are fewer than four lines of text. Usually preceded by a newline when two lines of text have been printed. + * + */ +#define EZTR_CC_CARRIAGE_RETURN "\x13" + +/** + * @brief Print: xx Spaces + * + * The value of the next byte will control how many spaces to print. + * + */ +#define EZTR_CC_SHIFT "\x14" + +/** + * @brief Print: %c Spaces + * + * The value of the next byte will control how many spaces to print. + * This macro adds a `%%c` flag after the control code, enabling you to set the argument byte using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + */ +#define EZTR_CC_SHIFT_ARGC "\x14%c" + +/** + * @brief Disable Text Skip I + * + * Triangle box. Does not play sound. + * + */ +#define EZTR_CC_CONTINUE "\x15" + +/** + * @brief Print: Player Name + */ +#define EZTR_CC_NAME "\x16" + +/** + * @brief Enable: Instantaneous Text + */ +#define EZTR_CC_QUICKTEXT_ENABLE "\x17" + +/** + * @brief Disable: Instantaneous Text + */ +#define EZTR_CC_QUICKTEXT_DISABLE "\x18" + +/** + * @brief Disable Text Skip II + * + * Triangle box. Plays "Text Finished" sound. + * + */ +#define EZTR_CC_EVENT "\x19" + +/** + * @brief Disable Text Box Close + * + * Used for shop item descriptions. + * + */ +#define EZTR_CC_PERSISTENT "\x1a" + +/** + * @brief Delay for xxxx Before Printing Remaining Text + * + * The next two bytes determine the length of the delay. + * + */ +#define EZTR_CC_BOX_BREAK_DELAYED "\x1b" + +/** + * @brief Delay for xxxx Before Printing Remaining Text + * + * The next two bytes determine the length of the delay. + * This macro adds a `%%w` flag after the control code, enabling you to set the argument bytes using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + */ +#define EZTR_CC_BOX_BREAK_DELAYED_ARGW "\x1b%w" + + +/** + * @brief Keep Text on Screen for xxxx Before Closing + * + * The next two bytes determine the length of the delay. + * + * Player can move around while text is displayed. + * + */ +#define EZTR_CC_FADE "\x1c" + +/** + * @brief Keep Text on Screen for xxxx Before Closing + * + * The next two bytes determine the length of the delay. + * This macro adds a `%%w` flag after the control code, enabling you to set the argument bytes using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * Player can move around while text is displayed. + * + */ +#define EZTR_CC_FADE_ARGW "\x1c%w" + +/** + * @brief Delay for xxxx Before Ending Conversation + * + * The next two bytes determine the length of the delay. + * + */ +#define EZTR_CC_FADE_SKIPPABLE "\x1d" + +/** + * @brief Delay for xxxx Before Ending Conversation + * + * The next two bytes determine the length of the delay. + * This macro adds a `%%w` flag after the control code, enabling you to set the argument bytes using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + */ +#define EZTR_CC_FADE_SKIPPABLE_ARGW "\x1d%w" + +/** + * @brief Play Sound Effect xxxx + * + * The next two bytes will be the ID of the sound effect. The ID values are the same as the ones used with `Audio_PlaySfx`. + * + */ +#define EZTR_CC_SFX "\x1e" + +/** + * @brief Play Sound Effect xxxx + * + * The next two bytes will be the ID of the sound effect. The ID values are the same as the ones used with `Audio_PlaySfx`. + * This macro adds a `%%w` flag after the control code, enabling you to set the argument bytes using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + */ +#define EZTR_CC_SFX_ARGW "\x1e%w" + +/** + * @brief Delay for xxxx Before Resuming Text Flow + * + * The next two bytes determine the length of the delay. + * + */ +#define EZTR_CC_DELAY "\x1f" + +/** + * @brief Delay for xxxx Before Resuming Text Flow + * + * The next two bytes determine the length of the delay. + * This macro adds a `%%w` flag after the control code, enabling you to set the argument bytes using EZTR's printf handling. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + */ +#define EZTR_CC_DELAY_ARGW "\x1f%w" + +/** + * @brief Displays the A Button icon + */ +#define EZTR_CC_BTN_A "\xb0" + +/** + * @brief Displays the B button icon + */ +#define EZTR_CC_BTN_B "\xb1" + +/** + * @brief Displays the C buttons icon + */ +#define EZTR_CC_BTN_C "\xb2" + +/** + * @brief Displays the L button icon + */ +#define EZTR_CC_BTN_L "\xb3" + +/** + * @brief Displays the R button icon + */ +#define EZTR_CC_BTN_R "\xb4" + +/** + * @brief Displays the Z button icon + */ +#define EZTR_CC_BTN_Z "\xb5" + +/** + * @brief Displays the C-up button icon + */ +#define EZTR_CC_BTN_CUP "\xb6" + +/** + * @brief Displays the C-down button icon + */ +#define EZTR_CC_BTN_CDOWN "\xb7" + +/** + * @brief Displays the C-left button icon + */ +#define EZTR_CC_BTN_CLEFT "\xb8" + +/** + * @brief Displays the C-right button icon + */ +#define EZTR_CC_BTN_CRIGHT "\xb9" + +/** + * @brief DDisplays the Z targeting icon + */ +#define EZTR_CC_Z_TARGET "\xba" + +/** + * @brief Displays the Control Pad icon + */ +#define EZTR_CC_CONTROL_PAD "\xbb" + +/** + * @brief Message End Marker + * + * This is the termination character for message content. + * + */ +#define EZTR_CC_END "\xbf" + +/** + * @brief Ocarina Song Failure + * + * Draws red X across the text box on the screen & centers text vertically/pushes it out. + * + */ +#define EZTR_CC_BACKGROUND "\xc1" + +/** + * @brief Initialize Selection: Two Choices + */ +#define EZTR_CC_TWO_CHOICE "\xc2" + +/** + * @brief Initialize Selection: Three Choices + */ +#define EZTR_CC_THREE_CHOICE "\xc3" + +/** + * @brief Print: Postman's Counting Game Results + */ +#define EZTR_CC_TIMER_POSTMAN "\xc4" + +/** + * @brief Timer Value + */ +#define EZTR_CC_TIMER_MINIGAME_1 "\xc5" + +/** + * @brief Timer Value + */ +#define EZTR_CC_TIMER_2 "\xc6" + +/** + * @brief Print: Remaining Time Till Moon Falls (Clock Tower Roof) + */ +#define EZTR_CC_TIMER_MOON_CRASH "\xc7" + +/** + * @brief Print: Deku Scrub Playground Results + */ +#define EZTR_CC_TIMER_MINIGAME_2 "\xc8" + +/** + * @brief Timer Value + */ +#define EZTR_CC_TIMER_ENV_HAZARD "\xc9" + +/** + * @brief Timer Value + */ +#define EZTR_CC_TIME "\xca" + +/** + * @brief Print: Shooting Gallery Minigame Results + */ +#define EZTR_CC_CHEST_FLAGS "\xcb" + +/** + * @brief Display Prompt: Withdraw or Deposit Rupees + */ +#define EZTR_CC_INPUT_BANK "\xcc" + +/** + * @brief Print: Number of Rupees Entered or Bet + */ +#define EZTR_CC_RUPEES_SELECTED "\xcd" + +/** + * @brief Print: Total Rupees in Bank or Won by Betting + */ +#define EZTR_CC_RUPEES_TOTAL "\xce" + +/** + * @brief Print: Time Remaining in Hours & Minutes + */ +#define EZTR_CC_TIME_UNTIL_MOON_CRASH "\xcf" + +/** + * @brief Display Prompt: Rupees to Bet + */ +#define EZTR_CC_INPUT_DOGGY_RACETRACK_BET "\xd0" + +/** + * @brief Display Prompt: Bombers' Code + */ +#define EZTR_CC_INPUT_BOMBER_CODE "\xd1" + +/** + * @brief Item Prompt + * + * Delays closing the text box. + * + */ +#define EZTR_CC_PAUSE_MENU "\xd2" + +/** + * @brief [?] + */ +#define EZTR_CC_TIME_SPEED "\xd3" + +/** + * @brief Print: Song of Soaring Destination + */ +#define EZTR_CC_OWL_WARP "\xd4" + +/** + * @brief Display Prompt: Lottery Number + */ +#define EZTR_CC_INPUT_LOTTERY_CODE "\xd5" + +/** + * @brief Print: 123456 + * + * Each number's color is indicative of the Spider House mask code. + * + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE "\xd6" + +/** + * @brief Print: Remaining Stray Fairies in Woodfall Temple + */ +#define EZTR_CC_STRAY_FAIRIES_LEFT_WOODFALL "\xd7" + +/** + * @brief Print: Remaining Stray Fairies in Snowhead Temple + */ +#define EZTR_CC_STRAY_FAIRIES_LEFT_SNOWHEAD "\xd8" + +/** + * @brief Print: Remaining Stray Fairies in Great Bay Temple + */ +#define EZTR_CC_STRAY_FAIRIES_LEFT_GREAT_BAY "\xd9" + +/** + * @brief Print: Remaining Stray Fairies in Stone Tower Temple + */ +#define EZTR_CC_STRAY_FAIRIES_LEFT_STONE_TOWER "\xda" + +/** + * @brief Print: Jungle Cruise Minigame Results + */ +#define EZTR_CC_POINTS_BOAT_ARCHERY "\xdb" + +/** + * @brief Print: Winning Lottery Numbers + */ +#define EZTR_CC_LOTTERY_CODE "\xdc" + +/** + * @brief Print: Player's Lottery Numbers + */ +#define EZTR_CC_LOTTERY_CODE_GUESS "\xdd" + +/** + * @brief Print: Item Value in Rupees + * + * Default: 51 Rupees + * + */ +#define EZTR_CC_HELD_ITEM_PRICE "\xde" + +/** + * @brief Print: Bombers' Code + */ +#define EZTR_CC_BOMBER_CODE "\xdf" + +/** + * @brief End Conversation + * + * Used exclusively for NPCs. Usually followed by a BF/0500 command. + * + */ +#define EZTR_CC_EVENT2 "\xe0" + +/** + * @brief Print: Color of Oceanside Spider House Mask 1 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_1 "\xe1" + +/** + * @brief Print: Color of Oceanside Spider House Mask 2 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_2 "\xe2" + +/** + * @brief Print: Color of Oceanside Spider House Mask 3 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_3 "\xe3" + +/** + * @brief Print: Color of Oceanside Spider House Mask 4 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_4 "\xe4" + +/** + * @brief Print: Color of Oceanside Spider House Mask 5 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_5 "\xe5" + +/** + * @brief Print: Color of Oceanside Spider House Mask 6 + */ +#define EZTR_CC_SPIDER_HOUSE_MASK_CODE_6 "\xe6" + +/** + * @brief Print: Remaining Time Till Moon Falls + */ +#define EZTR_CC_HOURS_UNTIL_MOON_CRASH "\xe7" + +/** + * @brief Print: Remaining Time Till Morning in Hours & Minutes + */ +#define EZTR_CC_TIME_UNTIL_NEW_DAY "\xe8" + +/** + * @brief Print: Total Rupees in Bank + */ +#define EZTR_CC_HS_POINTS_BANK_RUPEES "\xf0" + +/** + * @brief Print: 0 + */ +#define EZTR_CC_HS_POINTS_UNK_1 "\xf1" + +/** + * @brief Print: 0 + */ +#define EZTR_CC_HS_POINTS_FISHING "\xf2" + +/** + * @brief Print: 0"10' + */ +#define EZTR_CC_HS_TIME_BOAT_ARCHERY "\xf3" + +/** + * @brief Print: :0"00' + */ +#define EZTR_CC_HS_TIME_HORSE_BACK_BALLOON "\xf4" + +/** + * @brief Print: Timer or Highscore in 00"00' Format [?] + * + * SRAM Offset: 0xEF2 + * + */ +#define EZTR_CC_HS_TIME_LOTTERY_GUESS "\xf5" + +/** + * @brief Print: Town Shooting Gallery Highscore + */ +#define EZTR_CC_HS_TOWN_SHOOTING_GALLERY "\xf6" + +/** + * @brief Print: 00'00"00 + */ +#define EZTR_CC_HS_UNK_1 "\xf7" + +/** + * @brief Print: Magic Bean Price + */ +#define EZTR_CC_HS_UNK_3_LOWER "\xf8" + +/** + * @brief Print: Epona Balloon Archery Highscore I + */ +#define EZTR_CC_HS_HORSE_BACK_BALLOON "\xf9" + +/** + * @brief Print: Deku Scrub Playground Highscore (Day 1) + */ +#define EZTR_CC_HS_DEKU_PLAYGROUND_DAY_1 "\xfa" + +/** + * @brief Print: Deku Scrub Playground Highscore (Day 2) + */ +#define EZTR_CC_HS_DEKU_PLAYGROUND_DAY_2 "\xfb" + +/** + * @brief Print: Deku Scrub Playground Highscore (Day 3) + */ +#define EZTR_CC_HS_DEKU_PLAYGROUND_DAY_3 "\xfc" + +/** + * @brief Print: Broken Character [?] + */ +#define EZTR_CC_DEKU_PLAYGROUND_NAME_DAY_1 "\xfd" + +/** + * @brief [?] + */ +#define EZTR_CC_DEKU_PLAYGROUND_NAME_DAY_2 "\xfe" + +/** + * @brief [?] + */ +#define EZTR_CC_DEKU_PLAYGROUND_NAME_DAY_3 "\xff" + +/** @}*/ + +/** + * \defgroup Basic_Replacement + * \brief functions for replacing vanilla messages. + * + * These functions are currently your primary means of declaring replacements, using Majora's Mask's built-in dialog handling. + * + * @{ + */ + + +/** + * @brief Declare a replacement of a vanilla message by copying from a buffer defined by the user. + * + * If you've defined a message using the MsgBuffer/MsgSContent functions, you can use this to set it (or, rather, + * a copy of it) as a replacement for a vanilla message. + * + * Note that this function is meant for replacing vanilla messages only. It will not allow you to use a textId greater + * than 0x354C, as that is the highest textId value found in the vanilla game. + * If you wish to create/modify a custom message, see `EZTR_Basic_AddCustomBuffer()` and EZTR_Basic_ReplaceCustomBuffer()` + * + * @param textId The id of the vanilla message you wish to replace. + * @param buf The message buffer to copy from. + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic text. Set as NULL if + * you don't want to use a callback. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceBuffer(u16 textId, EZTR_MsgBuffer* buf, EZTR_MsgCallback callback)); + +/** + * @brief Declare a replacement of a vanilla message by defining the header attributes and message content. + * + * This is probably the easiest method to declare replacement text. + * + * The `content` argument uses EZTR's printf formatting arguments, specified after `callback`. + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * Note that this function is meant for replacing vanilla messages only. It will not allow you to use a textId greater + * than 0x354C, as that is the highest textId value found in the vanilla game. + * If you wish to create/modify a custom message, see `EZTR_Basic_AddCustomText()` and EZTR_Basic_ReplaceCustomText()` + * + * @param textId The id of the vanilla message you wish to replace. + * @param text_box_type The style of textbox to display. Use the `EZTR_TextBoxType` enum for more readable values. + * @param text_box_y_pos The vertical position of the textbox on-screen. + * @param display_icon Displays an icon in the textbox. Use the `EZTR_TextBoxIcon` enum for more readable values. + * Use `EZTR_ICON_NO_ICON` for no icon. + * @param next_message_id The next message to display. If there is no next message, or the next message is determined by code, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param first_item_rupees The price of the first item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param second_item_rupees The price of the second item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param pipe_escape_bytes If true, `content` is passed through `EZTR_MsgBuffer_Sprintf("%m", content)`. If false, + * then `content` is copied directly into storage. + * @param content The new text content to display. Accepts valid EZTR printf type specifiers. If you want empty content (for use with dynamic messages), use "\xBF". + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic messages. + * Set as NULL if you don't want to use a callback. See `EZTR_MsgCallback` for more information. + * @param ... variable arguments, using EZTR's printf implementation. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceText( + u16 textId, + u8 text_box_type, + u8 text_box_y_pos, + u8 display_icon, + u16 next_message_id, + u16 first_item_rupees, + u16 second_item_rupees, + bool pipe_escape_bytes, + char* content, + EZTR_MsgCallback callback, + ... +)); + +/** + * @brief Declare a replacement of a vanilla message, where the replacement message is empty. + * + * This is primarily used if you want the message to be completely dynamically generated. + * + * Note that this function is meant for replacing vanilla messages only. It will not allow you to use a textId greater + * than 0x354C, as that is the highest textId value found in the vanilla game. + * If you wish to create/modify a custom message, see `EZTR_Basic_AddCustomTextEmpty()` and EZTR_Basic_ReplaceCustomTextEmpty()` + * + * @param textId The id of the vanilla message you wish to replace. + * @param callback A function pointer to call right before this text is displayed, in which you will construct the + * complete message buffer dynamically. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceTextEmpty(u16 textId, EZTR_MsgCallback callback)); +/** @} */ + +/** + * \defgroup Basic_CustomMessages + * \brief Functions for creating and replacing new messages. + * @{ + * + */ + +/** + * @brief Declare a brand new (i.e: custom) message by copying from a buffer defined by the user. + * + * If you've defined a message using the MsgBuffer/MsgSContent functions, you can use this to set it (or, rather, + * a copy of it) as the new message. + * + * To avoid potential ID conflicts between mods, the u16 textId for this message will be assigned by EZTR and + * will be accessable via the handle. See `EZTR_CustomMsgHandle` for more information on how custom message handles work. + * + * @param handle The handle for the new message. + * @param buf The message buffer to copy from. + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic text. Set as NULL if + * you don't want to use a callback. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_AddCustomBuffer(EZTR_CustomMsgHandle handle, EZTR_MsgBuffer* buf, EZTR_MsgCallback callback)); + +/** + * @brief Declare a brand new (i.e: custom) message by defining the header attributes and message content. + * + * This is probably the easiest method to declare new messages. + * + * The `content` argument uses EZTR's printf formatting arguments, specified after `callback`. + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * To avoid potential ID conflicts between mods, the u16 textId for this message will be assigned by EZTR and + * will be accessable via the handle. See `EZTR_CustomMsgHandle` for more information on how custom message handles work. + * + * @param handle The handle for the new message. + * @param text_box_type The style of textbox to display. Use the `EZTR_TextBoxType` enum for more readable values. + * @param text_box_y_pos The vertical position of the textbox on-screen. + * @param display_icon Displays an icon in the textbox. Use the `EZTR_TextBoxIcon` enum for more readable values. + * Use `EZTR_ICON_NO_ICON` for no icon. + * @param next_message_id The next message to display. If there is no next message, or the next message is determined by code, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param first_item_rupees The price of the first item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param second_item_rupees The price of the second item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param pipe_escape_bytes If true, `content` is passed through `EZTR_MsgBuffer_Sprintf("%m", content)`. If false, + * then `content` is copied directly into storage. + * @param content The new text content to display. If you want empty content (for use with dynamic messages), use "\xBF". + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic messages. + * Set as NULL if you don't want to use a callback. See `EZTR_MsgCallback` for more information. + * @param ... variable arguments, using EZTR's printf implementation. + */ +EZTR_IMPORT(void EZTR_Basic_AddCustomText(EZTR_CustomMsgHandle handle, u8 text_box_type, u8 text_box_y_pos, u8 display_icon, + u16 next_message_id, u16 first_item_rupees, u16 second_item_rupees, bool pipe_escape_bytes, char* content, EZTR_MsgCallback callback, ...)); + +/** + * @brief Declare a brand new (i.e: custom) message, where the replacement message is empty. + * + * This is primarily used if you want the message to be completely dynamically generated. + * + * To avoid potential ID conflicts between mods, the u16 textId for this message will be assigned by EZTR and + * will be accessable via the handle. See `EZTR_CustomMsgHandle` for more information on how custom message handles work. + * + * @param handle The handle for the new message. + * @param callback A function pointer to call right before this text is displayed, in which you will construct the + * complete message buffer dynamically. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_AddCustomTextEmpty(EZTR_CustomMsgHandle handle, EZTR_MsgCallback callback)); + +/** + * @brief Declare a replacement for a custom message by copying from a buffer defined by the user. + * + * If you've defined a message using the MsgBuffer/MsgSContent functions, you can use this to set it (or, rather, + * a copy of it) as the new message. + * + * @deprecated since 2.3.0. The new handling of message replacement order makes this unnecessary. + * As of this version, this function just wraps `EZTR_Basic_AddCustomBuffer` for compatability. + * + * @param handle The handle for the message being replaced. + * @param buf The message buffer to copy from. + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic text. Set as NULL if + * you don't want to use a callback. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceCustomBuffer(EZTR_CustomMsgHandle handle, EZTR_MsgBuffer* buf, EZTR_MsgCallback callback)); + +/** + * @brief Declare a replacement of a custom message by defining the header attributes and message content. + * + * This is probably the easiest method to replace custom messages, even those defined by other mods. + * + * The `content` argument uses EZTR's printf formatting arguments, specified after `callback`. + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @deprecated since 2.3.0. The new handling of message replacement order makes this unnecessary. + * As of this version, this function just wraps `EZTR_Basic_AddCustomText` for compatability. + * + * @param handle The handle for the message being replaced. + * @param text_box_type The style of textbox to display. Use the `EZTR_TextBoxType` enum for more readable values. + * @param text_box_y_pos The vertical position of the textbox on-screen. + * @param display_icon Displays an icon in the textbox. Use the `EZTR_TextBoxIcon` enum for more readable values. + * Use `EZTR_ICON_NO_ICON` for no icon. + * @param next_message_id The next message to display. If there is no next message, or the next message is determined by code, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param first_item_rupees The price of the first item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param second_item_rupees The price of the second item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param pipe_escape_bytes If true, `content` is passed through `EZTR_MsgBuffer_Sprintf("%m", content)`. If false, + * then `content` is copied directly into storage. + * @param content The new text content to display. If you want empty content (for use with dynamic messages), use "\xBF". + * @param callback A function pointer to call right before this text is displayed. Useful for dynamic messages. + * Set as NULL if you don't want to use a callback. See `EZTR_MsgCallback` for more information. + * @param ... variable arguments, using EZTR's printf implementation. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceCustomText(EZTR_CustomMsgHandle handle, u8 text_box_type, u8 text_box_y_pos, u8 display_icon, + u16 next_message_id, u16 first_item_rupees, u16 second_item_rupees, bool pipe_escape_bytes, char* content, EZTR_MsgCallback callback, ...)); + +/** + * @brief Declare a replacement of a custom message, where the replacement message is empty. + * + * This is primarily used if you want the message to be completely dynamically generated. + * + * @deprecated since 2.3.0. The new handling of message replacement order makes this unnecessary. + * As of this version, this function just wraps `EZTR_Basic_AddCustomTextEmpty` for compatability. + * + * @param handle The handle for the message being replaced. + * @param callback A function pointer to call right before this text is displayed, in which you will construct the + * complete message buffer dynamically. See `EZTR_MsgCallback` for more information. + */ +EZTR_IMPORT(void EZTR_Basic_ReplaceCustomTextEmpty(EZTR_CustomMsgHandle handle, EZTR_MsgCallback callback)); + +/** @} */ + +/** + * \defgroup MsgBuffer + * \brief Functions for high-level message buffer operations. + * @{ + */ + + +/** + * @brief Creates a new message buffer object on the heap. + * + * The created buffer will be have a default header and an empty content region. + * You need to free any buffer you create using this function with `EZTR_MsgBuffer_Destroy()`, + * or else you will create a memory leak. + * + * @return MsgBuffer* A pointer to the buffer you created. + */ +EZTR_IMPORT(EZTR_MsgBuffer* EZTR_MsgBuffer_Create()); + +/** + * @brief Creates a new message buffer object on the heap, and copies `src` into it. + * + * Equivalent to `buf = EZTR_MsgBuffer_Create(); EZTR_MsgBuffer_Copy(buf);` + * + * You need to free any buffer you create using this function with `EZTR_MsgBuffer_Destroy()`, + * or else you will create a memory leak. + * + * @param src The content to copy into the buffer. Expected to have a header region, and be terminated with '\xBF'. + * @return MsgBuffer* A pointer to the buffer you created. + */ +EZTR_IMPORT(EZTR_MsgBuffer* EZTR_MsgBuffer_CreateFromStr(char* src)); + +/** + * @brief Creates a new message buffer object on the heap, and copies `src` into it for up to `len` bytes. + * + * Equivalent to `buf = EZTR_MsgBuffer_Create(); EZTR_MsgBuffer_CopyN(buf, len);` + * + * You need to free any buffer you create using this function with `EZTR_MsgBuffer_Destroy()`, + * or else you will create a memory leak. + * + * @param src The content to copy into the buffer. Expected to have a header region, and be terminated with '\xBF'. + * @param len The maximum number of bytes to copy. If a '\xBF` is encountered in the content region of `src`, the function will stop copying before `len` is reached. + * @return MsgBuffer* A pointer to the buffer you created. + */ +EZTR_IMPORT(EZTR_MsgBuffer* EZTR_MsgBuffer_CreateFromStrN(char* src, size_t len)); + +/** + * @brief Frees/destroys a message buffer. + * + * EZTR only expects you to destroy buffers that you create youself using one of the above functions. + * Buffers given to you by in `MsgCallback` functions are created and destroyed by EZTR. + * + * @param buf A pointer to the message buffer to destroy. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_Destroy(EZTR_MsgBuffer* buf)); + +// Copy: +/** + * @brief Copies data from `src` into the message buffer `dst`. + * + * Unlike something like `strcoy()`, this method is safe as long as dst is a full-sized message buffer, + * as it will not copy beyond the message buffer size. + * + * Because `src` is expected to have a header region, the message termination characters '\xBF' are ignored + * for the first 11 bytes. + * + * @param dst The message buffer to copy into. + * @param src The data to copy. If you want to copy from another message buffer, use `src->raw.schar` or typecast src as `char*`. + * @return u32 The number of bytes copied. + */ +EZTR_IMPORT(u32 EZTR_MsgBuffer_Copy(EZTR_MsgBuffer* dst, char* src)); + + /** + * @brief Copies data from `src` into the message buffer `dst`, up to `len` bytes. + * + * Because `src` is expected to have a header region, the message termination characters '\xBF' are ignored + * for the first 11 bytes. + * + * @param dst The message buffer to copy into. + * @param src The data to copy. If you want to copy from another message buffer, use `src->raw.schar` or typecast src as `char*`. + * @param len The maximum number of bytes to copy. If a '\xBF` is encountered in the content region of `src`, the function + * will stop copying before `len` is reached. + * @return u32 The number of bytes copied. + */ +EZTR_IMPORT(u32 EZTR_MsgBuffer_NCopy(EZTR_MsgBuffer* dst, char* src, size_t len)); + +/** + * @brief Gets the size of the message buffer's stored data, in bytes. + * + * Does not include the termination character '\xBF'. + * + * @param buf The buffer to measure. + * @return u32 The number of bytes the message buffer's data takes up. + */ +EZTR_IMPORT(u32 EZTR_MsgBuffer_Len(EZTR_MsgBuffer* buf)); + +/** + * @brief Gets the size of the message buffer's content region, in bytes. + * + * Effectively `EZTR_MsgBuffer_Len(buf) - 11` or `EZTR_MsgSContent_Len(buf->partition.content)`. + * Does not include the termination character '\xBF'. + * + * @param buf The buffer to measure. + * @return u32 The number of bytes the message buffer's content takes up. + */ +EZTR_IMPORT(u32 EZTR_MsgBuffer_ContentLen(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets a message buffer's header to default values. + * + * The default values for a message buffer header are: + * + * * text_box_type = EZTR_STANDARD_TEXT_BOX_I (0) + * * text_box_y_pos = 0 + * * display_icon = EZTR_ICON_NO_ICON (0xFE) + * * next_message_id = EZTR_NO_VALUE (0xFFFF) + * * first_item_rupees = EZTR_NO_VALUE (0xFFFF) + * * second_item_rupees = EZTR_NO_VALUE (0xFFFF) + * + * @param buf the message buffer to write to. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_WriteDefaultHeader(EZTR_MsgBuffer* buf)); + +/** + * @brief + * + * @param buf the message buffer to write to. + * @param text_box_type The style of textbox to display. Use the `EZTR_TextBoxType` enum for more readable values. + * @param text_box_y_pos The vertical position of the textbox on-screen. + * @param display_icon Displays an icon in the textbox. Use the `EZTR_TextBoxIcon` enum for more readable values. + * Use `EZTR_ICON_NO_ICON` for no icon. + * @param next_message_id The next message to display. If there is no next message, or the next message is determined by code, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param first_item_rupees The price of the first item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + * @param second_item_rupees The price of the second item being offered for sale, if one exists. If there is no item, + * use 0xFFFF or `EZTR_NO_VALUE`. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_WriteHeader(EZTR_MsgBuffer* buf, u8 text_box_type, u8 text_box_y_pos, u8 display_icon, + u16 next_message_id, u16 first_item_rupees, u16 second_item_rupees)); + +/** + * @brief Retrieves the text_box_type from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u8 The text_box_type of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.text_box_type`. + */ +EZTR_IMPORT(u8 EZTR_MsgBuffer_GetTextBoxType(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the text_box_type of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param type The new text_box_type value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.text_box_type = type` + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetTextBoxType(EZTR_MsgBuffer* buf, u8 type)); + +/** + * @brief Retrieves the text_box_y_pos from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u8 The text_box_y_pos of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.text_box_y_pos`. + */ +EZTR_IMPORT(u8 EZTR_MsgBuffer_GetTextBoxYPos(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the text_box_y_pos of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param pos The new text_box_y_pos value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.text_box_y_pos = pos` + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetTextBoxYPos(EZTR_MsgBuffer* buf, u8 pos)); + +/** + * @brief Retrieves the display_icon from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u8 The display_icon of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.display_icon`. + */ +EZTR_IMPORT(u8 EZTR_MsgBuffer_GetTextBoxDisplayIcon(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the display_icon of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param icon The new display_icon value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.display_icon = icon` + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetTextBoxDisplayIcon(EZTR_MsgBuffer* buf, u8 icon)); + +/** + * @brief Retrieves the next_message_id from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u16 The display_icon of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.next_message_id`. + */ +EZTR_IMPORT(u16 EZTR_MsgBuffer_GetNextMsg(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the next_message_id of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param textId The new display_icon value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.next_message_id = icon`. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetNextMsg(EZTR_MsgBuffer* buf, u16 textId)); + +/** + * @brief Retrieves the first_item_rupees from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u16 The first_item_rupees of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.first_item_rupees`. + */ +EZTR_IMPORT(u16 EZTR_MsgBuffer_GetFirstItemRupees(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the first_item_rupees of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param value The new first_item_rupees value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.first_item_rupees = icon`. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetFirstItemRupees(EZTR_MsgBuffer* buf, u16 val)); + +/** + * @brief Retrieves the second_item_rupees from a message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to read from. + * @return u16 The second_item_rupees of the message buffer. If `EZTR_MsgBufferData` is being packed correctly, this will be + * equivalent to `buf->data.second_item_rupees`. + */ +EZTR_IMPORT(u16 EZTR_MsgBuffer_GetSecondItemRupees(EZTR_MsgBuffer* buf)); + +/** + * @brief Sets the second_item_rupees of the message buffer's header. + * + * Useful if your compiler is having trouble with the `__attribute_((packed))` on `EZTR_MsgBufferData`, and the data isn't + * lining up correctly. + * + * @param buf The message buffer to write to. + * @param value The new second_item_rupees value. If `EZTR_MsgBufferData` is being packed correctly, this will be equivalent + * to `buf->data.second_item_rupees = icon`. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_SetSecondItemRupees(EZTR_MsgBuffer* buf, u16 val)); + +/** + * @brief Prints the contents of a message buffer to the console. + * + * Each value in the header will be labeled. The content region will stop printing after the '\xBF' termination character. + * + * @param buf The message buffer to print. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_Print(EZTR_MsgBuffer* buf)); + +/** + * @brief Prints the contents of a message buffer to the console, formatted as a `EZTR_Basic_ReplaceText` call. + * + * The string literal for the content will end with the '\xBF' termination character. + * + * @param buf The message buffer to print. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_PrintCCode(EZTR_MsgBuffer* buf)); + +/** + * @brief Prints the contents of a message buffer to the console. + * + * Each value in the header will be labeled. The this function prints the entire 1279 bytes of the content region. + * + * @param buf The message buffer to print. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_PrintFull(EZTR_MsgBuffer* buf)); + +/** + * @brief Prints the contents of a message buffer to the console, formatted as a `EZTR_Basic_ReplaceText` call. + * + * The this function prints the entire 1279 bytes of the content region. + * + * @param buf The message buffer to print. + */ +EZTR_IMPORT(void EZTR_MsgBuffer_PrintFullCCode(EZTR_MsgBuffer* buf)); + +/** + * @brief Gets a pointer to the beginning of the content region for a desired message buffer. + * + * Equivalent to `buf->partition.content`, or `buf->data.content` assuming EZTR_MsgBufferData is being packed correctly. + * + * @param buf The buffer to get the the content from. + * @return char* The beginning of the message buffer's content region. + */ +EZTR_IMPORT(char* EZTR_MsgBuffer_GetContentPtr(EZTR_MsgBuffer* buf)); + +/** @}*/ + + +/** + * \defgroup MsgSContent + * \brief Functions for manipulating message text content. + * @{ + */ + + +/** + * @brief Sets the message message content as empty. + * + * This is accomplished by setting the first character in the message content to the '\xBF' termination character. + * No other bytes are effected. + * + * @param cont A pointer to message content string. + */ +EZTR_IMPORT(void EZTR_MsgSContent_SetEmpty(char* cont)); + +/** + * @brief Gets the length of the a message content string in bytes, not counting the '\xBF' termination character + * + * Similar to `strlen()` for null-terminated strings. + * + * This function is safe as long as `cont` points to the beginning of a message buffer's content region, since it + * will not count bytes beyond that size. + * + * @param cont The message content you want to get the length of. + * @return u32 The length of the message content, in bytes. + */ +EZTR_IMPORT(u32 EZTR_MsgSContent_Len(char* cont)); + +/** + * @brief Copies message content from `src` into the `dst`, up to `len` bytes. + * + * Similar to `strncpy()` for null-terminated strings. + * + * @param dst The location to copy message content into. + * @param src The message content to copy. + * @param len The maximum number of bytes to copy. If a '\xBF' is encountered in `src`, the function will stop copying + * before `len` is reached. + * @return u32 The number of bytes copied. + */ +EZTR_IMPORT(u32 EZTR_MsgSContent_NCopy(char* dst, char* src, size_t len)); + +/** + * @brief Copies message content from `src` into the `dst`. + * + * Similar to `strcpy()` for null-terminated strings. + * + * This function is safe as long as `dst` points to the beginning of a message buffer's content region, since it + * will not copy bytes beyond that size. + * + * @param dst The location to copy message content into. + * @param src The message content to copy. Should be '\xBF' terminated. + * @return u32 The number of bytes copied. + */ +EZTR_IMPORT(u32 EZTR_MsgSContent_Copy(char* dst, char* src)); + +/** + * @brief Copies the message content of `src` onto the end of `dst`, up to `len` bytes from `src`. + * + * Similar to `strncat()` for null-terminated strings. + * + * This function will not produce message content larger than a message buffer's content region. Copying will + * stop once the maximum size is reached. + * + * @param dst The location to append message content into. + * @param src The message content to copy. + * @param len The maximum number of bytes to copy. If a '\xBF' is encountered in `src`, the function will stop copying + * before `len` is reached. + * @return char* The pointer to the new string (i.e: to `dst`). + */ +EZTR_IMPORT(char* EZTR_MsgSContent_NCat(char* dst, char* src, size_t len)); + +/** + * @brief Copies the message content of `src` onto the end of `dst`. + * + * Similar to `strcat()` for null-terminated strings. + * + * This function is safe as long as `dst` points to the beginning of a message buffer's content region, as it + * will not produce message content larger than a message buffer's content region. Copying will + * stop once the maximum size is reached. + * + * @param dst The location to append message content into. + * @param src The message content to copy. Should be '\xBF' terminated. + * @return char* The pointer to the new string (i.e: to `dst`). + */ +EZTR_IMPORT(char* EZTR_MsgSContent_Cat(char* dst, char* src)); + +/** + * @brief Compares up to `len` bytes of two message content strings. + * + * Similar to `strncmp()` for null-terminated strings, but with one notable difference: + * With `strncmp()`, if two strings are equal for the first `n` characters, but one string continues after `n` while + * the other doesn't, the shorter string is considered 'lesser' because the null terminator `'\x00'` is naturally + * the lowest possible ASCII value. Because strings in MM are `'\xBF'` terminated, that behavior won't apply here. + * + * In `EZTR_MsgSContent_NCmp()`, a special case is applied: If two strings are equal for `n` characters, but the + * next character after `n` is `'\xBF'` in one of the strings, it is considered the lesser string regardless of + * what the other character is. + * + * @param str1 The first message content string to compare. + * @param str2 The second message content string to compare. + * @param len The maximum number of bytes to compare. + * @return s32 Returns 0 is the strings are the same, 1 if the first string is greater than the second, and + * -1 if the second string is greater than the first. + */ +EZTR_IMPORT(s32 EZTR_MsgSContent_NCmp(char* str1, char* str2, size_t len)); + +/** + * @brief Compares two message content strings. + * + * This function is safe as long as both `str1` and `str2` point to the content region of message buffers, as the + * comparison will not continue beyond that size. + * + * Similar to `strcmp()` for null-terminated strings, but with one notable difference: + * With `strncmp()`, if two strings are equal for the first `n` characters, but one string continues after `n` while + * the other doesn't, the shorter string is considered 'lesser' because the null terminator `'\x00'` is naturally + * the lowest possible ASCII value. Because strings in MM are `'\xBF'` terminated, that behavior won't apply here. + * + * In `EZTR_MsgSContent_Cmp()`, a special case is applied: If two strings are equal for `n` characters, but the + * next character after `n` is `'\xBF'` in one of the strings, it is considered the lesser string regardless of + * what the other character is. + * + * @param str1 The first message content string to compare. + * @param str2 The second message content string to compare. + * @return s32 Returns 0 is the strings are the same, 1 if the first string is greater than the second, and + * -1 if the second string is greater than the first. + */ +EZTR_IMPORT(s32 EZTR_MsgSContent_Cmp(char* str1, char* str2)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Printf(const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_PrintfLine(const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * Unlike `EZTR_MsgSContent_Printf()`, this function will append a newline to the end of + * console output. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Sprintf(char* buffer, const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param count + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Snprintf(char* buffer, size_t count, const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param count + * @param format + * @param va + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Vsnprintf(char* buffer, size_t count, const char* format, va_list va)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version uses pipe-escaped byte handling in the main formatting argument. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param va + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Vprintf(const char* format, va_list va)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param out + * @param arg + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_Fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Printf(const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_PrintfLine(const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * Unlike `EZTR_MsgSContent_Printf()`, this function will append a newline to the end of + * console output. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Sprintf(char* buffer, const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param count + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Snprintf(char* buffer, size_t count, const char* format, ...)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param buffer + * @param count + * @param format + * @param va + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Vsnprintf(char* buffer, size_t count, const char* format, va_list va)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param format + * @param va + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Vprintf(const char* format, va_list va)); + +/** + * @brief A modified version of printf, specially designed to handle message content. + * This version does not use pipe-escaped byte handling in the main formatting argument, + * but are still used with the `%m` type specifier. + * + * See \ref prinf_functions for more information on EZTR's custom printf behavior. + * + * @param out + * @param arg + * @param format + * @param ... + * @return int + */ +EZTR_IMPORT(int EZTR_MsgSContent_NoPipe_Fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)); + +/** @}*/ + +#endif \ No newline at end of file diff --git a/mod.toml b/mod.toml index 3f98682..15829ea 100644 --- a/mod.toml +++ b/mod.toml @@ -25,7 +25,7 @@ https://github.com/RecompRando/MMRecompRando""" short_description = "hey game different now" # Authors of this mod. -authors = [ "LittleCube", "ThatHypedPerson", "PixelShake92", "Muervo_", "G4M3RL1F3", "dcvz", "CelestialKitsune", "VincentsSin" ] +authors = [ "LittleCube", "ThatHypedPerson", "PixelShake92", "Muervo_", "G4M3R L1F3", "dcvz", "CelestialKitsune", "VincentsSin" ] # ID of the target recomp game. game_id = "mm" @@ -37,7 +37,8 @@ minimum_recomp_version = "1.2.0" dependencies = [ "owls_never_quit:1.0.0", "mm_recomp_better_double_sot:0.0.1", - "mm_recomp_colors:0.5.0" + "mm_recomp_colors:0.5.0", + "MM_EZ_Text_Replacer_API:2.3.0" ] # Native libraries (e.g. DLLs) and the functions they export. diff --git a/src/eztr_replacements.c b/src/eztr_replacements.c new file mode 100644 index 0000000..de279b0 --- /dev/null +++ b/src/eztr_replacements.c @@ -0,0 +1,308 @@ +//#include "apcommon.h" +//#include "eztr_api.h" +//#include "modding.h" + +//EZTR_MSG_CALLBACK(cursed_spider_first_time_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "I have nothing to give you." EZTR_CC_NEWLINE "Go away." EZTR_CC_EVENT2 EZTR_CC_END); +// } +//} +//EZTR_ON_INIT void cursed_spider_first_time_text() { +// EZTR_Basic_ReplaceText( +// 0x910, // Text ID +// EZTR_STANDARD_TEXT_BOX_I, // Text box type +// 0, // Text box Y axis offset +// EZTR_ICON_NO_ICON, // Icon display +// 0x911, // Next message text ID +// EZTR_NO_VALUE, // First item rupee cost +// EZTR_NO_VALUE, // Second item rupee cose +// false, +// "Ah! Help me!" EZTR_CC_NEWLINE "I am not a monster!" EZTR_CC_NEWLINE +// "The spider's curse..." EZTR_CC_NEWLINE "It made me this way..." EZTR_CC_CONTINUE +// /*"I beg of you..." EZTR_CC_COLOR_RED "In here" EZTR_CC_COLOR_DEFAULT "...Find them" EZTR_CC_NEWLINE +// EZTR_CC_COLOR_RED "all" EZTR_CC_COLOR_DEFAULT "...The" EZTR_CC_COLOR_RED "gold" EZTR_CC_COLOR_DEFAULT "ones...The cursed" EZTR_CC_NEWLINE +// EZTR_CC_COLOR_RED "spiders" EZTR_CC_COLOR_DEFAULT "...Defeat them...Quickly!" EZTR_CC_EVENT2 EZTR_CC_END*/, +// cursed_spider_first_time_callback // Callback +// ); +//} +// +//EZTR_MSG_CALLBACK(curse_spider_recurring_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Do not bother lifting the curse." EZTR_CC_NEWLINE +// "The mask is mine!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +//} +//EZTR_ON_INIT void cursed_spider_recurring_text() { +// EZTR_Basic_ReplaceText( +// 0x914, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// 0x915, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// EZTR_CC_COLOR_RED "In here" EZTR_CC_COLOR_DEFAULT "...The gold ones...The cursed" EZTR_CC_NEWLINE +// EZTR_CC_COLOR_RED "spiders" EZTR_CC_COLOR_DEFAULT "...Defeat them " EZTR_CC_COLOR_RED "all" EZTR_CC_COLOR_DEFAULT "...Make me" EZTR_CC_NEWLINE +// "normal...again..." EZTR_CC_EVENT2 EZTR_CC_END, +// curse_spider_recurring_callback +// ); +//} +// +//EZTR_MSG_CALLBACK(ssh_guy_first_time_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "I am not giving you my mask." EZTR_CC_NEWLINE +// "It's mine and mine only!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +//} +//EZTR_ON_INIT void ssh_guy_first_time_text() { +// EZTR_Basic_ReplaceText( +// 0x91B, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "As soon as I calm down, I'm going" EZTR_CC_NEWLINE "to get rid of it." EZTR_CC_EVENT2 EZTR_CC_END, +// ssh_guy_first_time_callback +// ); +//} +// +//EZTR_MSG_CALLBACK(ssh_guy_recurring_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_spiderhouse_reward") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Great, now my mask is gone. That" EZTR_CC_NEWLINE +// "mask was giving me infinite riches." +// EZTR_CC_BOX_BREAK "Now what?" EZTR_CC_EVENT2 EZTR_CC_END); +// } +//} +//EZTR_ON_INIT void ssh_guy_recurring_text() { +// EZTR_Basic_ReplaceText( +// 0x918, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "I've had enough of this..." EZTR_CC_BOX_BREAK +// "As soon as I get it together," EZTR_CC_NEWLINE +// "I'm going home." EZTR_CC_EVENT2 EZTR_CC_END, +// ssh_guy_recurring_callback +// ); +//} + +//EZTR_MSG_CALLBACK(chest_game_init_as_human_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "Oh! A customer! Unfortunately," EZTR_CC_NEWLINE "we are under construction." EZTR_CC_CONTINUE); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Sorry, but we only accept" EZTR_CC_NEWLINE EZTR_CC_COLOR_RED "strong and burly" EZTR_CC_COLOR_DEFAULT "customers." EZTR_CC_CONTINUE +// ); +// } +//} +//EZTR_ON_INIT void chest_game_init_as_human_text() { +// EZTR_Basic_ReplaceText( +// 0x76D, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// 0x771, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "Come in! Oh, is the kid collecting" EZTR_CC_NEWLINE +// "masks? How about it? Wanna" EZTR_CC_NEWLINE +// "play?" EZTR_CC_CONTINUE, +// NULL +// ); +//} + +//EZTR_MSG_CALLBACK(chest_game_init_as_deku_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "Oh! A customer! Unfortunately," EZTR_CC_NEWLINE "we are under construction." EZTR_CC_CONTINUE); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Sorry, but we only accept" EZTR_CC_NEWLINE EZTR_CC_COLOR_RED "strong and burly" EZTR_CC_COLOR_DEFAULT "customers." EZTR_CC_CONTINUE +// ); +// } +//} +//EZTR_ON_INIT void chest_game_init_as_deku_text() { +// EZTR_Basic_ReplaceText( +// 0x76C, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE,//0x770, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "Oh, what a cute little customer!" EZTR_CC_NEWLINE +// "So, do you want to play?" EZTR_CC_CONTINUE, +// chest_game_init_as_deku_callback +// ); +//} + +//EZTR_MSG_CALLBACK(chest_game_init_as_goron_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "Oh! A customer! Unfortunately," EZTR_CC_NEWLINE "we are under construction." EZTR_CC_CONTINUE); +// } +//} +//EZTR_ON_INIT void chest_game_init_as_goron_text() { +// EZTR_Basic_ReplaceText( +// 0x76E, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE,//0x772, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "Well, aren't you a fit fellow!" EZTR_CC_NEWLINE +// "Wanna play?" EZTR_CC_CONTINUE, +// chest_game_init_as_goron_callback +// ); +//} + +//EZTR_MSG_CALLBACK(chest_game_init_as_zora_callback) { +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "Oh! A customer! Unfortunately," EZTR_CC_NEWLINE "we are under construction." EZTR_CC_CONTINUE); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Sorry, but we only accept" EZTR_CC_NEWLINE EZTR_CC_COLOR_RED "strong and burly" EZTR_CC_COLOR_DEFAULT "customers." EZTR_CC_CONTINUE +// ); +// } +//} +//EZTR_ON_INIT void chest_game_init_as_zora_text() { +// EZTR_Basic_ReplaceText( +// 0x76F, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE,//0x773, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "Well, hello there, handsome!" EZTR_CC_NEWLINE +// "Wanna play?" EZTR_CC_CONTINUE, +// chest_game_init_as_zora_callback +// ); +//} + +//EZTR_MSG_CALLBACK(chest_game_selection_as_human_callback) { +// Player* player = GET_PLAYER(play); +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "We'll be opening " EZTR_CC_COLOR_RED "after the carnival" EZTR_CC_COLOR_DEFAULT "." EZTR_CC_NEWLINE +// "We hope to see you!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1 && player->transformation == !PLAYER_FORM_GORON) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Looks like you're collecting " EZTR_CC_COLOR_RED "masks" EZTR_CC_COLOR_DEFAULT "!" EZTR_CC_NEWLINE +// "There's " EZTR_CC_COLOR_RED "one I like" EZTR_CC_COLOR_DEFAULT ", but I don't" EZTR_CC_NEWLINE +// "know if you have it..." EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +//} +//EZTR_ON_INIT void chest_game_selection_as_human_text() { +// EZTR_Basic_ReplaceText( +// 0x771, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "For you, it's " EZTR_CC_COLOR_PINK "20 Rupees" EZTR_CC_COLOR_DEFAULT "." EZTR_CC_NEWLINE +// EZTR_CC_NEWLINE +// EZTR_CC_COLOR_GREEN EZTR_CC_TWO_CHOICE "OK" EZTR_CC_NEWLINE +// "No thanks" EZTR_CC_EVENT2 EZTR_CC_END, +// chest_game_selection_as_human_callback +// ); +//} +// +//EZTR_MSG_CALLBACK(chest_game_selection_as_deku_callback) { +// Player* player = GET_PLAYER(play); +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "We'll be opening " EZTR_CC_COLOR_RED "after the carnival" EZTR_CC_COLOR_DEFAULT "." EZTR_CC_NEWLINE +// "We hope to see you!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1 && player->transformation == !PLAYER_FORM_GORON) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "Which is unfortunate because you" EZTR_CC_NEWLINE +// "are so cute!!!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +//} +//EZTR_ON_INIT void chest_game_selection_as_deku_text() { +// EZTR_Basic_ReplaceText( +// 0x770, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "Which is unfortunate because you" EZTR_CC_NEWLINE +// "are so cute!!!" EZTR_CC_EVENT2 EZTR_CC_END, +// chest_game_selection_as_deku_callback +// ); +//} +// +//EZTR_ON_INIT void chest_game_selection_as_goron_text() { +// EZTR_Basic_ReplaceText( +// 0x772, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "We'll be opening " EZTR_CC_COLOR_RED "after the carnival" EZTR_CC_COLOR_DEFAULT "." EZTR_CC_NEWLINE +// "We hope to see you!" EZTR_CC_EVENT2 EZTR_CC_END, +// NULL +// ); +//} +// +//EZTR_MSG_CALLBACK(chest_game_selection_as_zora_callback) { +// Player* player = GET_PLAYER(play); +// if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 0) { +// EZTR_MsgSContent_Sprintf(buf->data.content, +// "We'll be opening " EZTR_CC_COLOR_RED "after the carnival" EZTR_CC_COLOR_DEFAULT "." EZTR_CC_NEWLINE +// "We hope to see you!" EZTR_CC_EVENT2 EZTR_CC_END +// ); +// } +// else if ((s16) rando_get_slotdata_u32("shuffle_treasure_chest_game") == 1 && player->transformation == !PLAYER_FORM_GORON) { +// EZTR_MsgSContent_Sprintf(buf->data.content, "It's too bad... You look like my type..." EZTR_CC_EVENT2 EZTR_CC_END); +// } +//} +//EZTR_ON_INIT void chest_game_selection_as_zora_text() { +// EZTR_Basic_ReplaceText( +// 0x773, +// EZTR_STANDARD_TEXT_BOX_I, +// 0, +// EZTR_ICON_NO_ICON, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// EZTR_NO_VALUE, +// false, +// "It's too bad... You look like my type..." EZTR_CC_EVENT2 EZTR_CC_END, +// NULL +// ); +//} \ No newline at end of file From bcaea50d1cace77b44eff905c38eee84a597afbd Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 1 Feb 2026 18:11:57 -0400 Subject: [PATCH 08/19] Added ShuffleMinigames option Does not include text changes. Currently untested. I will test once everything I want to add has been added. --- src/fisherman_hooks.c | 4 ++-- src/honey_and_darling_hooks.c | 6 +++++- src/lift_nuts_hooks.c | 4 ++-- src/shooting_gallery_hooks.c | 34 ++++++++++++++++++++++++++++++---- src/yaml_generation_menu.c | 7 +++++++ 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/fisherman_hooks.c b/src/fisherman_hooks.c index 5310e02..0c4d916 100644 --- a/src/fisherman_hooks.c +++ b/src/fisherman_hooks.c @@ -54,8 +54,8 @@ RECOMP_PATCH void func_80C14554(EnJgameTsn* this, PlayState* play) { SET_WEEKEVENTREG(WEEKEVENTREG_82_10); } func_80C145FC(this); - // } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_82_10)) { - // Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); + } else if ((s16) rando_get_slotdata_u32("shuffle_minigames") != 0) { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); } else { Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); } diff --git a/src/honey_and_darling_hooks.c b/src/honey_and_darling_hooks.c index 5fc7eee..01a916a 100644 --- a/src/honey_and_darling_hooks.c +++ b/src/honey_and_darling_hooks.c @@ -60,11 +60,15 @@ typedef struct EnFu { void func_80963610(EnFu* this); RECOMP_PATCH void func_80963560(EnFu* this, PlayState* play) { - if (Actor_HasParent(&this->actor, play)) { + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 0) { + Actor_OfferGetItemHook(&this->actor, play, GI_RUPEE_PURPLE, 0, 500.0f, 100.0f, false, false); + } else if (Actor_HasParent(&this->actor, play)) { this->actor.parent = NULL; func_80963610(this); } else if ((this->unk_552 == 0x2880) && !rando_location_is_checked(LOCATION_HONEY_AND_DARLING_ALL_DAYS)) { Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); + } else if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 1) { + Actor_OfferGetItemHook(&this->actor, play, GI_RUPEE_PURPLE, 0, 500.0f, 100.0f, false, false); } else if (!rando_location_is_checked(LOCATION_HONEY_AND_DARLING_ANY_DAY)) { Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); } else { diff --git a/src/lift_nuts_hooks.c b/src/lift_nuts_hooks.c index 615a8b8..e78a4c8 100644 --- a/src/lift_nuts_hooks.c +++ b/src/lift_nuts_hooks.c @@ -77,10 +77,10 @@ RECOMP_PATCH void EnLiftNuts_GiveReward(EnLiftNuts* this, PlayState* play) { } EnLiftNuts_SetupResumeConversation(this); //} else if ((this->textId == 0x27F4) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_DEKU_PLAYGROUND_HEART_PIECE)) { - } else if ((this->textId == 0x27F4) && !rando_location_is_checked(LOCATION_PLAYGROUND_ALL_DAYS)) { + } if ((this->textId == 0x27F4) && !rando_location_is_checked(LOCATION_PLAYGROUND_ALL_DAYS) && (s16) rando_get_slotdata_u32("shuffle_minigames") == 0) { Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); //} else { - } else if (!rando_location_is_checked(LOCATION_PLAYGROUND_ANY_DAY)) { + } else if (!rando_location_is_checked(LOCATION_PLAYGROUND_ANY_DAY) && (s16) rando_get_slotdata_u32("shuffle_minigames") != 0) { Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); } else { Actor_OfferGetItemHook(&this->actor, play, GI_RUPEE_PURPLE, 0, 500.0f, 100.0f, false, false); diff --git a/src/shooting_gallery_hooks.c b/src/shooting_gallery_hooks.c index 6244a71..2bfcf2e 100644 --- a/src/shooting_gallery_hooks.c +++ b/src/shooting_gallery_hooks.c @@ -160,8 +160,20 @@ RECOMP_PATCH void EnSyatekiMan_Town_SetupGiveReward(EnSyatekiMan* this, PlayStat extraItem = 0; } } else if (offeringItem == 0) { - if (this->score == 50 && !(!rando_location_is_checked(GI_QUIVER_40) && rando_location_is_checked(LOCATION_TOWN_GALLERY_PERFECT))) { - if (rando_location_is_checked(LOCATION_TOWN_GALLERY_PERFECT)) { + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 0) { + if (this->score == 50) { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f); + } else { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); + } + } else if (this->score == 50 && !(!rando_location_is_checked(GI_QUIVER_40) && rando_location_is_checked(LOCATION_TOWN_GALLERY_PERFECT))) { + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 1) { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f); + if (!rando_location_is_checked(GI_QUIVER_40)) { + extraItem = GI_QUIVER_40; + } + } + else if (rando_location_is_checked(LOCATION_TOWN_GALLERY_PERFECT)) { Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f); } else { Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); @@ -355,10 +367,24 @@ RECOMP_PATCH void EnSyatekiMan_Swamp_SetupGiveReward(EnSyatekiMan* this, PlaySta extraItem = 0; } } else if (offeringItem == 0) { + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 0) { + if (this->score >= SG_SWAMP_HEART_PIECE_SCORE) { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f); + } else { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_RED, 500.0f, 100.0f); + } + } //~ if ((CUR_UPG_VALUE(UPG_QUIVER) < 3) && //~ !CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE)) { - if (!rando_location_is_checked(LOCATION_SWAMP_GALLERY_PERFECT)) { - Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_SWAMP_GALLERY_PERFECT), LOCATION_SWAMP_GALLERY_PERFECT, 500.0f, 100.0f, true, true); + else if (!rando_location_is_checked(LOCATION_SWAMP_GALLERY_PERFECT)) { + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 1) { + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f); + if (!rando_location_is_checked(GI_QUIVER_40)) { + extraItem = GI_QUIVER_40; + } + } else { + Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_SWAMP_GALLERY_PERFECT), LOCATION_SWAMP_GALLERY_PERFECT, 500.0f, 100.0f, true, true); + } if (!rando_location_is_checked(GI_QUIVER_50)) { extraItem = GI_QUIVER_50; } diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index ac42cf0..e4f1b2b 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -407,6 +407,12 @@ static EnumOptionValue rando_shopsanity_options[] = { { "advanced", NULL }, }; +static EnumOptionValue shuffle_minigames_options[] = { + { "disabled", NULL }, + { "single", NULL }, + { "everything", NULL } +}; + static EnumOptionValue treasure_chest_game_shuffle_options[] = { { "disabled", NULL }, { "goron_only", NULL }, @@ -527,6 +533,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "bosskeysanity", "Boss-Key-Sanity:", false); randoCreateBoolPropOption(&yaml_config_menu, "curiostity_shop_trades", "Curiosity Shop Trades:", false); randoCreateBoolPropOption(&yaml_config_menu, "intro_checks", "Intro Checks:", false); + randoCreateRadioOption(&yaml_config_menu, "shuffle_minigames", "Shuffle Minigames:", shuffle_minigames_options, ARRAY_COUNT(shuffle_minigames_options), 1); randoCreateRadioOption(&yaml_config_menu, "shuffle_treasure_chest_game", "Treasure Chest Game Shuffle:", treasure_chest_game_shuffle_options, ARRAY_COUNT(treasure_chest_game_shuffle_options), 1); randoCreateBoolPropOption(&yaml_config_menu, "start_with_consumables", "Start With Consumables:", true); randoCreateBoolPropOption(&yaml_config_menu, "permanent_chateau_romani", "Permanent Chateau Romani:", true); From e987b31249f8fde6e1ab634670dfebf0dac29ed6 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 17 May 2026 12:36:01 -0300 Subject: [PATCH 09/19] Added lottery shuffle option Currently untested --- src/lotto_hooks.c | 7 +++++-- src/yaml_generation_menu.c | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lotto_hooks.c b/src/lotto_hooks.c index 0caa7f7..cc5b421 100644 --- a/src/lotto_hooks.c +++ b/src/lotto_hooks.c @@ -11,7 +11,10 @@ RECOMP_PATCH void EnKujiya_GivePrize(EnKujiya* this, PlayState* play) { if (Actor_HasParent(&this->actor, play)) { EnKujiya_SetupFinishGivePrize(this); } else { - // Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); - Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_LOTTERY_SHOP), LOCATION_LOTTERY_SHOP, 500.0f, 100.0f, true, true); + if (rando_get_slotdata_u32("shuffle_lottery") == 0){ + Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); + } else { + Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_LOTTERY_SHOP), LOCATION_LOTTERY_SHOP, 500.0f, 100.0f, true, true); + } } } \ No newline at end of file diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index e4f1b2b..202d5e0 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -535,6 +535,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "intro_checks", "Intro Checks:", false); randoCreateRadioOption(&yaml_config_menu, "shuffle_minigames", "Shuffle Minigames:", shuffle_minigames_options, ARRAY_COUNT(shuffle_minigames_options), 1); randoCreateRadioOption(&yaml_config_menu, "shuffle_treasure_chest_game", "Treasure Chest Game Shuffle:", treasure_chest_game_shuffle_options, ARRAY_COUNT(treasure_chest_game_shuffle_options), 1); + randoCreateBoolPropOption(&yaml_config_menu, "shuffle_lottery", "Shuffle Lottery:", false); randoCreateBoolPropOption(&yaml_config_menu, "start_with_consumables", "Start With Consumables:", true); randoCreateBoolPropOption(&yaml_config_menu, "permanent_chateau_romani", "Permanent Chateau Romani:", true); randoCreateBoolPropOption(&yaml_config_menu, "start_with_inverted_time", "Start With Inverted Time:", true); From 08dc212ee2556a71fe94e47c2d5f7846c04b16c9 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 17 May 2026 13:51:08 -0300 Subject: [PATCH 10/19] Added beaver race shuffle option Currently untested. --- src/beaver_hooks.c | 4 ++-- src/yaml_generation_menu.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/beaver_hooks.c b/src/beaver_hooks.c index 1e8fa00..dd4eaa1 100644 --- a/src/beaver_hooks.c +++ b/src/beaver_hooks.c @@ -456,7 +456,7 @@ RECOMP_PATCH s32 func_80A9617C(EnAz* this, PlayState* play) { case 0x10F1: SET_WEEKEVENTREG(WEEKEVENTREG_93_01); // if (CHECK_WEEKEVENTREG(WEEKEVENTREG_23_80)) { - if (rando_location_is_checked(LOCATION_BEAVER_BOTTLE)) { + if (rando_location_is_checked(LOCATION_BEAVER_BOTTLE) || rando_get_slotdata_u32("shuffle_beaver_races") == 0) { this->getItemId = GI_RUPEE_RED; } else { this->getItemId = GI_BOTTLE; @@ -629,7 +629,7 @@ RECOMP_PATCH s32 func_80A9617C(EnAz* this, PlayState* play) { case 0x1105: // if (CHECK_WEEKEVENTREG(WEEKEVENTREG_25_01)) { - if (rando_location_is_checked(LOCATION_BEAVER_HP)) { + if (rando_location_is_checked(LOCATION_BEAVER_HP) || rando_get_slotdata_u32("shuffle_beaver_races") != 2){ this->getItemId = GI_RUPEE_PURPLE; } else { this->getItemId = GI_HEART_PIECE; diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index 202d5e0..9fa2c3e 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -535,6 +535,7 @@ void randoCreateYamlConfigMenu() { randoCreateBoolPropOption(&yaml_config_menu, "intro_checks", "Intro Checks:", false); randoCreateRadioOption(&yaml_config_menu, "shuffle_minigames", "Shuffle Minigames:", shuffle_minigames_options, ARRAY_COUNT(shuffle_minigames_options), 1); randoCreateRadioOption(&yaml_config_menu, "shuffle_treasure_chest_game", "Treasure Chest Game Shuffle:", treasure_chest_game_shuffle_options, ARRAY_COUNT(treasure_chest_game_shuffle_options), 1); + randoCreateIntSliderOption(&yaml_config_menu, "shuffle_beaver_races", "Shuffle Beaver Races:", 0, 2, 1, 0); randoCreateBoolPropOption(&yaml_config_menu, "shuffle_lottery", "Shuffle Lottery:", false); randoCreateBoolPropOption(&yaml_config_menu, "start_with_consumables", "Start With Consumables:", true); randoCreateBoolPropOption(&yaml_config_menu, "permanent_chateau_romani", "Permanent Chateau Romani:", true); From 1f4f97d5f6a55ac72c5b11f89d561f35b87fd310 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Mon, 18 May 2026 15:25:30 -0300 Subject: [PATCH 11/19] Added picture rewards shuffle option + bug fixes after testing BUG: If picture rewards shuffle is off and the player attempts to get the winning check, it'll give a grey AP item instead of a silver rupee. --- include/apcommon.h | 1 + src/honey_and_darling_hooks.c | 8 +- src/item_give.c | 65 +++-- src/swamp_guide_hooks.c | 442 ---------------------------------- src/yaml_generation_menu.c | 7 + src/zora_hooks.c | 7 +- 6 files changed, 69 insertions(+), 461 deletions(-) delete mode 100644 src/swamp_guide_hooks.c diff --git a/include/apcommon.h b/include/apcommon.h index 2cfe957..bb60aab 100644 --- a/include/apcommon.h +++ b/include/apcommon.h @@ -110,6 +110,7 @@ #define LOCATION_SWAMP_GALLERY_PERFECT 0x08011D #define LOCATION_BEAN_DADDY 0x0800A5 #define LOCATION_EVAN_SONG 0x070241 +#define LOCATION_SWAMP_GUIDE_WINNER 0x0701C5 #define LOCATION_SWAMP_GUIDE_GOOD 0x071C54 #define LOCATION_SWAMP_GUIDE_OKAY 0x071C52 diff --git a/src/honey_and_darling_hooks.c b/src/honey_and_darling_hooks.c index 01a916a..b598fed 100644 --- a/src/honey_and_darling_hooks.c +++ b/src/honey_and_darling_hooks.c @@ -66,9 +66,11 @@ RECOMP_PATCH void func_80963560(EnFu* this, PlayState* play) { this->actor.parent = NULL; func_80963610(this); } else if ((this->unk_552 == 0x2880) && !rando_location_is_checked(LOCATION_HONEY_AND_DARLING_ALL_DAYS)) { - Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); - } else if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 1) { - Actor_OfferGetItemHook(&this->actor, play, GI_RUPEE_PURPLE, 0, 500.0f, 100.0f, false, false); + if ((s16) rando_get_slotdata_u32("shuffle_minigames") == 1) { + Actor_OfferGetItemHook(&this->actor, play, GI_RUPEE_PURPLE, 0, 500.0f, 100.0f, false, false); + } else { + Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f); + } } else if (!rando_location_is_checked(LOCATION_HONEY_AND_DARLING_ANY_DAY)) { Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f); } else { diff --git a/src/item_give.c b/src/item_give.c index d479dbcb..63b0e1d 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -1452,7 +1452,10 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get (item == ITEM_HYLIAN_LOACH)) || (((item >= ITEM_POTION_RED) && (item <= ITEM_OBABA_DRINK) && (item != ITEM_CHATEAU)) || (item == ITEM_MILK) || (item == ITEM_CHATEAU_2) || (item == ITEM_GOLD_DUST_2) || (item == ITEM_HYLIAN_LOACH_2) || - (item == ITEM_SEAHORSE_CAUGHT))) { + (item == ITEM_SEAHORSE_CAUGHT)) || + (actor->id == ACTOR_ID_SWAMP_GUIDE && (getItemId == GI_HEART_PIECE && rando_get_slotdata_u32("shuffle_picture_rewards") == 0) || + ((getItemId == GI_RUPEE_RED || getItemId == GI_RUPEE_BLUE) && rando_get_slotdata_u32("shuffle_picture_rewards") != 2) + )) { } else { itemWorkaround = true; itemShuffled = true; @@ -1460,15 +1463,27 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get } if (getItemId == GI_HEART_PIECE) { recomp_printf("Actor HP: 0x%06X\n", LOCATION_QUEST_HEART_PIECE); - itemWorkaround = true; - itemShuffled = true; - trueGI = rando_get_item_id(LOCATION_QUEST_HEART_PIECE); - if (LOCATION_QUEST_HEART_PIECE == LOCATION_GRANNY_STORY_1 && rando_location_is_checked(LOCATION_GRANNY_STORY_1)) { - // stupid gramma double heart piece - location_to_send = LOCATION_GRANNY_STORY_2; - trueGI = rando_get_item_id(LOCATION_GRANNY_STORY_2); + if (actor->id == ACTOR_ID_SWAMP_GUIDE) { + if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { + itemWorkaround = false; + itemShuffled = false; + trueGI = getItemId; + SET_WEEKEVENTREG(WEEKEVENTREG_87_08); + } else { + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + } } else { - location_to_send = LOCATION_QUEST_HEART_PIECE; + itemWorkaround = true; + itemShuffled = true; + trueGI = rando_get_item_id(LOCATION_QUEST_HEART_PIECE); + if (LOCATION_QUEST_HEART_PIECE == LOCATION_GRANNY_STORY_1 && rando_location_is_checked(LOCATION_GRANNY_STORY_1)) { + // stupid gramma double heart piece + location_to_send = LOCATION_GRANNY_STORY_2; + trueGI = rando_get_item_id(LOCATION_GRANNY_STORY_2); + } else { + location_to_send = LOCATION_QUEST_HEART_PIECE; + } } } else if (getItemId >= GI_REMAINS_ODOLWA && getItemId <= GI_REMAINS_TWINMOLD) { itemWorkaround = true; @@ -1507,14 +1522,31 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get // Honey and Darling Any Day location_to_send = LOCATION_HONEY_AND_DARLING_ANY_DAY; trueGI = rando_get_item_id(LOCATION_HONEY_AND_DARLING_ANY_DAY); + //} else if (getItemId == GI_HEART_PIECE && actor->id == ACTOR_ID_SWAMP_GUIDE) { + // // Swamp Pictograph Contest Winning Picture + // if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { + // itemShuffled = false; + // getItemId = GI_RUPEE_SILVER; + // } else { + // location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + // trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + // } } else if (getItemId == GI_RUPEE_RED && actor->id == ACTOR_ID_SWAMP_GUIDE) { // && !rando_location_is_checked(LOCATION_SWAMP_GUIDE_GOOD)) { // Swamp Pictograph Contest Good Picture - location_to_send = LOCATION_SWAMP_GUIDE_GOOD; - trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_GOOD); + if (rando_get_slotdata_u32("shuffle_picture_rewards") != 2) { + itemShuffled = false; + } else { + location_to_send = LOCATION_SWAMP_GUIDE_GOOD; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_GOOD); + } } else if (getItemId == GI_RUPEE_BLUE && actor->id == ACTOR_ID_SWAMP_GUIDE) { // && !rando_location_is_checked(LOCATION_SWAMP_GUIDE_OKAY)) { // Swamp Pictograph Contest Okay Picture - location_to_send = LOCATION_SWAMP_GUIDE_OKAY; - trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_OKAY); + if (rando_get_slotdata_u32("shuffle_picture_rewards") != 2) { + itemShuffled = false; + } else { + location_to_send = LOCATION_SWAMP_GUIDE_OKAY; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_OKAY); + } } else if (getItemId == GI_POWDER_KEG && ((actor->id == ACTOR_ID_MEDIGORON && rando_location_is_checked(GI_POWDER_KEG)) || actor->id == ACTOR_ID_BOMBGORON)) { // Goron Village Medigoron Sale + Bomb Shop Goron Rebuy itemWorkaround = false; @@ -1528,7 +1560,12 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get if (itemShuffled) { player->getItemId = GI_DEED_LAND; } else { - player->getItemId = getItemId; + if (getItemId == GI_HEART_PIECE && actor->id == ACTOR_ID_SWAMP_GUIDE && rando_get_slotdata_u32("shuffle_picture_rewards") == 0) + { + player->getItemId = GI_RUPEE_SILVER; + } else { + player->getItemId = getItemId; + } } player->interactRangeActor = actor; player->getItemDirection = absYawDiff; diff --git a/src/swamp_guide_hooks.c b/src/swamp_guide_hooks.c deleted file mode 100644 index bf0de37..0000000 --- a/src/swamp_guide_hooks.c +++ /dev/null @@ -1,442 +0,0 @@ -#include "global.h" -#include "modding.h" - -#include "apcommon.h" - -#include "z64snap.h" -#include "z64msgevent.h" - -struct EnShn; - -typedef void (*EnShnActionFunc)(struct EnShn*, PlayState*); - -#define BURLY_GUY_LIMB_MAX 0x10 - -typedef struct EnShn { - /* 0x000 */ Actor actor; - /* 0x144 */ EnShnActionFunc actionFunc; - /* 0x148 */ SkelAnime skelAnime; - /* 0x18C */ UNK_TYPE1 pad_18C[0x4C]; - /* 0x1D8 */ u16 unk_1D8; - /* 0x1DA */ u16 unk_1DA; - /* 0x1DC */ MsgScript* msgScript; - /* 0x1E0 */ s32 msgScriptPos; - /* 0x1E4 */ Player* shnPlayerRef; - /* 0x1E8 */ Vec3f unk_1E8; - /* 0x1F4 */ Vec3s unk_1F4; - /* 0x1FA */ Vec3s jointTable[BURLY_GUY_LIMB_MAX]; - /* 0x25A */ Vec3s morphTable[BURLY_GUY_LIMB_MAX]; - /* 0x2BA */ s16 unk_2BA; - /* 0x2BC */ s16 unk_2BC; - /* 0x2BE */ s16 unk_2BE; - /* 0x2C0 */ s16 unk_2C0; - /* 0x2C2 */ s16 unk_2C2; - /* 0x2C4 */ s16 unk_2C4; - /* 0x2C6 */ s16 unk_2C6; - /* 0x2C8 */ s16 unk_2C8; - /* 0x2CA */ s16 unk_2CA; - /* 0x2CC */ f32 animPlaySpeed; - /* 0x2D0 */ f32 unk_2D0; - /* 0x2D4 */ f32 unk_2D4; - /* 0x2D8 */ MsgScriptCallback msgScriptCallback; - /* 0x2DC */ s32 prevTalkState; - /* 0x2E0 */ s32 unk_2E0; - /* 0x2E4 */ s32 unk_2E4; - /* 0x2E8 */ s32 animIndex; - /* 0x2EC */ s32 unk_2EC; -} EnShn; // size = 0x2F0 - -static MsgScript D_80AE6F00[] = { - /* 0x0000 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_23_08, 0x0010 - 0x0005), - /* 0x0005 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09C4), - /* 0x0008 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0009 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09C5), - /* 0x000C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x000D 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_23_08), - /* 0x0010 0x03 */ MSCRIPT_CMD_CHECK_DEKU(0x019F - 0x0013), - /* 0x0013 0x03 */ MSCRIPT_CMD_CHECK_HUMAN(0x01A4 - 0x0016), - /* 0x0016 0x03 */ MSCRIPT_CMD_JUMP(0x019F - 0x0019), - /* 0x0019 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x00FF), - /* 0x001C 0x09 */ MSCRIPT_CMD_CHECK_ITEM_ACTION(PLAYER_IA_PICTOGRAPH_BOX, 0x0, 0x013A - 0x0025, 0x016C - 0x0025), - /* 0x0025 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x003A - 0x0028), - /* 0x0028 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x0044 - 0x002B), - /* 0x002B 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x005B - 0x002E), - /* 0x002E 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x008E - 0x0031), - /* 0x0031 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x00C7 - 0x0034), - /* 0x0034 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x006A - 0x0037), - /* 0x0037 0x03 */ MSCRIPT_CMD_JUMP(0x0081 - 0x003A), - /* 0x003A 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E7), - /* 0x003D 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x003E 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0041 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0042 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x0043 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0044 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09CB), - /* 0x0047 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0048 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x004B 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x004C 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CC), - /* 0x004F 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0050 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CD), - /* 0x0053 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0054 0x07 */ MSCRIPT_CMD_CHECK_TEXT_CHOICE(0x0100 - 0x005B, 0x0126 - 0x005B, 0x0126 - 0x005B), - /* 0x005B 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D1), - /* 0x005E 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x005F 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0062 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0063 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D2), - /* 0x0066 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0067 0x03 */ MSCRIPT_CMD_JUMP(0x0050 - 0x006A), - - /* 0x006A 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D3), - /* 0x006D 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x006E 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0071 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0072 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D4), - /* 0x0075 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0076 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D5), - /* 0x0079 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x007A 0x07 */ MSCRIPT_CMD_CHECK_TEXT_CHOICE(0x0113 - 0x0081, 0x0133 - 0x0081, 0x0133 - 0x0081), - /* 0x0081 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D9), - /* 0x0084 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0085 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0088 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0089 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DA), - /* 0x008C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x008D 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x008E 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E8), - /* 0x0091 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0092 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0095 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0096 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E9), - /* 0x0099 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x009A 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09EA), - /* 0x009D 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x009E 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_87_04, 0x00BA - 0x00A3), - /* 0x00A3 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00A4 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00A9 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x000C), - /* 0x00AC 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00AD 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_87_04), - /* 0x00B0 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x00B3 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09EB), - /* 0x00B6 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00B7 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00B8 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x00B9 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x00BA 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - // /* 0x00BB 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_SILVER, 0x0), - /* 0x00BB 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00C0 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0006), - /* 0x00C3 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00C4 0x03 */ MSCRIPT_CMD_AUTOTALK(0x00B3 - 0x00C7), - - /* 0x00C7 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09EC), - /* 0x00CA 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00CB 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x00CE 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00CF 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09ED), - /* 0x00D2 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00D3 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09EE), - /* 0x00D6 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00D7 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_87_04, 0x00F3 - 0x00DC), - /* 0x00DC 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00DD 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00E2 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x000C), - /* 0x00E5 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00E6 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_87_04), - /* 0x00E9 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x00EC 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09EF), - /* 0x00EF 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00F0 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00F1 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x00F2 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x00F3 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - // /* 0x00F4 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_SILVER, 0x0), - /* 0x00F4 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00F9 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0006), - /* 0x00FC 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00FD 0x03 */ MSCRIPT_CMD_AUTOTALK(0x00EC - 0x0100), - - /* 0x0100 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x0101 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_RED, 0x0), - /* 0x0106 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0004), - /* 0x0109 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x010A 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x010D 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09CE), - /* 0x0110 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0111 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x0112 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0113 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x0114 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_BLUE, 0x0), - /* 0x0119 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0002), - /* 0x011C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x011D 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x0120 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09D8), - /* 0x0123 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0124 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x0125 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0126 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0127 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CF), - /* 0x012A 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x012B 0x03 */ MSCRIPT_CMD_SET_EVENT_INF(EVENTINF_50), - /* 0x012E 0x01 */ MSCRIPT_CMD_PAUSE(), - /* 0x012F 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK(0x0), - /* 0x0132 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0133 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09D6), - /* 0x0136 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0137 0x03 */ MSCRIPT_CMD_JUMP(0x012B - 0x013A), - - /* 0x013A 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_55_40, 0x015B - 0x013F), - /* 0x013F 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09DB), - /* 0x0142 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0143 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0146 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0147 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DC), - /* 0x014A 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x014B 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DD), - /* 0x014E 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x014F 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DE), - /* 0x0152 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0153 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DF), - /* 0x0156 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0157 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_55_40), - /* 0x015A 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x015B 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E0), - /* 0x015E 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x015F 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0162 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0163 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E1), - /* 0x0166 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0167 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E2), - /* 0x016A 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x016B 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x016C 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_55_40, 0x0189 - 0x0171), - /* 0x0171 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09DB), - /* 0x0174 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0175 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DC), - /* 0x0178 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0179 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DD), - /* 0x017C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x017D 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DE), - /* 0x0180 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0181 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DF), - /* 0x0184 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0185 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_55_40), - /* 0x0188 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0189 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09E0), - /* 0x018C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x018D 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E1), - /* 0x0190 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0191 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E2), - /* 0x0194 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0195 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0196 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09C9), - /* 0x0199 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x019A 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CA), - /* 0x019D 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x019E 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x019F 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09C6), - /* 0x01A2 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x01A3 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x01A4 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE, 0x0196 - 0x01A9), - /* 0x01A9 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09C8), - /* 0x01AC 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x01AD 0x03 */ MSCRIPT_CMD_JUMP(0x0019 - 0x01B0), -}; - -static MsgScript D_80AE70B0[] = { - /* 0x0000 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09D0), - /* 0x0003 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0004 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x0005 0x01 */ MSCRIPT_CMD_DONE(), -}; - -static MsgScript D_80AE70B8[] = { - /* 0x0000 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x0015 - 0x0003), - /* 0x0003 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x001B - 0x0006), - /* 0x0006 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x0031 - 0x0009), - /* 0x0009 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x0061 - 0x000C), - /* 0x000C 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x0099 - 0x000F), - /* 0x000F 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK_CONTINUE(0x003F - 0x0012), - /* 0x0012 0x03 */ MSCRIPT_CMD_JUMP(0x0055 - 0x0015), - /* 0x0015 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E7), - /* 0x0018 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0019 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x001A 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x001B 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09CB), - /* 0x001E 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0021 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0022 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CC), - /* 0x0025 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0026 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CD), - /* 0x0029 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x002A 0x07 */ MSCRIPT_CMD_CHECK_TEXT_CHOICE(0x00D1 - 0x0031, 0x00F7 - 0x0031, 0x00F7 - 0x0031), - /* 0x0031 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D1), - /* 0x0034 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0037 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0038 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D2), - /* 0x003B 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x003C 0x03 */ MSCRIPT_CMD_JUMP(0x0026 - 0x003F), - - /* 0x003F 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D3), - /* 0x0042 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0045 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0046 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D4), - /* 0x0049 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x004A 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09D5), - /* 0x004D 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x004E 0x07 */ MSCRIPT_CMD_CHECK_TEXT_CHOICE(0x00E4 - 0x0055, 0x0104 - 0x0055, 0x0104 - 0x0055), - /* 0x0055 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09D9), - /* 0x0058 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x005B 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x005C 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DA), - /* 0x005F 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0060 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0061 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E8), - /* 0x0064 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0067 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0068 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E9), - /* 0x006B 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x006C 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09EA), - /* 0x006F 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0070 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_87_04, 0x008C - 0x0075), - /* 0x0075 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x0076 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x007B 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x000C), - /* 0x007E 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x007F 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_87_04), - /* 0x0082 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x0085 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09EB), - /* 0x0088 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0089 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x008A 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x008B 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x008C 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - // /* 0x008D 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_SILVER, 0x0), - /* 0x008D 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x0092 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0006), - /* 0x0095 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0096 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0085 - 0x0099), - - /* 0x0099 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09EC), - /* 0x009C 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x009F 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00A0 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09ED), - /* 0x00A3 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00A4 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09EE), - /* 0x00A7 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00A8 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_87_08, 0x00C4 - 0x00AD), - /* 0x00AD 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00AE 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00B3 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x000C), - /* 0x00B6 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00B7 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_87_08), - /* 0x00BA 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x00BD 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09EF), - /* 0x00C0 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00C1 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00C2 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x00C3 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x00C4 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - // /* 0x00C5 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_SILVER, 0x0), - /* 0x00C5 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_HEART_PIECE, 0x0), - /* 0x00CA 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0006), - /* 0x00CD 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00CE 0x03 */ MSCRIPT_CMD_AUTOTALK(0x00BD - 0x00D1), - - /* 0x00D1 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00D2 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_RED, 0x0), - /* 0x00D7 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0004), - /* 0x00DA 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00DB 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x00DE 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09CE), - /* 0x00E1 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00E2 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x00E3 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x00E4 0x01 */ MSCRIPT_CMD_CLOSE_TEXT(), - /* 0x00E5 0x05 */ MSCRIPT_CMD_OFFER_ITEM(GI_RUPEE_BLUE, 0x0), - /* 0x00EA 0x03 */ MSCRIPT_CMD_SET_COLLECTIBLE(0x0002), - /* 0x00ED 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00EE 0x03 */ MSCRIPT_CMD_AUTOTALK(0x0), - /* 0x00F1 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09D8), - /* 0x00F4 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00F5 0x01 */ MSCRIPT_CMD_UNSET_AUTOTALK(), - /* 0x00F6 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x00F7 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00F8 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09CF), - /* 0x00FB 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x00FC 0x03 */ MSCRIPT_CMD_SET_EVENT_INF(EVENTINF_50), - /* 0x00FF 0x01 */ MSCRIPT_CMD_PAUSE(), - /* 0x0100 0x03 */ MSCRIPT_CMD_CHECK_CALLBACK(0x0), - /* 0x0103 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0104 0x03 */ MSCRIPT_CMD_BEGIN_TEXT(0x09D6), - /* 0x0107 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0108 0x03 */ MSCRIPT_CMD_JUMP(0x00FC - 0x010B), -}; - -static MsgScript D_80AE71C4[] = { - /* 0x0000 0x05 */ MSCRIPT_CMD_CHECK_WEEK_EVENT_REG(WEEKEVENTREG_55_40, 0x0021 - 0x0005), - /* 0x0005 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09DB), - /* 0x0008 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0009 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x000C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x000D 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DC), - /* 0x0010 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0011 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DD), - /* 0x0014 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0015 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DE), - /* 0x0018 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0019 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09DF), - /* 0x001C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x001D 0x03 */ MSCRIPT_CMD_SET_WEEK_EVENT_REG(WEEKEVENTREG_55_40), - /* 0x0020 0x01 */ MSCRIPT_CMD_DONE(), - - /* 0x0021 0x03 */ MSCRIPT_CMD_PLAYER_TALK(0x09E0), - /* 0x0024 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0025 0x03 */ MSCRIPT_CMD_JUMP_3(0x0), - /* 0x0028 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0029 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E1), - /* 0x002C 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x002D 0x03 */ MSCRIPT_CMD_CONTINUE_TEXT(0x09E2), - /* 0x0030 0x01 */ MSCRIPT_CMD_AWAIT_TEXT(), - /* 0x0031 0x01 */ MSCRIPT_CMD_DONE(), -}; - -s32 func_80AE6704(Actor* thisx, PlayState* play); - -RECOMP_PATCH MsgScript* func_80AE6880(EnShn* this, PlayState* play) { -// RECOMP_PATCH MsgScript* EnShn_GetMsgScript(EnShn* this, PlayState* play) { - if (this->unk_2BE != 0) { - return D_80AE70B0; - } - if (this->unk_1D8 & 0x80) { - this->msgScriptCallback = func_80AE6704; - return D_80AE70B8; - } - if (this->unk_1D8 & 0x100) { - return D_80AE71C4; - } - this->msgScriptCallback = func_80AE6704; - return D_80AE6F00; -} \ No newline at end of file diff --git a/src/yaml_generation_menu.c b/src/yaml_generation_menu.c index 9fa2c3e..5a1fcc9 100644 --- a/src/yaml_generation_menu.c +++ b/src/yaml_generation_menu.c @@ -419,6 +419,12 @@ static EnumOptionValue treasure_chest_game_shuffle_options[] = { { "everything", NULL }, }; +static EnumOptionValue rando_shuffle_picture_rewards_options[] = { + { "disabled", NULL }, + { "winning_only", NULL }, + { "all_pictures", NULL } +}; + static EnumOptionValue rando_damage_multiplier_options[] = { { "half", NULL }, { "normal", NULL }, @@ -537,6 +543,7 @@ void randoCreateYamlConfigMenu() { randoCreateRadioOption(&yaml_config_menu, "shuffle_treasure_chest_game", "Treasure Chest Game Shuffle:", treasure_chest_game_shuffle_options, ARRAY_COUNT(treasure_chest_game_shuffle_options), 1); randoCreateIntSliderOption(&yaml_config_menu, "shuffle_beaver_races", "Shuffle Beaver Races:", 0, 2, 1, 0); randoCreateBoolPropOption(&yaml_config_menu, "shuffle_lottery", "Shuffle Lottery:", false); + randoCreateRadioOption(&yaml_config_menu, "shuffle_picture_rewards", "Shuffle Picture Rewards:", rando_shuffle_picture_rewards_options, ARRAY_COUNT(rando_shuffle_picture_rewards_options), 1); randoCreateBoolPropOption(&yaml_config_menu, "start_with_consumables", "Start With Consumables:", true); randoCreateBoolPropOption(&yaml_config_menu, "permanent_chateau_romani", "Permanent Chateau Romani:", true); randoCreateBoolPropOption(&yaml_config_menu, "start_with_inverted_time", "Start With Inverted Time:", true); diff --git a/src/zora_hooks.c b/src/zora_hooks.c index 093b910..e79760b 100644 --- a/src/zora_hooks.c +++ b/src/zora_hooks.c @@ -120,7 +120,10 @@ RECOMP_PATCH void func_80B9854C(EnZot* this, PlayState* play) { this->actor.flags |= ACTOR_FLAG_10000; Actor_OfferTalkExchange(&this->actor, play, 1000.0f, 1000.0f, PLAYER_IA_MINUS1); } else { - // Actor_OfferGetItem(&this->actor, play, this->unk_2D4, 10000.0f, 50.0f); - Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_ZORA_PICTOGRAPH), LOCATION_ZORA_PICTOGRAPH, 10000.0f, 50.0f, true, true); + if (rando_get_slotdata_u32("shuffle_picture_rewards") != 2) { + Actor_OfferGetItem(&this->actor, play, this->unk_2D4, 10000.0f, 50.0f); + } else { + Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_ZORA_PICTOGRAPH), LOCATION_ZORA_PICTOGRAPH, 10000.0f, 50.0f, true, true); + } } } \ No newline at end of file From 9e91eebd6cc3e0818d6001ab0058c98ddeb7eb5a Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Mon, 18 May 2026 20:42:27 -0300 Subject: [PATCH 12/19] Fixed swamp guide not giving silver rupee when picture rewards' disabled --- src/item_give.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/item_give.c b/src/item_give.c index 63b0e1d..eb54649 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -1416,6 +1416,7 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get Player* player = GET_PLAYER(play); u32 i; u8 item; + recomp_printf("Actor's getItemId: 0x%06X\n", getItemId); if (!(player->stateFlags1 & (PLAYER_STATE1_80 | PLAYER_STATE1_1000 | PLAYER_STATE1_2000 | PLAYER_STATE1_4000 | PLAYER_STATE1_40000 | @@ -1465,9 +1466,9 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get recomp_printf("Actor HP: 0x%06X\n", LOCATION_QUEST_HEART_PIECE); if (actor->id == ACTOR_ID_SWAMP_GUIDE) { if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { - itemWorkaround = false; + itemWorkaround = true; itemShuffled = false; - trueGI = getItemId; + trueGI = GI_RUPEE_SILVER; SET_WEEKEVENTREG(WEEKEVENTREG_87_08); } else { location_to_send = LOCATION_SWAMP_GUIDE_WINNER; @@ -1522,15 +1523,17 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get // Honey and Darling Any Day location_to_send = LOCATION_HONEY_AND_DARLING_ANY_DAY; trueGI = rando_get_item_id(LOCATION_HONEY_AND_DARLING_ANY_DAY); - //} else if (getItemId == GI_HEART_PIECE && actor->id == ACTOR_ID_SWAMP_GUIDE) { - // // Swamp Pictograph Contest Winning Picture - // if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { - // itemShuffled = false; - // getItemId = GI_RUPEE_SILVER; - // } else { - // location_to_send = LOCATION_SWAMP_GUIDE_WINNER; - // trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); - // } + } else if (getItemId == GI_RUPEE_SILVER && actor->id == ACTOR_ID_SWAMP_GUIDE) { + // Swamp Pictograph Contest Winning Picture + if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { + recomp_printf("The game detected that picture rewards shuffle is disabled."); + itemShuffled = false; + trueGI = GI_RUPEE_SILVER; + } else { + recomp_printf("The game detected that picture rewards shuffle is NOT disabled."); + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + } } else if (getItemId == GI_RUPEE_RED && actor->id == ACTOR_ID_SWAMP_GUIDE) { // && !rando_location_is_checked(LOCATION_SWAMP_GUIDE_GOOD)) { // Swamp Pictograph Contest Good Picture if (rando_get_slotdata_u32("shuffle_picture_rewards") != 2) { @@ -1560,12 +1563,7 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get if (itemShuffled) { player->getItemId = GI_DEED_LAND; } else { - if (getItemId == GI_HEART_PIECE && actor->id == ACTOR_ID_SWAMP_GUIDE && rando_get_slotdata_u32("shuffle_picture_rewards") == 0) - { - player->getItemId = GI_RUPEE_SILVER; - } else { - player->getItemId = getItemId; - } + player->getItemId = getItemId; } player->interactRangeActor = actor; player->getItemDirection = absYawDiff; From 725cc72eb04b9e4d17250edce241a8ab94d05593 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Tue, 21 Jul 2026 21:26:22 -0300 Subject: [PATCH 13/19] Finally fixed Tourist Center item sending The Tourist guide winning picture will properly give and display the correct item depending of circumstances. - If shuffle_picture_rewards is disabled: - When trying to give a heart piece, it will give a silver rupee instead; - When trying to give a silver rupee, it will still give a silver rupee. - If shuffle_picture_rewards is NOT disabled: - When trying to give a heart piece, it will give and display the randomized item; - When trying to give a silver rupee, but the location HAS NOT been sent (if the AP servers are borked or something), it will give and display the randomized item; - When trying to give a silver rupee and the location HAS been sent, it will give a silver rupee. --- src/item_give.c | 63 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/item_give.c b/src/item_give.c index eb54649..a0f5b2e 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -1412,6 +1412,8 @@ RECOMP_PATCH s32 Player_ActionChange_2(Player* this, PlayState* play) { extern bool rChecked[4]; +s16 swampWinningRewardBuffer = false; + RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId getItemId, f32 xzRange, f32 yRange) { Player* player = GET_PLAYER(play); u32 i; @@ -1454,8 +1456,9 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get (((item >= ITEM_POTION_RED) && (item <= ITEM_OBABA_DRINK) && (item != ITEM_CHATEAU)) || (item == ITEM_MILK) || (item == ITEM_CHATEAU_2) || (item == ITEM_GOLD_DUST_2) || (item == ITEM_HYLIAN_LOACH_2) || (item == ITEM_SEAHORSE_CAUGHT)) || - (actor->id == ACTOR_ID_SWAMP_GUIDE && (getItemId == GI_HEART_PIECE && rando_get_slotdata_u32("shuffle_picture_rewards") == 0) || - ((getItemId == GI_RUPEE_RED || getItemId == GI_RUPEE_BLUE) && rando_get_slotdata_u32("shuffle_picture_rewards") != 2) + ((actor->id == ACTOR_ID_SWAMP_GUIDE) && ((getItemId == GI_HEART_PIECE) && + ((rando_get_slotdata_u32("shuffle_picture_rewards") == 0) || ((rando_get_slotdata_u32("shuffle_picture_rewards") != 0) && (rando_location_is_checked(LOCATION_SWAMP_GUIDE_WINNER))))) || + (((getItemId == GI_RUPEE_RED) || (getItemId == GI_RUPEE_BLUE)) && (rando_get_slotdata_u32("shuffle_picture_rewards") != 2)) )) { } else { itemWorkaround = true; @@ -1465,14 +1468,35 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get if (getItemId == GI_HEART_PIECE) { recomp_printf("Actor HP: 0x%06X\n", LOCATION_QUEST_HEART_PIECE); if (actor->id == ACTOR_ID_SWAMP_GUIDE) { + recomp_printf("Swamp guide giving heart piece (winning reward check)\n"); if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { itemWorkaround = true; itemShuffled = false; trueGI = GI_RUPEE_SILVER; - SET_WEEKEVENTREG(WEEKEVENTREG_87_08); } else { - location_to_send = LOCATION_SWAMP_GUIDE_WINNER; - trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + if (rando_location_is_checked(LOCATION_SWAMP_GUIDE_WINNER)) { + if (swampWinningRewardBuffer == true) { + itemWorkaround = true; + itemShuffled = true; + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + SET_WEEKEVENTREG(WEEKEVENTREG_87_08); + swampWinningRewardBuffer = false; + } else { + recomp_printf("Winning picture location checked, give a silver rupee\n"); + itemWorkaround = true; + itemShuffled = false; + trueGI = GI_RUPEE_SILVER; + } + } else { + recomp_printf("Winning picture location not checked, send the randomized item\n"); + itemWorkaround = true; + itemShuffled = true; + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + SET_WEEKEVENTREG(WEEKEVENTREG_87_08); + swampWinningRewardBuffer = true; + } } } else { itemWorkaround = true; @@ -1524,15 +1548,36 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get location_to_send = LOCATION_HONEY_AND_DARLING_ANY_DAY; trueGI = rando_get_item_id(LOCATION_HONEY_AND_DARLING_ANY_DAY); } else if (getItemId == GI_RUPEE_SILVER && actor->id == ACTOR_ID_SWAMP_GUIDE) { + recomp_printf("Swamp guide giving silver rupee\n"); // Swamp Pictograph Contest Winning Picture if (rando_get_slotdata_u32("shuffle_picture_rewards") == 0) { - recomp_printf("The game detected that picture rewards shuffle is disabled."); + recomp_printf("The game detected that picture rewards shuffle is disabled\n"); itemShuffled = false; trueGI = GI_RUPEE_SILVER; } else { - recomp_printf("The game detected that picture rewards shuffle is NOT disabled."); - location_to_send = LOCATION_SWAMP_GUIDE_WINNER; - trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + recomp_printf("The game detected that picture rewards shuffle is NOT disabled\n"); + if (rando_location_is_checked(LOCATION_SWAMP_GUIDE_WINNER)) { + recomp_printf("Winning reward location is checked\n"); + if (swampWinningRewardBuffer == true) { + recomp_printf("Buffer is enabled: display the randomized item and disable the buffer\n"); + itemWorkaround = true; + itemShuffled = true; + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + swampWinningRewardBuffer = false; + } else { + recomp_printf("Buffer is disabled: display the silver rupee\n"); + itemShuffled = false; + trueGI = GI_RUPEE_SILVER; + } + } else { + recomp_printf("Winning reward location is not checked: send location and enable buffer"); + itemWorkaround = true; + itemShuffled = true; + location_to_send = LOCATION_SWAMP_GUIDE_WINNER; + trueGI = rando_get_item_id(LOCATION_SWAMP_GUIDE_WINNER); + swampWinningRewardBuffer = true; + } } } else if (getItemId == GI_RUPEE_RED && actor->id == ACTOR_ID_SWAMP_GUIDE) { // && !rando_location_is_checked(LOCATION_SWAMP_GUIDE_GOOD)) { // Swamp Pictograph Contest Good Picture From 58bed759d083992473a8ae119206060b2e8a9cad Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Wed, 22 Jul 2026 07:10:56 -0300 Subject: [PATCH 14/19] Added comments to explain the buffer for Southern Swamp Winning Picture --- src/item_give.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/item_give.c b/src/item_give.c index a0f5b2e..d96f3a9 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -1412,6 +1412,12 @@ RECOMP_PATCH s32 Player_ActionChange_2(Player* this, PlayState* play) { extern bool rChecked[4]; +/* + * For some reason, the game tries to send the Tourist Center winning picture check twice. It sends the randomized item + * properly the first time, but the second time, it either displays a grey AP item or a heart piece (vanilla reward). + * This buffer is there to make the game behave as if the second send acts as the first, mainly to display the + * randomized item. + */ s16 swampWinningRewardBuffer = false; RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId getItemId, f32 xzRange, f32 yRange) { From 1f78bf6b78f7394975053812db171d68585da448 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Thu, 23 Jul 2026 22:41:47 -0300 Subject: [PATCH 15/19] Modified option for third Progressive Magic for permanent magic --- mod.toml | 1 - src/init_save.c | 3 +-- src/item_give.c | 8 +++++--- src/play_main_hooks.c | 8 ++++++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/mod.toml b/mod.toml index 15829ea..c20eb11 100644 --- a/mod.toml +++ b/mod.toml @@ -54,7 +54,6 @@ native_libraries = [ "rando_is_magic_trap", "rando_get_camc_enabled", "rando_get_start_with_consumables_enabled", - "rando_get_permanent_chateau_romani_enabled", "rando_get_start_with_inverted_time_enabled", "rando_get_receive_filled_wallets_enabled", "rando_get_remains_allow_boss_warps_enabled", diff --git a/src/init_save.c b/src/init_save.c index bc98380..0dc8429 100644 --- a/src/init_save.c +++ b/src/init_save.c @@ -7,7 +7,6 @@ bool saveOpened = false; -RECOMP_IMPORT(".", bool rando_get_permanent_chateau_romani_enabled()); RECOMP_IMPORT(".", bool rando_get_start_with_consumables_enabled()); RECOMP_IMPORT(".", bool rando_get_start_with_inverted_time_enabled()); @@ -110,7 +109,7 @@ void Sram_SetInitialWeekEvents(void) { } // restore chateau romani state after cycle reset - if (drankChateau && rando_get_permanent_chateau_romani_enabled()) { + if ((drankChateau && rando_get_slotdata_u32("infinite_magic_behavior") == 1) || (rando_get_slotdata_u32("infinite_magic_behavior") == 2 && rando_has_item_async(AP_ITEM_ID_MAGIC) >= 3)) { SET_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI); drankChateau = false; } diff --git a/src/item_give.c b/src/item_give.c index d96f3a9..ee4f90a 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -1999,16 +1999,18 @@ u8 randoItemGive(u32 gi) { case 0x020000: switch (gi & 0xFF) { - case 0x00: - if (!gSaveContext.save.saveInfo.playerData.isMagicAcquired) { + case 0x00:if (gSaveContext.save.saveInfo.playerData.isMagicAcquired == false) { gSaveContext.save.saveInfo.playerData.isMagicAcquired = true; gSaveContext.magicFillTarget = MAGIC_NORMAL_METER; gSaveContext.save.saveInfo.playerData.magic = MAGIC_NORMAL_METER; - } else { + } else if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired == false) { gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired = true; gSaveContext.magicFillTarget = MAGIC_DOUBLE_METER; gSaveContext.save.saveInfo.playerData.magicLevel = 0; gSaveContext.save.saveInfo.playerData.magic = MAGIC_DOUBLE_METER; + } else if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired == true) { + SET_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI); + Magic_Add(play, MAGIC_FILL_TO_CAPACITY); } break; case 0x01: diff --git a/src/play_main_hooks.c b/src/play_main_hooks.c index b4b022d..acbcab2 100644 --- a/src/play_main_hooks.c +++ b/src/play_main_hooks.c @@ -5,6 +5,8 @@ #include "apcommon.h" #include "yaml_generation.h" +RECOMP_IMPORT("*", int recomp_printf(const char* fmt, ...)); + #define LOCATION_INVENTORY_SWORD 0x000037 #define LOCATION_INVENTORY_SHIELD 0x000032 @@ -425,6 +427,12 @@ void update_rando(PlayState* play) { randoItemGive(AP_ITEM_ID_MAGIC); } + if (new_magic_level >= 3) { + randoItemGive(AP_ITEM_ID_MAGIC); + SET_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI); + Magic_Add(play, MAGIC_FILL_TO_CAPACITY); + } + if (!rando_is_magic_trap()) { if (new_magic_level < 1) { gSaveContext.save.saveInfo.playerData.magic = 0; From a58824468683e0ab68a31bd839b73f5764ba9002 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Fri, 24 Jul 2026 18:25:28 -0300 Subject: [PATCH 16/19] Fixed bug that allowed to play H&D day 1 game (bombchus) with bomb bag instead of bombchu bag --- src/honey_and_darling_hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/honey_and_darling_hooks.c b/src/honey_and_darling_hooks.c index b598fed..f3513db 100644 --- a/src/honey_and_darling_hooks.c +++ b/src/honey_and_darling_hooks.c @@ -85,7 +85,7 @@ RECOMP_PATCH void func_809639D0(EnFu* this, PlayState* play) { switch (CURRENT_DAY) { case 1: if (GET_PLAYER_FORM == PLAYER_FORM_HUMAN) { - if (!INV_HAS(ITEM_BOMBCHU) && CUR_UPG_VALUE(UPG_BOMB_BAG) == 0) { + if (!INV_HAS(ITEM_BOMBCHU)) { Message_StartTextbox(play, 0x2853, &this->actor); this->unk_552 = 0x2853; } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_22_10)) { From 126175a4a762ccb969e58cff603484efcb4dc249 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sat, 25 Jul 2026 16:34:33 -0300 Subject: [PATCH 17/19] Changed glue imports for option settings to rando_get_slotdata_u32 This is mostly to prepare for whenever the APCpp glue gets abandoned in favor of the Python glue. --- include/apcommon.h | 1 - src/barten_hooks.c | 2 +- src/bombgoron_hooks.c | 4 ++-- src/cow_hooks.c | 6 +++--- src/door_warp1_hooks.c | 10 ++++------ src/game_over_hooks.c | 4 ++-- src/gorman_brothers_hooks.c | 8 ++++---- src/init_save.c | 7 ++----- src/item_give.c | 12 +++++------- src/item_text.c | 8 ++++---- src/menus.c | 3 +-- src/play_main_hooks.c | 21 +++++++++++++-------- src/shop_hooks.c | 20 ++++++++++---------- src/shop_item_hooks.c | 8 ++++---- src/skulltula_token_hooks.c | 8 ++++---- src/trade_scrub_hooks.c | 10 +++++----- 16 files changed, 64 insertions(+), 68 deletions(-) diff --git a/include/apcommon.h b/include/apcommon.h index bb60aab..a3f7e83 100644 --- a/include/apcommon.h +++ b/include/apcommon.h @@ -122,7 +122,6 @@ RECOMP_IMPORT(".", bool rando_get_death_link_pending()); RECOMP_IMPORT(".", void rando_reset_death_link_pending()); RECOMP_IMPORT(".", bool rando_get_death_link_enabled()); RECOMP_IMPORT(".", void rando_send_death_link()); -RECOMP_IMPORT(".", u32 rando_damage_multiplier()); RECOMP_IMPORT(".", u32 rando_death_behavior()); RECOMP_IMPORT(".", u32 rando_get_moon_remains_required()); RECOMP_IMPORT(".", u32 rando_get_majora_remains_required()); diff --git a/src/barten_hooks.c b/src/barten_hooks.c index 5affbdc..0dce852 100644 --- a/src/barten_hooks.c +++ b/src/barten_hooks.c @@ -5,5 +5,5 @@ // why is this a seperate function??? RECOMP_PATCH s32 func_80BE0D38(Actor* thisx, PlayState* play) { - return rando_shopsanity_enabled() || Inventory_HasEmptyBottle(); + return rando_get_slotdata_u32("shopsanity") || Inventory_HasEmptyBottle(); } \ No newline at end of file diff --git a/src/bombgoron_hooks.c b/src/bombgoron_hooks.c index 97c3219..bd16b5d 100644 --- a/src/bombgoron_hooks.c +++ b/src/bombgoron_hooks.c @@ -240,7 +240,7 @@ RECOMP_PATCH u16 EnSGoro_BombshopGoron_NextTextId(EnSGoro* this, PlayState* play case 0x670: if (this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_YESBUY) { - if (AMMO(ITEM_POWDER_KEG) != 0 && (rando_location_is_checked(LOCATION_BOMBSHOP_KEG) || !rando_shopsanity_enabled())) { + if (AMMO(ITEM_POWDER_KEG) != 0 && (rando_location_is_checked(LOCATION_BOMBSHOP_KEG) || !rando_get_slotdata_u32("shopsanity"))) { this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; Audio_PlaySfx(NA_SE_SY_ERROR); return 0x673; @@ -323,7 +323,7 @@ RECOMP_PATCH void EnSGoro_ShopGoron_Talk(EnSGoro* this, PlayState* play) { if ((this->textId == 0x675) || (this->textId == 0x676)) { play->msgCtx.msgMode = MSGMODE_TEXT_CLOSING; play->msgCtx.stateTimer = 4; - if (rando_location_is_checked(LOCATION_BOMBSHOP_KEG) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_BOMBSHOP_KEG) || !rando_get_slotdata_u32("shopsanity")) { this->actionFunc = EnSGoro_ShopGoron_TakePayment; } else { this->actionFunc = EnSGoro_ShopGoron_GiveRandoItem; diff --git a/src/cow_hooks.c b/src/cow_hooks.c index 5fb2abd..11fe67e 100644 --- a/src/cow_hooks.c +++ b/src/cow_hooks.c @@ -142,7 +142,7 @@ RECOMP_PATCH void EnCow_GiveMilkWait(EnCow* this, PlayState* play) { this->actor.parent = NULL; this->actionFunc = EnCow_GiveMilkEnd; } else { - if (rando_location_is_checked(LOCATION_COW) || !rando_cows_enabled()) { + if (rando_location_is_checked(LOCATION_COW) || !rando_get_slotdata_u32("cowsanity")) { Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 100.0f); } else { Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_COW), LOCATION_COW, 300.0f, 300.0f, true, true); @@ -155,7 +155,7 @@ RECOMP_PATCH void EnCow_GiveMilk(EnCow* this, PlayState* play) { this->actor.flags &= ~ACTOR_FLAG_10000; Message_CloseTextbox(play); this->actionFunc = EnCow_GiveMilkWait; - if (rando_location_is_checked(LOCATION_COW) || !rando_cows_enabled()) { + if (rando_location_is_checked(LOCATION_COW) || !rando_get_slotdata_u32("cowsanity")) { Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 100.0f); } else { Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_COW), LOCATION_COW, 300.0f, 300.0f, true, true); @@ -167,7 +167,7 @@ void EnCow_TalkEnd(EnCow* this, PlayState* play); RECOMP_PATCH void EnCow_CheckForEmptyBottle(EnCow* this, PlayState* play) { if ((Message_GetState(&play->msgCtx) == TEXT_STATE_5) && Message_ShouldAdvance(play)) { - if (Inventory_HasEmptyBottle() || rando_cows_enabled()) { + if (Inventory_HasEmptyBottle() || rando_get_slotdata_u32("cowsanity")) { Message_ContinueTextbox(play, 0x32C9); // Text to give milk. this->actionFunc = EnCow_GiveMilk; } else { diff --git a/src/door_warp1_hooks.c b/src/door_warp1_hooks.c index dcb1403..5087a6c 100644 --- a/src/door_warp1_hooks.c +++ b/src/door_warp1_hooks.c @@ -3,8 +3,6 @@ #include "apcommon.h" -RECOMP_IMPORT(".", bool rando_get_remains_allow_boss_warps_enabled()); - struct DoorWarp1; #define FLAGS 0x00000000 @@ -249,16 +247,16 @@ RECOMP_PATCH void func_808B8C48(DoorWarp1* this, PlayState* play) { Lights_PointNoGlowSetInfo(&this->unk_1F4, this->dyna.actor.world.pos.x, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 200, 255, 255, 255); if (((DOORWARP1_GET_FF(&this->dyna.actor) == ENDOORWARP1_FF_2) - && ((CHECK_QUEST_ITEM(QUEST_REMAINS_ODOLWA) && rando_get_remains_allow_boss_warps_enabled()) + && ((CHECK_QUEST_ITEM(QUEST_REMAINS_ODOLWA) && rando_get_slotdata_u32("remains_allow_boss_warps")) || rando_location_is_checked(LOCATION_REMAINS_ODOLWA))) || ((DOORWARP1_GET_FF(&this->dyna.actor) == ENDOORWARP1_FF_3) - && ((CHECK_QUEST_ITEM(QUEST_REMAINS_GOHT) && rando_get_remains_allow_boss_warps_enabled()) + && ((CHECK_QUEST_ITEM(QUEST_REMAINS_GOHT) && rando_get_slotdata_u32("remains_allow_boss_warps")) || rando_location_is_checked(LOCATION_REMAINS_GOHT))) || ((DOORWARP1_GET_FF(&this->dyna.actor) == ENDOORWARP1_FF_4) - && ((CHECK_QUEST_ITEM(QUEST_REMAINS_GYORG) && rando_get_remains_allow_boss_warps_enabled()) + && ((CHECK_QUEST_ITEM(QUEST_REMAINS_GYORG) && rando_get_slotdata_u32("remains_allow_boss_warps")) || rando_location_is_checked(LOCATION_REMAINS_GYORG))) || ((DOORWARP1_GET_FF(&this->dyna.actor) == ENDOORWARP1_FF_5) - && ((CHECK_QUEST_ITEM(QUEST_REMAINS_TWINMOLD) && rando_get_remains_allow_boss_warps_enabled()) + && ((CHECK_QUEST_ITEM(QUEST_REMAINS_TWINMOLD) && rando_get_slotdata_u32("remains_allow_boss_warps")) || rando_location_is_checked(LOCATION_REMAINS_TWINMOLD)))) { s16 params = DOORWARP1_GET_FF00_2(&this->dyna.actor); diff --git a/src/game_over_hooks.c b/src/game_over_hooks.c index 5c4e340..fc09a14 100644 --- a/src/game_over_hooks.c +++ b/src/game_over_hooks.c @@ -59,7 +59,7 @@ RECOMP_PATCH void GameOver_Update(PlayState* play) { break; case GAMEOVER_DEATH_FADE_OUT: - if (AudioSeq_GetActiveSeqId(SEQ_PLAYER_FANFARE) != NA_BGM_GAME_OVER || rando_death_behavior() >= 1) { + if (AudioSeq_GetActiveSeqId(SEQ_PLAYER_FANFARE) != NA_BGM_GAME_OVER || rando_get_slotdata_u32("death_behavior") >= 1) { func_80169F78(&play->state); if (gSaveContext.respawnFlag != -7) { gSaveContext.respawnFlag = -6; @@ -132,7 +132,7 @@ RECOMP_PATCH void func_80831F34(PlayState* play, Player* this, PlayerAnimationHe Player_SetAction(play, this, sp24 ? Player_Action_62 : Player_Action_24, 0); Player_AnimationPlayOnce(play, this, anim); - if (rando_death_behavior() >= 2) { + if (rando_get_slotdata_u32("death_behavior") >= 2) { this->skelAnime.endFrame = 0.0f; } else { if (anim == &gPlayerAnim_link_derth_rebirth) { diff --git a/src/gorman_brothers_hooks.c b/src/gorman_brothers_hooks.c index 6112206..93dd545 100644 --- a/src/gorman_brothers_hooks.c +++ b/src/gorman_brothers_hooks.c @@ -257,7 +257,7 @@ RECOMP_PATCH s32 func_808F4414(PlayState* play, EnIn* this, s32 arg2) { if (msgCtx->choiceIndex == 0) { Audio_PlaySfx_MessageDecide(); if (gSaveContext.save.saveInfo.playerData.rupees >= play->msgCtx.unk1206C) { - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { this->actionFunc = func_808F3C40; Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_GORMAN_MILK), LOCATION_GORMAN_MILK, 500.0f, 100.0f, true, true); Rupees_ChangeBy(-play->msgCtx.unk1206C); @@ -435,7 +435,7 @@ RECOMP_PATCH s32 func_808F4414(PlayState* play, EnIn* this, s32 arg2) { case 0x347E: func_808F35D8(this, play); - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { this->actionFunc = func_808F3B40; Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_GORMAN_MILK), LOCATION_GORMAN_MILK, 500.0f, 100.0f, true, true); ret = true; @@ -570,7 +570,7 @@ RECOMP_PATCH s32 func_808F4414(PlayState* play, EnIn* this, s32 arg2) { if (msgCtx->choiceIndex == 0) { Audio_PlaySfx_MessageDecide(); if (gSaveContext.save.saveInfo.playerData.rupees >= play->msgCtx.unk1206C) { - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { this->actionFunc = func_808F3C40; Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_GORMAN_MILK), LOCATION_GORMAN_MILK, 500.0f, 100.0f, true, true); Rupees_ChangeBy(-play->msgCtx.unk1206C); @@ -689,7 +689,7 @@ RECOMP_PATCH s32 func_808F4414(PlayState* play, EnIn* this, s32 arg2) { case 0x34A1: func_808F35D8(this, play); - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_GORMAN_MILK)) { this->actionFunc = func_808F3B40; Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_GORMAN_MILK), LOCATION_GORMAN_MILK, 500.0f, 100.0f, true, true); ret = true; diff --git a/src/init_save.c b/src/init_save.c index 0dc8429..56fbdf2 100644 --- a/src/init_save.c +++ b/src/init_save.c @@ -7,9 +7,6 @@ bool saveOpened = false; -RECOMP_IMPORT(".", bool rando_get_start_with_consumables_enabled()); -RECOMP_IMPORT(".", bool rando_get_start_with_inverted_time_enabled()); - RECOMP_CALLBACK("*", recomp_on_load_save) void rando_on_load_save(FileSelectState* fileSelect, SramContext* sramCtx) { saveOpened = true; @@ -125,7 +122,7 @@ RECOMP_PATCH void Sram_InitNewSave(void) { gSaveContext.save.hasTatl = true; - if (rando_get_start_with_consumables_enabled()) { + if (rando_get_slotdata_u32("start_with_consumables")) { // start with basic consumables gSaveContext.save.saveInfo.playerData.rupees = gUpgradeCapacities[UPG_WALLET][0]; gSaveContext.save.saveInfo.inventory.items[SLOT_DEKU_STICK] = ITEM_DEKU_STICK; @@ -134,7 +131,7 @@ RECOMP_PATCH void Sram_InitNewSave(void) { gSaveContext.save.saveInfo.inventory.ammo[SLOT_DEKU_NUT] = 20; } - if (rando_get_start_with_inverted_time_enabled()) { + if (rando_get_slotdata_u32("start_with_inverted_time")) { gSaveContext.save.timeSpeedOffset = -2; } diff --git a/src/item_give.c b/src/item_give.c index ee4f90a..bda8e55 100644 --- a/src/item_give.c +++ b/src/item_give.c @@ -6,8 +6,6 @@ #include "apcommon.h" -RECOMP_IMPORT(".", bool rando_get_receive_filled_wallets_enabled()); - extern s16 sExtraItemBases[]; extern s16 sAmmoRefillCounts[]; extern s16 sBombchuRefillCounts[]; @@ -1528,13 +1526,13 @@ RECOMP_PATCH s32 Actor_OfferGetItem(Actor* actor, PlayState* play, GetItemId get itemShuffled = true; trueGI = rando_get_item_id(LOCATION_QUEST_BOTTLE); location_to_send = LOCATION_QUEST_BOTTLE; - } else if (getItemId == GI_MILK && actor->id == ACTOR_ID_BARTEN && !rando_location_is_checked(LOCATION_MILK) && rando_shopsanity_enabled()) { + } else if (getItemId == GI_MILK && actor->id == ACTOR_ID_BARTEN && !rando_location_is_checked(LOCATION_MILK) && rando_get_slotdata_u32("shopsanity")) { // Milk Bar Milk Purchase itemWorkaround = true; itemShuffled = true; location_to_send = LOCATION_MILK; trueGI = rando_get_item_id(LOCATION_MILK); - } else if (getItemId == GI_CHATEAU && actor->id == ACTOR_ID_BARTEN && !rando_location_is_checked(GI_CHATEAU) && rando_shopsanity_enabled()) { + } else if (getItemId == GI_CHATEAU && actor->id == ACTOR_ID_BARTEN && !rando_location_is_checked(GI_CHATEAU) && rando_get_slotdata_u32("shopsanity")) { // Milk Bar Chateau Purchase itemWorkaround = true; itemShuffled = true; @@ -2234,19 +2232,19 @@ u8 randoItemGive(u32 gi) { } else if (item == ITEM_WALLET_ADULT) { if (CUR_UPG_VALUE(UPG_WALLET) == 2) { // stop sending yourself wallets you freaks - if (rando_get_receive_filled_wallets_enabled()) { + if (rando_get_slotdata_u32("receive_filled_wallets")) { Rupees_ChangeBy(gUpgradeCapacities[UPG_WALLET][3]); // you can get money though } return ITEM_NONE; } else if (CUR_UPG_VALUE(UPG_WALLET) == 1) { Inventory_ChangeUpgrade(UPG_WALLET, 2); - if (rando_get_receive_filled_wallets_enabled()) { + if (rando_get_slotdata_u32("receive_filled_wallets")) { Rupees_ChangeBy(gUpgradeCapacities[UPG_WALLET][2]); } return ITEM_NONE; } Inventory_ChangeUpgrade(UPG_WALLET, 1); - if (rando_get_receive_filled_wallets_enabled()) { + if (rando_get_slotdata_u32("receive_filled_wallets")) { Rupees_ChangeBy(gUpgradeCapacities[UPG_WALLET][1]); } return ITEM_NONE; diff --git a/src/item_text.c b/src/item_text.c index ecbf58a..2cd60ed 100644 --- a/src/item_text.c +++ b/src/item_text.c @@ -133,7 +133,7 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { // recomp_printf("text id: 0x%04X\n", textId); - if (textId == 0x52 && rando_skulltulas_enabled()) { + if (textId == 0x52 && rando_get_slotdata_u32("skullsanity") != 2) { textId = 0x75; } @@ -463,7 +463,7 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { font->msgBuf.schar[0] = 0x00; } - if ((textId & 0xFF00) == 0x3600 || (textId & 0xFF00) == 0x3700 || (textId == 0x0880 && rando_shopsanity_enabled() && !rando_location_is_checked_async(0x090002))) { + if ((textId & 0xFF00) == 0x3600 || (textId & 0xFF00) == 0x3700 || (textId == 0x0880 && rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked_async(0x090002))) { msg = shop_msg; font->msgBuf.schar[0] = 0x06; font->msgBuf.schar[1] = 0x30; @@ -482,7 +482,7 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { u8 count_str[128] = "\x11This is your \xbf"; u8 count_done_str[128] = "\x11You've found all of them!\xbf"; u8* count_msg = count_str; - u8 swamp_token_count = ((rando_skulltulas_enabled()) ? rando_has_item(GI_TRUE_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x27)); + u8 swamp_token_count = ((rando_get_slotdata_u32("skullsanity") != 2) ? rando_has_item(GI_TRUE_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x27)); if (swamp_token_count >= 30) { count_msg = count_done_str; } @@ -523,7 +523,7 @@ RECOMP_PATCH void Message_OpenText(PlayState* play, u16 textId) { u8 count_str[128] = "\x11This is your \xbf"; u8 count_done_str[128] = "\x11You've found all of them!\xbf"; u8* count_msg = count_str; - u8 ocean_token_count = ((rando_skulltulas_enabled()) ? rando_has_item(GI_OCEAN_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x28)); + u8 ocean_token_count = ((rando_get_slotdata_u32("skullsanity") != 2) ? rando_has_item(GI_OCEAN_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x28)); if (ocean_token_count >= 30) { count_msg = count_done_str; } diff --git a/src/menus.c b/src/menus.c index d5baac1..7cae0f5 100644 --- a/src/menus.c +++ b/src/menus.c @@ -72,7 +72,6 @@ void createUiFrame(RecompuiContext context, UiFrame* frame) { #define C_TO_PARAMS(c) (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF -RECOMP_IMPORT(".", int rando_get_tunic_color()); RECOMP_IMPORT("mm_recomp_colors", void colors_set_human_tunic(u8 r, u8 g, u8 b)); RECOMP_DECLARE_EVENT(rando_on_connect()); @@ -109,7 +108,7 @@ void RandoMenu_Main(GameState* thisx) { } recomp_change_save_file(file_name); - colors_set_human_tunic(C_TO_PARAMS(rando_get_tunic_color())); + colors_set_human_tunic(C_TO_PARAMS(rando_get_slotdata_u32("link_tunic_color"))); rando_on_connect(); Setup_InitImpl(this); } diff --git a/src/play_main_hooks.c b/src/play_main_hooks.c index acbcab2..8e7f5bd 100644 --- a/src/play_main_hooks.c +++ b/src/play_main_hooks.c @@ -18,9 +18,6 @@ RECOMP_IMPORT("*", int recomp_set_no_bow_epona_fix(bool new_val)); RECOMP_IMPORT("*", int recomp_set_allow_no_ocarina_tf(bool new_val)); RECOMP_IMPORT("*", int recomp_set_h_and_d_no_sword_fix(bool new_val)); -RECOMP_IMPORT(".", int rando_get_starting_heart_locations()); -RECOMP_IMPORT(".", int rando_get_tunic_color()); - RECOMP_IMPORT("mm_recomp_better_double_sot", void dsot_set_skip_dsot_cutscene(bool new_val)); RECOMP_IMPORT("mm_recomp_colors", void colors_set_human_tunic(u8 r, u8 g, u8 b)); @@ -247,6 +244,14 @@ u32 old_items_size; bool waiting_death_link = false; bool sending_death_link = false; +s16 rando_damage_multiplier() { + u32 multiplier_option = rando_get_slotdata_u32("damage_multiplier"); + if (multiplier_option == 4) { + return 0xF; + } + return multiplier_option; +} + /** * @return false if player is out of health */ @@ -283,7 +288,7 @@ RECOMP_PATCH s32 Health_ChangeBy(PlayState* play, s16 healthChange) { rando_send_death_link(); } - if (rando_death_behavior() == 3) { + if (rando_get_slotdata_u32("death_behavior") == 3) { Interface_StartMoonCrash(play); } @@ -324,7 +329,7 @@ s32 Health_ChangeBy_NoSound(PlayState* play, s16 healthChange) { rando_send_death_link(); } - if (rando_death_behavior() == 3) { + if (rando_get_slotdata_u32("death_behavior") == 3) { Interface_StartMoonCrash(play); } @@ -433,7 +438,7 @@ void update_rando(PlayState* play) { Magic_Add(play, MAGIC_FILL_TO_CAPACITY); } - if (!rando_is_magic_trap()) { + if (!rando_get_slotdata_u32("magic_is_a_trap")) { if (new_magic_level < 1) { gSaveContext.save.saveInfo.playerData.magic = 0; } @@ -560,7 +565,7 @@ void update_rando(PlayState* play) { rando_send_location(LOCATION_INVENTORY_SWORD); rando_send_location(LOCATION_INVENTORY_SHIELD); - for (int i = 0; i < rando_get_starting_heart_locations(); ++i) + for (int i = 0; i < rando_get_slotdata_u32("starting_heart_locations"); ++i) { rando_send_location(0x0D0000 | i); } @@ -587,7 +592,7 @@ void update_rando(PlayState* play) { if (play->pauseCtx.state == 0 && rando_get_death_link_enabled() && rando_get_death_link_pending()) { Play_KillPlayer(); - if (rando_death_behavior() == 3) { + if (rando_get_slotdata_u32("death_behavior") == 3) { Interface_StartMoonCrash(play); } rando_reset_death_link_pending(); diff --git a/src/shop_hooks.c b/src/shop_hooks.c index 8b7ffa4..9a974e3 100644 --- a/src/shop_hooks.c +++ b/src/shop_hooks.c @@ -270,7 +270,7 @@ RECOMP_PATCH void EnFsn_GiveItem(EnFsn* this, PlayState* play) { this->actionFunc = EnFsn_SetupResumeInteraction; this->getItemId = 0; } else if (this->isSelling == true) { - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -279,7 +279,7 @@ RECOMP_PATCH void EnFsn_GiveItem(EnFsn* this, PlayState* play) { if (this->getItemId == GI_MASK_KEATON || this->getItemId == GI_LETTER_TO_MAMA) { Actor_OfferGetItem(&this->actor, play, this->getItemId, 300.0f, 300.0f); } else { - if (!rando_get_curiostity_shop_trades() || rando_location_is_checked(LOCATION_FSN_RUPEE)) { + if (!rando_get_slotdata_u32("curiostity_shop_trades") || rando_location_is_checked(LOCATION_FSN_RUPEE)) { Actor_OfferGetItem(&this->actor, play, this->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, rando_get_item_id(LOCATION_FSN_RUPEE), LOCATION_FSN_RUPEE, 300.0f, 300.0f, true, true); @@ -304,7 +304,7 @@ RECOMP_PATCH void EnFsn_HandleCanPlayerBuyItem(EnFsn* this, PlayState* play) { Audio_PlaySfx_MessageDecide(); item = this->items[this->cursorIndex]; item->buyFanfareFunc(play, item); - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -353,7 +353,7 @@ RECOMP_PATCH void EnOssan_BuyItemWithFanfare(EnOssan* this, PlayState* play) { this->actor.parent = NULL; EnOssan_SetupAction(this, EnOssan_SetupItemPurchased); } else { - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -364,7 +364,7 @@ RECOMP_PATCH void EnOssan_BuyItemWithFanfare(EnOssan* this, PlayState* play) { RECOMP_PATCH void EnOssan_SetupBuyItemWithFanfare(PlayState* play, EnOssan* this) { Player* player = GET_PLAYER(play); - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -387,7 +387,7 @@ RECOMP_PATCH void EnSob1_BuyItemWithFanfare(EnSob1* this, PlayState* play) { this->actor.parent = NULL; EnSob1_SetupAction(this, EnSob1_SetupItemPurchased); } else { - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -398,7 +398,7 @@ RECOMP_PATCH void EnSob1_BuyItemWithFanfare(EnSob1* this, PlayState* play) { RECOMP_PATCH void EnSob1_SetupBuyItemWithFanfare(PlayState* play, EnSob1* this) { Player* player = GET_PLAYER(play); - if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_shopsanity_enabled()) { + if (rando_location_is_checked(LOCATION_SHOP_ITEM) || !rando_get_slotdata_u32("shopsanity")) { Actor_OfferGetItem(&this->actor, play, this->items[this->cursorIndex]->getItemId, 300.0f, 300.0f); } else { Actor_OfferGetItemHook(&this->actor, play, this->items[this->cursorIndex]->getItemId, LOCATION_SHOP_ITEM, 300.0f, 300.0f, true, true); @@ -439,7 +439,7 @@ void EnTrt_VanillaBuyItemWithFanfare(EnTrt* this, PlayState* play) { } RECOMP_PATCH void EnTrt_BuyItemWithFanfare(EnTrt* this, PlayState* play) { - if (!rando_shopsanity_enabled() || rando_location_is_checked(location_to_buy)) { + if (!rando_get_slotdata_u32("shopsanity") || rando_location_is_checked(location_to_buy)) { EnTrt_VanillaBuyItemWithFanfare(this, play); } else { EnTrt_ShopsanityBuyItemWithFanfare(this, play); @@ -582,7 +582,7 @@ RECOMP_PATCH void EnTrt_SelectItem(EnTrt* this, PlayState* play) { if (!EnTrt_TestCancelOption(this, play, CONTROLLER1(&play->state)) && Message_ShouldAdvance(play)) { switch (play->msgCtx.choiceIndex) { case 0: - kotake_is_weird = rando_shopsanity_enabled() && !shopItemIsChecked(item, play); + kotake_is_weird = rando_get_slotdata_u32("shopsanity") && !shopItemIsChecked(item, play); EnTrt_HandleCanBuyItem(play, this); break; @@ -598,7 +598,7 @@ RECOMP_PATCH void EnTrt_SelectItem(EnTrt* this, PlayState* play) { } } else if ((talkState == TEXT_STATE_5) && Message_ShouldAdvance(play)) { // if (!Inventory_HasEmptyBottle()) { - if (!Inventory_HasEmptyBottle() && (rando_location_is_checked(location_to_buy) || !rando_shopsanity_enabled())) { + if (!Inventory_HasEmptyBottle() && (rando_location_is_checked(location_to_buy) || !rando_get_slotdata_u32("shopsanity"))) { Audio_PlaySfx(NA_SE_SY_ERROR); EnTrt_SetupCannotBuy(play, this, 0x846); } else { diff --git a/src/shop_item_hooks.c b/src/shop_item_hooks.c index 3b79754..956ff66 100644 --- a/src/shop_item_hooks.c +++ b/src/shop_item_hooks.c @@ -61,7 +61,7 @@ void EnGirlA_WaitForObject(EnGirlA* this, PlayState* play) { RECOMP_PATCH void EnGirlA_Update(Actor* thisx, PlayState* play) { EnGirlA* this = THIS; - if (!shopObjectLoaded[this->actor.params] && rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_SHOP_ITEM)) { + if (!shopObjectLoaded[this->actor.params] && rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_SHOP_ITEM)) { EnGirlA_WaitForObject(this, play); } @@ -76,7 +76,7 @@ RECOMP_PATCH void EnGirlA_Draw(Actor* thisx, PlayState* play) { this->drawFunc(&this->actor, play, 0); } - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_SHOP_ITEM)) { + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_SHOP_ITEM)) { s16 getItemId = rando_get_item_id(LOCATION_SHOP_ITEM); if (shopObjectLoaded[this->actor.params]) { // fix rotation of some items @@ -168,7 +168,7 @@ void EnGirlA_RandoBuyFanfare(PlayState* play, EnGirlA* this) { } RECOMP_PATCH void EnGirlA_InitItem(PlayState* play, EnGirlA* this) { - if (!rando_shopsanity_enabled() || rando_location_is_checked(LOCATION_SHOP_ITEM)) { + if (!rando_get_slotdata_u32("shopsanity") || rando_location_is_checked(LOCATION_SHOP_ITEM)) { ShopItemEntry* shopItem = &sShopItemEntries[this->actor.params]; this->actor.textId = shopItem->descriptionTextId; @@ -190,7 +190,7 @@ RECOMP_PATCH void EnGirlA_InitItem(PlayState* play, EnGirlA* this) { RECOMP_PATCH void EnGirlA_InitalUpdate(EnGirlA* this, PlayState* play) { s16 params = this->actor.params; - if (rando_shopsanity_enabled() && !rando_location_is_checked(LOCATION_SHOP_ITEM) + if (rando_get_slotdata_u32("shopsanity") && !rando_location_is_checked(LOCATION_SHOP_ITEM) && !(this->actor.params == SI_BOTTLE || this->actor.params == SI_SWORD_GREAT_FAIRY || this->actor.params == SI_SWORD_KOKIRI || diff --git a/src/skulltula_token_hooks.c b/src/skulltula_token_hooks.c index 20ddae6..0d18ff1 100644 --- a/src/skulltula_token_hooks.c +++ b/src/skulltula_token_hooks.c @@ -8,7 +8,7 @@ RECOMP_IMPORT("*", int recomp_printf(const char* fmt, ...)); #define ENSI_GET_CHEST_FLAG(thisx) (((thisx)->params & 0xFC) >> 2) #define LOCATION_SKULL_TOKEN (0x060000 | (play->sceneId << 8) | ENSI_GET_CHEST_FLAG(&this->actor)) -#define GET_GI_TOKEN ((rando_skulltulas_enabled()) ? rando_get_item_id(LOCATION_SKULL_TOKEN) : GI_SKULL_TOKEN) +#define GET_GI_TOKEN ((rando_get_slotdata_u32("skullsanity") != 2) ? rando_get_item_id(LOCATION_SKULL_TOKEN) : GI_SKULL_TOKEN) #define SPIDER_HOUSE_TOKENS_REQUIRED 30 @@ -117,7 +117,7 @@ void EnSi_TokenCollected(EnSi* this, PlayState* play) { RECOMP_PATCH void EnSi_GiveToken(EnSi* this, PlayState* play) { Player* player = GET_PLAYER(play); s32 chestFlag = ENSI_GET_CHEST_FLAG(&this->actor); - u8 swamp_token_count = (rando_skulltulas_enabled() ? rando_has_item(GI_TRUE_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x27)); + u8 swamp_token_count = (rando_get_slotdata_u32("skullsanity") != 2 ? rando_has_item(GI_TRUE_SKULL_TOKEN) : Inventory_GetSkullTokenCount(0x27)); if ((chestFlag < 0x20) && (chestFlag >= 0)) { Flags_SetTreasure(play, chestFlag); @@ -126,7 +126,7 @@ RECOMP_PATCH void EnSi_GiveToken(EnSi* this, PlayState* play) { tokenPickedUp[chestFlag] = true; recomp_printf("token location: 0x%06X\n", LOCATION_SKULL_TOKEN); - if (rando_skulltulas_enabled()) { + if (rando_get_slotdata_u32("skullsanity") != 2) { rando_send_location(LOCATION_SKULL_TOKEN); Message_StartTextbox(play, getTextId(tokenPrevGI[chestFlag]), NULL); Audio_PlayFanfare(NA_BGM_GET_SMALL_ITEM); @@ -193,7 +193,7 @@ RECOMP_PATCH void EnSi_Init(Actor* thisx, PlayState* play) { EnSi* this = THIS; s32 chestFlag = ENSI_GET_CHEST_FLAG(&this->actor); - if (rando_skulltulas_enabled() && rando_location_is_checked(LOCATION_SKULL_TOKEN)) { + if (rando_get_slotdata_u32("skullsanity") != 2 && rando_location_is_checked(LOCATION_SKULL_TOKEN)) { Actor_Kill(thisx); return; } diff --git a/src/trade_scrub_hooks.c b/src/trade_scrub_hooks.c index e852345..2f80d52 100644 --- a/src/trade_scrub_hooks.c +++ b/src/trade_scrub_hooks.c @@ -105,7 +105,7 @@ void EnAkindonuts_OfferRandoShopItem(EnAkindonuts* this, PlayState* play) { RECOMP_PATCH void func_80BEF360(EnAkindonuts* this, PlayState* play) { if (this->unk_32C & 0x40) { - if (!rando_scrubs_enabled() || rando_location_is_checked(LOCATION_SCRUB_SHOP)) { + if (!rando_get_slotdata_u32("scrubsanity") || rando_location_is_checked(LOCATION_SCRUB_SHOP)) { this->actionFunc = EnAkindonuts_OfferNormalShopItem; } else { this->actionFunc = EnAkindonuts_OfferRandoShopItem; @@ -124,7 +124,7 @@ RECOMP_PATCH void func_80BEF360(EnAkindonuts* this, PlayState* play) { } RECOMP_PATCH s32 func_80BED208(EnAkindonuts* this) { - if (!rando_scrubs_enabled()) { + if (!rando_get_slotdata_u32("scrubsanity")) { if ((u32)INV_CONTENT(ITEM_MAGIC_BEANS) != ITEM_MAGIC_BEANS) { return 0; } @@ -144,7 +144,7 @@ RECOMP_PATCH s32 func_80BED208(EnAkindonuts* this) { } RECOMP_PATCH s32 func_80BED27C(EnAkindonuts* this) { - if (!rando_scrubs_enabled()) { + if (!rando_get_slotdata_u32("scrubsanity")) { if (GET_CUR_UPG_VALUE(UPG_BOMB_BAG) == 3) { return 2; } @@ -164,7 +164,7 @@ RECOMP_PATCH s32 func_80BED27C(EnAkindonuts* this) { } RECOMP_PATCH s32 func_80BED2FC(EnAkindonuts* this) { - if (!Inventory_HasEmptyBottle() && !rando_scrubs_enabled()) { + if (!Inventory_HasEmptyBottle() && !rando_get_slotdata_u32("scrubsanity")) { return 2; } @@ -178,7 +178,7 @@ RECOMP_PATCH s32 func_80BED2FC(EnAkindonuts* this) { } RECOMP_PATCH s32 func_80BED35C(EnAkindonuts* this) { - if (!Inventory_HasEmptyBottle() && !rando_scrubs_enabled()) { + if (!Inventory_HasEmptyBottle() && !rando_get_slotdata_u32("scrubsanity")) { return 2; } From 9b7b2164ecf989e006858d8d7b4f41b1448e8df0 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 26 Jul 2026 22:24:00 -0300 Subject: [PATCH 18/19] Updated setup guide in the README --- README.md | 85 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 9909d15..f92244d 100644 --- a/README.md +++ b/README.md @@ -8,42 +8,61 @@ This randomizer is still under development in the beta phase but is considered s ## Setup -> [!IMPORTANT] -> To install mods (including MMRecompRando), drag and drop the downloaded mod zip onto the Zelda64Recomp window before you press "Start Game" and the game will handle extracting and installing the mods for you. + +### Prerequesites +In order to be able to play the randomizer, you'll first need the following: +- Download [Zelda64Recomp](https://github.com/Zelda64Recomp/Zelda64Recomp/releases/latest) and unzip its contents anywhere except in any folder related to OneDrive, such as `Documents` or `Pictures`; +- Downlaod [Visual Studio C++ Redist](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version); +- A legal ROM of The Legend of Zelda: Majora's Mask - US. ### Mod Installation -1. Download the latest [Visual Studio C++ Redist](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version). -2. Download [Zelda64Recomp](https://github.com/Zelda64Recomp/Zelda64Recomp/releases/latest). -3. Download [MMRecompRando.zip](https://github.com/RecompRando/MMRecompRando/releases/latest). -4. Optionally download any additional mods or texture packs you'd like from [Thunderstore](https://thunderstore.io/c/zelda-64-recompiled/). - - You only need to drag and drop mod zips from GitHub or Thunderstore onto the game window to install them. -5. You can also download [poptracker](https://github.com/black-sliver/PopTracker/releases/latest) along with [G4M3RL1F3's fork of Seto's pack](https://github.com/G4M3RL1F3/Majoras-Mask-AP-PopTracker-Pack/releases/latest) -6. Open `Zelda64Recompiled`. - 1. Select your ROM file. - 2. Install MMRecompRando and any additional mods. - 3. Select Start Game. -7. Go nuts. +1. Download the mod: [MMRecompRando.zip](https://github.com/RecompRando/MMRecompRando/releases/latest); +2. Launch `Zelda 64: Recompiled`; +3. Install the mod using one of the following methods: +> [!IMPORTANT] +> Do not unzip the `MMRecompRando.zip` file. + + a. Click on `Mods` to open the mod menu, click `Install Mods`, then select `MMRecompRando.zip`; + b. Click and drag the `MMRecompRando.zip` file on top of the `Zelda 64: Recompiled` window. + +### Optional Setup +- [Thunderstore](https://thunderstore.io/c/zelda-64-recompiled/) to download additional mods or texture packs; + - The installation process for any mod/texture pack is the same as instructed above in the [Mod Installation](#mod-installation) section. +- [PopTracker](https://github.com/black-sliver/PopTracker/releases/latest) along with the [pack](https://github.com/G4M3RL1F3/Majoras-Mask-AP-PopTracker-Pack/releases/latest) for auto-tracking. ### Solo Setup -1. Launch the game with the randomizer mod enabled. -2. Select `Solo` in the randomizer menu. -3. Create a new session and choose which settings you'd like. - - Details about these settings are currently not available through the mod only, you will have to look at the [multiworld's example YAML](https://github.com/RecompRando/MMRecompRando/releases/download/v0.9.5/EXAMPLE_YAML.yaml) for more information on what each setting does. -4. Hit `Generate` and select your seed. +1. With the `MMRecompRando` mod enabled, click `Start Game`; +2. Select `Solo` in the randomizer menu; +3. Create a new session and choose which settings you'd like; +4. Click `Generate` and select your seed. ### Multiworld Setup -1. Launch the game with the randomizer mod enabled. -2. Select `Multiworld` in the randomizer menu. -3. Input your Server Address, Player/Slot Name, and optionally a Password. -4. Hit `Connect`. -5. Profit. - -### Multiworld Archipelago Setup -1. Know [Archipelago](https://archipelago.gg/tutorial/Archipelago/setup/en). -2. Download the [apworld](https://github.com/RecompRando/MMRecompRando/releases/latest). -3. **MAKE SURE** to clear out _any_ apworlds named `mm-recomp.apworld` or `mm_recomp.apworld` from your `Archipelago/lib/worlds` folder and your `Archipelago/custom_worlds` folder. -4. Place the apworld into `Archipelago/custom_worlds/`. -5. Generate a multiworld, and host the game either locally or on the website. + +#### YAML Creation +Every player wishing to play Majora's Mask: Recompiled Randomizer requires a YAML file. A YAML file is the file used to configure each player's world. To obtain and configure such a file, you must follow these steps: +1. Download and install the [Archipelago software](https://github.com/ArchipelagoMW/Archipelago/releases/latest) (install directory defaults to `C:\ProgramData\Archipelago`); +2. Download `mm_recomp.apworld` found in the [latest release page](https://github.com/RecompRando/MMRecompRando/releases/latest); +3. Move the `mm_recomp.apworld` file in `Archipelago\custom_worlds`; +4. Launch the Archipelago launcher; +5. Follow one of these two steps: + a. Search for and click `Generate Template Options`. This will open a window with YAMLs of every world installed (if not, they can be found in `Archipelago\Players\Templates`). Search for and open `Majora's Mask Recompiled.yaml` and edit your options as desired with the use of a text editor, such as Notepad++; + b. Search for and click `Options Creator` and edit your options. Once it's done, click the `Export Options` and save it somewhere. + +#### Seed Creation +Only the host needs to follow the following steps in order to create a seed: +1. Collect each player's YAML files and move them all to `Archipelago\Players`; + - If there are players playing other games, make sure to collect the corresponding APWorlds as well and move them to `Archipelago\custom_worlds`. +2. Launch the Archipelago launcher; +3. Search for and click `Generate`. If the generation was successful, the output `.zip` file is in `Archipelago\output`; +4. Go to the [Archipelago](https://archipelago.gg/) website, click on `Get Started` → `Host Game`, then upload the `.zip` file you generated in the previous step. + +#### Connecting to a Multiworld +1. Launch `Zelda 64: Recompiled` and make sure the randomizer mod is enabled; +2. Click `Start Game`; +3. Select `Multiworld` in the randomizer menu; +3. Input your Server Address (usually `archipelago.gg`), Player/Slot Name, and Password (if applicable); +4. Click `Connect`. +At this point, you are ready to play the randomizer. ## FAQ @@ -51,13 +70,13 @@ This randomizer is still under development in the beta phase but is considered s Don't worry, your vanilla saves are intact. When playing this mod, a per-session savefile will be created. Your normal save file will not be touched. -### I got Letter to Kafei and now I can't use the Pendant of Memories! Is it just gone? +### I got a trade item that occupies the same slot of another in the inventory. Is it just gone? -Try moving your cursor to the Letter to Kafei and pressing the N64's L or A button. That should cycle through all quest items in that slot. That's true for the Moon's Tear item slot and the Room Key item slot as well. +Move your cursor to that slot and press the `L` or `A` button, however they're bound on your controller/keyboard. It will cycle through all available trade items in that slot. ### I opened a chest/got a check and it always shows a grey Archipelago item, what's wrong with you? -The phantom AP item means either something went wrong with your connection or the check is not yet implemented. Please use a text client or Seto's/G4M3RL1F3's amazing poptracker pack from step 5 to see checks that you can definitely get (though some implemented checks may be missing until the tracker is updated). +The phantom AP item means either something went wrong with your connection or the check is not yet implemented. Please use a text client or the PopTracker pack (see [Optional Setup](#optional-setup)) to see checks that you can definitely get. If you picked up a phantom on a check that should be implemented, you can open an issue on this repo letting us know! From d676ea8da110bf59301718734ad08cf6b08e1caa Mon Sep 17 00:00:00 2001 From: G4M3RL1F3 Date: Sun, 26 Jul 2026 22:34:31 -0300 Subject: [PATCH 19/19] Update README to fix formating bugs --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f92244d..fe33393 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,11 @@ In order to be able to play the randomizer, you'll first need the following: 1. Download the mod: [MMRecompRando.zip](https://github.com/RecompRando/MMRecompRando/releases/latest); 2. Launch `Zelda 64: Recompiled`; 3. Install the mod using one of the following methods: + 1. Click on `Mods` to open the mod menu, click `Install Mods`, then select `MMRecompRando.zip`; + 2. Click and drag the `MMRecompRando.zip` file on top of the `Zelda 64: Recompiled` window. > [!IMPORTANT] > Do not unzip the `MMRecompRando.zip` file. - a. Click on `Mods` to open the mod menu, click `Install Mods`, then select `MMRecompRando.zip`; - b. Click and drag the `MMRecompRando.zip` file on top of the `Zelda 64: Recompiled` window. - ### Optional Setup - [Thunderstore](https://thunderstore.io/c/zelda-64-recompiled/) to download additional mods or texture packs; - The installation process for any mod/texture pack is the same as instructed above in the [Mod Installation](#mod-installation) section. @@ -45,13 +44,13 @@ Every player wishing to play Majora's Mask: Recompiled Randomizer requires a YAM 3. Move the `mm_recomp.apworld` file in `Archipelago\custom_worlds`; 4. Launch the Archipelago launcher; 5. Follow one of these two steps: - a. Search for and click `Generate Template Options`. This will open a window with YAMLs of every world installed (if not, they can be found in `Archipelago\Players\Templates`). Search for and open `Majora's Mask Recompiled.yaml` and edit your options as desired with the use of a text editor, such as Notepad++; - b. Search for and click `Options Creator` and edit your options. Once it's done, click the `Export Options` and save it somewhere. + 1. Search for and click `Generate Template Options`. This will open a window with YAMLs of every world installed (if not, they can be found in `Archipelago\Players\Templates`). Search for and open `Majora's Mask Recompiled.yaml` and edit your options as desired with the use of a text editor, such as Notepad++; + 2. Search for and click `Options Creator` and edit your options. Once it's done, click the `Export Options` and save it somewhere. #### Seed Creation Only the host needs to follow the following steps in order to create a seed: 1. Collect each player's YAML files and move them all to `Archipelago\Players`; - - If there are players playing other games, make sure to collect the corresponding APWorlds as well and move them to `Archipelago\custom_worlds`. + - If there are players playing other games, make sure to collect the corresponding APWorlds as well and move them to `Archipelago\custom_worlds`. 2. Launch the Archipelago launcher; 3. Search for and click `Generate`. If the generation was successful, the output `.zip` file is in `Archipelago\output`; 4. Go to the [Archipelago](https://archipelago.gg/) website, click on `Get Started` → `Host Game`, then upload the `.zip` file you generated in the previous step.