summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaladius <Caladius@users.noreply.github.com>2025-10-29 12:57:28 -0400
committerGitHub <noreply@github.com>2025-10-29 12:57:28 -0400
commite5db91da04b507c194c25fce45d5c87cb992123c (patch)
treef803c43f41d7a41778e74a7be8a9c8745b27ef08
parent83921dc012588c520efe0ed8c7ac1406806543c7 (diff)
[Rando] Enemy Drop Shuffle (#1282)
* Implement most of the Enemy Drops * Fix Glitchless Generation * Fix duplicate Logic Checks * Add Slime Items and fix Linux Floating Point. * Add Comment for Enemy Drops RC Sets * Adds Leever and fixes Position Check issue. * Adds GBC for Logic check * Add Hiploop * Adds Skullfish (Enemy only drops items inside GBT) * Feedback Updates * Updates * Update to Switch for Actor Selection * More Enemy Locations * Fix Mini Baba and remove actors that dont drop items * Update mm/2s2h/Rando/Logic/Logic.h Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Add case for ACTOR_BOSS_05 in Logic.h * Update mm/2s2h/Rando/Types.h Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Clang format actor position * Need swim for Bio Deku Baba * Define RC_ENEMY_DROP_BIO_DEKU_BABA in checks * GitHub spacing how dare you * Update mm/2s2h/Rando/StaticData/Checks.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Types.h Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/StaticData/Checks.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Types.h Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/StaticData/Checks.cpp Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Update mm/2s2h/Rando/Types.h Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com> * Apply suggestion from @Eblo --------- Co-authored-by: Eblo <7004497+Eblo@users.noreply.github.com>
-rw-r--r--mm/2s2h/GameInteractor/GameInteractor.h2
-rw-r--r--mm/2s2h/Rando/ActorBehavior/ActorBehavior.cpp1
-rw-r--r--mm/2s2h/Rando/ActorBehavior/ActorBehavior.h1
-rw-r--r--mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp151
-rw-r--r--mm/2s2h/Rando/CheckTracker/CheckTracker.cpp4
-rw-r--r--mm/2s2h/Rando/Logic/Logic.cpp4
-rw-r--r--mm/2s2h/Rando/Logic/Logic.h82
-rw-r--r--mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp51
-rw-r--r--mm/2s2h/Rando/Logic/Regions/TerminaField.cpp1
-rw-r--r--mm/2s2h/Rando/Menu.cpp2
-rw-r--r--mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp5
-rw-r--r--mm/2s2h/Rando/StaticData/Checks.cpp37
-rw-r--r--mm/2s2h/Rando/StaticData/Options.cpp1
-rw-r--r--mm/2s2h/Rando/Types.h40
-rw-r--r--mm/src/code/z_en_item00.c8
-rw-r--r--mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c12
16 files changed, 395 insertions, 7 deletions
diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h
index e27e7069b..8c44f5b5a 100644
--- a/mm/2s2h/GameInteractor/GameInteractor.h
+++ b/mm/2s2h/GameInteractor/GameInteractor.h
@@ -254,6 +254,8 @@ typedef enum {
VB_SET_CAMERA_AT_EYE,
VB_SET_CAMERA_FOV,
VB_USE_ITEM_CONSIDER_ITEM_ACTION,
+ VB_ENEMY_DROP_COLLECTIBLE,
+ VB_DRAW_SLIME_RANDO_ITEM
} GIVanillaBehavior;
typedef enum {
diff --git a/mm/2s2h/Rando/ActorBehavior/ActorBehavior.cpp b/mm/2s2h/Rando/ActorBehavior/ActorBehavior.cpp
index a0e9da23f..04600c8bd 100644
--- a/mm/2s2h/Rando/ActorBehavior/ActorBehavior.cpp
+++ b/mm/2s2h/Rando/ActorBehavior/ActorBehavior.cpp
@@ -78,6 +78,7 @@ void Rando::ActorBehavior::OnFileLoad() {
Rando::ActorBehavior::InitEnDnhBehavior();
Rando::ActorBehavior::InitEnElfgrpBehavior();
Rando::ActorBehavior::InitEnElforgBehavior();
+ Rando::ActorBehavior::InitEnemyDropBehavior();
Rando::ActorBehavior::InitEnFish2Behavior();
Rando::ActorBehavior::InitEnFsnBehavior();
Rando::ActorBehavior::InitEnFuBehavior();
diff --git a/mm/2s2h/Rando/ActorBehavior/ActorBehavior.h b/mm/2s2h/Rando/ActorBehavior/ActorBehavior.h
index f1ec06fe4..30b82dfda 100644
--- a/mm/2s2h/Rando/ActorBehavior/ActorBehavior.h
+++ b/mm/2s2h/Rando/ActorBehavior/ActorBehavior.h
@@ -35,6 +35,7 @@ void InitEnDnhBehavior();
void InitEnElfgrpBehavior();
void InitEnElforgBehavior();
void InitEnFish2Behavior();
+void InitEnemyDropBehavior();
void InitEnFsnBehavior();
void InitEnFuBehavior();
void InitEnGamelupyBehavior();
diff --git a/mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp b/mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp
new file mode 100644
index 000000000..98ba30e5d
--- /dev/null
+++ b/mm/2s2h/Rando/ActorBehavior/EnemyDrops.cpp
@@ -0,0 +1,151 @@
+#include "ActorBehavior.h"
+#include <libultraship/bridge/consolevariablebridge.h>
+#include "2s2h/CustomItem/CustomItem.h"
+
+extern "C" {
+#include "variables.h"
+#include "functions.h"
+
+#include "overlays/actors/ovl_En_Slime/z_en_slime.h"
+#include "overlays/actors/ovl_En_Sw/z_en_sw.h"
+}
+
+std::unordered_map<int16_t, RandoCheckId> actorIdToRandoCheckIdMap = {
+ { ACTOR_EN_AM, RC_ENEMY_DROP_ARMOS },
+ { ACTOR_EN_VM, RC_ENEMY_DROP_BEAMOS },
+ { ACTOR_BOSS_05, RC_ENEMY_DROP_BIO_DEKU_BABA },
+ { ACTOR_EN_BB, RC_ENEMY_DROP_BLUE_BUBBLE },
+ { ACTOR_EN_RAT, RC_ENEMY_DROP_BOMBCHU },
+ { ACTOR_EN_SLIME, RC_ENEMY_DROP_CHU },
+ { ACTOR_EN_FAMOS, RC_ENEMY_DROP_DEATH_ARMOS },
+ { ACTOR_EN_DEKUBABA, RC_ENEMY_DROP_DEKU_BABA },
+ { ACTOR_EN_DODONGO, RC_ENEMY_DROP_DODONGO },
+ { ACTOR_EN_GRASSHOPPER, RC_ENEMY_DROP_DRAGONFLY },
+ { ACTOR_EN_SNOWMAN, RC_ENEMY_DROP_EENO },
+ { ACTOR_EN_TUBO_TRAP, RC_ENEMY_DROP_FLYING_POT },
+ { ACTOR_EN_FLOORMAS, RC_ENEMY_DROP_FLOORMASTER },
+ { ACTOR_EN_FZ, RC_ENEMY_DROP_FREEZARD },
+ { ACTOR_EN_CROW, RC_ENEMY_DROP_GUAY },
+ { ACTOR_EN_PP, RC_ENEMY_DROP_HIPLOOP },
+ { ACTOR_EN_IK, RC_ENEMY_DROP_IRON_KNUCKLE },
+ { ACTOR_EN_FIREFLY, RC_ENEMY_DROP_KEESE },
+ { ACTOR_EN_NEO_REEBA, RC_ENEMY_DROP_LEEVER },
+ { ACTOR_EN_RR, RC_ENEMY_DROP_LIKE_LIKE },
+ { ACTOR_EN_DEKUNUTS, RC_ENEMY_DROP_MAD_SCRUB },
+ { ACTOR_EN_KAREBABA, RC_ENEMY_DROP_MINI_BABA },
+ { ACTOR_EN_BAGUO, RC_ENEMY_DROP_NEJIRON },
+ { ACTOR_EN_OKUTA, RC_ENEMY_DROP_OCTOROK },
+ { ACTOR_EN_PEEHAT, RC_ENEMY_DROP_PEAHAT },
+ { ACTOR_EN_BBFALL, RC_ENEMY_DROP_RED_BUBBLE },
+ { ACTOR_EN_RD, RC_ENEMY_DROP_REDEAD_GIBDO },
+ { ACTOR_EN_SB, RC_ENEMY_DROP_SHELLBLADE },
+ { ACTOR_EN_PR2, RC_ENEMY_DROP_SKULLFISH },
+ { ACTOR_EN_ST, RC_ENEMY_DROP_SKULLTULA },
+ { ACTOR_EN_SW, RC_ENEMY_DROP_SKULLWALLTULA },
+ { ACTOR_EN_KAME, RC_ENEMY_DROP_SNAPPER },
+ { ACTOR_EN_SKB, RC_ENEMY_DROP_STALCHILD },
+ { ACTOR_EN_TITE, RC_ENEMY_DROP_TEKTITE },
+ { ACTOR_EN_WF, RC_ENEMY_DROP_WOLFOS },
+ { ACTOR_EN_WALLMAS, RC_ENEMY_DROP_WALLMASTER },
+};
+
+RandoCheckId GetRandoCheckByActorId(int16_t actorId) {
+ for (auto& map : actorIdToRandoCheckIdMap) {
+ if (map.first == actorId) {
+ return map.second;
+ }
+ }
+
+ return RC_UNKNOWN;
+}
+
+Actor* FindActor(Vec3f position, ActorType actorType) {
+ ActorListEntry actorList = gPlayState->actorCtx.actorLists[actorType];
+
+ Actor* currentActor = actorList.first;
+ for (size_t i = 0; i < actorList.length; i++) {
+ if (currentActor->world.pos.x == position.x && currentActor->world.pos.y == position.y &&
+ currentActor->world.pos.z == position.z) {
+ return currentActor;
+ } else {
+ currentActor = currentActor->next;
+ }
+ }
+ return nullptr;
+}
+
+void SpawnEnemyDrop(Vec3f position, Actor* actor, RandoCheckId randoCheckId) {
+ CustomItem::Spawn(
+ position.x, position.y, position.z, 0,
+ CustomItem::KILL_ON_TOUCH | CustomItem::TOSS_ON_SPAWN | CustomItem::ABLE_TO_ZORA_RANG, randoCheckId,
+ [](Actor* actor, PlayState* play) {
+ RandoSaveCheck& randoSaveCheck = RANDO_SAVE_CHECKS[CUSTOM_ITEM_PARAM];
+ randoSaveCheck.eligible = true;
+ },
+ [](Actor* actor, PlayState* play) {
+ auto& randoSaveCheck = RANDO_SAVE_CHECKS[CUSTOM_ITEM_PARAM];
+ RandoItemId randoItemId = Rando::ConvertItem(randoSaveCheck.randoItemId);
+ Matrix_Scale(30.0f, 30.0f, 30.0f, MTXMODE_APPLY);
+ Rando::DrawItem(Rando::ConvertItem(randoSaveCheck.randoItemId, (RandoCheckId)CUSTOM_ITEM_PARAM), actor);
+ });
+}
+
+void Rando::ActorBehavior::InitEnemyDropBehavior() {
+ COND_VB_SHOULD(VB_ENEMY_DROP_COLLECTIBLE, IS_RANDO, {
+ Vec3f position = va_arg(args, Vec3f);
+
+ if (RANDO_SAVE_OPTIONS[RO_SHUFFLE_ENEMY_DROPS] == RO_GENERIC_OFF) {
+ return;
+ }
+
+ Actor* foundActor = FindActor(position, ACTORCAT_ENEMY);
+ if (foundActor == nullptr || foundActor->category != ACTORCAT_ENEMY) {
+ return;
+ }
+
+ int16_t actorId = foundActor->id;
+
+ // Skullwalltulas need special handling because most of them drop tokens
+ if (actorId == ACTOR_EN_SW) {
+ return;
+ }
+
+ RandoCheckId randoCheckId = GetRandoCheckByActorId(actorId);
+ if (randoCheckId == RC_UNKNOWN || RANDO_SAVE_CHECKS[randoCheckId].cycleObtained) {
+ return;
+ }
+
+ SpawnEnemyDrop(position, foundActor, randoCheckId);
+ *should = false;
+ });
+
+ COND_ID_HOOK(OnActorKill, ACTOR_EN_SW, IS_RANDO, [](Actor* actor) {
+ if (!ENSW_GET_3(actor)) {
+ RandoCheckId randoCheckId = GetRandoCheckByActorId(ACTOR_EN_SW);
+ if (RANDO_SAVE_CHECKS[randoCheckId].cycleObtained) {
+ return;
+ }
+
+ SpawnEnemyDrop(actor->world.pos, actor, randoCheckId);
+ }
+ });
+
+ COND_VB_SHOULD(VB_DRAW_SLIME_RANDO_ITEM, IS_RANDO, {
+ if (RANDO_SAVE_OPTIONS[RO_SHUFFLE_ENEMY_DROPS] == RO_GENERIC_OFF) {
+ return;
+ }
+
+ EnSlime* slime = va_arg(args, EnSlime*);
+ RandoCheckId randoCheckId = GetRandoCheckByActorId(ACTOR_EN_SLIME);
+ if (RANDO_SAVE_CHECKS[randoCheckId].cycleObtained) {
+ return;
+ }
+ RandoItemId randoItemId = Rando::ConvertItem(RANDO_SAVE_CHECKS[randoCheckId].randoItemId);
+
+ Matrix_RotateYS(slime->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_Scale(0.25f, 0.25f, 0.25f, MTXMODE_APPLY);
+ Rando::DrawItem(randoItemId);
+
+ *should = false;
+ });
+}
diff --git a/mm/2s2h/Rando/CheckTracker/CheckTracker.cpp b/mm/2s2h/Rando/CheckTracker/CheckTracker.cpp
index b93807f88..48dfddb94 100644
--- a/mm/2s2h/Rando/CheckTracker/CheckTracker.cpp
+++ b/mm/2s2h/Rando/CheckTracker/CheckTracker.cpp
@@ -68,6 +68,7 @@ std::vector<const char*> checkTypeIconList = {
/*RCTYPE_CHEST*/ gChestTrackerIcon,
/*RCTYPE_COW*/ gItemIconRomaniMaskTex,
/*RCTYPE_CRATE*/ gCrateTrackerIcon,
+ /*RCTYPE_ENEMY_DROP*/ gDungeonMapSkullTex,
/*RCTYPE_FREESTANDING*/ gRupeeCounterIconTex,
/*RCTYPE_FROG*/ gItemIconDonGeroMaskTex,
/*RCTYPE_GRASS*/ gameplay_keep_Tex_053140,
@@ -375,6 +376,9 @@ void CheckTrackerDrawNonLogicalList() {
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0, 0, 0, 0));
std::string headerText = Ship_GetSceneName(sceneId);
+ if (sceneId == SCENE_SPOT00) {
+ headerText = "Various Regions";
+ }
headerText += " (" + std::to_string(obtainedCheckSum) + "/" + std::to_string(unfilteredChecks.size()) + ")";
ImGui::PushStyleColor(ImGuiCol_Text, obtainedCheckSum == unfilteredChecks.size()
diff --git a/mm/2s2h/Rando/Logic/Logic.cpp b/mm/2s2h/Rando/Logic/Logic.cpp
index b76397557..11958e09b 100644
--- a/mm/2s2h/Rando/Logic/Logic.cpp
+++ b/mm/2s2h/Rando/Logic/Logic.cpp
@@ -72,6 +72,10 @@ static RegisterShipInitFunc initFunc([]() {
EXIT(ENTRANCE(ZORA_CAPE, 6), ONE_WAY_EXIT, CAN_PLAY_SONG(SOARING) && CAN_OWL_WARP(OWL_WARP_ZORA_CAPE)),
EXIT(ENTRANCE(IKANA_CANYON, 4), ONE_WAY_EXIT, CAN_PLAY_SONG(SOARING) && CAN_OWL_WARP(OWL_WARP_IKANA_CANYON)),
EXIT(ENTRANCE(STONE_TOWER, 3), ONE_WAY_EXIT, CAN_PLAY_SONG(SOARING) && CAN_OWL_WARP(OWL_WARP_STONE_TOWER)),
+ EXIT(ENTRANCE(CUTSCENE, 0), ONE_WAY_EXIT, true), // Enemy Drop Region
+ },
+ .connections = {
+ CONNECTION(RR_MISCELLANEOUS, true), // Enemy Drop Region
},
};
}, {});
diff --git a/mm/2s2h/Rando/Logic/Logic.h b/mm/2s2h/Rando/Logic/Logic.h
index adde65a4c..2c0ed8db3 100644
--- a/mm/2s2h/Rando/Logic/Logic.h
+++ b/mm/2s2h/Rando/Logic/Logic.h
@@ -119,6 +119,17 @@ extern std::map<RandoRegionId, RandoRegion> Regions;
} \
}
+inline bool CanReachRegions(std::vector<RandoRegionId> regionList) {
+ std::set<RandoRegionId> reachableRegions;
+ FindReachableRegions(GetRegionIdFromEntrance(gSaveContext.save.entrance), reachableRegions);
+ for (auto& target : regionList) {
+ if (reachableRegions.count(target) > 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
inline std::string LogicString(std::string condition) {
if (condition == "true")
return "";
@@ -214,7 +225,7 @@ inline bool CanKillEnemy(ActorId EnemyId) {
return (HAS_ITEM(ITEM_BOW) && (CAN_BE_DEKU || CAN_USE_EXPLOSIVE || CAN_BE_GORON));
case ACTOR_EN_BIGSLIME: // Great Bay Gekko
return (CAN_USE_MAGIC_ARROW(ICE));
- case ACTOR_EN_SW: // Gold Skulltula
+ case ACTOR_EN_SW: // Gold Skulltula & Skullwalltula
return (CAN_USE_PROJECTILE || CAN_BE_DEKU || CAN_BE_GORON || CAN_USE_HUMAN_SWORD || CAN_USE_EXPLOSIVE);
case ACTOR_EN_DINOFOS: // Dinofos
return (CAN_USE_SWORD || CAN_BE_GORON || HAS_ITEM(ITEM_BOW) || (CAN_BE_DEKU && HAS_MAGIC));
@@ -244,6 +255,75 @@ inline bool CanKillEnemy(ActorId EnemyId) {
CAN_USE_EXPLOSIVE || HAS_ITEM(ITEM_DEKU_STICK));
case ACTOR_OBJ_SNOWBALL: // Large Snowball
return (CAN_USE_EXPLOSIVE || CAN_BE_GORON || CAN_USE_MAGIC_ARROW(FIRE));
+ case ACTOR_EN_AM: // Armos
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU || CAN_USE_EXPLOSIVE);
+ case ACTOR_EN_VM: // Beamos
+ return (CAN_USE_EXPLOSIVE);
+ case ACTOR_EN_BB: // Blue Bubble
+ case ACTOR_EN_BBFALL: // Red Bubble
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || HAS_ITEM(ITEM_BOW) || HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_RAT: // Real Bombchu
+ case ACTOR_EN_TUBO_TRAP: // Flying Pot
+ return true;
+ case ACTOR_EN_FAMOS: // Death Armos
+ return (CAN_USE_MAGIC_ARROW(LIGHT));
+ case ACTOR_EN_DODONGO: // Dodongo
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC));
+ case ACTOR_EN_FLOORMAS: // Floormaster
+ case ACTOR_EN_WALLMAS: // Wallmaster
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_FZ: // Freezard
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_USE_MAGIC_ARROW(FIRE) ||
+ HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_CROW: // Guay (Generic, excludes the one circling Clock Town En_Ruppecrow)
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_FIREFLY: // Keese
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_RR: // Like Like
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_DEKUNUTS: // Mad Scrub
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_KAREBABA: // Wilted/Mini Babas
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU);
+ case ACTOR_EN_PEEHAT: // Peahat
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || CAN_BE_DEKU || HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_RD: // Redead & Gibdos
+ return (CAN_USE_SWORD || CAN_BE_DEKU || CAN_BE_GORON || CAN_BE_ZORA || HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_SKB: // Stalchild
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_TITE: // Tektite
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW));
+ case ACTOR_EN_SLIME: // Chuchus
+ return (CAN_USE_SWORD || CAN_BE_ZORA || CAN_BE_DEKU || HAS_ITEM(ITEM_BOW) || HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_SNOWMAN: // Eeno
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_WDHAND: // Dexihand (Basic kill method, seems like a pain to require other things)
+ return (CAN_BE_ZORA && HAS_MAGIC);
+ case ACTOR_EN_KAME: // Snapper (non Gekko Miniboss)
+ return (CAN_BE_DEKU || CAN_USE_EXPLOSIVE || CAN_BE_GORON);
+ case ACTOR_EN_SB: // Shellblade
+ return (CAN_BE_ZORA && HAS_MAGIC);
+ case ACTOR_EN_OKUTA: // Octorok
+ return (CAN_USE_PROJECTILE);
+ case ACTOR_EN_BAGUO: // Nejiron
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_NEO_REEBA: // Leever
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK));
+ case ACTOR_EN_PP:
+ return (CAN_USE_SWORD || CAN_BE_GORON || CAN_BE_ZORA || (CAN_BE_DEKU && HAS_MAGIC) || HAS_ITEM(ITEM_BOW) ||
+ HAS_ITEM(ITEM_DEKU_STICK) || HAS_ITEM(ITEM_HOOKSHOT));
+ case ACTOR_EN_PR2:
+ return (CAN_BE_ZORA && HAS_MAGIC);
+ case ACTOR_BOSS_05: // Bio Deku Baba
+ return CAN_BE_ZORA && CAN_USE_ABILITY(SWIM);
default: // Incorrect actor ID inputed.
assert(false);
return false;
diff --git a/mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp b/mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp
new file mode 100644
index 000000000..80b187a72
--- /dev/null
+++ b/mm/2s2h/Rando/Logic/Regions/Miscellaneous.cpp
@@ -0,0 +1,51 @@
+#include "2s2h/GameInteractor/GameInteractor.h"
+#include "2s2h/ShipInit.hpp"
+
+#include "2s2h/Rando/Logic/Logic.h"
+
+using namespace Rando::Logic;
+
+// clang-format off
+static RegisterShipInitFunc initFunc([]() {
+ Regions[RR_MISCELLANEOUS] = RandoRegion{ .name = "Various Regions", .sceneId = SCENE_SPOT00,
+ .checks = {
+ CHECK(RC_ENEMY_DROP_ARMOS, CanKillEnemy(ACTOR_EN_AM) && CanReachRegions({ RR_STONE_TOWER_TEMPLE_ARMOS_ROOM })),
+ CHECK(RC_ENEMY_DROP_BEAMOS, CanKillEnemy(ACTOR_EN_VM) && CanReachRegions({ RR_STONE_TOWER_BOTTOM, RR_STONE_TOWER_MIDDLE, RR_STONE_TOWER_TEMPLE_SHALLOW_POOL_ROOM })),
+ CHECK(RC_ENEMY_DROP_BLUE_BUBBLE, CanKillEnemy(ACTOR_EN_BB) && CanReachRegions({ RR_TERMINA_FIELD, RR_ROAD_TO_IKANA_FIELD_SIDE, RR_ROAD_TO_IKANA_BELOW_LEDGE, RR_IKANA_CASTLE_BUBBLE_ROOM, RR_STONE_TOWER_TEMPLE_INVERTED_PATH_TO_GOMESS })),
+ CHECK(RC_ENEMY_DROP_BIO_DEKU_BABA, CanKillEnemy(ACTOR_BOSS_05) && CanReachRegions({ RR_TERMINA_FIELD_BIO_BABA_GROTTO, RR_STONE_TOWER_TEMPLE_DEEP_POOL_ROOM, RR_GREAT_BAY_TEMPLE_COMPASS_ROOM, RR_GREAT_BAY_TEMPLE_BABA_CHEST_ROOM })),
+ CHECK(RC_ENEMY_DROP_BOMBCHU, CanKillEnemy(ACTOR_EN_RAT) && CanReachRegions({ RR_TERMINA_FIELD, RR_ROAD_TO_IKANA_FIELD_SIDE, RR_ROAD_TO_IKANA_BELOW_LEDGE, RR_SNOWHEAD_TEMPLE_MAP_ROOM_LOWER, RR_STONE_TOWER_TEMPLE_LAVA_WIND_ROOM, RR_GREAT_BAY_TEMPLE_COMPASS_ROOM, RR_GREAT_BAY_TEMPLE_GREEN_PIPE_3 })),
+ CHECK(RC_ENEMY_DROP_CHU, CanKillEnemy(ACTOR_EN_SLIME) && CanReachRegions({ RR_TERMINA_FIELD, RR_ROAD_TO_SOUTHERN_SWAMP, RR_GREAT_BAY_TEMPLE_BEFORE_WART, RR_GREAT_BAY_TEMPLE_GREEN_PIPE_3, RR_STONE_TOWER_TEMPLE_INVERTED_BLOCK_FLIP_ROOM })),
+ CHECK(RC_ENEMY_DROP_DEATH_ARMOS, CanKillEnemy(ACTOR_EN_FAMOS) && CanReachRegions({ RR_STONE_TOWER_TEMPLE_INVERTED_SIDE_OF_ENTRANCE, RR_STONE_TOWER_TEMPLE_INVERTED_POE_ROOM })),
+ CHECK(RC_ENEMY_DROP_DEKU_BABA, CanKillEnemy(ACTOR_EN_DEKUBABA) && CanReachRegions({ RR_TERMINA_FIELD, RR_ROAD_TO_SOUTHERN_SWAMP, RR_SOUTHERN_SWAMP_SOUTH, RR_WOODFALL, RR_WOODFALL_TEMPLE_MAIN_ROOM, RR_WOODFALL_TEMPLE_MAZE_ROOM, RR_BENEATH_THE_WELL_BABA_AND_POTS_ROOM, RR_SAKON_HIDEOUT })),
+ CHECK(RC_ENEMY_DROP_DODONGO, CanKillEnemy(ACTOR_EN_DODONGO) && CanReachRegions({ RR_TERMINA_FIELD, RR_TERMINA_FIELD_DODONGO_GROTTO })),
+ CHECK(RC_ENEMY_DROP_DRAGONFLY, CanKillEnemy(ACTOR_EN_GRASSHOPPER) && CanReachRegions({ RR_SOUTHERN_SWAMP_SOUTH, RR_WOODFALL, RR_STONE_TOWER_TEMPLE_ENTRANCE, RR_STONE_TOWER_TEMPLE_OUTSIDE_SWITCH_ROOM, RR_WOODFALL_TEMPLE_PRE_BOSS_ROOM, RR_WOODFALL_TEMPLE_MAIN_ROOM_UPPER })),
+ CHECK(RC_ENEMY_DROP_EENO, CanKillEnemy(ACTOR_EN_SNOWMAN) && CanReachRegions({ RR_TERMINA_FIELD, RR_SNOWHEAD_TEMPLE_SNOW_ROOM })),
+ CHECK(RC_ENEMY_DROP_FLYING_POT, CanKillEnemy(ACTOR_EN_TUBO_TRAP) && CanReachRegions({ RR_STONE_TOWER_TEMPLE_INVERTED_UNDER_BRIDGE, RR_SNOWHEAD_TEMPLE_BLOCK_ROOM })),
+ CHECK(RC_ENEMY_DROP_FLOORMASTER, CanKillEnemy(ACTOR_EN_FLOORMAS) && CanReachRegions({ RR_IKANA_CASTLE_FLOORMASTER_ROOM })),
+ CHECK(RC_ENEMY_DROP_FREEZARD, CanKillEnemy(ACTOR_EN_FZ) && CanReachRegions({ RR_SNOWHEAD_TEMPLE_BRIDGE_ROOM_AFTER, RR_SNOWHEAD_TEMPLE_MAP_ROOM_UPPER, RR_SNOWHEAD_TEMPLE_PILLARS_ROOM_UPPER, RR_BENEATH_THE_WELL_FREEZARD_ROOM })),
+ CHECK(RC_ENEMY_DROP_GUAY, CanKillEnemy(ACTOR_EN_CROW) && CanReachRegions({ RR_IKANA_CANYON_UPPER, RR_IKANA_CASTLE_COURTYARD, RR_PATH_TO_GORON_VILLAGE, RR_IKANA_CASTLE_COURTYARD, RR_ZORA_CAPE }) || (CanReachRegions({ RR_MOUNTAIN_VILLAGE, RR_PATH_TO_GORON_VILLAGE }) && RANDO_EVENTS[RE_CLEARED_SNOWHEAD_TEMPLE])),
+ CHECK(RC_ENEMY_DROP_HIPLOOP, CanKillEnemy(ACTOR_EN_PP) && CanReachRegions({ RR_WOODFALL, RR_STONE_TOWER_TEMPLE_INVERTED_WIND_ROOM, RR_STONE_TOWER_TEMPLE_SPIKED_BAR_ROOM_UPPER })),
+ CHECK(RC_ENEMY_DROP_IRON_KNUCKLE, CanKillEnemy(ACTOR_EN_IK) && CanReachRegions({ RR_BENEATH_THE_GRAVEYARD_NIGHT_1_BOSS, RR_BENEATH_THE_GRAVEYARD_NIGHT_2_BOSS, RR_MOON_LINK_TRIAL })),
+ CHECK(RC_ENEMY_DROP_KEESE, CanKillEnemy(ACTOR_EN_FIREFLY) && CanReachRegions({ RR_TERMINA_FIELD, RR_STONE_TOWER_TOP, RR_STONE_TOWER_UPPER, RR_STONE_TOWER_MIDDLE, RR_BENEATH_THE_WELL_LEFT_FIRE_KEESE, RR_BENEATH_THE_WELL_RIGHT_FIRE_KEESE, RR_BENEATH_THE_WELL_FREEZARD_ROOM, RR_BENEATH_THE_GRAVEYARD_NIGHT_2_GRAVE_BEFORE_PIT, RR_SNOWHEAD_NEAR_TEMPLE, RR_PATH_TO_SNOWHEAD_LOWER, RR_PATH_TO_SNOWHEAD_MIDDLE })),
+ CHECK(RC_ENEMY_DROP_LEEVER, CanKillEnemy(ACTOR_EN_NEO_REEBA) && CanReachRegions({ RR_TERMINA_FIELD, RR_GREAT_BAY_COAST, RR_ZORA_CAPE })),
+ CHECK(RC_ENEMY_DROP_LIKE_LIKE, CanKillEnemy(ACTOR_EN_RR) && CanReachRegions({ RR_ZORA_CAPE, RR_GREAT_BAY_COAST })),
+ CHECK(RC_ENEMY_DROP_MAD_SCRUB, CanKillEnemy(ACTOR_EN_DEKUNUTS) && CanReachRegions({ RR_WOODFALL, RR_DEKU_PALACE_INSIDE })),
+ CHECK(RC_ENEMY_DROP_MINI_BABA, CanKillEnemy(ACTOR_EN_KAREBABA) && CanReachRegions({ RR_SOUTHERN_SWAMP_NORTH, RR_SOUTHERN_SWAMP_NEAR_WOODS, RR_BENEATH_THE_WELL_BABA_AND_POTS_ROOM })),
+ CHECK(RC_ENEMY_DROP_NEJIRON, CanKillEnemy(ACTOR_EN_BAGUO) && CanReachRegions({ RR_ROAD_TO_IKANA_ABOVE_LEDGE, RR_STONE_TOWER_TEMPLE_MIRROR_PILLAR_ROOM })),
+ CHECK(RC_ENEMY_DROP_OCTOROK, CanKillEnemy(ACTOR_EN_OKUTA) && CanReachRegions({ RR_SOUTHERN_SWAMP_NORTH, RR_GREAT_BAY_TEMPLE_RED_PIPE_BEFORE_WART, RR_IKANA_CANYON_LOWER })),
+ CHECK(RC_ENEMY_DROP_PEAHAT, CanKillEnemy(ACTOR_EN_PEEHAT) && CanReachRegions({ RR_TERMINA_FIELD_PEAHAT_GROTTO })),
+ CHECK(RC_ENEMY_DROP_RED_BUBBLE, CanKillEnemy(ACTOR_EN_BBFALL) && CanReachRegions({ RR_SNOWHEAD_TEMPLE_CENTRAL_ROOM_BOTTOM })),
+ CHECK(RC_ENEMY_DROP_REDEAD_GIBDO, CanKillEnemy(ACTOR_EN_RD) && CanReachRegions({ RR_IKANA_CANYON_UPPER, RR_IKANA_CASTLE_FRONT_ENTRANCE, RR_STONE_TOWER_UPPER, RR_BENEATH_THE_WELL_ENTRANCE, RR_BENEATH_THE_WELL_THREE_SPIKED_BARS, RR_BENEATH_THE_WELL_TWO_SPIKED_BARS, RR_BENEATH_THE_WELL_FREEZARD_ROOM, RR_BENEATH_THE_WELL_RIGHT_FIRE_KEESE, RR_BENEATH_THE_WELL_BABA_AND_POTS_ROOM, RR_BENEATH_THE_WELL_FOUR_SPIKED_BARS })),
+ CHECK(RC_ENEMY_DROP_SHELLBLADE, CanKillEnemy(ACTOR_EN_SB) && CanReachRegions({ RR_PIRATES_FORTRESS_LEFT_CLAM_EGG_ROOM, RR_PIRATES_FORTRESS_RIGHT_CLAM_EGG_ROOM, RR_PIRATES_FORTRESS_CAPTAIN_ROOM, RR_GREAT_BAY_TEMPLE_RED_PIPE_BEFORE_WART })),
+ CHECK(RC_ENEMY_DROP_SKULLFISH, CanKillEnemy(ACTOR_EN_PR2) && CanReachRegions({ RR_GREAT_BAY_TEMPLE_MAP_ROOM, RR_GREAT_BAY_TEMPLE_RED_PIPE_BEFORE_WART, })),
+ CHECK(RC_ENEMY_DROP_SKULLTULA, CanKillEnemy(ACTOR_EN_ST) && CanReachRegions({ RR_ASTRAL_OBSERVATORY_PASSAGE, RR_WOODFALL_TEMPLE_MAZE_ROOM, RR_OCEAN_SPIDER_HOUSE_MEETING_ROOM, RR_BENEATH_THE_WELL_SKULLTULA_ROOM, RR_BENEATH_THE_WELL_FOUR_SPIKED_BARS, RR_BENEATH_THE_GRAVEYARD_NIGHT_1_GRAVE, RR_GREAT_BAY_TEMPLE_WATER_WHEEL_ROOM, RR_IKANA_CASTLE_SKULLTULA_ROOM })),
+ CHECK(RC_ENEMY_DROP_SKULLWALLTULA, CanKillEnemy(ACTOR_EN_SW) && CanReachRegions({ RR_TERMINA_FIELD_GOSSIP_STONE_GROTTO_1, RR_LONE_PEAK_SHRINE })),
+ CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_EN_KAME) && CanReachRegions({ RR_WOODS_OF_MYSTERY, RR_WOODFALL_TEMPLE_MAP_ROOM })),
+ CHECK(RC_ENEMY_DROP_STALCHILD, CanKillEnemy(ACTOR_EN_SKB) && CanReachRegions({ RR_IKANA_GRAVEYARD_LOWER, RR_OCEAN_SPIDER_HOUSE_LIBRARY_ROOM, RR_OCEAN_SPIDER_HOUSE_MEETING_ROOM })),
+ CHECK(RC_ENEMY_DROP_TEKTITE, CanKillEnemy(ACTOR_EN_TITE) && CanReachRegions({ RR_GORON_VILLAGE, RR_PATH_TO_MOUNTAIN_VILLAGE_LOWER, RR_PATH_TO_GORON_VILLAGE, RR_GREAT_BAY_TEMPLE_GREEN_PIPE_1 })),
+ CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_EN_WF) && CanReachRegions({ RR_ROAD_TO_SOUTHERN_SWAMP, RR_PATH_TO_GORON_VILLAGE, RR_SNOWHEAD_TEMPLE_ENTRANCE_AFTER_BLOCK, RR_SNOWHEAD_NEAR_TEMPLE, RR_SNOWHEAD_TEMPLE_COMPASS_ROOM, RR_SAKON_HIDEOUT })),
+ CHECK(RC_ENEMY_DROP_WALLMASTER, CanKillEnemy(ACTOR_EN_WALLMAS) && CanReachRegions({ RR_BENEATH_THE_GRAVEYARD_DAMPE, RR_BENEATH_THE_WELL_FREEZARD_ROOM, RR_BENEATH_THE_WELL_LEFT_FIRE_KEESE, RR_BENEATH_THE_WELL_FOUR_SPIKED_BARS, RR_BENEATH_THE_WELL_TWO_SPIKED_BARS })),
+ },
+ };
+}, {});
+// clang-format on \ No newline at end of file
diff --git a/mm/2s2h/Rando/Logic/Regions/TerminaField.cpp b/mm/2s2h/Rando/Logic/Regions/TerminaField.cpp
index 53b4bcdfc..0eeb63bf6 100644
--- a/mm/2s2h/Rando/Logic/Regions/TerminaField.cpp
+++ b/mm/2s2h/Rando/Logic/Regions/TerminaField.cpp
@@ -487,7 +487,6 @@ static RegisterShipInitFunc initFunc([]() {
CHECK(RC_TERMINA_FIELD_GRASS_214, true),
CHECK(RC_TERMINA_FIELD_GRASS_215, true),
CHECK(RC_TERMINA_FIELD_GRASS_216, true),
-
},
.exits = { // TO FROM
EXIT(ENTRANCE(GROTTOS, 0), ENTRANCE(TERMINA_FIELD, 0), CAN_USE_EXPLOSIVE || CAN_BE_GORON), // TODO: Grotto mapping Gossip Stone #3
diff --git a/mm/2s2h/Rando/Menu.cpp b/mm/2s2h/Rando/Menu.cpp
index 02554e8c5..4bc454904 100644
--- a/mm/2s2h/Rando/Menu.cpp
+++ b/mm/2s2h/Rando/Menu.cpp
@@ -323,6 +323,8 @@ static void DrawItemsTab() {
"that must be found in order for their corresponding boss to spawn.",
.disabled = IncompatibleWithLogicSetting(RO_SHUFFLE_BOSS_SOULS),
.disabledTooltip = "Incompatible with current Logic Setting" } }));
+ CVarCheckbox("Enemy Drops", Rando::StaticData::Options[RO_SHUFFLE_ENEMY_DROPS].cvar,
+ CheckboxOptions({ { .tooltip = "Shuffles the first drop from a non Boss Enemy." } }));
CVarCheckbox("Enemy Souls", "gPlaceholderBool",
CheckboxOptions({ { .disabled = true, .disabledTooltip = "Coming Soon" } }));
ImGui::EndChild();
diff --git a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
index b87d7d01a..42e712ac5 100644
--- a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
+++ b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
@@ -183,6 +183,11 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) {
continue;
}
+ if (randoStaticCheck.randoCheckType == RCTYPE_ENEMY_DROP &&
+ RANDO_SAVE_OPTIONS[RO_SHUFFLE_ENEMY_DROPS] == RO_GENERIC_NO) {
+ continue;
+ }
+
if (randoStaticCheck.randoCheckType == RCTYPE_TINGLE_SHOP &&
RANDO_SAVE_OPTIONS[RO_SHUFFLE_TINGLE_SHOPS] == RO_GENERIC_NO) {
continue;
diff --git a/mm/2s2h/Rando/StaticData/Checks.cpp b/mm/2s2h/Rando/StaticData/Checks.cpp
index e6c7a9cee..4c2e84b80 100644
--- a/mm/2s2h/Rando/StaticData/Checks.cpp
+++ b/mm/2s2h/Rando/StaticData/Checks.cpp
@@ -2230,6 +2230,43 @@ std::map<RandoCheckId, RandoStaticCheck> Checks = {
RC(RC_ZORA_CAPE_GROTTO_GRASS_13, RCTYPE_GRASS, SCENE_KAKUSIANA, FLAG_NONE, 0x0, RI_JUNK),
RC(RC_ZORA_CAPE_GROTTO_GRASS_14, RCTYPE_GRASS, SCENE_KAKUSIANA, FLAG_NONE, 0x0, RI_JUNK),
+ // Enemy Drops
+ RC(RC_ENEMY_DROP_ARMOS, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_BEAMOS, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_BIO_DEKU_BABA, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_BLUE_BUBBLE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_BOMBCHU, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_CHU, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_DEATH_ARMOS, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_DEKU_BABA, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_DODONGO, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_DRAGONFLY, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_EENO, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_FLYING_POT, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_FLOORMASTER, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_FREEZARD, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_GUAY, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_HIPLOOP, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_IRON_KNUCKLE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_KEESE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_LEEVER, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_LIKE_LIKE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_MAD_SCRUB, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_MINI_BABA, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_NEJIRON, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_OCTOROK, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_PEAHAT, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_RED_BUBBLE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_REDEAD_GIBDO, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_SHELLBLADE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_SKULLFISH, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_SKULLTULA, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_SKULLWALLTULA, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_SNAPPER, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_STALCHILD, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_TEKTITE, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_WOLFOS, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
+ RC(RC_ENEMY_DROP_WALLMASTER, RCTYPE_ENEMY_DROP, SCENE_SPOT00, FLAG_NONE, 0x0, RI_JUNK),
};
// clang-format on
diff --git a/mm/2s2h/Rando/StaticData/Options.cpp b/mm/2s2h/Rando/StaticData/Options.cpp
index 1f42b8930..b7d40747f 100644
--- a/mm/2s2h/Rando/StaticData/Options.cpp
+++ b/mm/2s2h/Rando/StaticData/Options.cpp
@@ -31,6 +31,7 @@ std::map<RandoOptionId, RandoStaticOption> Options = {
RO(RO_SHUFFLE_BOSS_SOULS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_COWS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_CRATE_DROPS, RO_GENERIC_OFF),
+ RO(RO_SHUFFLE_ENEMY_DROPS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_FREESTANDING_ITEMS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_FROGS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_GOLD_SKULLTULAS, RO_GENERIC_OFF),
diff --git a/mm/2s2h/Rando/Types.h b/mm/2s2h/Rando/Types.h
index e236fbe02..8841137d7 100644
--- a/mm/2s2h/Rando/Types.h
+++ b/mm/2s2h/Rando/Types.h
@@ -7,6 +7,7 @@ typedef enum {
RCTYPE_CHEST,
RCTYPE_COW,
RCTYPE_CRATE,
+ RCTYPE_ENEMY_DROP,
RCTYPE_FREESTANDING,
RCTYPE_FROG,
RCTYPE_GRASS,
@@ -2234,6 +2235,43 @@ typedef enum {
RC_ZORA_CAPE_GROTTO_GRASS_13,
RC_ZORA_CAPE_GROTTO_GRASS_14,
+ RC_ENEMY_DROP_ARMOS,
+ RC_ENEMY_DROP_BEAMOS,
+ RC_ENEMY_DROP_BIO_DEKU_BABA,
+ RC_ENEMY_DROP_BLUE_BUBBLE,
+ RC_ENEMY_DROP_BOMBCHU,
+ RC_ENEMY_DROP_CHU,
+ RC_ENEMY_DROP_DEATH_ARMOS,
+ RC_ENEMY_DROP_DEKU_BABA,
+ RC_ENEMY_DROP_DODONGO,
+ RC_ENEMY_DROP_DRAGONFLY,
+ RC_ENEMY_DROP_EENO,
+ RC_ENEMY_DROP_FLYING_POT,
+ RC_ENEMY_DROP_FLOORMASTER,
+ RC_ENEMY_DROP_FREEZARD,
+ RC_ENEMY_DROP_GUAY,
+ RC_ENEMY_DROP_HIPLOOP,
+ RC_ENEMY_DROP_IRON_KNUCKLE,
+ RC_ENEMY_DROP_KEESE,
+ RC_ENEMY_DROP_LEEVER,
+ RC_ENEMY_DROP_LIKE_LIKE,
+ RC_ENEMY_DROP_MAD_SCRUB,
+ RC_ENEMY_DROP_MINI_BABA,
+ RC_ENEMY_DROP_NEJIRON,
+ RC_ENEMY_DROP_OCTOROK,
+ RC_ENEMY_DROP_PEAHAT,
+ RC_ENEMY_DROP_RED_BUBBLE,
+ RC_ENEMY_DROP_REDEAD_GIBDO,
+ RC_ENEMY_DROP_SHELLBLADE,
+ RC_ENEMY_DROP_SKULLFISH,
+ RC_ENEMY_DROP_SKULLTULA,
+ RC_ENEMY_DROP_SKULLWALLTULA,
+ RC_ENEMY_DROP_SNAPPER,
+ RC_ENEMY_DROP_STALCHILD,
+ RC_ENEMY_DROP_TEKTITE,
+ RC_ENEMY_DROP_WOLFOS,
+ RC_ENEMY_DROP_WALLMASTER,
+
RC_MAX,
} RandoCheckId;
@@ -2537,6 +2575,7 @@ typedef enum {
RR_MAGIC_HAGS_POTION_SHOP,
RR_MARINE_RESEARCH_LAB,
RR_MAYOR_RESIDENCE,
+ RR_MISCELLANEOUS,
RR_MILK_BAR,
RR_MILK_ROAD,
RR_MOON_DEKU_TRIAL,
@@ -2754,6 +2793,7 @@ typedef enum {
RO_SHUFFLE_BOSS_SOULS,
RO_SHUFFLE_COWS,
RO_SHUFFLE_CRATE_DROPS,
+ RO_SHUFFLE_ENEMY_DROPS,
RO_SHUFFLE_FREESTANDING_ITEMS,
RO_SHUFFLE_FROGS,
RO_SHUFFLE_GRASS_DROPS,
diff --git a/mm/src/code/z_en_item00.c b/mm/src/code/z_en_item00.c
index ec357c076..12233a36f 100644
--- a/mm/src/code/z_en_item00.c
+++ b/mm/src/code/z_en_item00.c
@@ -918,6 +918,10 @@ s16 func_800A7650(s16 dropId) {
}
Actor* Item_DropCollectible(PlayState* play, Vec3f* spawnPos, u32 params) {
+ if (!(GameInteractor_Should(VB_ENEMY_DROP_COLLECTIBLE, true, *spawnPos))) {
+ return;
+ }
+
s32 pad;
Actor* spawnedActor = NULL;
s32 newParamFF;
@@ -1333,6 +1337,10 @@ u8 sDropTableAmounts[DROP_TABLE_SIZE * DROP_TABLE_NUMBER] = {
};
void Item_DropCollectibleRandom(PlayState* play, Actor* fromActor, Vec3f* spawnPos, s16 params) {
+ if (!(GameInteractor_Should(VB_ENEMY_DROP_COLLECTIBLE, true, *spawnPos))) {
+ return;
+ }
+
EnItem00* spawnedActor;
u8 dropId;
s32 dropQuantity;
diff --git a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c
index abe8498d8..eaa0a11e1 100644
--- a/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c
+++ b/mm/src/overlays/actors/ovl_En_Slime/z_en_slime.c
@@ -1245,12 +1245,14 @@ void EnSlime_Draw(Actor* thisx, PlayState* play) {
Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + (2000.0f * this->actor.scale.y),
this->actor.world.pos.z, MTXMODE_NEW);
- if (GameInteractor_Should(VB_DRAW_SLIME_BODY_ITEM, true, this)) {
- Matrix_Scale(0.03f, 0.03f, 0.03f, MTXMODE_APPLY);
+ if (GameInteractor_Should(VB_DRAW_SLIME_RANDO_ITEM, true, this)) {
+ if (GameInteractor_Should(VB_DRAW_SLIME_BODY_ITEM, true, this)) {
+ Matrix_Scale(0.03f, 0.03f, 0.03f, MTXMODE_APPLY);
- gSPSegment(POLY_OPA_DISP++, 0x08, this->itemDropTex);
- MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
- gSPDisplayList(POLY_OPA_DISP++, gItemDropDL);
+ gSPSegment(POLY_OPA_DISP++, 8, (uintptr_t)this->itemDropTex);
+ MATRIX_FINALIZE_AND_LOAD(POLY_OPA_DISP++, play->state.gfxCtx);
+ gSPDisplayList(POLY_OPA_DISP++, gItemDropDL);
+ }
}
}