From 9b34fd8f8f16fb18062573171a097b3549709491 Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Wed, 29 Apr 2026 16:15:29 -0700 Subject: [PATCH] implement kak malo mart shop checks --- include/d/d_a_shop_item_static.h | 10 ++ src/d/actor/d_a_obj_item.cpp | 2 +- src/d/actor/d_a_shop_item.cpp | 98 ++++++++++---- src/d/d_a_shop_item_static.cpp | 67 ++++++---- src/d/d_item.cpp | 48 +++++++ src/d/d_msg_flow.cpp | 11 ++ src/d/d_shop_system.cpp | 17 ++- .../randomizer/game/randomizer_context.cpp | 19 +++ .../randomizer/game/randomizer_context.hpp | 1 + .../generator/data/actor_additions.yaml | 16 +++ .../generator/data/actor_patches.yaml | 123 +++++++++++++++++- src/dusk/randomizer/generator/data/items.yaml | 12 +- .../randomizer/generator/data/locations.yaml | 29 +++-- .../data/world/overworld/Eldin Province.yaml | 34 +++-- 14 files changed, 399 insertions(+), 88 deletions(-) diff --git a/include/d/d_a_shop_item_static.h b/include/d/d_a_shop_item_static.h index 0091c0b83c..ee0d41f388 100644 --- a/include/d/d_a_shop_item_static.h +++ b/include/d/d_a_shop_item_static.h @@ -74,7 +74,17 @@ public: s16 getAngleY() const { return mAngleY; } void setAngleY(s16 angle) { mAngleY = angle;} +#if TARGET_PC + BOOL isRandomized() const; +#endif + static ResourceData const mData[23]; +#if TARGET_PC + static ResourceData mRandoData[23]; + #define M_SHOP_DATA (isRandomized() ? mRandoData : mData) +#else + #define M_SHOP_DATA mData +#endif static f32 const m_cullfar_max; enum { diff --git a/src/d/actor/d_a_obj_item.cpp b/src/d/actor/d_a_obj_item.cpp index 972ea24544..1cda8f110d 100644 --- a/src/d/actor/d_a_obj_item.cpp +++ b/src/d/actor/d_a_obj_item.cpp @@ -13,12 +13,12 @@ #include "d/d_item.h" #include "d/d_item_data.h" #include "d/d_s_play.h" -#include "dusk/randomizer/game/verify_item_functions.h" #include "f_op/f_op_camera_mng.h" #include "m_Do/m_Do_mtx.h" #if TARGET_PC #include "dusk/randomizer/game/tools.h" +#include "dusk/randomizer/game/verify_item_functions.h" #include "dusk/frame_interpolation.h" #endif diff --git a/src/d/actor/d_a_shop_item.cpp b/src/d/actor/d_a_shop_item.cpp index 0a98dc9868..f86a8447ce 100644 --- a/src/d/actor/d_a_shop_item.cpp +++ b/src/d/actor/d_a_shop_item.cpp @@ -13,6 +13,7 @@ #if TARGET_PC #include "d/d_item_data.h" +#include "dusk/randomizer/game/tools.h" #include "dusk/randomizer/game/verify_item_functions.h" #endif @@ -94,26 +95,54 @@ const char* daShopItem_c::getShopArcname() { } #if TARGET_PC - // Override the item model with whichever item is randomized to this shop item - if (randomizer_IsActive()) { - u8 randoItem{0}; - switch (mShopItemID) { - // Sera's Shop Slingshot - case SHOP_ITEMNO_PACHINKO: - randoItem = randomizer_getItemAtLocation("Sera Shop Slingshot"); - break; - default: - break; + if (isRandomized()) { + // Override the item model with whichever item is randomized to this shop item + u8 stage = getStageID(); + u16 key = (stage << 8) | m_itemNo; + u8 itemId = randomizer_GetContext().mShopOverrides.at(key); + itemId = verifyProgressiveItem(itemId); + + // Replace the necessary index in daShopItem_c::mRandoData with the model data from dItem_data + auto& shopModel = mRandoData[mShopItemID]; + shopModel.mArcName = dItem_data::getArcName(itemId); + shopModel.mBmdName = dItem_data::getBmdName(itemId); + shopModel.mBtkName = dItem_data::getBtkName(itemId); + shopModel.mBckName = dItem_data::getBckName(itemId); + shopModel.mBrkName = dItem_data::getBrkName(itemId); + shopModel.mBtpName = dItem_data::getBtpName(itemId); + shopModel.mTevFrm = dItem_data::getTevFrm(itemId); + shopModel.mBtpFrm = -1; + shopModel.mFlag = -1; + + // Move the item higher up if it's the magic armor slot + if (mShopItemID == SHOP_ITEMNO_ARMOR) { + switch (itemId) { + case dItemNo_Randomizer_GREEN_RUPEE_e: + case dItemNo_Randomizer_BLUE_RUPEE_e: + case dItemNo_Randomizer_YELLOW_RUPEE_e: + case dItemNo_Randomizer_RED_RUPEE_e: + case dItemNo_Randomizer_PURPLE_RUPEE_e: + case dItemNo_Randomizer_ORANGE_RUPEE_e: + case dItemNo_Randomizer_SILVER_RUPEE_e: + case dItemNo_Randomizer_LINKS_SAVINGS_e: + shopModel.mOffsetY = 65.0f; + default: + shopModel.mOffsetY = 60.0f; + } + } else { + shopModel.mOffsetY = 15.0f; } - if (randoItem) { - randoItem = verifyProgressiveItem(randoItem); - return dItem_data::getArcName(randoItem); + // Scale down the Master Sword model so it looks better + if (itemId == dItemNo_Randomizer_MASTER_SWORD_e || itemId == dItemNo_Randomizer_LIGHT_SWORD_e) { + shopModel.mScale = 0.35f; + } else { + shopModel.mScale = 1.0f; } } #endif - return mData[mShopItemID].get_arcName(); + return M_SHOP_DATA[mShopItemID].get_arcName(); } const f32 daShopItem_c::m_cullfar_max = 5000.0f; @@ -144,11 +173,11 @@ void daShopItem_c::CreateInit() { if (strcmp("R_SP109", dComIfGp_getStartStageName()) == 0 && dComIfGp_getStartStageRoomNo() == 1) { - scale.set(mData[mShopItemID].get_scale() * 0.8f, mData[mShopItemID].get_scale() * 0.8f, - mData[mShopItemID].get_scale() * 0.8f); + scale.set(M_SHOP_DATA[mShopItemID].get_scale() * 0.8f, M_SHOP_DATA[mShopItemID].get_scale() * 0.8f, + M_SHOP_DATA[mShopItemID].get_scale() * 0.8f); } else { - scale.set(mData[mShopItemID].get_scale(), mData[mShopItemID].get_scale(), - mData[mShopItemID].get_scale()); + scale.set(M_SHOP_DATA[mShopItemID].get_scale(), M_SHOP_DATA[mShopItemID].get_scale(), + M_SHOP_DATA[mShopItemID].get_scale()); } home.pos = current.pos; @@ -162,7 +191,7 @@ void daShopItem_c::set_mtx() { if (daShopItem_prm::getGroup(this) == 15) { mDoMtx_stack_c::transS(current.pos.x, current.pos.y, current.pos.z); } else { - mDoMtx_stack_c::transS(current.pos.x, current.pos.y + mData[mShopItemID].get_offsetY(), + mDoMtx_stack_c::transS(current.pos.x, current.pos.y + M_SHOP_DATA[mShopItemID].get_offsetY(), current.pos.z); } @@ -172,8 +201,8 @@ void daShopItem_c::set_mtx() { if (daShopItem_prm::getGroup(this) == 15) { mDoMtx_stack_c::ZXYrotM(-11300, 32700, 7300); } else { - mDoMtx_stack_c::ZXYrotM(mAngleX + mData[mShopItemID].get_angleX(), - mData[mShopItemID].get_angleY(), mData[mShopItemID].get_angleZ()); + mDoMtx_stack_c::ZXYrotM(mAngleX + M_SHOP_DATA[mShopItemID].get_angleX(), + M_SHOP_DATA[mShopItemID].get_angleY(), M_SHOP_DATA[mShopItemID].get_angleZ()); } mDoMtx_stack_c::ZXYrotM(current.angle.x, current.angle.y, current.angle.z); @@ -181,7 +210,7 @@ void daShopItem_c::set_mtx() { if (daShopItem_prm::getGroup(this) == 15) { mDoMtx_stack_c::XrotM(0); } else { - mDoMtx_stack_c::XrotM(mData[mShopItemID].get_angleOffsetX()); + mDoMtx_stack_c::XrotM(M_SHOP_DATA[mShopItemID].get_angleOffsetX()); } mpModel->setBaseTRMtx(mDoMtx_stack_c::get()); @@ -215,29 +244,42 @@ void daShopItem_c::setShadow() { } BOOL daShopItem_c::chkFlag(int i_flag) { - return mData[mShopItemID].get_flag() & i_flag; + return M_SHOP_DATA[mShopItemID].get_flag() & i_flag; } s8 daShopItem_c::getTevFrm() { - return mData[mShopItemID].get_tevfrm(); + return M_SHOP_DATA[mShopItemID].get_tevfrm(); } s8 daShopItem_c::getBtpFrm() { - return mData[mShopItemID].get_btpfrm(); + return M_SHOP_DATA[mShopItemID].get_btpfrm(); } u8 daShopItem_c::getShadowSize() { - return mData[mShopItemID].get_shadowSize(); + return M_SHOP_DATA[mShopItemID].get_shadowSize(); } u8 daShopItem_c::getCollisionH() { - return mData[mShopItemID].get_collisionH(); + return M_SHOP_DATA[mShopItemID].get_collisionH(); } u8 daShopItem_c::getCollisionR() { - return mData[mShopItemID].get_collisionR(); + return M_SHOP_DATA[mShopItemID].get_collisionR(); } +#if TARGET_PC +// Custom function to check if this shop item is randomized +BOOL daShopItem_c::isRandomized() const { + if (randomizer_IsActive()) { + u8 stage = getStageID(); + u8 itemId = m_itemNo; + u16 key = (stage << 8) | itemId; + return randomizer_GetContext().mShopOverrides.contains(key); + } + return false; +} +#endif + int daShopItem_c::_create() { fopAcM_ct(this, daShopItem_c); diff --git a/src/d/d_a_shop_item_static.cpp b/src/d/d_a_shop_item_static.cpp index 1cf39a1629..c91389bfeb 100644 --- a/src/d/d_a_shop_item_static.cpp +++ b/src/d/d_a_shop_item_static.cpp @@ -7,11 +7,6 @@ #include "d/d_a_shop_item_static.h" -#if TARGET_PC -#include "dusk/randomizer/game/verify_item_functions.h" -#include "d/d_item_data.h" -#endif - csXyz* daShopItem_c::getRotateP() { return ¤t.angle; } @@ -46,35 +41,51 @@ ResourceData const daShopItem_c::mData[23] = { {"O_mD_bott", 6, 12, -1, -1, -1, 9, 15, 0.0f, 1.0f, 0, {0, 0, 0}, 4, 0, 0, 0, 12, 0}, }; +#if TARGET_PC +// Make a copy of mData that we can overwrite for randomized items +ResourceData daShopItem_c::mRandoData[23] = { + {"B_mD_sold", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, -0x8000, 0}, 0, 0, 0, 0, -1, -1}, + {"B_mD_oil", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_red", 3, -1, -1, -1, -1, -1, -11, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"B_mD_milk", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_bott", 6, 12, -1, -1, -1, 9, 15, 0.0f, 1.0f, 0, {0, 0, 0}, 4, 0, 0, 0, 3, 1}, + {"O_mD_arw", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_SHB", 3, -1, -1, -1, -1, -1, -1, 30.0f, 1.0f, 0, {0, 0x7FFF, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_SHA", 3, -1, -1, -1, -1, -1, -1, 30.0f, 1.0f, 0, {0, 0x7FFF, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_bomb", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_pg", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_bi", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_bmcs", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_bmc2", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_jira", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, 0, -1}, + {"O_mD_bott", 6, 12, -1, -1, -1, 9, 15, 0.0f, 1.0f, 0, {0, 0, 0}, 4, 0, 0, 0, 1, 0}, + {"O_mD_hati", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_pach", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_blue", 3, -1, -1, -1, -1, -1, -11, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_hawk", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_marm", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_marm", 4, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_gren", 3, -1, -1, -1, -1, -1, -1, 0.0f, 1.0f, 0, {0, 0, 0}, 0, 0, 0, 0, -1, -1}, + {"O_mD_bott", 6, 12, -1, -1, -1, 9, 15, 0.0f, 1.0f, 0, {0, 0, 0}, 4, 0, 0, 0, 12, 0}, +}; +#endif + int CheckShopItemCreateHeap(fopAc_ac_c* i_this) { daShopItem_c* a_this1 = static_cast(i_this); daShopItem_c* a_this2 = static_cast(i_this); u8 a_ShopItemID = a_this2->getShopItemID(); -#if TARGET_PC - // In randomizer, create the model for the randomized shop item - if (randomizer_IsActive()) { - u8 randoItem{0}; - switch (a_ShopItemID) { - // Sera Shop Slingshot - case daShopItem_c::SHOP_ITEMNO_PACHINKO: - randoItem = randomizer_getItemAtLocation("Sera Shop Slingshot"); - break; - default: - break; - } - if (randoItem) { - randoItem = verifyProgressiveItem(randoItem); - return a_this1->CreateItemHeap(dItem_data::getArcName(randoItem), - dItem_data::getBmdName(randoItem), - dItem_data::getBtkName(randoItem), - dItem_data::getBpkName(randoItem), - dItem_data::getBckName(randoItem), - dItem_data::getBxaName(randoItem), - dItem_data::getBrkName(randoItem), - dItem_data::getBtpName(randoItem)); - } +#if TARGET_PC + if (a_this2->isRandomized()) { + return a_this1->CreateItemHeap(daShopItem_c::mRandoData[a_ShopItemID].get_arcName(), + daShopItem_c::mRandoData[a_ShopItemID].get_bmdName(), + daShopItem_c::mRandoData[a_ShopItemID].get_btk1Name(), + daShopItem_c::mRandoData[a_ShopItemID].get_bpk1Name(), + daShopItem_c::mRandoData[a_ShopItemID].get_bck1Name(), + daShopItem_c::mRandoData[a_ShopItemID].get_bxa1Name(), + daShopItem_c::mRandoData[a_ShopItemID].get_brk1Name(), + daShopItem_c::mRandoData[a_ShopItemID].get_btp1Name()); } #endif diff --git a/src/d/d_item.cpp b/src/d/d_item.cpp index d46857a763..f9a23378a9 100644 --- a/src/d/d_item.cpp +++ b/src/d/d_item.cpp @@ -9,6 +9,9 @@ #include "d/d_com_inf_game.h" #include "d/d_meter2_info.h" #if TARGET_PC +#include "dusk/randomizer/game/flags.h" +#include "dusk/randomizer/game/tools.h" +#include "dusk/randomizer/game/stages.h" #include "dusk/randomizer/game/verify_item_functions.h" #endif #include @@ -1081,6 +1084,51 @@ inline int getCheckItemFunc(u8 i_itemNo) { } int checkItemGet(u8 i_itemNo, int i_default) { +#if TARGET_PC + // Check special randomizer cases + if (randomizer_IsActive()) { + switch (i_itemNo) { + case dItemNo_Randomizer_HYLIA_SHIELD_e: + // Check if we are at Kakariko Malo mart and verify that we have not bought the shield. + if (playerIsInRoomStage(3, allStages[Kakariko_Village_Interiors]) && + !dComIfGs_isEventBit(BOUGHT_HYLIAN_SHIELD_AT_MALO_MART)) { + // Return false so we can buy the shield. + return 0; + } + break; + case dItemNo_Randomizer_HAWK_EYE_e: + // Check if we are at Kakariko Village and that the hawkeye is currently not for sale. + if (getStageID() == Kakariko_Village && !dComIfGs_isSwitch(0x3E, 0)) { + // Return false so we can buy the hawkeye. + return 0; + } + break; + case dItemNo_Randomizer_SHIELD_e: + case dItemNo_Randomizer_WOOD_SHIELD_e: + // Check if we are at Kakariko Malo mart and that the Wooden Shield has not been bought. + if (playerIsInRoomStage(3, allStages[Kakariko_Village_Interiors]) && + !dComIfGs_isSwitch(0x5, 3)) { + // Return false so we can buy the shield. + return 0; + } + break; + case dItemNo_Randomizer_TOMATO_PUREE_e: + case dItemNo_Randomizer_TASTE_e: + // Check to see if currently in Snowpeak Ruins + if (getStageID() == Snowpeak_Ruins) { + // Return false so that yeta will give the map item no matter what. + return 0; + } + break; + case dItemNo_Randomizer_IRONBALL_e: + // Check to see if currently in Snowpeak Ruins Darkhammer room + if (getStageID() == Darkhammer) { + return dComIfGs_isSwitch(0x5F, 51); // Picked up the Ball and Chain check. + } + } + } +#endif + int result = getCheckItemFunc(i_itemNo); if (result == -1) { diff --git a/src/d/d_msg_flow.cpp b/src/d/d_msg_flow.cpp index aa9256f44c..a316e588ea 100644 --- a/src/d/d_msg_flow.cpp +++ b/src/d/d_msg_flow.cpp @@ -16,6 +16,7 @@ #include #if TARGET_PC +#include "dusk/randomizer/game/tools.h" #include "dusk/randomizer/game/stages.h" #endif @@ -1200,6 +1201,16 @@ u16 dMsgFlow_c::query025(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_spea const u8 prm0 = i_flowNode_p->param; u16 ret = dComIfGs_checkEmptyBottle() >= prm0 ? 0 : 1; +#if TARGET_PC + // Check to see if currently in one of the Kakariko interiors and if the red potion item is randomized + if (randomizer_IsActive() && playerIsInRoomStage(3, allStages[Kakariko_Village_Interiors]) && + randomizer_GetContext().mShopOverrides.contains(0x4461)) // 0x4461 is the key for the red potion item + { + // Return 0 so the player can buy the red potion item from the shop. + return 0; + } +#endif + if (param_2 != 0) { // "Empty Bottle Count Check" OS_REPORT("\x1B[44;33m空きビン数チェック         \x1B[m|:"); diff --git a/src/d/d_shop_system.cpp b/src/d/d_shop_system.cpp index 091eec3435..530d732484 100644 --- a/src/d/d_shop_system.cpp +++ b/src/d/d_shop_system.cpp @@ -19,6 +19,11 @@ #include "d/actor/d_a_tag_shop_item.h" #include +#if TARGET_PC +#include "dusk/randomizer/game/verify_item_functions.h" +#include "dusk/randomizer/game/tools.h" +#include "dusk/randomizer/game/stages.h" +#endif static daTag_ShopItem_c* dShopSystem_itemActor[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1208,10 +1213,14 @@ int dShopSystem_c::seq_decide_yes(fopAc_ac_c* actor, dMsgFlow_c* i_flow) { #if TARGET_PC // In rando, override the item if it's one of our unique shop checks if (randomizer_IsActive()) { - switch (itemNo) { - case dItemNo_Randomizer_PACHINKO_e: - itemNo = randomizer_getItemAtLocation("Sera Shop Slingshot"); - break; + u8 stageId = getStageID(); + u16 key = (stageId << 8) | itemNo; + if (randomizer_GetContext().mShopOverrides.contains(key)) { + itemNo = verifyProgressiveItem(randomizer_GetContext().mShopOverrides[key]); + // Update the shop item flag no matter what in Kak Malo Mart + if (playerIsInRoomStage(3, "R_SP109")) { + setSoldOutFlag(); + } } } #endif diff --git a/src/dusk/randomizer/game/randomizer_context.cpp b/src/dusk/randomizer/game/randomizer_context.cpp index a3f5b58452..bb9472d797 100644 --- a/src/dusk/randomizer/game/randomizer_context.cpp +++ b/src/dusk/randomizer/game/randomizer_context.cpp @@ -70,6 +70,9 @@ std::optional RandomizerContext::WriteToFile() { const std::unordered_map u16GoldenWolfOverrides(this->mGoldenWolfOverrides.begin(), this->mGoldenWolfOverrides.end()); out["mGoldenWolfOverrides"] = u16GoldenWolfOverrides; + const std::unordered_map u16ShopOverrides(this->mShopOverrides.begin(), this->mShopOverrides.end()); + out["mShopOverrides"] = u16ShopOverrides; + out["mItemLocations"] = this->mItemLocations; out["mStartHour"] = static_cast(this->mStartHour); @@ -182,6 +185,13 @@ std::optional RandomizerContext::LoadFromHash(const std::string& ha this->mGoldenWolfOverrides[key] = itemId; } + // Shop Items + for (const auto& shopNode : in["mShopOverrides"]) { + u16 key = shopNode.first.as(); + u8 itemId = shopNode.second.as(); + this->mShopOverrides[key] = itemId; + } + // Items we call by location name for (const auto& locationNode : in["mItemLocations"]) { const auto& locationName = locationNode.first.as(); @@ -642,6 +652,15 @@ void GenerateAndWriteSeed(std::string& generationStatusMsg) { randoData.mGoldenWolfOverrides[flag] = itemId; } + // Shop Items + // Keyed by u16 of the stage and original shop item + if (location->HasCategories("Shop") && world->Setting("Shop Items") == "On") { + u8 stage = metaData[0]["Stage"].as(); + u8 originalItem = metaData[0]["Item"].as(); + u16 key = (stage << 8) | originalItem; + randoData.mShopOverrides[key] = location->GetCurrentItem()->GetID(); + } + // Items that we lookup just by calling their location name if (location->HasCategories("Location Name Lookup")) { const auto& locationName = metaData.as(); diff --git a/src/dusk/randomizer/game/randomizer_context.hpp b/src/dusk/randomizer/game/randomizer_context.hpp index 2796a81ac9..d8cbd1cb4d 100644 --- a/src/dusk/randomizer/game/randomizer_context.hpp +++ b/src/dusk/randomizer/game/randomizer_context.hpp @@ -35,6 +35,7 @@ public: std::unordered_map mBugRewardOverrides{}; std::unordered_map mSkyCharacterOverrides{}; std::unordered_map mGoldenWolfOverrides{}; + std::unordered_map mShopOverrides{}; std::unordered_map mItemLocations{}; u8 mStartHour{0}; u8 mMapBits{}; diff --git a/src/dusk/randomizer/generator/data/actor_additions.yaml b/src/dusk/randomizer/generator/data/actor_additions.yaml index 8d13cfd283..9c6d7f99fa 100644 --- a/src/dusk/randomizer/generator/data/actor_additions.yaml +++ b/src/dusk/randomizer/generator/data/actor_additions.yaml @@ -72,3 +72,19 @@ ACTR: # Objects which have the ACTR dzx type layers: - 2 + R_SP109: # Kakariko Interiors + 3: # Kak Malo Mart + # Spawn in a middle item Sold Out Sign + - name: TGSPITM + parameters: 0x02FFFFFF + position: + x: -650.0 + y: 450.0 + z: -500.0 + angle: + x: 0x0147 + y: 0x8000 + z: 0x05FF + layers: + - 2 + - 3 diff --git a/src/dusk/randomizer/generator/data/actor_patches.yaml b/src/dusk/randomizer/generator/data/actor_patches.yaml index 397a830ce2..ce5c7df743 100644 --- a/src/dusk/randomizer/generator/data/actor_patches.yaml +++ b/src/dusk/randomizer/generator/data/actor_patches.yaml @@ -1010,6 +1010,127 @@ F_SP126: # Kakariko Village Interiors R_SP109: + # Room 3 - Kak Malo Mart + 3: + # Red Potion Shop item (left side) + - name: TGSPITM + parameters: 0x01001E61 + position: + x: -550 + y: 450 + z: -500 + angle: + x: 0x014D + y: 0x0000 + z: 0x74FF + patch: + # Change this into a sold out sign until the hawkeye is available + parameters: 0x01FFFFFF + angle: + x: 0x014B + y: 0x8000 + z: 0x0BFF + layers: + - 2 + - 3 + + # Hawkeye Shop Item (left side) + - name: TGSPITM + parameters: 0x0100643E + position: + x: -550 + y: 450 + z: -500 + angle: + x: 0x0149 + y: 0x0000 + z: 0x3E33 + patch: + # Give the hawkeye shop item a different bought flag + angle: + z: 0x3E3D + layers: + - 2 + - 3 + + # Wooden Shield Shop Item (middle) + - name: TGSPITM + parameters: 0x0200322B + position: + x: -650 + y: 450 + z: -500 + angle: + x: 0x0143 + y: 0x0000 + z: 0xFFFF + patch: + # Give the wooden shield item a different bought flag + angle: + z: 0xFF05 + layers: + - 2 + - 3 + + # Red Potion Shop item (Right Side) + - name: TGSPITM + parameters: 0x03001E61 + position: + x: -750 + y: 450 + z: -500 + angle: + x: 0x014D + y: 0x8000 + z: 0x76FF + patch: + # Give this item a unique flag, and make it set the + # flag for the right side sold out sign + angle: + z: 0x3904 + layers: + - 2 + - 3 + + # Right side Sold Out shop item + - name: TGSPITM + parameters: 0x03FFFFFF + position: + x: -750 + y: 450 + z: -500 + angle: + x: 0x0147 + y: 0x8000 + z: 0x3976 + patch: + # Give the sign a different set of flags + angle: + z: 0x04FF + layers: + - 2 + - 3 + + # Left side Sold Out Sign + - name: TGSPITM + parameters: 0x01FFFFFF + position: + x: -550 + y: 450 + z: -500 + angle: + x: 0x014B + y: 0x8000 + z: 0x333D + patch: + # Change the sign to the Hylian Shield sold out sign + angle: + x: 0x0147 + z: 0x33FF + layers: + - 2 + - 3 + # Room 6 - Abandoned House 6: # Female Ant @@ -1031,4 +1152,4 @@ R_SP109: - 0 - 1 - 2 - - 3 \ No newline at end of file + - 3 diff --git a/src/dusk/randomizer/generator/data/items.yaml b/src/dusk/randomizer/generator/data/items.yaml index 2cac3af06a..2529e0f76d 100644 --- a/src/dusk/randomizer/generator/data/items.yaml +++ b/src/dusk/randomizer/generator/data/items.yaml @@ -506,6 +506,14 @@ Importance: Major Id: 0x60 +- Name: Red Potion Shop + Importance: Junk + Id: 0x61 + +- Name: Blue Potion Shop + Importance: Junk + Id: 0x63 + - Name: Bottle with Lantern Oil Importance: Major Id: 0x9D @@ -630,10 +638,6 @@ Importance: Major Id: 0x105 -- Name: Red Potion Shop - Importance: Junk - Id: 0x106 - - Name: Fairy Tears Importance: Junk Id: 0x107 diff --git a/src/dusk/randomizer/generator/data/locations.yaml b/src/dusk/randomizer/generator/data/locations.yaml index 0931d65c8f..9e416b47d6 100644 --- a/src/dusk/randomizer/generator/data/locations.yaml +++ b/src/dusk/randomizer/generator/data/locations.yaml @@ -45,8 +45,9 @@ - Overworld - Shop - Ordona Province - - Location Name Lookup - Metadata: Sera Shop Slingshot + Metadata: + - Stage: 65 + Item: 0x4B - Name: Ordon Shield Original Item: Ordon Shield @@ -1244,7 +1245,6 @@ - Stage: 46 Flag: 0x89 -# TODO - Name: Kakariko Village Malo Mart Hawkeye Original Item: Hawkeye Categories: @@ -1253,9 +1253,9 @@ - ARC - Shop Metadata: - - None + - Stage: 68 + Item: 0x3E -# TODO - Name: Kakariko Village Malo Mart Hylian Shield Original Item: Hylian Shield Categories: @@ -1264,9 +1264,9 @@ - ARC - Shop Metadata: - - None + - Stage: 68 + Item: 0x2C -# TODO - Name: Kakariko Village Malo Mart Red Potion Original Item: Red Potion Shop Categories: @@ -1275,9 +1275,9 @@ - ARC - Shop Metadata: - - None + - Stage: 68 + Item: 0x61 -# TODO - Name: Kakariko Village Malo Mart Wooden Shield Original Item: Wooden Shield Categories: @@ -1286,7 +1286,8 @@ - ARC - Shop Metadata: - - None + - Stage: 68 + Item: 0x2B - Name: Kakariko Inn Chest Original Item: Red Rupee @@ -1322,6 +1323,7 @@ - Stage: 46 Flag: 0x85 +# TODO - Name: Barnes Bomb Bag Original Item: Bomb Bag Categories: @@ -1331,7 +1333,8 @@ - Kakariko Village - ARC Metadata: - - None + - Stage: 0xFF + Item: 0xFF - Name: Kakariko Village Bomb Shop Poe Original Item: Poe Soul @@ -2279,6 +2282,9 @@ - Castle Town - ARC - Shop + Metadata: + - Stage: 0xFF + Item: 0xFF # HD Only location # - Name: Castle Town Malo Mart Stamp @@ -2291,7 +2297,6 @@ # Metadata: # - None -# TODO - Name: North Castle Town Golden Wolf Original Item: Progressive Hidden Skill Categories: diff --git a/src/dusk/randomizer/generator/data/world/overworld/Eldin Province.yaml b/src/dusk/randomizer/generator/data/world/overworld/Eldin Province.yaml index e447663406..69fb939acb 100644 --- a/src/dusk/randomizer/generator/data/world/overworld/Eldin Province.yaml +++ b/src/dusk/randomizer/generator/data/world/overworld/Eldin Province.yaml @@ -210,13 +210,12 @@ Twilight: Eldin Can Transform: If Transform Anywhere Events: - Can Buy Wooden Shield: Not_Twilight and 'Can_Farm_Lots_of_Rupees' - Can Fund Malo Mart: Not_Twilight and Can_Complete_Lanayru_Twilight and 'Can_Farm_Lots_of_Rupees' + Can Fund Malo Mart: Can_Talk_to_Humans and Not_Twilight and Can_Complete_Lanayru_Twilight and 'Can_Farm_Lots_of_Rupees' Locations: - Kakariko Village Malo Mart Hylian Shield: Not_Twilight and 'Can_Farm_Lots_of_Rupees' - Kakariko Village Malo Mart Hawkeye: Not_Twilight and 'Can_Farm_Lots_of_Rupees' - Kakariko Village Malo Mart Red Potion: Not_Twilight and 'Can_Farm_Lots_of_Rupees' - Kakariko Village Malo Mart Wooden Shield: Not_Twilight and 'Can_Farm_Lots_of_Rupees' + Kakariko Village Malo Mart Hylian Shield: Can_Talk_to_Humans and Not_Twilight and 'Can_Farm_Lots_of_Rupees' + Kakariko Village Malo Mart Hawkeye: "'Can_Start_Talo_Sharpshooting' and 'Can_Farm_Lots_of_Rupees'" + Kakariko Village Malo Mart Red Potion: Can_Talk_to_Humans and Not_Twilight and 'Can_Farm_Lots_of_Rupees' + Kakariko Village Malo Mart Wooden Shield: Can_Talk_to_Humans and Not_Twilight and 'Can_Farm_Lots_of_Rupees' Kakariko Malo Mart Twilit Insect: Can_Defeat_Eldin_Twilit_Insect Exits: Lower Kakariko Village: Nothing @@ -356,8 +355,10 @@ Region: Kakariko Village Twilight: Eldin Can Warp: True + Events: + Can Start Talo Sharpshooting: Day and Can_Climb_Ladders and Bow and 'Can_Complete_Goron_Mines' Locations: - Talo Sharpshooting: Day and Can_Climb_Ladders and Bow and 'Can_Complete_Goron_Mines' + Talo Sharpshooting: "'Can_Start_Talo_Sharpshooting'" Exits: Kakariko Watchtower Upper Interior: Can_Open_Doors @@ -403,14 +404,26 @@ Can Warp: True Locations: Death Mountain Warp Portal: Nothing - Death Mountain Volcano Pipe Ledge Rock Rupee: Can_Complete_Eldin_Twilight and (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') + Death Mountain Volcano Pipe Ledge Rock Rupee: Can_Complete_Eldin_Twilight and (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') Death Mountain Trail Twilit Insect on Wall: Can_Defeat_Eldin_Twilit_Insect - Death Mountain Trail Twilit Insect in Hot Spring: Can_Defeat_Eldin_Twilit_Insect Exits: + Death Mountain Hot Spring: Twilight or (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') Death Mountain Lower Elevator: Goron_Mines_Entrance == Open or 'Can_Access_Death_Mountain_Lower_Elevator' Death Mountain Outside Sumo Hall: Iron_Boots and (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') and Can_Complete_Eldin_Twilight Death Mountain Trail: Nothing - + +- Name: Death Mountain Hot Spring + Map Sector: Eldin Province + Region: Death Mountain + Twilight: Eldin + Can Warp: True + Events: + Can Buy Wooden Shield: Can_Talk_to_Humans and 'Can_Farm_Rupees' and (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') + Locations: + Death Mountain Trail Twilit Insect in Hot Spring: Can_Defeat_Eldin_Twilit_Insect + Exits: + Death Mountain Volcano: Nothing + - Name: Death Mountain Lower Elevator Map Sector: Eldin Province Region: Death Mountain @@ -431,6 +444,7 @@ Death Mountain Volcano Ledge Rupee 3: Can_Complete_Eldin_Twilight and (Can_Defeat_Goron or 'Can_Complete_Goron_Mines') Exits: Death Mountain Sumo Hall: Nothing + Death Mountain Hot Spring: Nothing Death Mountain Volcano: Nothing - Name: Death Mountain Sumo Hall Elevator