summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libultraship/libultraship/ImGuiImpl.cpp4
-rw-r--r--soh/include/z64actor.h3
-rw-r--r--soh/src/code/z_en_item00.c67
3 files changed, 69 insertions, 5 deletions
diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp
index f35ab484d..fdaeb4eee 100644
--- a/libultraship/libultraship/ImGuiImpl.cpp
+++ b/libultraship/libultraship/ImGuiImpl.cpp
@@ -1359,6 +1359,8 @@ namespace SohImGui {
);
PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false);
Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
+ PaddedEnhancementCheckbox("Enable Bombchu Drops", "gBombchuDrops", true, false);
+ Tooltip("Bombchus will sometimes drop in place of bombs");
PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false);
Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false);
@@ -2228,6 +2230,8 @@ namespace SohImGui {
CVar_SetS32("gNoRandomDrops", 0);
// No Heart Drops
CVar_SetS32("gNoHeartDrops", 0);
+ // Enable Bombchu Drops
+ CVar_SetS32("gBombchuDrops", 0);
// Always Win Goron Pot
CVar_SetS32("gGoronPot", 0);
diff --git a/soh/include/z64actor.h b/soh/include/z64actor.h
index cd58ac20b..01eb28a1d 100644
--- a/soh/include/z64actor.h
+++ b/soh/include/z64actor.h
@@ -271,7 +271,8 @@ typedef enum {
/* 0x16 */ ITEM00_SHIELD_HYLIAN,
/* 0x17 */ ITEM00_TUNIC_ZORA,
/* 0x18 */ ITEM00_TUNIC_GORON,
- /* 0x19 */ ITEM00_BOMBS_SPECIAL
+ /* 0x19 */ ITEM00_BOMBS_SPECIAL,
+ /* 0x20 */ ITEM00_BOMBCHU,
} Item00Type;
struct EnItem00;
diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c
index a50c74e87..54beafdab 100644
--- a/soh/src/code/z_en_item00.c
+++ b/soh/src/code/z_en_item00.c
@@ -70,6 +70,7 @@ static void* sItemDropTex[] = {
gDropRecoveryHeartTex, gDropBombTex, gDropArrows1Tex, gDropArrows2Tex,
gDropArrows3Tex, gDropBombTex, gDropDekuNutTex, gDropDekuStickTex,
gDropMagicLargeTex, gDropMagicSmallTex, gDropDekuSeedsTex, gDropKeySmallTex,
+ // OTRTODO: use 2D bombchu texture
};
static u8 sItemDropIds[] = {
@@ -390,6 +391,7 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) {
case ITEM00_RUPEE_ORANGE:
case ITEM00_RUPEE_PURPLE:
case ITEM00_FLEXIBLE:
+ case ITEM00_BOMBCHU:
yOffset = 500.0f;
Actor_SetScale(&this->actor, 0.01f);
this->scale = 0.01f;
@@ -507,6 +509,9 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) {
case ITEM00_TUNIC_GORON:
case ITEM00_BOMBS_SPECIAL:
break;
+ case ITEM00_BOMBCHU:
+ Item_Give(globalCtx, ITEM_BOMBCHUS_5);
+ break;
}
if (!Actor_HasParent(&this->actor, globalCtx)) {
@@ -537,7 +542,8 @@ void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) {
(this->actor.params == ITEM00_HEART_PIECE)) {
this->actor.shape.rot.y += 960;
} else {
- if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL)) {
+ if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL) &&
+ (this->actor.params != ITEM00_BOMBCHU)) {
if (this->unk_15A == -1) {
if (Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.world.rot.x - 0x4000, 2, 3000, 1500) ==
0) {
@@ -640,7 +646,8 @@ void func_8001E304(EnItem00* this, GlobalContext* globalCtx) {
if (this->actor.params <= ITEM00_RUPEE_RED) {
this->actor.shape.rot.y += 960;
- } else if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL)) {
+ } else if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL) &&
+ (this->actor.params != ITEM00_BOMBCHU)) {
this->actor.world.rot.x -= 700;
this->actor.shape.rot.y += 400;
this->actor.shape.rot.x = this->actor.world.rot.x - 0x4000;
@@ -722,7 +729,8 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
EnItem00* this = (EnItem00*)thisx;
s32 pad;
- if (CVar_GetS32("gNewDrops", 0)) { //set the rotation system on selected model only :)
+ // OTRTODO: remove special case for bombchu when its 2D drop is implemented
+ if (CVar_GetS32("gNewDrops", 0) || this->actor.params == ITEM00_BOMBCHU) { //set the rotation system on selected model only :)
if ((this->actor.params == ITEM00_RUPEE_GREEN) || (this->actor.params == ITEM00_RUPEE_BLUE) ||
(this->actor.params == ITEM00_RUPEE_RED) || (this->actor.params == ITEM00_ARROWS_SINGLE) ||
(this->actor.params == ITEM00_ARROWS_SMALL) || (this->actor.params == ITEM00_ARROWS_MEDIUM) ||
@@ -730,7 +738,8 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
(this->actor.params == ITEM00_BOMBS_B) || (this->actor.params == ITEM00_NUTS) ||
(this->actor.params == ITEM00_MAGIC_SMALL) || (this->actor.params == ITEM00_SEEDS) ||
(this->actor.params == ITEM00_MAGIC_LARGE) || (this->actor.params == ITEM00_HEART) ||
- (this->actor.params == ITEM00_BOMBS_SPECIAL) || this->actor.params == ITEM00_HEART_PIECE) {
+ (this->actor.params == ITEM00_BOMBS_SPECIAL) || this->actor.params == ITEM00_HEART_PIECE ||
+ (this->actor.params == ITEM00_BOMBCHU)) {
this->actor.shape.rot.y += 960;
}
if (this->actor.params == ITEM00_SMALL_KEY && !gSaveContext.n64ddFlag) {
@@ -891,6 +900,9 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
break;
case ITEM00_BOMBS_SPECIAL:
break;
+ case ITEM00_BOMBCHU:
+ Item_Give(globalCtx, ITEM_BOMBCHUS_5);
+ break;
}
params = &this->actor.params;
@@ -1212,6 +1224,15 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) {
EnItem00_DrawCollectible(this, globalCtx);
break;
}
+ case ITEM00_BOMBCHU:
+ // OTRTODO: Stop forcing chu drops to be 3D when the texture is added
+ Actor_SetScale(&this->actor, 0.2f);
+ this->scale = 0.2f;
+ this->actor.shape.yOffset = 50.0f;
+ this->actor.world.rot.x = 0x4000;
+ this->actor.shape.shadowScale = 0.3f;
+ GetItem_Draw(globalCtx, GID_BOMBCHU);
+ break;
case ITEM00_SHIELD_DEKU:
GetItem_Draw(globalCtx, GID_SHIELD_DEKU);
break;
@@ -1370,6 +1391,9 @@ void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) {
if (this->actor.params == ITEM00_BOMBS_SPECIAL) {
texIndex = 1;
+ // OTRTODO: 2D bombchu drops
+ //} else if (this->actor.params == ITEM00_BOMBCHU) {
+ // texIndex = 12;
} else if (this->actor.params >= ITEM00_ARROWS_SMALL) {
texIndex -= 3;
}
@@ -1436,6 +1460,36 @@ void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) {
}
/**
+ * Sometimes convert the given drop ID into a bombchu.
+ * Returns the new drop type ID.
+ */
+s16 EnItem00_ConvertBombDropToBombchu(s16 dropId) {
+ if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE) {
+ return dropId;
+ }
+
+ if (INV_CONTENT(ITEM_BOMB) == ITEM_NONE) {
+ return ITEM00_BOMBCHU;
+ }
+
+ if (AMMO(ITEM_BOMB) <= 15) {
+ // Player needs bombs and might need chus, so drop whichever has less
+ if (AMMO(ITEM_BOMB) <= AMMO(ITEM_BOMBCHU)) {
+ return dropId;
+ } else {
+ return ITEM00_BOMBCHU;
+ }
+ } else {
+ // Player has enough bombs, so drop chus if they need some, else it's 50/50
+ if (AMMO(ITEM_BOMBCHU) <= 15) {
+ return ITEM00_BOMBCHU;
+ } else {
+ return Rand_Next() % 2 ? dropId : ITEM00_BOMBCHU;
+ }
+ }
+}
+
+/**
* Converts a given drop type ID based on link's current age, health and owned items.
* Returns a new drop type ID or -1 to cancel the drop.
*/
@@ -1452,6 +1506,11 @@ s16 func_8001F404(s16 dropId) {
}
}
+ if (CVar_GetS32("gBombchuDrops", 0) &&
+ (dropId == ITEM00_BOMBS_A || dropId == ITEM00_BOMBS_B || dropId == ITEM00_BOMBS_SPECIAL)) {
+ dropId = EnItem00_ConvertBombDropToBombchu(dropId);
+ }
+
// This is convoluted but it seems like it must be a single condition to match
// clang-format off
if (((dropId == ITEM00_BOMBS_A || dropId == ITEM00_BOMBS_SPECIAL || dropId == ITEM00_BOMBS_B) && INV_CONTENT(ITEM_BOMB) == ITEM_NONE) ||