summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranthony-barricelli <104381450+anthony-barricelli@users.noreply.github.com>2026-07-03 11:28:20 -0400
committerGitHub <noreply@github.com>2026-07-03 10:28:20 -0500
commit1c35785ea36892c0baaaa766cb6a2268dadc805a (patch)
tree12fe93a70dabf2a13bf96044263459095ebc3d3e
parented0eb99b0e476e7eea55617f67e220082a345a9d (diff)
New Features: No random drops + No heart/healing drops (#1547)
* no random drops * no heart/fairy drops * add item spawns to prevent soft locks * remove redundancies, use collectible vb behavior for hearts * feedback -- move vb check
-rw-r--r--mm/2s2h/BenGui/BenMenu.cpp6
-rw-r--r--mm/2s2h/Enhancements/DifficultyOptions/NoHeartDrops.cpp19
-rw-r--r--mm/2s2h/Enhancements/DifficultyOptions/NoRandomDrops.cpp35
-rw-r--r--mm/src/code/z_en_item00.c6
4 files changed, 63 insertions, 3 deletions
diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp
index c8dacb690..15917f1a4 100644
--- a/mm/2s2h/BenGui/BenMenu.cpp
+++ b/mm/2s2h/BenGui/BenMenu.cpp
@@ -1905,6 +1905,12 @@ void BenMenu::AddEnhancements() {
.Options(CheckboxOptions().Tooltip(
"Prevents the Takkuri from stealing key items like bottles and swords. It may still steal "
"other items."));
+ AddWidget(path, "No Heart Drops", WIDGET_CVAR_CHECKBOX)
+ .CVar("gEnhancements.DifficultyOptions.NoHeartDrops")
+ .Options(CheckboxOptions().Tooltip("Prevents spawning of any hearts or fairies."));
+ AddWidget(path, "No Random Drops", WIDGET_CVAR_CHECKBOX)
+ .CVar("gEnhancements.DifficultyOptions.NoRandomDrops")
+ .Options(CheckboxOptions().Tooltip("Prevents spawning of any collectibles."));
AddWidget(path, "Deku Guard Search Balls", WIDGET_CVAR_COMBOBOX)
.CVar("gEnhancements.DifficultyOptions.DekuGuardSearchBalls")
.Options(
diff --git a/mm/2s2h/Enhancements/DifficultyOptions/NoHeartDrops.cpp b/mm/2s2h/Enhancements/DifficultyOptions/NoHeartDrops.cpp
new file mode 100644
index 000000000..72f98078f
--- /dev/null
+++ b/mm/2s2h/Enhancements/DifficultyOptions/NoHeartDrops.cpp
@@ -0,0 +1,19 @@
+#include <libultraship/bridge/consolevariablebridge.h>
+#include "2s2h/GameInteractor/GameInteractor.h"
+#include "2s2h/ShipInit.hpp"
+
+#define CVAR_NAME "gEnhancements.DifficultyOptions.NoHeartDrops"
+#define CVAR CVarGetInteger(CVAR_NAME, 0)
+
+void RegisterNoHeartDrops() {
+ // Disable spawning of hearts and fairies
+ COND_VB_SHOULD(VB_DROP_COLLECTIBLE, CVAR, {
+ Vec3f unused = va_arg(args, Vec3f);
+ u32 item = va_arg(args, u32) & 0xFF;
+ if (item == ITEM00_RECOVERY_HEART || item == ITEM00_3_HEARTS || item == ITEM00_FLEXIBLE) {
+ *should = false;
+ }
+ });
+}
+
+static RegisterShipInitFunc initFunc(RegisterNoHeartDrops, { CVAR_NAME });
diff --git a/mm/2s2h/Enhancements/DifficultyOptions/NoRandomDrops.cpp b/mm/2s2h/Enhancements/DifficultyOptions/NoRandomDrops.cpp
new file mode 100644
index 000000000..44220ffda
--- /dev/null
+++ b/mm/2s2h/Enhancements/DifficultyOptions/NoRandomDrops.cpp
@@ -0,0 +1,35 @@
+#include <libultraship/bridge/consolevariablebridge.h>
+#include "2s2h/GameInteractor/GameInteractor.h"
+#include "2s2h/ShipInit.hpp"
+
+#define CVAR_NAME "gEnhancements.DifficultyOptions.NoRandomDrops"
+#define CVAR CVarGetInteger(CVAR_NAME, 0)
+
+#define DISABLE_VB_DROP(vb) COND_VB_SHOULD(vb, CVAR, { *should = false; })
+
+void RegisterNoRandomDrops() {
+ COND_VB_SHOULD(VB_DROP_COLLECTIBLE, CVAR, {
+ Vec3f unused = va_arg(args, Vec3f);
+ u32 item = va_arg(args, u32) & 0xFF;
+
+ s16 scene = gPlayState->sceneId;
+ s8 room = gPlayState->roomCtx.curRoom.num;
+
+ // Gekko mini-boss in Woodfall Temple and Poe Sisters fight should allow arrow drops
+ if (((scene == SCENE_MITURIN && room == 8) || scene == SCENE_TOUGITES) && item == ITEM00_ARROWS_10) {
+ return;
+ }
+
+ // Gekko mini-boss in Great Bay Temple as well as Gomess and the Flippy room in Inverted Stone Tower Temple
+ // should allow both arrows and magic
+ if (((scene == SCENE_SEA && room == 5) || (scene == SCENE_INISIE_R && (room == 5 || room == 11))) &&
+ (item == ITEM00_ARROWS_10 || item == ITEM00_MAGIC_JAR_SMALL || item == ITEM00_MAGIC_JAR_BIG)) {
+ return;
+ }
+
+ // Everything else blocked
+ *should = false;
+ });
+}
+
+static RegisterShipInitFunc initFunc(RegisterNoRandomDrops, { CVAR_NAME });
diff --git a/mm/src/code/z_en_item00.c b/mm/src/code/z_en_item00.c
index 6567dd295..925fd8644 100644
--- a/mm/src/code/z_en_item00.c
+++ b/mm/src/code/z_en_item00.c
@@ -1337,9 +1337,6 @@ u8 sDropTableAmounts[DROP_TABLE_SIZE * DROP_TABLE_NUMBER] = {
};
void Item_DropCollectibleRandom(PlayState* play, Actor* fromActor, Vec3f* spawnPos, s16 params) {
- if (!(GameInteractor_Should(VB_DROP_COLLECTIBLE, true, *spawnPos, params))) {
- return;
- }
EnItem00* spawnedActor;
u8 dropId;
@@ -1353,6 +1350,9 @@ void Item_DropCollectibleRandom(PlayState* play, Actor* fromActor, Vec3f* spawnP
if (params < 0x101) {
dropId = sDropTable[params + dropTableIndex];
dropQuantity = sDropTableAmounts[params + dropTableIndex];
+ if (!(GameInteractor_Should(VB_DROP_COLLECTIBLE, true, *spawnPos, dropId))) {
+ return;
+ }
if (dropId == ITEM00_MASK) {
switch (GET_PLAYER_FORM) {