diff --git a/CMakeLists.txt b/CMakeLists.txt index 85ea03232..84da81a12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE) project(Ship LANGUAGES C CXX - VERSION 5.1.1) -set(PROJECT_BUILD_NAME "BRADLEY BRAVO" CACHE STRING "") + VERSION 5.1.3) +set(PROJECT_BUILD_NAME "BRADLEY DELTA" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) diff --git a/ZAPDTR/ZAPD/ZFile.cpp b/ZAPDTR/ZAPD/ZFile.cpp index 1ea5cd553..a1d9978a1 100644 --- a/ZAPDTR/ZAPD/ZFile.cpp +++ b/ZAPDTR/ZAPD/ZFile.cpp @@ -221,7 +221,7 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) // Check for repeated attributes. if (offsetXml != nullptr) { - rawDataIndex = strtol(StringHelper::Split(offsetXml, "0x")[1].c_str(), NULL, 16); + rawDataIndex = strtol(StringHelper::Split(std::string(offsetXml), "0x")[1].c_str(), NULL, 16); if (offsetSet.find(offsetXml) != offsetSet.end()) { @@ -831,7 +831,7 @@ void ZFile::GenerateSourceHeaderFiles() xmlPath = StringHelper::Replace(xmlPath, "\\", "/"); auto pathList = StringHelper::Split(xmlPath, "/"); std::string outPath = ""; - + for (int i = 0; i < 3; i++) outPath += pathList[i] + "/"; @@ -1192,7 +1192,7 @@ std::string ZFile::ProcessTextureIntersections([[maybe_unused]] const std::strin if (declarations.find(currentOffset) != declarations.end()) declarations.at(currentOffset)->size = currentTex->GetRawDataSize(); - + currentTex->DeclareVar(GetName(), ""); } else diff --git a/libultraship b/libultraship index df3a6dd29..b1c75c86e 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit df3a6dd292c3fbed56969f17d9d018b44c8d2a46 +Subproject commit b1c75c86e902e5036ee1d36afad1a35313988fe7 diff --git a/soh/soh/Enhancements/enemyrandomizer.cpp b/soh/soh/Enhancements/enemyrandomizer.cpp index 9b09fce22..a5c0b9b6b 100644 --- a/soh/soh/Enhancements/enemyrandomizer.cpp +++ b/soh/soh/Enhancements/enemyrandomizer.cpp @@ -259,6 +259,10 @@ bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, // Only randomize the initial deku scrub actor (single and triple attack), not the flower they spawn. case ACTOR_EN_DEKUNUTS: return (params == -256 || params == 768); + // Don't randomize the OoB wallmaster in the silver rupee room because it's only there to + // not trigger unlocking the door after killing the other wallmaster in authentic gameplay. + case ACTOR_EN_WALLMAS: + return (!(!isMQ && sceneNum == SCENE_MEN && roomNum == 2 && posX == -2345)); // Only randomize initial floormaster actor (it can split and does some spawning on init). case ACTOR_EN_FLOORMAS: return (params == 0 || params == -32768); diff --git a/soh/soh/Enhancements/item-tables/ItemTableManager.cpp b/soh/soh/Enhancements/item-tables/ItemTableManager.cpp index 57f6464e3..69ac56553 100644 --- a/soh/soh/Enhancements/item-tables/ItemTableManager.cpp +++ b/soh/soh/Enhancements/item-tables/ItemTableManager.cpp @@ -23,7 +23,10 @@ bool ItemTableManager::AddItemEntry(uint16_t tableID, uint16_t getItemID, GetIte GetItemEntry ItemTableManager::RetrieveItemEntry(uint16_t tableID, uint16_t itemID) { try { ItemTable* itemTable = RetrieveItemTable(tableID); - return itemTable->at(itemID); + GetItemEntry getItemEntry = itemTable->at(itemID); + getItemEntry.drawItemId = getItemEntry.itemId; + getItemEntry.drawModIndex = getItemEntry.modIndex; + return getItemEntry; } catch (std::out_of_range& oor) { return GET_ITEM_NONE; } } diff --git a/soh/soh/Enhancements/item-tables/ItemTableTypes.h b/soh/soh/Enhancements/item-tables/ItemTableTypes.h index 34c7b556b..f16762db9 100644 --- a/soh/soh/Enhancements/item-tables/ItemTableTypes.h +++ b/soh/soh/Enhancements/item-tables/ItemTableTypes.h @@ -52,5 +52,7 @@ typedef struct GetItemEntry { /* 0x0C */ uint16_t collectable; // determines whether the item can be collected on the overworld. Will be true in most cases. /* 0x0E */ GetItemFrom getItemFrom; /* 0x0F */ GetItemCategory getItemCategory; // Primarily made and used for chest size/texture matches contents + /* 0x10 */ uint16_t drawItemId; // Will be a copy of itemId unless the item is an ice trap. Needed for particles to function on ice traps. + /* 0x11 */ uint16_t drawModIndex; // Will be a copy of modIndex unless the item is an ice trap. Needed for particles to function on ice traps. CustomDrawFunc drawFunc; -}; // size = 0x0F +}; // size = 0x11 diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index dc4ca4701..d88117cec 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -807,14 +807,14 @@ void LocationTable_Init() { locationTable[KF_SHOP_ITEM_7] = ItemLocation::Base(RC_KF_SHOP_ITEM_7, 0x2D, 0x36, "KF Shop Item 7", KF_SHOP_ITEM_7, BUY_ARROWS_30, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 6), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); locationTable[KF_SHOP_ITEM_8] = ItemLocation::Base(RC_KF_SHOP_ITEM_8, 0x2D, 0x37, "KF Shop Item 8", KF_SHOP_ITEM_8, BUY_HEART, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 7), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); - locationTable[KAK_POTION_SHOP_ITEM_1] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_1, 0x30, 0x30, "Kak Potion Shop Item 1", KAK_POTION_SHOP_ITEM_1, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_POTION_SHOP_ITEM_2] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_2, 0x30, 0x31, "Kak Potion Shop Item 2", KAK_POTION_SHOP_ITEM_2, BUY_FISH, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_1] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_1, 0x30, 0x30, "Kak Potion Shop Item 1", KAK_POTION_SHOP_ITEM_1, BUY_GREEN_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_2] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_2, 0x30, 0x31, "Kak Potion Shop Item 2", KAK_POTION_SHOP_ITEM_2, BUY_BLUE_FIRE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_POTION_SHOP_ITEM_3] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_3, 0x30, 0x32, "Kak Potion Shop Item 3", KAK_POTION_SHOP_ITEM_3, BUY_RED_POTION_30, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 2), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_POTION_SHOP_ITEM_4] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_4, 0x30, 0x33, "Kak Potion Shop Item 4", KAK_POTION_SHOP_ITEM_4, BUY_GREEN_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_POTION_SHOP_ITEM_5] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_5, 0x30, 0x34, "Kak Potion Shop Item 5", KAK_POTION_SHOP_ITEM_5, BUY_BLUE_FIRE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_4] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_4, 0x30, 0x33, "Kak Potion Shop Item 4", KAK_POTION_SHOP_ITEM_4, BUY_FAIRYS_SPIRIT, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_5] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_5, 0x30, 0x34, "Kak Potion Shop Item 5", KAK_POTION_SHOP_ITEM_5, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_POTION_SHOP_ITEM_6] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_6, 0x30, 0x35, "Kak Potion Shop Item 6", KAK_POTION_SHOP_ITEM_6, BUY_BOTTLE_BUG, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 5), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_POTION_SHOP_ITEM_7] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_7, 0x30, 0x36, "Kak Potion Shop Item 7", KAK_POTION_SHOP_ITEM_7, BUY_POE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_POTION_SHOP_ITEM_8] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_8, 0x30, 0x37, "Kak Potion Shop Item 8", KAK_POTION_SHOP_ITEM_8, BUY_FAIRYS_SPIRIT, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_8] = ItemLocation::Base(RC_KAK_POTION_SHOP_ITEM_8, 0x30, 0x37, "Kak Potion Shop Item 8", KAK_POTION_SHOP_ITEM_8, BUY_FISH, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[MARKET_BOMBCHU_SHOP_ITEM_1] = ItemLocation::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_1, 0x32, 0x30, "MK Bombchu Shop Item 1", MARKET_BOMBCHU_SHOP_ITEM_1, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_BOMBCHU_SHOP_ITEM_2] = ItemLocation::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_2, 0x32, 0x31, "MK Bombchu Shop Item 2", MARKET_BOMBCHU_SHOP_ITEM_2, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index e67cb031c..c72fbde1b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -2608,6 +2608,8 @@ GetItemEntry Randomizer::GetItemEntryFromRGData(RandomizerGetData rgData, GetIte GetItemEntry fakeGiEntry = ItemTableManager::Instance->RetrieveItemEntry(modIndex, GetItemIdFromRandomizerGet(rgData.fakeRgID, ogItemId)); giEntry.gid = fakeGiEntry.gid; giEntry.gi = fakeGiEntry.gi; + giEntry.drawItemId = fakeGiEntry.drawItemId; + giEntry.drawModIndex = fakeGiEntry.drawModIndex; giEntry.drawFunc = fakeGiEntry.drawFunc; } return giEntry; diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp index 43367f749..357b911f2 100644 --- a/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp @@ -181,6 +181,28 @@ std::map> sfxEditorSequenceMa {NA_SE_EV_CHICKEN_CRY_A, {"Chicken Cry", "NA_SE_EV_CHICKEN_CRY_A", SEQ_SFX}}, }; +// Grabs the current BGM sequence ID and replays it +// which will lookup the proper override, or reset back to vanilla +void ReplayCurrentBGM() { + u16 curSeqId = func_800FA0B4(SEQ_PLAYER_BGM_MAIN); + // TODO: replace with Audio_StartSeq when the macro is shared + // The fade time and audio player flags will always be 0 in the case of replaying the BGM, so they are not set here + Audio_QueueSeqCmd(0x00000000 | curSeqId); +} + +// Attempt to update the BGM if it matches the current sequence that is being played +// The seqKey that is passed in should be the vanilla ID, not the override ID +void UpdateCurrentBGM(u16 seqKey, SeqType seqType) { + if (seqType != SEQ_BGM_WORLD) { + return; + } + + u16 curSeqId = func_800FA0B4(SEQ_PLAYER_BGM_MAIN); + if (curSeqId == seqKey) { + ReplayCurrentBGM(); + } +} + void Draw_SfxTab(const std::string& tabId, const std::map>& map, SeqType type) { const std::string hiddenTabId = "##" + tabId; const std::string resetAllButton = "Reset All" + hiddenTabId; @@ -198,6 +220,9 @@ void Draw_SfxTab(const std::string& tabId, const std::map(seqData).c_str())) { CVar_SetS32(cvarKey.c_str(), value); SohImGui::RequestCvarSaveOnNextTick(); + UpdateCurrentBGM(defaultValue, type); } } @@ -299,6 +328,7 @@ void Draw_SfxTab(const std::string& tabId, const std::map splitName = StringHelper::Split(otrPath, "/"); + std::vector splitName = StringHelper::Split(std::string(otrPath), "/"); std::string fileName = splitName[splitName.size() - 1]; std::vector splitFileName = StringHelper::Split(fileName, "_"); std::string sequenceName = splitFileName[0]; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index a0fe66a2e..d63aee918 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1757,12 +1757,13 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { } } -extern "C" int Controller_ShouldRumble(size_t i) { +extern "C" int Controller_ShouldRumble(size_t slot) { auto controlDeck = Ship::Window::GetInstance()->GetControlDeck(); - - for (int i = 0; i < controlDeck->GetNumVirtualDevices(); ++i) { - auto physicalDevice = controlDeck->GetPhysicalDeviceFromVirtualSlot(i); - if (physicalDevice->CanRumble()) { + + if (slot < controlDeck->GetNumVirtualDevices()) { + auto physicalDevice = controlDeck->GetPhysicalDeviceFromVirtualSlot(slot); + + if (physicalDevice->getProfile(slot)->UseRumble && physicalDevice->CanRumble()) { return 1; } } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 51744dfb4..e8f068429 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -104,7 +104,7 @@ int AudioPlayer_Buffered(void); int AudioPlayer_GetDesiredBuffered(void); void AudioPlayer_Play(const uint8_t* buf, uint32_t len); void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); -int Controller_ShouldRumble(size_t i); +int Controller_ShouldRumble(size_t slot); void Controller_BlockGameInput(); void Controller_UnblockGameInput(); void Hooks_ExecuteAudioInit(); diff --git a/soh/src/code/padmgr.c b/soh/src/code/padmgr.c index ed18dcbac..48752fed1 100644 --- a/soh/src/code/padmgr.c +++ b/soh/src/code/padmgr.c @@ -331,7 +331,7 @@ void PadMgr_HandleRetraceMsg(PadMgr* padMgr) { osContGetReadData(padMgr->pads); for (i = 0; i < __osMaxControllers; i++) { - padMgr->padStatus[i].status = CVar_GetS32("gRumbleEnabled", 0) && Controller_ShouldRumble(i); + padMgr->padStatus[i].status = Controller_ShouldRumble(i); } if (padMgr->preNMIShutdown) { diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index c4e89adf7..48ca8d414 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -3326,6 +3326,15 @@ Actor* Actor_SpawnAsChild(ActorContext* actorCtx, Actor* parent, PlayState* play return NULL; } + // The following enemies break when the parent actor isn't the same as what would happen in authentic gameplay. + // As such, don't assign a parent to them at all when spawned with Enemy Randomizer. + // Gohma (z_boss_goma.c), the Stalchildren spawner (z_en_encount1.c) and the falling platform spawning Stalfos in + // Forest Temple (z_bg_mori_bigst.c) that normally rely on this behaviour are changed when + // Enemy Rando is on so they still work properly even without assigning a parent. + if (CVar_GetS32("gRandomizedEnemies", 0) && (spawnedActor->id == ACTOR_EN_FLOORMAS || spawnedActor->id == ACTOR_EN_PEEHAT)) { + return spawnedActor; + } + parent->child = spawnedActor; spawnedActor->parent = parent; diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 627776ffa..9a4b53124 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -1264,9 +1264,9 @@ void EnItem00_Draw(Actor* thisx, PlayState* play) { void EnItem00_CustomItemsParticles(Actor* Parent, PlayState* play, GetItemEntry giEntry) { s16 color_slot; - switch (giEntry.modIndex) { + switch (giEntry.drawModIndex) { case MOD_NONE: - switch (giEntry.itemId) { + switch (giEntry.drawItemId) { case ITEM_SONG_MINUET: color_slot = 0; break; @@ -1298,7 +1298,7 @@ void EnItem00_CustomItemsParticles(Actor* Parent, PlayState* play, GetItemEntry } break; case MOD_RANDOMIZER: - switch (giEntry.itemId) { + switch (giEntry.drawItemId) { case RG_MAGIC_SINGLE: case RG_MAGIC_DOUBLE: case RG_MAGIC_BEAN_PACK: @@ -1339,25 +1339,26 @@ void EnItem00_CustomItemsParticles(Actor* Parent, PlayState* play, GetItemEntry { 154, 154, 154 } // White Color placeholder }; - static Vec3f velocity = { 0.0f, 0.2f, 0.0f }; - static Vec3f accel = { 0.0f, 0.05f, 0.0f }; + static Vec3f velocity = { 0.0f, 0.0f, 0.0f }; + static Vec3f accel = { 0.0f, 0.0f, 0.0f }; Color_RGBA8 primColor = { colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 0 }; Color_RGBA8 envColor = { colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 0 }; Vec3f pos; - velocity.y = -0.00f; - accel.y = -0.0f; - pos.x = Rand_CenteredFloat(15.0f) + Parent->world.pos.x; - // Shop items are rendered at a different height than the rest, so a different y offset is required + // Make particles more compact for shop items and use a different height offset for them. if (Parent->id == ACTOR_EN_GIRLA) { + pos.x = Rand_CenteredFloat(15.0f) + Parent->world.pos.x; pos.y = (Rand_ZeroOne() * 10.0f) + Parent->world.pos.y + 3; + pos.z = Rand_CenteredFloat(15.0f) + Parent->world.pos.z; + EffectSsKiraKira_SpawnFocused(play, &pos, &velocity, &accel, &primColor, &envColor, 1000, 30); } else { - pos.y = (Rand_ZeroOne() * 10.0f) + Parent->world.pos.y + 25; + pos.x = Rand_CenteredFloat(32.0f) + Parent->world.pos.x; + pos.y = (Rand_ZeroOne() * 6.0f) + Parent->world.pos.y + 25; + pos.z = Rand_CenteredFloat(32.0f) + Parent->world.pos.z; + velocity.y = -0.05f; + accel.y = -0.025f; + EffectSsKiraKira_SpawnDispersed(play, &pos, &velocity, &accel, &primColor, &envColor, 1000, 30); } - pos.z = Rand_CenteredFloat(15.0f) + Parent->world.pos.z; - - - EffectSsKiraKira_SpawnFocused(play, &pos, &velocity, &accel, &primColor, &envColor, 1000, 30); } /** diff --git a/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c b/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c index ea355b8ad..eefb5b21c 100644 --- a/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c +++ b/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c @@ -113,9 +113,17 @@ void func_8087B938(BgHaka* this, PlayState* play) { actor = actor->next; } player->stateFlags2 &= ~0x10; + if (this->dyna.actor.params == 1) { func_80078884(NA_SE_SY_CORRECT_CHIME); - } else if (play->sceneNum == SCENE_SPOT02 && allPulled) { + } else if (!IS_DAY && play->sceneNum == SCENE_SPOT02) { + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_POH, this->dyna.actor.home.pos.x, + this->dyna.actor.home.pos.y, this->dyna.actor.home.pos.z, 0, this->dyna.actor.shape.rot.y, 0, + 1, true); + } + + // un tss un tss + if (play->sceneNum == SCENE_SPOT02 && allPulled) { func_80078884(NA_SE_SY_CORRECT_CHIME); func_800F5ACC(NA_BGM_STAFF_2); Actor* actor2 = play->actorCtx.actorLists[ACTORCAT_BG].head; @@ -126,11 +134,8 @@ void func_8087B938(BgHaka* this, PlayState* play) { } actor2 = actor2->next; } - } else if (!IS_DAY && play->sceneNum == SCENE_SPOT02) { - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_POH, this->dyna.actor.home.pos.x, - this->dyna.actor.home.pos.y, this->dyna.actor.home.pos.z, 0, this->dyna.actor.shape.rot.y, 0, - 1, true); } + this->actionFunc = func_8087BAAC; } func_8002F974(&this->dyna.actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG); diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index faf5f92db..1ceb58e36 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -422,10 +422,10 @@ void EnGirlA_InitItem(EnGirlA* this, PlayState* play) { objectId = getItemEntry.objectId; } - // Weird edge case here, sold out object reports as loaded for Kokiri shop but doesn't render so we force it to load here - if (Object_IsLoaded(&play->objectCtx, objectId) && (params != SI_SOLD_OUT && play->sceneNum == SCENE_KOKIRI_SHOP)) { - this->objBankIndex = Object_GetIndex(&play->objectCtx, objectId); - } else { + this->objBankIndex = Object_GetIndex(&play->objectCtx, objectId); + + // If the object isn't normally spawned by the shop scene, then spawn it now + if (this->objBankIndex < 0) { this->objBankIndex = Object_Spawn(&play->objectCtx, objectId); } } diff --git a/soh/src/overlays/actors/ovl_En_Ik/z_en_ik.c b/soh/src/overlays/actors/ovl_En_Ik/z_en_ik.c index 80259df9a..4f9a898f5 100644 --- a/soh/src/overlays/actors/ovl_En_Ik/z_en_ik.c +++ b/soh/src/overlays/actors/ovl_En_Ik/z_en_ik.c @@ -656,7 +656,9 @@ void func_80A75A38(EnIk* this, PlayState* play) { } if (this->unk_2F9 == 0) { Item_DropCollectibleRandom(play, &this->actor, &this->actor.world.pos, 0xB0); - if (this->switchFlags != 0xFF) { + // Don't set flag when Iron Knuckle is spawned by Enemy Rando. + // Instead Iron Knuckles rely on the "clear room" flag when Enemy Rando is on. + if (this->switchFlags != 0xFF && !CVar_GetS32("gRandomizedEnemies",0)) { Flags_SetSwitch(play, this->switchFlags); } Actor_Kill(&this->actor); diff --git a/soh/src/overlays/actors/ovl_En_Rd/z_en_rd.c b/soh/src/overlays/actors/ovl_En_Rd/z_en_rd.c index d01d3c4e7..7aa37cedb 100644 --- a/soh/src/overlays/actors/ovl_En_Rd/z_en_rd.c +++ b/soh/src/overlays/actors/ovl_En_Rd/z_en_rd.c @@ -663,7 +663,8 @@ void func_80AE3C98(EnRd* this, PlayState* play) { if (SkelAnime_Update(&this->skelAnime)) { if (this->unk_30C == 0) { - if (!Flags_GetSwitch(play, this->unk_312 & 0x7F)) { + // Don't set this flag in Enemy Rando as it can overlap with other objects using the same flag. + if (!Flags_GetSwitch(play, this->unk_312 & 0x7F) && !CVar_GetS32("gRandomizedEnemies", 0)) { Flags_SetSwitch(play, this->unk_312 & 0x7F); } if (this->unk_314 != 0) {