From 509985f5b51ca1f113d5c100ff91a7ebe392e252 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 14 Dec 2023 00:24:58 -0600 Subject: [PATCH 01/60] Bomb Arrows --- soh/include/variables.h | 2 +- soh/include/z64item.h | 171 +++++++++--------- soh/include/z64player.h | 8 +- soh/src/code/code_80097A00.c | 1 + soh/src/code/z_parameter.c | 12 +- soh/src/code/z_player_lib.c | 16 +- .../overlays/actors/ovl_En_Arrow/z_en_arrow.c | 7 +- .../overlays/actors/ovl_En_Arrow/z_en_arrow.h | 2 +- soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c | 145 ++++++++++++++- soh/src/overlays/actors/ovl_En_Bom/z_en_bom.h | 5 +- .../actors/ovl_player_actor/z_player.c | 35 ++-- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 12 +- 12 files changed, 292 insertions(+), 124 deletions(-) diff --git a/soh/include/variables.h b/soh/include/variables.h index 2bad8335c99..ed64357f7f1 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -99,7 +99,7 @@ extern "C" extern u16 gUpgradeCapacities[8][4]; extern u32 gGsFlagsMasks[4]; extern u32 gGsFlagsShifts[4]; - extern void* gItemIcons[0x82]; + extern void* gItemIcons[0x83]; extern u8 gItemAgeReqs[]; extern u8 gSlotAgeReqs[]; extern u8 gItemSlots[56]; diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 1fc919a45f6..5aa02469afa 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -221,91 +221,92 @@ typedef enum { /* 0x44 */ ITEM_BOOTS_KOKIRI, /* 0x45 */ ITEM_BOOTS_IRON, /* 0x46 */ ITEM_BOOTS_HOVER, - /* 0x47 */ ITEM_BULLET_BAG_30, - /* 0x48 */ ITEM_BULLET_BAG_40, - /* 0x49 */ ITEM_BULLET_BAG_50, - /* 0x4A */ ITEM_QUIVER_30, - /* 0x4B */ ITEM_QUIVER_40, - /* 0x4C */ ITEM_QUIVER_50, - /* 0x4D */ ITEM_BOMB_BAG_20, - /* 0x4E */ ITEM_BOMB_BAG_30, - /* 0x4F */ ITEM_BOMB_BAG_40, - /* 0x50 */ ITEM_BRACELET, - /* 0x51 */ ITEM_GAUNTLETS_SILVER, - /* 0x52 */ ITEM_GAUNTLETS_GOLD, - /* 0x53 */ ITEM_SCALE_SILVER, - /* 0x54 */ ITEM_SCALE_GOLDEN, - /* 0x55 */ ITEM_SWORD_KNIFE, - /* 0x56 */ ITEM_WALLET_ADULT, - /* 0x57 */ ITEM_WALLET_GIANT, - /* 0x58 */ ITEM_SEEDS, - /* 0x59 */ ITEM_FISHING_POLE, - /* 0x5A */ ITEM_SONG_MINUET, - /* 0x5B */ ITEM_SONG_BOLERO, - /* 0x5C */ ITEM_SONG_SERENADE, - /* 0x5D */ ITEM_SONG_REQUIEM, - /* 0x5E */ ITEM_SONG_NOCTURNE, - /* 0x5F */ ITEM_SONG_PRELUDE, - /* 0x60 */ ITEM_SONG_LULLABY, - /* 0x61 */ ITEM_SONG_EPONA, - /* 0x62 */ ITEM_SONG_SARIA, - /* 0x63 */ ITEM_SONG_SUN, - /* 0x64 */ ITEM_SONG_TIME, - /* 0x65 */ ITEM_SONG_STORMS, - /* 0x66 */ ITEM_MEDALLION_FOREST, - /* 0x67 */ ITEM_MEDALLION_FIRE, - /* 0x68 */ ITEM_MEDALLION_WATER, - /* 0x69 */ ITEM_MEDALLION_SPIRIT, - /* 0x6A */ ITEM_MEDALLION_SHADOW, - /* 0x6B */ ITEM_MEDALLION_LIGHT, - /* 0x6C */ ITEM_KOKIRI_EMERALD, - /* 0x6D */ ITEM_GORON_RUBY, - /* 0x6E */ ITEM_ZORA_SAPPHIRE, - /* 0x6F */ ITEM_STONE_OF_AGONY, - /* 0x70 */ ITEM_GERUDO_CARD, - /* 0x71 */ ITEM_SKULL_TOKEN, - /* 0x72 */ ITEM_HEART_CONTAINER, - /* 0x73 */ ITEM_HEART_PIECE, - /* 0x74 */ ITEM_KEY_BOSS, - /* 0x75 */ ITEM_COMPASS, - /* 0x76 */ ITEM_DUNGEON_MAP, - /* 0x77 */ ITEM_KEY_SMALL, - /* 0x78 */ ITEM_MAGIC_SMALL, - /* 0x79 */ ITEM_MAGIC_LARGE, - /* 0x7A */ ITEM_HEART_PIECE_2, - /* 0x7B */ ITEM_SINGLE_MAGIC, - /* 0x7C */ ITEM_DOUBLE_MAGIC, - /* 0x7D */ ITEM_DOUBLE_DEFENSE, - /* 0x7E */ ITEM_INVALID_4, - /* 0x7F */ ITEM_INVALID_5, - /* 0x80 */ ITEM_INVALID_6, - /* 0x81 */ ITEM_INVALID_7, - /* 0x82 */ ITEM_MILK, - /* 0x83 */ ITEM_HEART, - /* 0x84 */ ITEM_RUPEE_GREEN, - /* 0x85 */ ITEM_RUPEE_BLUE, - /* 0x86 */ ITEM_RUPEE_RED, - /* 0x87 */ ITEM_RUPEE_PURPLE, - /* 0x88 */ ITEM_RUPEE_GOLD, - /* 0x89 */ ITEM_INVALID_8, - /* 0x8A */ ITEM_STICKS_5, - /* 0x8B */ ITEM_STICKS_10, - /* 0x8C */ ITEM_NUTS_5, - /* 0x8D */ ITEM_NUTS_10, - /* 0x8E */ ITEM_BOMBS_5, - /* 0x8F */ ITEM_BOMBS_10, - /* 0x90 */ ITEM_BOMBS_20, - /* 0x91 */ ITEM_BOMBS_30, - /* 0x92 */ ITEM_ARROWS_SMALL, - /* 0x93 */ ITEM_ARROWS_MEDIUM, - /* 0x94 */ ITEM_ARROWS_LARGE, - /* 0x95 */ ITEM_SEEDS_30, - /* 0x96 */ ITEM_BOMBCHUS_5, - /* 0x97 */ ITEM_BOMBCHUS_20, - /* 0x98 */ ITEM_STICK_UPGRADE_20, - /* 0x99 */ ITEM_STICK_UPGRADE_30, - /* 0x9A */ ITEM_NUT_UPGRADE_30, - /* 0x9B */ ITEM_NUT_UPGRADE_40, + ITEM_BOW_ARROW_BOMB, + /* 0x48 */ ITEM_BULLET_BAG_30, + /* 0x49 */ ITEM_BULLET_BAG_40, + /* 0x4a */ ITEM_BULLET_BAG_50, + /* 0x4B */ ITEM_QUIVER_30, + /* 0x4C */ ITEM_QUIVER_40, + /* 0x4D */ ITEM_QUIVER_50, + /* 0x4E */ ITEM_BOMB_BAG_20, + /* 0x4F */ ITEM_BOMB_BAG_30, + /* 0x50 */ ITEM_BOMB_BAG_40, + /* 0x51 */ ITEM_BRACELET, + /* 0x52 */ ITEM_GAUNTLETS_SILVER, + /* 0x53 */ ITEM_GAUNTLETS_GOLD, + /* 0x54 */ ITEM_SCALE_SILVER, + /* 0x55 */ ITEM_SCALE_GOLDEN, + /* 0x56 */ ITEM_SWORD_KNIFE, + /* 0x57 */ ITEM_WALLET_ADULT, + /* 0x58 */ ITEM_WALLET_GIANT, + /* 0x59 */ ITEM_SEEDS, + /* 0x5a */ ITEM_FISHING_POLE, + /* 0x5B */ ITEM_SONG_MINUET, + /* 0x5C */ ITEM_SONG_BOLERO, + /* 0x5D */ ITEM_SONG_SERENADE, + /* 0x5E */ ITEM_SONG_REQUIEM, + /* 0x5F */ ITEM_SONG_NOCTURNE, + /* 0x60 */ ITEM_SONG_PRELUDE, + /* 0x61 */ ITEM_SONG_LULLABY, + /* 0x62 */ ITEM_SONG_EPONA, + /* 0x63 */ ITEM_SONG_SARIA, + /* 0x64 */ ITEM_SONG_SUN, + /* 0x65 */ ITEM_SONG_TIME, + /* 0x66 */ ITEM_SONG_STORMS, + /* 0x67 */ ITEM_MEDALLION_FOREST, + /* 0x68 */ ITEM_MEDALLION_FIRE, + /* 0x69 */ ITEM_MEDALLION_WATER, + /* 0x6a */ ITEM_MEDALLION_SPIRIT, + /* 0x6B */ ITEM_MEDALLION_SHADOW, + /* 0x6C */ ITEM_MEDALLION_LIGHT, + /* 0x6D */ ITEM_KOKIRI_EMERALD, + /* 0x6E */ ITEM_GORON_RUBY, + /* 0x6F */ ITEM_ZORA_SAPPHIRE, + /* 0x70 */ ITEM_STONE_OF_AGONY, + /* 0x71 */ ITEM_GERUDO_CARD, + /* 0x72 */ ITEM_SKULL_TOKEN, + /* 0x73 */ ITEM_HEART_CONTAINER, + /* 0x74 */ ITEM_HEART_PIECE, + /* 0x75 */ ITEM_KEY_BOSS, + /* 0x76 */ ITEM_COMPASS, + /* 0x77 */ ITEM_DUNGEON_MAP, + /* 0x78 */ ITEM_KEY_SMALL, + /* 0x79 */ ITEM_MAGIC_SMALL, + /* 0x7a */ ITEM_MAGIC_LARGE, + /* 0x7B */ ITEM_HEART_PIECE_2, + /* 0x7C */ ITEM_SINGLE_MAGIC, + /* 0x7D */ ITEM_DOUBLE_MAGIC, + /* 0x7E */ ITEM_DOUBLE_DEFENSE, + /* 0x7F */ ITEM_INVALID_4, + /* 0x80 */ ITEM_INVALID_5, + /* 0x81 */ ITEM_INVALID_6, + /* 0x82 */ ITEM_INVALID_7, + /* 0x83 */ ITEM_MILK, + /* 0x84 */ ITEM_HEART, + /* 0x85 */ ITEM_RUPEE_GREEN, + /* 0x86 */ ITEM_RUPEE_BLUE, + /* 0x87 */ ITEM_RUPEE_RED, + /* 0x88 */ ITEM_RUPEE_PURPLE, + /* 0x89 */ ITEM_RUPEE_GOLD, + /* 0x8a */ ITEM_INVALID_8, + /* 0x8B */ ITEM_STICKS_5, + /* 0x8C */ ITEM_STICKS_10, + /* 0x8D */ ITEM_NUTS_5, + /* 0x8E */ ITEM_NUTS_10, + /* 0x8F */ ITEM_BOMBS_5, + /* 0x90 */ ITEM_BOMBS_10, + /* 0x91 */ ITEM_BOMBS_20, + /* 0x92 */ ITEM_BOMBS_30, + /* 0x93 */ ITEM_ARROWS_SMALL, + /* 0x94 */ ITEM_ARROWS_MEDIUM, + /* 0x95 */ ITEM_ARROWS_LARGE, + /* 0x96 */ ITEM_SEEDS_30, + /* 0x97 */ ITEM_BOMBCHUS_5, + /* 0x98 */ ITEM_BOMBCHUS_20, + /* 0x99 */ ITEM_STICK_UPGRADE_20, + /* 0x9a */ ITEM_STICK_UPGRADE_30, + /* 0x9B */ ITEM_NUT_UPGRADE_30, + /* 0x9C */ ITEM_NUT_UPGRADE_40, /* 0xFC */ ITEM_LAST_USED = 0xFC, /* 0xFE */ ITEM_NONE_FE = 0xFE, /* 0xFF */ ITEM_NONE = 0xFF diff --git a/soh/include/z64player.h b/soh/include/z64player.h index ff30cc17094..968c3ca0058 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -77,7 +77,7 @@ typedef enum { /* 0x09 */ PLAYER_IA_BOW_FIRE, /* 0x0A */ PLAYER_IA_BOW_ICE, /* 0x0B */ PLAYER_IA_BOW_LIGHT, - /* 0x0C */ PLAYER_IA_BOW_0C, + /* 0x0C */ PLAYER_IA_BOW_BOMB, /* 0x0D */ PLAYER_IA_BOW_0D, /* 0x0E */ PLAYER_IA_BOW_0E, /* 0x0F */ PLAYER_IA_SLINGSHOT, @@ -426,14 +426,14 @@ typedef struct { #define PLAYER_STATE1_ENEMY_TARGET (1 << 4) #define PLAYER_STATE1_INPUT_DISABLED (1 << 5) #define PLAYER_STATE1_TEXT_ON_SCREEN (1 << 6) -#define PLAYER_STATE1_DEAD (1 << 7) +#define PLAYER_STATE1_DEAD (1 << 7) #define PLAYER_STATE1_START_PUTAWAY (1 << 8) #define PLAYER_STATE1_READY_TO_FIRE (1 << 9) #define PLAYER_STATE1_GETTING_ITEM (1 << 10) #define PLAYER_STATE1_ITEM_OVER_HEAD (1 << 11) #define PLAYER_STATE1_CHARGING_SPIN_ATTACK (1 << 12) #define PLAYER_STATE1_HANGING_OFF_LEDGE (1 << 13) -#define PLAYER_STATE1_CLIMBING_LEDGE (1 << 14) +#define PLAYER_STATE1_CLIMBING_LEDGE (1 << 14) #define PLAYER_STATE1_TARGETING (1 << 15) #define PLAYER_STATE1_TARGET_LOCKED (1 << 16) #define PLAYER_STATE1_TARGET_NOTHING (1 << 17) @@ -490,7 +490,7 @@ typedef struct { #define PLAYER_STATE3_PAUSE_ACTION_FUNC (1 << 2) #define PLAYER_STATE3_FINISHED_ATTACKING (1 << 3) #define PLAYER_STATE3_CHECK_FLOOR_WATER_COLLISION (1 << 4) -#define PLAYER_STATE3_FORCE_PULL_OCARINA (1 << 5) +#define PLAYER_STATE3_FORCE_PULL_OCARINA (1 << 5) #define PLAYER_STATE3_RESTORE_NAYRUS_LOVE (1 << 6) // Set by ocarina effects actors when destroyed to signal Nayru's Love may be restored (see `ACTOROVL_ALLOC_ABSOLUTE`) #define PLAYER_STATE3_HOOKSHOT_TRAVELLING (1 << 7) //Travelling to target diff --git a/soh/src/code/code_80097A00.c b/soh/src/code/code_80097A00.c index eb83738e360..49eab232998 100644 --- a/soh/src/code/code_80097A00.c +++ b/soh/src/code/code_80097A00.c @@ -108,6 +108,7 @@ void* gItemIcons[] = { gItemIconBootsKokiriTex, gItemIconBootsIronTex, gItemIconBootsHoverTex, + gItemIconBowFireTex, gItemIconBulletBag30Tex, gItemIconBulletBag40Tex, gItemIconBulletBag50Tex, diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 20debfd79e2..495825e9d59 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -4839,14 +4839,18 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { i = gSaveContext.equips.buttonItems[button]; if ((i == ITEM_STICK) || (i == ITEM_NUT) || (i == ITEM_BOMB) || (i == ITEM_BOW) || - ((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) || (i == ITEM_SLINGSHOT) || (i == ITEM_BOMBCHU) || - (i == ITEM_BEAN)) { + ((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) || (i == ITEM_BOW_ARROW_BOMB) || (i == ITEM_SLINGSHOT) || + (i == ITEM_BOMBCHU) || (i == ITEM_BEAN)) { - if ((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) { + if (((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) || (i == ITEM_BOW_ARROW_BOMB)) { i = ITEM_BOW; } - ammo = AMMO(i); + if (i == ITEM_BOW_ARROW_BOMB) { + ammo = MIN(AMMO(ITEM_BOW), AMMO(ITEM_BOMB)); + } else { + ammo = AMMO(i); + } gDPPipeSync(OVERLAY_DISP++); diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 820f2c67267..d579ffcb12e 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -626,7 +626,7 @@ void Player_SetModels(Player* this, s32 modelGroup) { // Left hand this->leftHandType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_LEFT_HAND]; this->leftHandDLists = &sPlayerDListGroups[this->leftHandType][gSaveContext.linkAge]; - + // Right hand this->rightHandType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_RIGHT_HAND]; this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][gSaveContext.linkAge]; @@ -798,6 +798,7 @@ s32 Player_HoldsBow(Player* this) { case PLAYER_IA_BOW_FIRE: case PLAYER_IA_BOW_ICE: case PLAYER_IA_BOW_LIGHT: + case PLAYER_IA_BOW_BOMB: return true; default: return false; @@ -1274,7 +1275,7 @@ s32 Player_OverrideLimbDrawGameplayCommon(PlayState* play, s32 limbIndex, Gfx** s32 Player_OverrideLimbDrawGameplayDefault(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) { Player* this = (Player*)thisx; - if (!Player_OverrideLimbDrawGameplayCommon(play, limbIndex, dList, pos, rot, thisx)) + if (!Player_OverrideLimbDrawGameplayCommon(play, limbIndex, dList, pos, rot, thisx)) { if (limbIndex == PLAYER_LIMB_L_HAND) { Gfx** dLists = this->leftHandDLists; @@ -1323,7 +1324,7 @@ s32 Player_OverrideLimbDrawGameplayDefault(PlayState* play, s32 limbIndex, Gfx** } else if (limbIndex == PLAYER_LIMB_WAIST) { - + if (!Player_IsCustomLinkModel()) { *dList = ResourceMgr_LoadGfxByName( this->waistDLists[sDListsLodOffset]); // NOTE: This needs to be disabled when using custom @@ -1833,6 +1834,7 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve (this->heldItemAction == PLAYER_IA_BOW_FIRE) || (this->heldItemAction == PLAYER_IA_BOW_ICE) || (this->heldItemAction == PLAYER_IA_BOW_LIGHT) || + (this->heldItemAction == PLAYER_IA_BOW_BOMB) || (this->heldItemAction == PLAYER_IA_BOW) || (this->heldItemAction == PLAYER_IA_SLINGSHOT))) { if (heldActor != NULL) { @@ -1907,7 +1909,7 @@ u32 func_80091738(PlayState* play, u8* segment, SkelAnime* skelAnime) { return size + 0x8800 + 0x90; } -u8 sPauseModelGroupBySword[] = { +u8 sPauseModelGroupBySword[] = { PLAYER_MODELGROUP_SWORD, // PLAYER_SWORD_KOKIRI PLAYER_MODELGROUP_SWORD, // PLAYER_SWORD_MASTER PLAYER_MODELGROUP_BGS, // PLAYER_SWORD_BIGGORON @@ -1931,7 +1933,7 @@ s32 Player_OverrideLimbDrawPause(PlayState* play, s32 limbIndex, Gfx** dList, Ve type = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_LEFT_HAND]; sLeftHandType = type; - // SOH: Handle unexpected swordless case. Previously OOB array access is avoided, but we want the + // SOH: Handle unexpected swordless case. Previously OOB array access is avoided, but we want the // hand model-type to be set to open (otherwise it is set to holding sword model-type) if (playerSwordAndShield[0] == PLAYER_SWORD_NONE) { type = PLAYER_MODELTYPE_LH_OPEN; @@ -1956,7 +1958,7 @@ s32 Player_OverrideLimbDrawPause(PlayState* play, s32 limbIndex, Gfx** dList, Ve } } else if (limbIndex == PLAYER_LIMB_WAIST) { type = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_WAIST]; - + if (Player_IsCustomLinkModel()) { return 0; } @@ -2225,7 +2227,7 @@ void Player_DrawPause(PlayState* play, u8* segment, SkelAnime* skelAnime, Vec3f* } else { SelectedAnim=randval; } - } + } } else if ((CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_NONE) && (CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) == EQUIP_VALUE_SHIELD_NONE)) { // if the player has no sword or shield equipped s16 randval = (rand() % (4 - 2 + 1)) + 2; // 3 animations if (randval==4) { //if its the shield anim diff --git a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c index 8b1d191a618..db1f0fd13bb 100644 --- a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c +++ b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c @@ -5,6 +5,7 @@ */ #include "z_en_arrow.h" +#include "overlays/actors/ovl_en_bom/z_en_bom.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_gi_nuts/object_gi_nuts.h" @@ -214,6 +215,7 @@ void EnArrow_Shoot(EnArrow* this, PlayState* play) { case ARROW_NORMAL_LIT: case ARROW_NORMAL_HORSE: case ARROW_NORMAL: + case ARROW_BOMB: Player_PlaySfx(&player->actor, NA_SE_IT_ARROW_SHOT); break; @@ -441,11 +443,12 @@ void EnArrow_Update(Actor* thisx, PlayState* play) { if ((this->actor.params >= ARROW_FIRE) && (this->actor.params <= ARROW_0E)) { s16 elementalActorIds[] = { ACTOR_ARROW_FIRE, ACTOR_ARROW_ICE, ACTOR_ARROW_LIGHT, - ACTOR_ARROW_FIRE, ACTOR_ARROW_FIRE, ACTOR_ARROW_FIRE }; + ACTOR_EN_BOM, ACTOR_ARROW_FIRE, ACTOR_ARROW_FIRE }; if (this->actor.child == NULL) { Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, elementalActorIds[this->actor.params - 3], - this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0); + this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, + this->actor.params == ARROW_BOMB ? BOMB_ARROW : 0); } } else if (this->actor.params == ARROW_NORMAL_LIT) { static Vec3f velocity = { 0.0f, 0.5f, 0.0f }; diff --git a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.h b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.h index 4ee84d3315b..7e9b9c1967e 100644 --- a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.h +++ b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.h @@ -34,7 +34,7 @@ typedef enum { /* 3 */ ARROW_FIRE, /* 4 */ ARROW_ICE, /* 5 */ ARROW_LIGHT, - /* 6 */ ARROW_0C, + /* 6 */ ARROW_BOMB, /* 7 */ ARROW_0D, /* 8 */ ARROW_0E, /* 9 */ ARROW_SEED, diff --git a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c index 40adc1a6f1a..f7b263299c0 100644 --- a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c +++ b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c @@ -20,6 +20,8 @@ void EnBom_Draw(Actor* thisx, PlayState* play); void EnBom_Move(EnBom* this, PlayState* play); void EnBom_WaitForRelease(EnBom* this, PlayState* play); +void ArrowBomb_Init(EnBom* this, PlayState* play); + const ActorInit En_Bom_InitVars = { ACTOR_EN_BOM, ACTORCAT_EXPLOSIVE, @@ -93,6 +95,11 @@ void EnBom_SetupAction(EnBom* this, EnBomActionFunc actionFunc) { void EnBom_Init(Actor* thisx, PlayState* play) { EnBom* this = (EnBom*)thisx; + if (this->actor.params == BOMB_ARROW) { + ArrowBomb_Init(this, play); + return; + } + Actor_ProcessInitChain(thisx, sInitChain); ActorShape_Init(&thisx->shape, 700.0f, ActorShadow_DrawCircle, 16.0f); thisx->colChkInfo.mass = 200; @@ -205,7 +212,7 @@ void EnBom_Explode(EnBom* this, PlayState* play) { } else { this->explosionCollider.elements[0].dim.worldSphere.radius += this->actor.shape.rot.z + 8; } - + if (this->actor.params == BOMB_EXPLOSION) { CollisionCheck_SetAT(play, &play->colChkCtx, &this->explosionCollider.base); @@ -348,6 +355,52 @@ void EnBom_Update(Actor* thisx, PlayState* play2) { Audio_PlayActorSound2(thisx, NA_SE_IT_BOMB_EXPLOSION); + play->envCtx.adjLight1Color[0] = play->envCtx.adjLight1Color[1] = + play->envCtx.adjLight1Color[2] = 250; + + play->envCtx.adjAmbientColor[0] = play->envCtx.adjAmbientColor[1] = + play->envCtx.adjAmbientColor[2] = 250; + + Camera_AddQuake(&play->mainCamera, 2, 0xB, 8); + thisx->params = BOMB_EXPLOSION; + this->timer = 10; + thisx->flags |= ACTOR_FLAG_DRAW_WHILE_CULLED; + EnBom_SetupAction(this, EnBom_Explode); + } + } else if (thisx->params == BOMB_ARROW) { + dustAccel.y = 0.2f; + + // spawn spark effect on even frames + effPos = thisx->world.pos; + effPos.y += 5.0f; + if ((play->gameplayFrames % 2) == 0) { + EffectSsGSpk_SpawnFuse(play, thisx, &effPos, &effVelocity, &effAccel); + } + + Audio_PlayActorSound2(thisx, NA_SE_IT_BOMB_IGNIT - SFX_FLAG); + + effPos.y += 1.0f; + func_8002829C(play, &effPos, &effVelocity, &dustAccel, &dustColor, &dustColor, 50, 5); + + dustAccel.y = 0.2f; + effPos = thisx->world.pos; + effPos.y += 1.0f; + + if (this->timer == 0) { + effPos = thisx->world.pos; + + effPos.y += 10.0f; + + EffectSsBomb2_SpawnLayered(play, &effPos, &effVelocity, &bomb2Accel, 100, + (thisx->shape.rot.z * 6) + 19); + + effPos.y = thisx->floorHeight; + if (thisx->floorHeight > BGCHECK_Y_MIN) { + EffectSsBlast_SpawnWhiteShockwave(play, &effPos, &effVelocity, &effAccel); + } + + Audio_PlayActorSound2(thisx, NA_SE_IT_BOMB_EXPLOSION); + play->envCtx.adjLight1Color[0] = play->envCtx.adjLight1Color[1] = play->envCtx.adjLight1Color[2] = 250; @@ -364,7 +417,7 @@ void EnBom_Update(Actor* thisx, PlayState* play2) { Actor_SetFocus(thisx, 20.0f); - if (thisx->params <= BOMB_BODY) { + if (thisx->params != BOMB_EXPLOSION) { Collider_UpdateCylinder(thisx, &this->bombCollider); // if link is not holding the bomb anymore and bump conditions are met, subscribe to OC @@ -395,7 +448,7 @@ void EnBom_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - if (thisx->params == BOMB_BODY) { + if (thisx->params != BOMB_EXPLOSION) { Gfx_SetupDL_25Opa(play->state.gfxCtx); if (!CVarGetInteger("gDisableBombBillboarding", 0)) { Matrix_ReplaceRotation(&play->billboardMtxF); @@ -415,3 +468,89 @@ void EnBom_Draw(Actor* thisx, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } + + +#include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" + +void ArrowBomb_Charge(EnBom* this, PlayState* play); +void ArrowBomb_Fly(EnBom* this, PlayState* play); + +void ArrowBomb_Init(EnBom* this, PlayState* play) { + Actor_ProcessInitChain(&this->actor, sInitChain); + ActorShape_Init(&this->actor.shape, 700.0f, ActorShadow_DrawCircle, 16.0f); + + this->flashSpeedScale = 7; + Collider_InitCylinder(play, &this->bombCollider); + Collider_InitJntSph(play, &this->explosionCollider); + Collider_SetCylinder(play, &this->bombCollider, &this->actor, &sCylinderInit); + Collider_SetJntSph(play, &this->explosionCollider, &this->actor, &sJntSphInit, &this->explosionColliderItems[0]); + this->explosionColliderItems[0].info.toucher.damage += (this->actor.shape.rot.z & 0xFF00) >> 8; + + this->actor.shape.rot.z &= 0xFF; + if (this->actor.shape.rot.z & 0x80) { + this->actor.shape.rot.z |= 0xFF00; + } + + Actor_SetScale(&this->actor, 0.003f); + + EnBom_SetupAction(this, ArrowBomb_Charge); +} + +void ArrowBomb_Charge(EnBom* this, PlayState* play) { + EnArrow* arrow = (EnArrow*)this->actor.parent; + if ((arrow == NULL) || (arrow->actor.update == NULL)) { + Actor_Kill(&this->actor); + return; + } + + // copy position and rotation from arrow + this->actor.world.pos = arrow->actor.world.pos; + f32 r = 10.0f; + f32 xrot = arrow->actor.world.rot.x; + f32 yrot = arrow->actor.world.rot.y; + this->actor.world.pos.x += r * Math_CosS(xrot) * Math_SinS(yrot); + this->actor.world.pos.y -= r * Math_SinS(xrot); + this->actor.world.pos.z += r * Math_CosS(xrot) * Math_CosS(yrot); + + this->timer = 10; + + // if arrow has no parent, player has fired the arrow + if (arrow->actor.parent == NULL) { + this->unkPos = this->actor.world.pos; + EnBom_SetupAction(this, ArrowBomb_Fly); + } +} + +void ArrowBomb_Fly(EnBom* this, PlayState* play) { + EnArrow* arrow; + f32 distanceScaled; + s32 pad; + + arrow = (EnArrow*)this->actor.parent; + if ((arrow == NULL) || (arrow->actor.update == NULL)) { + Actor_Kill(&this->actor); + return; + } + // copy position and rotation from arrow + this->actor.world.pos = arrow->actor.world.pos; + f32 r = 10.0f; + f32 xrot = arrow->actor.world.rot.x; + f32 yrot = arrow->actor.world.rot.y; + this->actor.world.pos.x += r * Math_SinS(yrot) * Math_CosS(xrot); + this->actor.world.pos.y -= r * Math_SinS(xrot); + this->actor.world.pos.z += r * Math_CosS(yrot) * Math_CosS(xrot); + + distanceScaled = Math_Vec3f_DistXYZ(&this->unkPos, &this->actor.world.pos) * (1.0f / 24.0f); + this->unk_158 = distanceScaled; + if (distanceScaled < 1.0f) { + this->unk_158 = 1.0f; + } + func_80865ECC(&this->unkPos, &this->actor.world.pos, 0.05f); + + if (arrow->hitFlags & 1) { + this->timer = 0; + this->actor.shape.rot.z = 0; + } else { + this->timer = 10; + } +} diff --git a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.h b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.h index 15e391226d8..90d7465f5f4 100644 --- a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.h +++ b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.h @@ -18,11 +18,14 @@ typedef struct EnBom { /* 0x01FC */ f32 flashIntensity; /* 0x0200 */ u8 bumpOn; /* 0x0204 */ EnBomActionFunc actionFunc; + /* 0x014C */ Vec3f unkPos; + /* 0x0158 */ f32 unk_158; } EnBom; // size = 0x0208 typedef enum { /* 0x00 */ BOMB_BODY, - /* 0x01 */ BOMB_EXPLOSION + /* 0x01 */ BOMB_EXPLOSION, + /* 0x02 */ BOMB_ARROW, } EnBomType; #endif diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 52dc2a3e448..4d013642e40 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -1062,6 +1062,7 @@ static s8 sItemActionParams[] = { PLAYER_IA_BOOTS_KOKIRI, PLAYER_IA_BOOTS_IRON, PLAYER_IA_BOOTS_HOVER, + PLAYER_IA_BOW_BOMB, }; static u8 sMaskMemory; @@ -2213,6 +2214,14 @@ s32 func_80834380(PlayState* play, Player* this, s32* itemPtr, s32* typePtr) { return play->interfaceCtx.hbaAmmo; } else if (play->shootingGalleryStatus != 0) { return play->shootingGalleryStatus; + } else if (this->heldItemAction == PLAYER_IA_BOW_BOMB) { + if (AMMO(*itemPtr) == 0) { + return 0; + } else if (AMMO(ITEM_BOMB) == 0) { + *typePtr = ARROW_NORMAL; + } else { + return MIN(AMMO(*itemPtr), AMMO(ITEM_BOMB)); + } } else { return AMMO(*itemPtr); } @@ -2224,7 +2233,7 @@ s32 func_8083442C(Player* this, PlayState* play) { s32 arrowType; s32 magicArrowType; - if ((this->heldItemAction >= PLAYER_IA_BOW_FIRE) && (this->heldItemAction <= PLAYER_IA_BOW_0E) && + if ((this->heldItemAction >= PLAYER_IA_BOW_FIRE) && (this->heldItemAction < PLAYER_IA_BOW_BOMB) && (gSaveContext.magicState != MAGIC_STATE_IDLE)) { func_80078884(NA_SE_SY_ERROR); } else { @@ -4934,7 +4943,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5378,7 +5387,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6106,8 +6115,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6350,8 +6359,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -7759,7 +7768,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -11187,7 +11196,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11238,7 +11247,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -13569,7 +13578,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -14996,7 +15005,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15005,7 +15014,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 665c95b81af..c38c3cd7496 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -42,6 +42,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 130, 130, 130, pauseCtx->alpha); } else if ((item == ITEM_BOMB && AMMO(item) == CUR_CAPACITY(UPG_BOMB_BAG)) || (item == ITEM_BOW && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || + (item == ITEM_BOW_ARROW_BOMB && MIN(AMMO(ITEM_BOW), AMMO(ITEM_BOMB)) == MIN(CUR_CAPACITY(UPG_QUIVER), CUR_CAPACITY(UPG_BOMB_BAG))) || (item == ITEM_SLINGSHOT && AMMO(item) == CUR_CAPACITY(UPG_BULLET_BAG)) || (item == ITEM_STICK && AMMO(item) == CUR_CAPACITY(UPG_STICKS)) || (item == ITEM_NUT && AMMO(item) == CUR_CAPACITY(UPG_NUTS)) || (item == ITEM_BOMBCHU && ammo == 50) || @@ -813,8 +814,8 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; s16 DPad_ItemsOffset[4][2] = { @@ -1027,11 +1028,16 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { pauseCtx->equipTargetSlot = SLOT_BOW; } } - + // If the item is on another button already, swap the two uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1; for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); otherSlotIndex++) { + if (gSaveContext.equips.buttonItems[targetButtonIndex] == ITEM_BOW && pauseCtx->equipTargetItem == ITEM_BOMB) { + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_BOMB; + pauseCtx->equipTargetSlot = SLOT_BOW; + } + uint16_t otherButtonIndex = otherSlotIndex + 1; if (otherSlotIndex == pauseCtx->equipTargetCBtn) { continue; From f4a22cead462053985c0b7cc76f88d6e9dbe8159 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 14 Dec 2023 09:51:50 -0600 Subject: [PATCH 02/60] Bomb arrows: Improvements and fixes --- soh/src/code/z_parameter.c | 59 ++++++++++--------- soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c | 32 +++++----- .../actors/ovl_player_actor/z_player.c | 3 + .../misc/ovl_kaleido_scope/z_kaleido_item.c | 7 ++- 4 files changed, 54 insertions(+), 47 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 495825e9d59..4290dcd53e9 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1441,7 +1441,7 @@ void Inventory_SwapAgeEquipment(void) { u16 shieldEquipValue; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (i != 0) { @@ -1483,13 +1483,13 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; - + gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) | (EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) | (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) | (EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4)); - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.equips.buttonItems[0] == ITEM_NONE) { gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); } @@ -1814,14 +1814,14 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { /** * @brief Adds the given item to Link's inventory. - * + * * NOTE: This function has been edited to be safe to use with a NULL play. * If you need to add to this function, be sure you check if the play is not * NULL before doing any operations requiring it. - * - * @param play - * @param item - * @return u8 + * + * @param play + * @param item + * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { lusprintf(__FILE__, __LINE__, 2, "Item Give - item: %#x", item); @@ -1902,10 +1902,10 @@ u8 Item_Give(PlayState* play, u8 item) { // In rando, when buying Giant's Knife, also check // without the Koriri Sword in case we don't have it - if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_KOKIRI) | (1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | - (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || - (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || + (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)))) { gSaveContext.inventory.equipment ^= OWNED_EQUIP_FLAG_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); @@ -1917,7 +1917,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - + } else if (item == ITEM_SWORD_MASTER) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); @@ -2657,7 +2657,7 @@ u8 Item_CheckObtainability(u8 item) { return ITEM_NONE; } } - + if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { return ITEM_NONE; } else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) { @@ -2921,7 +2921,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); } - if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { return 0; } @@ -2960,7 +2960,7 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l } doAction = newName[loadOffset]; } - + char* segment = interfaceCtx->doActionSegment[loadOffset]; interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; @@ -3027,7 +3027,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { } interfaceCtx->unk_1FC = action; - + char* segment = interfaceCtx->doActionSegment[1]; interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); @@ -3052,7 +3052,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3121,7 +3121,7 @@ void Rupees_ChangeBy(s16 rupeeChange) { void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { - switch (item) { + switch (item) { case ITEM_STICK: gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; @@ -4307,7 +4307,7 @@ void Interface_DrawItemButtons(PlayState* play) { G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, (C_Up_BTN_Pos[0]-LabelX_Navi + 32) << 2, (C_Up_BTN_Pos[1]+LabelY_Navi + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -4425,7 +4425,7 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, cRightButtonColor.r, cRightButtonColor.g, cRightButtonColor.b, interfaceCtx->cRightAlpha); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, ItemIconPos[temp-1][0], ItemIconPos[temp-1][1], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][1], ItemIconWidthFactor[temp-1][1]); @@ -4500,8 +4500,8 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; u16 ItemsSlotsAlpha[8] = { @@ -4842,7 +4842,7 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { ((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) || (i == ITEM_BOW_ARROW_BOMB) || (i == ITEM_SLINGSHOT) || (i == ITEM_BOMBCHU) || (i == ITEM_BEAN)) { - if (((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) || (i == ITEM_BOW_ARROW_BOMB)) { + if ((i >= ITEM_BOW_ARROW_FIRE) && (i <= ITEM_BOW_ARROW_LIGHT)) { i = ITEM_BOW; } @@ -4865,6 +4865,7 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } } else if (((i == ITEM_BOW) && (AMMO(i) == CUR_CAPACITY(UPG_QUIVER))) || ((i == ITEM_BOMB) && (AMMO(i) == CUR_CAPACITY(UPG_BOMB_BAG))) || + ((i == ITEM_BOW_ARROW_BOMB) && MIN(AMMO(ITEM_BOW), AMMO(ITEM_BOMB)) == MIN(CUR_CAPACITY(UPG_QUIVER), CUR_CAPACITY(UPG_BOMB_BAG))) || ((i == ITEM_SLINGSHOT) && (AMMO(i) == CUR_CAPACITY(UPG_BULLET_BAG))) || ((i == ITEM_STICK) && (AMMO(i) == CUR_CAPACITY(UPG_STICKS))) || ((i == ITEM_NUT) && (AMMO(i) == CUR_CAPACITY(UPG_NUTS))) || ((i == ITEM_BOMBCHU) && (ammo == 50)) || @@ -4881,11 +4882,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, ItemIconPos[button][0], ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, ItemIconPos[button][0] + 6, ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } @@ -5390,7 +5391,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5708,7 +5709,7 @@ void Interface_Draw(PlayState* play) { CarrotsPosY = CVarGetInteger("gCarrotsPosY", 0); if (CVarGetInteger("gCarrotsPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Left_HUD_Margin;}; - CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); + CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); } else if (CVarGetInteger("gCarrotsPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Right_HUD_Margin;}; CarrotsPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); @@ -6218,7 +6219,7 @@ void Interface_Draw(PlayState* play) { for (svar1 = 0; svar1 < 5; svar1++) { // clang-format off //svar5 = svar5 + 8; - //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); + //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, digitTextures[timerDigits[svar1]], 8, 16, svar5 + timerDigitLeftPos[svar1], svar2, digitWidth[svar1], VREG(42), VREG(43) << 1, @@ -6362,7 +6363,7 @@ void Interface_Update(PlayState* play) { Left_HUD_Margin = CVarGetInteger("gHUDMargin_L", 0); Right_HUD_Margin = CVarGetInteger("gHUDMargin_R", 0); Bottom_HUD_Margin = CVarGetInteger("gHUDMargin_B", 0); - + GameInteractor_ExecuteOnInterfaceUpdate(); if (CHECK_BTN_ALL(debugInput->press.button, BTN_DLEFT)) { diff --git a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c index f7b263299c0..7d53d7942fb 100644 --- a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c +++ b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c @@ -253,6 +253,9 @@ void EnBom_Explode(EnBom* this, PlayState* play) { } Actor_Kill(&this->actor); + if (this->actor.parent && this->actor.parent->id == ACTOR_EN_ARROW) { + Actor_Kill(this->actor.parent); + } } } @@ -496,6 +499,17 @@ void ArrowBomb_Init(EnBom* this, PlayState* play) { EnBom_SetupAction(this, ArrowBomb_Charge); } +void ArrowBomb_SetPosition(EnBom* this, EnArrow* arrow) { + // copy position and rotation from arrow + this->actor.world.pos = arrow->actor.world.pos; + f32 r = 8.0f; + f32 xrot = arrow->actor.world.rot.x; + f32 yrot = arrow->actor.world.rot.y; + this->actor.world.pos.x += r * Math_CosS(xrot) * Math_SinS(yrot); + this->actor.world.pos.y -= r * Math_SinS(xrot) + 2.0f; + this->actor.world.pos.z += r * Math_CosS(xrot) * Math_CosS(yrot); +} + void ArrowBomb_Charge(EnBom* this, PlayState* play) { EnArrow* arrow = (EnArrow*)this->actor.parent; if ((arrow == NULL) || (arrow->actor.update == NULL)) { @@ -503,14 +517,7 @@ void ArrowBomb_Charge(EnBom* this, PlayState* play) { return; } - // copy position and rotation from arrow - this->actor.world.pos = arrow->actor.world.pos; - f32 r = 10.0f; - f32 xrot = arrow->actor.world.rot.x; - f32 yrot = arrow->actor.world.rot.y; - this->actor.world.pos.x += r * Math_CosS(xrot) * Math_SinS(yrot); - this->actor.world.pos.y -= r * Math_SinS(xrot); - this->actor.world.pos.z += r * Math_CosS(xrot) * Math_CosS(yrot); + ArrowBomb_SetPosition(this, arrow); this->timer = 10; @@ -531,14 +538,7 @@ void ArrowBomb_Fly(EnBom* this, PlayState* play) { Actor_Kill(&this->actor); return; } - // copy position and rotation from arrow - this->actor.world.pos = arrow->actor.world.pos; - f32 r = 10.0f; - f32 xrot = arrow->actor.world.rot.x; - f32 yrot = arrow->actor.world.rot.y; - this->actor.world.pos.x += r * Math_SinS(yrot) * Math_CosS(xrot); - this->actor.world.pos.y -= r * Math_SinS(xrot); - this->actor.world.pos.z += r * Math_CosS(yrot) * Math_CosS(xrot); + ArrowBomb_SetPosition(this, arrow); distanceScaled = Math_Vec3f_DistXYZ(&this->unkPos, &this->actor.world.pos) * (1.0f / 24.0f); this->unk_158 = distanceScaled; diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 4d013642e40..9bd4e9922ff 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2558,6 +2558,9 @@ s32 func_808350A4(PlayState* play, Player* this) { if (!CVarGetInteger("gInfiniteAmmo", 0)) { play->shootingGalleryStatus--; } + } else if (item == ITEM_BOW && this->heldItemAction == PLAYER_IA_BOW_BOMB) { + Inventory_ChangeAmmo(ITEM_BOW, -1); + Inventory_ChangeAmmo(ITEM_BOMB, -1); } else { Inventory_ChangeAmmo(item, -1); } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index c38c3cd7496..8a16d240986 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -42,7 +42,6 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 130, 130, 130, pauseCtx->alpha); } else if ((item == ITEM_BOMB && AMMO(item) == CUR_CAPACITY(UPG_BOMB_BAG)) || (item == ITEM_BOW && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || - (item == ITEM_BOW_ARROW_BOMB && MIN(AMMO(ITEM_BOW), AMMO(ITEM_BOMB)) == MIN(CUR_CAPACITY(UPG_QUIVER), CUR_CAPACITY(UPG_BOMB_BAG))) || (item == ITEM_SLINGSHOT && AMMO(item) == CUR_CAPACITY(UPG_BULLET_BAG)) || (item == ITEM_STICK && AMMO(item) == CUR_CAPACITY(UPG_STICKS)) || (item == ITEM_NUT && AMMO(item) == CUR_CAPACITY(UPG_NUTS)) || (item == ITEM_BOMBCHU && ammo == 50) || @@ -1033,7 +1032,11 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1; for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); otherSlotIndex++) { - if (gSaveContext.equips.buttonItems[targetButtonIndex] == ITEM_BOW && pauseCtx->equipTargetItem == ITEM_BOMB) { + int slot_item = gSaveContext.equips.buttonItems[targetButtonIndex]; + // Don't check for bomb arrows so you can replace bomb arrow equip with just bombs + if ((slot_item == ITEM_BOW || slot_item == ITEM_BOW_ARROW_FIRE || + slot_item == ITEM_BOW_ARROW_ICE || slot_item == ITEM_BOW_ARROW_LIGHT) + && pauseCtx->equipTargetItem == ITEM_BOMB) { pauseCtx->equipTargetItem = ITEM_BOW_ARROW_BOMB; pauseCtx->equipTargetSlot = SLOT_BOW; } From df01a29bfbf3550a09c96d22708a750c235d1224 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 14 Dec 2023 10:45:55 -0600 Subject: [PATCH 03/60] Bomb Arrows: Add enhancement checkbutton --- soh/soh/Enhancements/presets.h | 1 + soh/soh/SohMenuBar.cpp | 28 ++++++++++--------- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 7 +++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..29a8c428541 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -242,6 +242,7 @@ const std::vector enhancementsCvars = { "gAddTraps.Speed", "gAddTraps.Tele", "gAddTraps.Void", + "gBombArrows", }; const std::vector cheatCvars = { diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 0c0a1240b5e..9900cd50bc9 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -606,6 +606,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); + UIWidgets::PaddedEnhancementCheckbox("Bomb Arrows", "gBombArrows", true, false); + UIWidgets::Tooltip("Equip bombs onto the same button as your bow to shoot arrows that explode on impact"); UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); @@ -878,7 +880,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -887,7 +889,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -1062,8 +1064,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1396,12 +1398,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndDisabled(); @@ -1581,12 +1583,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1642,4 +1644,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 8a16d240986..071ea3423fa 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -1034,9 +1034,10 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { otherSlotIndex++) { int slot_item = gSaveContext.equips.buttonItems[targetButtonIndex]; // Don't check for bomb arrows so you can replace bomb arrow equip with just bombs - if ((slot_item == ITEM_BOW || slot_item == ITEM_BOW_ARROW_FIRE || - slot_item == ITEM_BOW_ARROW_ICE || slot_item == ITEM_BOW_ARROW_LIGHT) - && pauseCtx->equipTargetItem == ITEM_BOMB) { + if (CVarGetInteger("gBombArrows", 0) && + (slot_item == ITEM_BOW || slot_item == ITEM_BOW_ARROW_FIRE || + slot_item == ITEM_BOW_ARROW_ICE || slot_item == ITEM_BOW_ARROW_LIGHT) && + pauseCtx->equipTargetItem == ITEM_BOMB) { pauseCtx->equipTargetItem = ITEM_BOW_ARROW_BOMB; pauseCtx->equipTargetSlot = SLOT_BOW; } From 517e37dd3b84fec978b982aadb7d524e7d289581 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Wed, 28 Sep 2022 13:57:49 -0500 Subject: [PATCH 04/60] Add arrow switching with customizable button --- soh/include/functions.h | 1 + .../controls/GameControlEditor.cpp | 22 +++ soh/soh/Enhancements/presets.h | 1 + soh/soh/SohMenuBar.cpp | 29 ++-- soh/src/code/z_map_exp.c | 6 +- .../actors/ovl_player_actor/z_player.c | 161 +++++++++++++++--- 6 files changed, 187 insertions(+), 33 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 3a1aa8ae24a..3af7011647e 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1140,6 +1140,7 @@ s32 Player_ActionToBottle(Player* player, s32 actionParam); s32 Player_GetBottleHeld(Player* player); s32 Player_ActionToExplosive(Player* player, s32 actionParam); s32 Player_GetExplosiveHeld(Player* player); +bool Player_CanSwitchArrows(Player* player); s32 func_8008F2BC(Player* player, s32 actionParam); s32 Player_GetEnvironmentalHazard(PlayState* play); void Player_DrawImpl(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, s32 lod, s32 tunic, diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index eb69f3cc852..ad29fb39ef8 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -85,6 +85,9 @@ namespace GameControlEditor { static CustomButtonMap ocarinaSharp = {"Pitch up", "gOcarinaSharpBtnMap", BTN_R}; static CustomButtonMap ocarinaFlat = {"Pitch down", "gOcarinaFlatBtnMap", BTN_Z}; + // Misc. + static CustomButtonMap arrowSwitch = {"Switch arrows", "gArrowSwitchBtnMap", BTN_R}; + void GameControlEditorWindow::InitElement() { addButtonName(BTN_A, "A"); addButtonName(BTN_B, "B"); @@ -328,6 +331,25 @@ namespace GameControlEditor { UIWidgets::Spacer(0); UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL"); DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up"); + + float longestLabelWidth = ImGui::CalcTextSize(arrowSwitch.label).x + 10; + + // Switch arrows + bool arrowSwitchingEnabled = CVarGetInteger("gArrowSwitching", 0); + if (!arrowSwitchingEnabled) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + N64ButtonMask arrowSwitchAllowedButtons = BTN_A | BTN_L | BTN_R | BTN_CUP; + DrawMapping(arrowSwitch, longestLabelWidth, ~arrowSwitchAllowedButtons); + if (!arrowSwitchingEnabled) { + ImGui::PopStyleVar(1); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + ImGui::SetTooltip("%s", "This option is disabled because Arrow Switching from Enhancements > Gameplay > Time Savers is disabled"); + } + ImGui::PopItemFlag(); + } + window->EndGroupPanelPublic(0); } diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..c598e47494f 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -184,6 +184,7 @@ const std::vector enhancementsCvars = { "gBombchuBowlingNoBigCucco", "gBombchuBowlingAmmunition", "gCreditsFix", + "gArrowSwitching", "gSilverRupeeJingleExtend", "gStaticExplosionRadius", "gNoInputForCredits", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..df957204ee3 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -608,6 +608,9 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)"); + UIWidgets::PaddedEnhancementCheckbox("Switch Arrow Types", "gArrowSwitching", true, false); + UIWidgets::Tooltip("Press R with the bow out to switch between normal, fire, ice, and light arrows\n" + "Use the \"Customize Game Controls\" window to switch with a different button"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); @@ -878,7 +881,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -887,7 +890,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -1064,8 +1067,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1398,12 +1401,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndDisabled(); @@ -1583,12 +1586,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1644,4 +1647,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index c4db0098b23..e10ab39de46 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -964,7 +964,11 @@ void Minimap_Draw(PlayState* play) { Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + u16 minimapButton = BTN_L; + if (Player_CanSwitchArrows(GET_PLAYER(play))) { + minimapButton &= ~CVarGetInteger("gArrowSwitchBtnMap", BTN_R); + } + if (minimapButton && CHECK_BTN_ALL(play->state.input[0].press.button, minimapButton) && !Play_InCsMode(play) && enableMapToggle) { // clang-format off if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index ca7333497a0..04865b61ecf 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2218,6 +2218,98 @@ s32 func_80834380(PlayState* play, Player* this, s32* itemPtr, s32* typePtr) { } } +typedef struct { + u8 asArrow; + u8 asBowArrow; +} ArrowItems; + +static ArrowItems arrowTypeToItem[] = { + /* normal arrows */ { ITEM_BOW, ITEM_BOW }, + /* fire arrows */ { ITEM_ARROW_FIRE, ITEM_BOW_ARROW_FIRE }, + /* ice arrows */ { ITEM_ARROW_ICE, ITEM_BOW_ARROW_ICE }, + /* light arrows */ { ITEM_ARROW_LIGHT, ITEM_BOW_ARROW_LIGHT }, + /* unused arrow types are excluded from cycling */ +}; + +static bool gSwitchingArrow = false; + +// Returns true if the player is in a state where they can switch arrows. +// Specifically, the gArrowSwitching CVar is enabled, the player is holding the +// bow with normal, fire, ice, or light arrows, and they're either aiming or +// have an arrow notched. +bool Player_CanSwitchArrows(Player* this) { + if (!CVarGetInteger("gArrowSwitching", 0)) { + return false; + } + + if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_LIGHT) { + return false; + } + + return this->func_82C == func_808351D4 || this->func_82C == func_808353D8; +} + +bool Player_SwitchArrowsIfEnabled(Player* this) { + if (!CVarGetInteger("gArrowSwitching", 0)) { + return false; + } + if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_LIGHT) { + return false; + } + if (!CHECK_BTN_ANY(sControlInput->press.button, CVarGetInteger("gArrowSwitchBtnMap", BTN_R))) { + return false; + } + + u8 i, newItem, newItemAction; + const u8 arrowCount = ARRAY_COUNT(arrowTypeToItem); + u8 heldArrowAP = this->heldItemAction - PLAYER_IA_BOW; + for (i = 1; i < arrowCount; i++) { + u8 arrowAP = (heldArrowAP + i) % arrowCount; + ArrowItems items = arrowTypeToItem[arrowAP]; + if (INV_CONTENT(items.asArrow) != ITEM_NONE) { + newItem = items.asBowArrow; + newItemAction = PLAYER_IA_BOW + arrowAP; + break; + } + } + if (i == arrowCount) { + return false; + } + + gSaveContext.equips.buttonItems[this->heldItemButton] = newItem; + this->heldItemId = newItem; + this->itemAction = newItemAction; + this->heldItemAction = newItemAction; + return true; +} + +// Replace previously nocked arrow with the new arrow type +void Player_ReplaceSwitchedArrow(PlayState* play, Player* this) { + s32 item, arrowType; + if (this->unk_860 < 0 || func_80834380(play, this, &item, &arrowType) <= 0) { + return; + } + + s32 newMagicArrowType = arrowType - ARROW_FIRE; + s32 arrowCost; + if (newMagicArrowType < 0 || newMagicArrowType > 2) { + arrowCost = 0; + } else { + arrowCost = sMagicArrowCosts[newMagicArrowType]; + } + + if (arrowCost == 0 || !Magic_RequestChange(play, arrowCost, MAGIC_CONSUME_WAIT_PREVIEW)) { + arrowType = ARROW_NORMAL; + } + + if (this->heldActor != NULL) { + Actor_Kill(this->heldActor); + } + this->heldActor = Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_ARROW, + this->actor.world.pos.x, this->actor.world.pos.y, + this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0, arrowType); +} + // The player has pressed the bow or hookshot button s32 func_8083442C(Player* this, PlayState* play) { s32 item; @@ -2241,7 +2333,8 @@ s32 func_8083442C(Player* this, PlayState* play) { if (this->unk_860 >= 0) { if ((magicArrowType >= 0) && (magicArrowType <= 2) && - !Magic_RequestChange(play, sMagicArrowCosts[magicArrowType], MAGIC_CONSUME_NOW)) { + !Magic_RequestChange(play, sMagicArrowCosts[magicArrowType], + CVarGetInteger("gArrowSwitching", 0) ? 4 : MAGIC_CONSUME_NOW)) { arrowType = ARROW_NORMAL; } @@ -2308,7 +2401,7 @@ s32 func_80834758(PlayState* play, Player* this) { if (!(this->stateFlags1 & (PLAYER_STATE1_SHIELDING | PLAYER_STATE1_ON_HORSE | PLAYER_STATE1_IN_CUTSCENE)) && (play->shootingGalleryStatus == 0) && (this->heldItemAction == this->itemAction) && (this->currentShield != PLAYER_SHIELD_NONE) && !Player_IsChildWithHylianShield(this) && func_80833BCC(this) && - CHECK_BTN_ALL(sControlInput->cur.button, BTN_R)) { + !Player_CanSwitchArrows(this) && CHECK_BTN_ALL(sControlInput->cur.button, BTN_R)) { anim = func_808346C4(play, this); frame = Animation_GetLastFrame(anim); @@ -2551,6 +2644,12 @@ s32 func_808350A4(PlayState* play, Player* this) { } } else { Inventory_ChangeAmmo(item, -1); + if (CVarGetInteger("gArrowSwitching", 0) && + arrowType >= ARROW_FIRE && arrowType <= ARROW_LIGHT + && this->heldActor->child != NULL) { + gSaveContext.magicState = 0; + Magic_RequestChange(play, sMagicArrowCosts[arrowType - ARROW_FIRE], MAGIC_CONSUME_NOW); + } } if (play->shootingGalleryStatus == 1) { @@ -2604,6 +2703,11 @@ s32 func_808351D4(Player* this, PlayState* play) { func_80834EB8(this, play); + if (gSwitchingArrow) { + Player_ReplaceSwitchedArrow(play, this); + gSwitchingArrow = false; + } + if ((this->unk_836 > 0) && ((this->unk_860 < 0) || (!D_80853618 && !func_80834E7C(play)))) { func_80833638(this, func_808353D8); if (this->unk_860 >= 0) { @@ -2621,6 +2725,14 @@ s32 func_808351D4(Player* this, PlayState* play) { this->stateFlags1 |= PLAYER_STATE1_READY_TO_FIRE; } + gSwitchingArrow = Player_SwitchArrowsIfEnabled(this); + if (gSwitchingArrow && this->heldActor != NULL) { + if (this->heldActor->child != NULL) { + Actor_Kill(this->heldActor->child); + } + gSwitchingArrow = true; + } + return 1; } @@ -2631,6 +2743,8 @@ s32 func_808353D8(Player* this, PlayState* play) { return 1; } + Player_SwitchArrowsIfEnabled(this); + if (!func_80834758(play, this) && (D_80853614 || ((this->unk_860 < 0) && D_80853618) || func_80834E44(play))) { this->unk_860 = ABS(this->unk_860); @@ -4934,7 +5048,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5213,7 +5327,11 @@ s32 func_8083B644(Player* this, PlayState* play) { this->stateFlags2 |= PLAYER_STATE2_NAVI_ALERT; } - if (!CHECK_BTN_ALL(sControlInput->press.button, CVarGetInteger("gNaviOnL", 0) ? BTN_L : BTN_CUP) && + u16 naviButton = CVarGetInteger("gNaviOnL", 0) ? BTN_L : BTN_CUP; + if (Player_CanSwitchArrows(this)) { + naviButton &= ~CVarGetInteger("gArrowSwitchBtnMap", BTN_R); + } + if (!(naviButton && CHECK_BTN_ALL(sControlInput->press.button, naviButton)) && !sp28) { return 0; } @@ -5378,7 +5496,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6106,8 +6224,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6350,8 +6468,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -7759,7 +7877,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -11194,7 +11312,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11245,7 +11363,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -11597,15 +11715,20 @@ void func_8084B1D8(Player* this, PlayState* play) { func_80836670(this, play); } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 itemButtons = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + itemButtons |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + } + u16 returnButtons = BTN_A | BTN_B | BTN_R; + if (Player_CanSwitchArrows(this)) { + itemButtons &= ~CVarGetInteger("gArrowSwitchBtnMap", BTN_R); + returnButtons &= ~CVarGetInteger("gArrowSwitchBtnMap", BTN_R); } if ((this->csMode != 0) || (this->unk_6AD == 0) || (this->unk_6AD >= 4) || func_80833B54(this) || (this->unk_664 != NULL) || !func_8083AD4C(play, this) || - (((this->unk_6AD == 2) && (CHECK_BTN_ANY(sControlInput->press.button, BTN_A | BTN_B | BTN_R) || + (((this->unk_6AD == 2) && (CHECK_BTN_ANY(sControlInput->press.button, returnButtons) || func_80833B2C(this) || (!func_8002DD78(this) && !func_808334B4(this)))) || - ((this->unk_6AD == 1) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)))) { + ((this->unk_6AD == 1) && CHECK_BTN_ANY(sControlInput->press.button, itemButtons)))) { func_8083C148(this, play); func_80078884(NA_SE_SY_CAMERA_ZOOM_UP); } else if ((DECR(this->unk_850) == 0) || (this->unk_6AD != 2)) { @@ -13576,7 +13699,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -15003,7 +15126,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15012,7 +15135,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); From 6b981f12f38a949ee84f6e0f00b253d8489d75e2 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Tue, 23 Aug 2022 18:18:13 -0500 Subject: [PATCH 05/60] Ask to Continue After Saving --- soh/soh/Enhancements/presets.h | 1 + soh/soh/SohMenuBar.cpp | 5 ++ .../misc/ovl_kaleido_scope/z_kaleido_prompt.c | 2 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 66 +++++++++++++++++-- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..e270cd67882 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -170,6 +170,7 @@ const std::vector enhancementsCvars = { "gRestoreRBAValues", "gSkipSaveConfirmation", "gAutosave", + "gSaveAndQuit", "gDisableCritWiggle", "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..e94e02378fe 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -899,6 +899,11 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Targetable Hookshot Reticle", "gHookshotableReticle", true, false); UIWidgets::Tooltip("Use a different color when aiming at hookshotable collision"); + UIWidgets::PaddedEnhancementCheckbox("Ask to continue playing after saving", "gSaveAndQuit", true, false); + UIWidgets::Tooltip( + "The save dialog from the pause menu will ask you to continue playing after you select Yes or No.\n" + "Pressing B or Start on the save prompt will close the pause menu without displaying the extra screen."); + ImGui::EndMenu(); } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c index 0807b8356a8..53e30257fe7 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c @@ -9,7 +9,7 @@ void KaleidoScope_UpdatePrompt(PlayState* play) { s16 step; bool dpad = CVarGetInteger("gDpadPause", 0); - if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC == 1)) || (pauseCtx->state == 0xE) || (pauseCtx->state == 0x10)) { + if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC == 1 || pauseCtx->unk_1EC == 7)) || (pauseCtx->state == 0xE) || (pauseCtx->state == 0x10)) { if ((pauseCtx->promptChoice == 0) && ((relStickX >= 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT)))) { Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); pauseCtx->promptChoice = 4; diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 877ea7e6f42..c6e16daf499 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -1601,9 +1601,17 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->saveVtx[60], 32, 0); - if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC < 4)) || (pauseCtx->state == 0xE)) { - POLY_KAL_DISP = - KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sSavePromptTexs[gSaveContext.language], 152, 16, 0); + if (((pauseCtx->state == 7) && + (pauseCtx->unk_1EC < 4 || pauseCtx->unk_1EC == 7 || + (CVarGetInteger("gSaveAndQuit", 0) && pauseCtx->unk_1EC == 5))) || + (pauseCtx->state == 0xE)) { + if (pauseCtx->unk_1EC == 7 || pauseCtx->unk_1EC == 5) { + POLY_KAL_DISP = + KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sContinuePromptTexs[gSaveContext.language], 152, 16, 0); + } else { + POLY_KAL_DISP = + KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sSavePromptTexs[gSaveContext.language], 152, 16, 0); + } gDPSetCombineLERP(POLY_KAL_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0); @@ -4047,6 +4055,12 @@ void KaleidoScope_Update(PlayState* play) case 1: if (CHECK_BTN_ALL(input->press.button, BTN_A)) { if (pauseCtx->promptChoice != 0) { + if (CVarGetInteger("gSaveAndQuit", 0)) { + pauseCtx->promptChoice = 0; + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + pauseCtx->unk_1EC = 7; + break; + } Interface_SetDoAction(play, DO_ACTION_NONE); gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = gSaveContext.buttonStatus[3] = BTN_ENABLED; @@ -4062,7 +4076,7 @@ void KaleidoScope_Update(PlayState* play) Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Play_PerformSave(play); - pauseCtx->unk_1EC = 4; + pauseCtx->unk_1EC = CVarGetInteger("gSaveAndQuit", 0) ? 7 : 4; D_8082B25C = CVarGetInteger("gSkipSaveConfirmation", 0) ? 3 /* 0.1 sec */ : 90 /* 3 secs */; } } else if (CHECK_BTN_ALL(input->press.button, BTN_START) || @@ -4084,6 +4098,10 @@ void KaleidoScope_Update(PlayState* play) case 4: if (CHECK_BTN_ALL(input->press.button, BTN_B) || CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START) || (--D_8082B25C == 0)) { + if (CVarGetInteger("gSaveAndQuit", 0)) { + pauseCtx->unk_1EC = 7; + break; + } Interface_SetDoAction(play, DO_ACTION_NONE); gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = gSaveContext.buttonStatus[3] = BTN_ENABLED; @@ -4134,6 +4152,46 @@ void KaleidoScope_Update(PlayState* play) pauseCtx->unk_204 = -434.0f; } break; + + // 7 and 8 are used by "Prompt to quit after saving" enhancement + case 7: + if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_B) || + CHECK_BTN_ALL(input->press.button, BTN_START)) { + if (pauseCtx->promptChoice == 0 || CHECK_BTN_ALL(input->press.button, BTN_B)) { + Interface_SetDoAction(play, DO_ACTION_NONE); + gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = + gSaveContext.buttonStatus[3] = BTN_ENABLED; + gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] = + gSaveContext.buttonStatus[8] = BTN_ENABLED; + gSaveContext.unk_13EA = 0; + Interface_ChangeAlpha(50); + pauseCtx->unk_1EC = 5; + WREG(2) = -6240; + YREG(8) = pauseCtx->unk_204; + func_800F64E0(0); + } else { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + pauseCtx->unk_1EC = 8; + } + } + break; + + case 8: + if (interfaceCtx->unk_244 != 255) { + interfaceCtx->unk_244 += 10; + if (interfaceCtx->unk_244 >= 255) { + interfaceCtx->unk_244 = 255; + pauseCtx->state = 0; + R_UPDATE_RATE = 3; + R_PAUSE_MENU_MODE = 0; + func_800981B8(&play->objectCtx); + func_800418D0(&play->colCtx, play); + play->state.running = 0; + SET_NEXT_GAMESTATE(&play->state, Opening_Init, OpeningContext); + } + } + break; } break; From 5222bcf54a640fd451bc9f236439e29281a39ca9 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Thu, 24 Nov 2022 23:56:21 -0600 Subject: [PATCH 06/60] Enhancement: Catch Poes with bottles --- soh/soh/Enhancements/presets.h | 1 + soh/soh/SohMenuBar.cpp | 28 ++++++++++--------- .../actors/ovl_En_Po_Field/z_en_po_field.c | 12 ++++++-- soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c | 13 +++++++-- .../actors/ovl_player_actor/z_player.c | 22 +++++++++++++-- 5 files changed, 57 insertions(+), 19 deletions(-) diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..2fa06642fc3 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -73,6 +73,7 @@ const std::vector enhancementsCvars = { "gFasterHeavyBlockLift", "gNoForcedNavi", "gSkulltulaFreeze", + "gMMPoeBottling", "gMMBunnyHood", "gAdultBunnyHood", "gFastChests", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..2303c32f82c 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -604,6 +604,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Allows the bunny hood to be equipped normally from the pause menu as adult."); UIWidgets::PaddedEnhancementCheckbox("Mask Select in Inventory", "gMaskSelect", true, false); UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); + UIWidgets::PaddedEnhancementCheckbox("Catch Poes with a bottle", "gMMPoeBottling", true, false); + UIWidgets::Tooltip("Catch Poes by swinging an empty bottle at them instead of from a text box like you can in Majora's Mask."); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); @@ -878,7 +880,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -887,7 +889,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -1064,8 +1066,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1398,12 +1400,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndDisabled(); @@ -1583,12 +1585,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1644,4 +1646,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui diff --git a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c index c11feb327d9..b7f2f5bb4ec 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c +++ b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c @@ -658,7 +658,7 @@ void func_80AD58D4(EnPoField* this, PlayState* play) { if (this->actionTimer != 0) { this->actionTimer--; } - if (Actor_ProcessTalkRequest(&this->actor, play)) { + if (!CVarGetInteger("gMMPoeBottling", 0) && Actor_ProcessTalkRequest(&this->actor, play)) { EnPoField_SetupInteractWithSoul(this); return; } @@ -668,7 +668,15 @@ void func_80AD58D4(EnPoField* this, PlayState* play) { EnPoField_SetupSoulDisappear(this); return; } - if (this->collider.base.ocFlags1 & OC1_HIT) { + if (CVarGetInteger("gMMPoeBottling", 0)) { + // do not collide + if (Actor_HasParent(&this->actor, play)) { + Actor_Kill(&this->actor); + } + + // GI_MAX in this case allows the player to catch the actor in a bottle + func_8002F434(&this->actor, play, GI_MAX, 35.0f, 60.0f); + } else if (this->collider.base.ocFlags1 & OC1_HIT) { this->actor.flags |= ACTOR_FLAG_WILL_TALK; func_8002F2F4(&this->actor, play); } else { diff --git a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c index 809150fe630..fb682b7037e 100644 --- a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c +++ b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c @@ -770,7 +770,8 @@ void func_80ADFE80(EnPoh* this, PlayState* play) { if (this->unk_198 != 0) { this->unk_198--; } - if (Actor_ProcessTalkRequest(&this->actor, play)) { + if (!(CVarGetInteger("gMMPoeBottling", 0) && this->actor.params < EN_POH_SHARP) && + Actor_ProcessTalkRequest(&this->actor, play)) { if (this->actor.params >= EN_POH_SHARP) { func_80ADE9BC(this); } else { @@ -783,7 +784,15 @@ void func_80ADFE80(EnPoh* this, PlayState* play) { this->actor.flags &= ~ACTOR_FLAG_WILL_TALK; return; } - if (this->colliderCyl.base.ocFlags1 & OC1_HIT) { + if (CVarGetInteger("gMMPoeBottling", 0) && this->actor.params < EN_POH_SHARP) { + if (Actor_HasParent(&this->actor, play)) { + Actor_Kill(&this->actor); + return; + } + + // GI_MAX in this case allows the player to catch the actor in a bottle + func_8002F434(&this->actor, play, GI_MAX, 35.0f, 60.0f); + } else if (this->colliderCyl.base.ocFlags1 & OC1_HIT) { this->actor.flags |= ACTOR_FLAG_WILL_TALK; func_8002F2F4(&this->actor, play); } else { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index ca7333497a0..bb8fcddaf1f 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -13247,6 +13247,8 @@ static BottleCatchInfo D_80854A04[] = { { ACTOR_EN_FISH, ITEM_FISH, 0x1F, 0x47 }, { ACTOR_EN_ICE_HONO, ITEM_BLUE_FIRE, 0x20, 0x5D }, { ACTOR_EN_INSECT, ITEM_BUG, 0x21, 0x7A }, + { ACTOR_EN_POH, ITEM_POE, PLAYER_IA_BOTTLE_POE, 0x97 }, + { ACTOR_EN_PO_FIELD, ITEM_BIG_POE, PLAYER_IA_BOTTLE_BIG_POE, 0xF9 }, }; void func_8084ECA4(Player* this, PlayState* play) { @@ -13289,13 +13291,29 @@ void func_8084ECA4(Player* this, PlayState* play) { if (this->interactRangeActor != NULL) { catchInfo = &D_80854A04[0]; - for (i = 0; i < 4; i++, catchInfo++) { + for (i = 0; i < ARRAY_COUNT(D_80854A04); i++, catchInfo++) { if (this->interactRangeActor->id == catchInfo->actorId) { break; } } - if (i < 4) { + if (catchInfo->actorId == ACTOR_EN_POH || catchInfo->actorId == ACTOR_EN_PO_FIELD) { + // Don't catch Sharp or Flat + // I think they talk to you before you can get in catching range, but might as well prevent it outright + if (catchInfo->actorId == ACTOR_EN_POH && this->interactRangeActor->params >= 2) { + i = ARRAY_COUNT(D_80854A04); + } + // If the catch is a small field Poe (as opposed to a Big Poe), catch a graveyard Poe instead + if (catchInfo->actorId == ACTOR_EN_PO_FIELD && this->interactRangeActor->params == 0) { + i--; + catchInfo--; + } + if (!CVarGetInteger("gMMPoeBottling", 0)) { + i = ARRAY_COUNT(D_80854A04); + } + } + + if (i < ARRAY_COUNT(D_80854A04)) { this->unk_84F = i + 1; this->unk_850 = 0; this->interactRangeActor->parent = &this->actor; From 29d3056a70540d42cd90c6fd4b4bea8c214dcc65 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Wed, 21 Jun 2023 21:28:45 -0500 Subject: [PATCH 07/60] Visual Small Key display --- soh/soh/Enhancements/presets.h | 3 +++ soh/soh/SohMenuBar.cpp | 5 +++++ soh/src/code/z_parameter.c | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..14e71e170cd 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -211,6 +211,9 @@ const std::vector enhancementsCvars = { "gFPSGauntlets", "gSceneSpecificDirtPathFix", "gZFightingMode", + "gVisualKeys", + "gSmallKeySpacing", + "gRightAlignKeys", "gAuthenticLogo", "gPauseLiveLinkRotationSpeed", "gBowReticle", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..720e7dc1846 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1001,6 +1001,11 @@ void DrawEnhancementsMenu() { "Consistent: Certain paths vanish the same way in all resolutions\n" "No Vanish: Paths do not vanish, Link seems to sink in to some paths\n" "This might affect other decal effects\n"); + UIWidgets::PaddedEnhancementCheckbox("Visual Small Key display", "gVisualKeys", true, false); + UIWidgets::Tooltip("Displays Small Key count using multiple icons rather than a numeric counter"); + const bool disableKeySpacing = !CVarGetInteger("gVisualKeys", 0); + static const char* disableKeySpacingTooltip = "This option is disabled because \"Visual Small Key display\" is turned off"; + UIWidgets::EnhancementSliderInt("Small Key icon spacing: %d", "##SmallKeySpacing", "gSmallKeySpacing", 1, 16, "", 8, true, disableKeySpacing, disableKeySpacingTooltip); UIWidgets::PaddedEnhancementSliderInt("Text Spacing: %d", "##TEXTSPACING", "gTextSpacing", 4, 6, "", 6, true, true, true); UIWidgets::Tooltip("Space between text characters (useful for HD font textures)"); UIWidgets::PaddedEnhancementCheckbox("More info in file select", "gFileSelectMoreInfo", true, false); diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a4d61f87769..f244691f71e 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -5254,6 +5254,21 @@ void Interface_Draw(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, keyCountColor.r,keyCountColor.g,keyCountColor.b, interfaceCtx->magicAlpha); gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 20, 255); //We reset this here so it match user color :) + + if (CVarGetInteger("gVisualKeys", 0)) { + s8 keyCount = gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]; + s16 rectLeft = PosX_SKC; + s16 keyOffset = CVarGetInteger("gSmallKeySpacing", 8); + if (CVarGetInteger("gRightAlignKeys", 0)) { + keyOffset = -keyOffset; + } + for (int i = 0; i < keyCount; i++, rectLeft += keyOffset) { + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, rectLeft, PosY_SKC, 16, 16, + 1 << 10, 1 << 10); + } + break; + } + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, PosX_SKC, PosY_SKC, 16, 16, 1 << 10, 1 << 10); From 5f0519dc2cbee61bebc8dc368da68cc77383d918 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Fri, 4 Aug 2023 22:38:05 -0500 Subject: [PATCH 08/60] Enhanced Iron Boots --- soh/soh/SohMenuBar.cpp | 2 + soh/src/code/z_parameter.c | 76 +++++++++++-------- .../actors/ovl_player_actor/z_player.c | 33 ++++---- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..2f5663c7a62 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -860,6 +860,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Allows equipping the tunic and boots to c-buttons"); UIWidgets::PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false); UIWidgets::Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen."); + UIWidgets::PaddedEnhancementCheckbox("Extra Underwater Actions", "gEnhancedIronBoots", true, false); + UIWidgets::Tooltip("Allows opening chests and using your sword and Bombchus when underwater with Iron Boots"); UIWidgets::PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false); UIWidgets::Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); UIWidgets::PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false); diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a4d61f87769..3b3dfaf54f5 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -964,11 +964,19 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[3] = gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] = gSaveContext.buttonStatus[8] = BTN_DISABLED; } else if ((Player_GetEnvironmentalHazard(play) >= 2) && (Player_GetEnvironmentalHazard(play) < 5)) { - if (gSaveContext.buttonStatus[0] != BTN_DISABLED) { - sp28 = 1; - } + if (CVarGetInteger("gEnhancedIronBoots", 0) && Player_GetEnvironmentalHazard(play) == 2) { + if (gSaveContext.buttonStatus[0] == BTN_DISABLED) { + sp28 = 1; + } - gSaveContext.buttonStatus[0] = BTN_DISABLED; + gSaveContext.buttonStatus[0] = BTN_ENABLED; + } else { + if (gSaveContext.buttonStatus[0] != BTN_DISABLED) { + sp28 = 1; + } + + gSaveContext.buttonStatus[0] = BTN_DISABLED; + } for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] >= ITEM_SHIELD_DEKU) && @@ -981,7 +989,9 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_ENABLED; } else if (Player_GetEnvironmentalHazard(play) == 2) { if ((gSaveContext.equips.buttonItems[i] != ITEM_HOOKSHOT) && - (gSaveContext.equips.buttonItems[i] != ITEM_LONGSHOT)) { + (gSaveContext.equips.buttonItems[i] != ITEM_LONGSHOT) && + (CVarGetInteger("gEnhancedIronBoots", 0) + && gSaveContext.equips.buttonItems[i] != ITEM_BOMBCHU)) { if (gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] == BTN_ENABLED) { sp28 = 1; } @@ -1441,7 +1451,7 @@ void Inventory_SwapAgeEquipment(void) { u16 shieldEquipValue; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (i != 0) { @@ -1483,13 +1493,13 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; - + gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) | (EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) | (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) | (EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4)); - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.equips.buttonItems[0] == ITEM_NONE) { gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); } @@ -1828,14 +1838,14 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { /** * @brief Adds the given item to Link's inventory. - * + * * NOTE: This function has been edited to be safe to use with a NULL play. * If you need to add to this function, be sure you check if the play is not * NULL before doing any operations requiring it. - * - * @param play - * @param item - * @return u8 + * + * @param play + * @param item + * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { lusprintf(__FILE__, __LINE__, 2, "Item Give - item: %#x", item); @@ -1916,10 +1926,10 @@ u8 Item_Give(PlayState* play, u8 item) { // In rando, when buying Giant's Knife, also check // without the Koriri Sword in case we don't have it - if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_KOKIRI) | (1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | - (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || - (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || + (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)))) { gSaveContext.inventory.equipment ^= OWNED_EQUIP_FLAG_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); @@ -1931,7 +1941,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - + } else if (item == ITEM_SWORD_MASTER) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); @@ -2671,7 +2681,7 @@ u8 Item_CheckObtainability(u8 item) { return ITEM_NONE; } } - + if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { return ITEM_NONE; } else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) { @@ -2935,7 +2945,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); } - if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { return 0; } @@ -2974,7 +2984,7 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l } doAction = newName[loadOffset]; } - + char* segment = interfaceCtx->doActionSegment[loadOffset]; interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; @@ -3041,7 +3051,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { } interfaceCtx->unk_1FC = action; - + char* segment = interfaceCtx->doActionSegment[1]; interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); @@ -3066,7 +3076,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3135,7 +3145,7 @@ void Rupees_ChangeBy(s16 rupeeChange) { void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { - switch (item) { + switch (item) { case ITEM_STICK: gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; @@ -4321,7 +4331,7 @@ void Interface_DrawItemButtons(PlayState* play) { G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, (C_Up_BTN_Pos[0]-LabelX_Navi + 32) << 2, (C_Up_BTN_Pos[1]+LabelY_Navi + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -4439,7 +4449,7 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, cRightButtonColor.r, cRightButtonColor.g, cRightButtonColor.b, interfaceCtx->cRightAlpha); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, ItemIconPos[temp-1][0], ItemIconPos[temp-1][1], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][1], ItemIconWidthFactor[temp-1][1]); @@ -4514,8 +4524,8 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; u16 ItemsSlotsAlpha[8] = { @@ -4891,11 +4901,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, ItemIconPos[button][0], ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, ItemIconPos[button][0] + 6, ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } @@ -5400,7 +5410,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5718,7 +5728,7 @@ void Interface_Draw(PlayState* play) { CarrotsPosY = CVarGetInteger("gCarrotsPosY", 0); if (CVarGetInteger("gCarrotsPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Left_HUD_Margin;}; - CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); + CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); } else if (CVarGetInteger("gCarrotsPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Right_HUD_Margin;}; CarrotsPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); @@ -6228,7 +6238,7 @@ void Interface_Draw(PlayState* play) { for (svar1 = 0; svar1 < 5; svar1++) { // clang-format off //svar5 = svar5 + 8; - //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); + //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, digitTextures[timerDigits[svar1]], 8, 16, svar5 + timerDigitLeftPos[svar1], svar2, digitWidth[svar1], VREG(42), VREG(43) << 1, @@ -6372,7 +6382,7 @@ void Interface_Update(PlayState* play) { Left_HUD_Margin = CVarGetInteger("gHUDMargin_L", 0); Right_HUD_Margin = CVarGetInteger("gHUDMargin_R", 0); Bottom_HUD_Margin = CVarGetInteger("gHUDMargin_B", 0); - + GameInteractor_ExecuteOnInterfaceUpdate(); if (CHECK_BTN_ALL(debugInput->press.button, BTN_DLEFT)) { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index ca7333497a0..9d96f98ec10 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2960,7 +2960,9 @@ void func_80835F44(PlayState* play, Player* this, s32 item) { if ((actionParam == PLAYER_IA_NONE) || !(this->stateFlags1 & PLAYER_STATE1_IN_WATER) || ((this->actor.bgCheckFlags & 1) && - ((actionParam == PLAYER_IA_HOOKSHOT) || (actionParam == PLAYER_IA_LONGSHOT))) || + ((actionParam == PLAYER_IA_HOOKSHOT) || (actionParam == PLAYER_IA_LONGSHOT) || + (CVarGetInteger("gEnhancedIronBoots", 0) && + ((Player_ActionToMeleeWeapon(actionParam) != 0) || (actionParam == PLAYER_IA_BOMBCHU))))) || ((actionParam >= PLAYER_IA_SHIELD_DEKU) && (actionParam <= PLAYER_IA_BOOTS_HOVER))) { if ((play->bombchuBowlingStatus == 0) && @@ -4934,7 +4936,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5378,7 +5380,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6106,8 +6108,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6350,8 +6352,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -6386,7 +6388,7 @@ s32 func_8083E5A8(Player* this, PlayState* play) { this->getItemEntry = (GetItemEntry)GET_ITEM_NONE; } } else if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && !(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) && - !(this->stateFlags2 & PLAYER_STATE2_UNDERWATER)) { + (CVarGetInteger("gEnhancedIronBoots", 0) || !(this->stateFlags2 & PLAYER_STATE2_UNDERWATER))) { if (this->getItemId != GI_NONE) { GetItemEntry giEntry; if (this->getItemEntry.objectId == OBJECT_INVALID) { @@ -7759,7 +7761,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -9841,7 +9843,8 @@ void func_808473D4(PlayState* play, Player* this) { } else if ((!(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) || (heldActor == NULL)) && (interactRangeActor != NULL) && ((!sp1C && (this->getItemId == GI_NONE)) || - (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER)))) { + (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER)) || + CVarGetInteger("gEnhancedIronBoots", 0) && this->stateFlags2 & PLAYER_STATE2_UNDERWATER)) { if (this->getItemId < 0) { doAction = DO_ACTION_OPEN; } else if ((interactRangeActor->id == ACTOR_BG_TOKI_SWD) && LINK_IS_ADULT) { @@ -11194,7 +11197,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11245,7 +11248,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -13576,7 +13579,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -15003,7 +15006,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15012,7 +15015,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); From 812d1d3673f817dab871eb43967fa099d087e91f Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Sat, 26 Nov 2022 11:39:04 -0600 Subject: [PATCH 09/60] Overhaul item menu layout --- soh/include/variables.h | 2 +- soh/include/z64.h | 2 + soh/include/z64item.h | 60 +-- soh/include/z64save.h | 5 +- .../controls/GameControlEditor.cpp | 2 + .../cosmetics/CosmeticsEditor.cpp | 2 +- .../custom-message/CustomMessageTypes.h | 3 + .../Enhancements/debugger/debugSaveEditor.cpp | 12 +- soh/soh/Enhancements/presets.h | 7 - soh/soh/OTRGlobals.cpp | 31 +- soh/soh/SaveManager.cpp | 19 +- soh/soh/SohMenuBar.cpp | 28 +- soh/soh/z_message_OTR.cpp | 37 +- soh/src/code/code_80097A00.c | 4 +- soh/src/code/z_en_item00.c | 10 +- soh/src/code/z_map_exp.c | 22 +- soh/src/code/z_parameter.c | 231 +++++----- .../actors/ovl_Arms_Hook/z_arms_hook.c | 4 +- .../actors/ovl_Obj_Tsubo/z_obj_tsubo.c | 7 + .../actors/ovl_player_actor/z_player.c | 70 +-- .../ovl_kaleido_scope/z_kaleido_equipment.c | 28 +- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 400 ++++++++++++++---- .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 9 + .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 82 ++-- 24 files changed, 738 insertions(+), 339 deletions(-) diff --git a/soh/include/variables.h b/soh/include/variables.h index 2bad8335c99..ce1a9dbec95 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -102,7 +102,7 @@ extern "C" extern void* gItemIcons[0x82]; extern u8 gItemAgeReqs[]; extern u8 gSlotAgeReqs[]; - extern u8 gItemSlots[56]; + extern u8 gItemSlots[71]; extern void (*gSceneCmdHandlers[SCENE_CMD_ID_MAX])(PlayState*, SceneCmd*); extern s16 gLinkObjectIds[2]; extern u32 gObjectTableSize; diff --git a/soh/include/z64.h b/soh/include/z64.h index 23ffcfb1717..5cc757fd535 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -914,6 +914,8 @@ typedef struct { /* 0x0266 */ u8 worldMapPoints[20]; // 0 = hidden; 1 = displayed; 2 = highlighted /* 0x027A */ u8 tradeQuestLocation; /* 0x027C */ SkelAnime playerSkelAnime; + Vtx* arrowSelectVtx; + s16 arrowMenuAnimPos; } PauseContext; // size = 0x2C0 typedef enum { diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 1fc919a45f6..9e58b460ea1 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -116,36 +116,38 @@ typedef enum { } DungeonItem; typedef enum { - /* 0x00 */ SLOT_STICK, - /* 0x01 */ SLOT_NUT, - /* 0x02 */ SLOT_BOMB, - /* 0x03 */ SLOT_BOW, - /* 0x04 */ SLOT_ARROW_FIRE, - /* 0x05 */ SLOT_DINS_FIRE, - /* 0x06 */ SLOT_SLINGSHOT, - /* 0x07 */ SLOT_OCARINA, - /* 0x08 */ SLOT_BOMBCHU, - /* 0x09 */ SLOT_HOOKSHOT, - /* 0x0A */ SLOT_ARROW_ICE, - /* 0x0B */ SLOT_FARORES_WIND, - /* 0x0C */ SLOT_BOOMERANG, - /* 0x0D */ SLOT_LENS, - /* 0x0E */ SLOT_BEAN, + /* 0x00 */ SLOT_DINS_FIRE, + /* 0x01 */ SLOT_BOMB, + /* 0x02 */ SLOT_BOMBCHU, + /* 0x03 */ SLOT_NUT, + /* 0x04 */ SLOT_LENS, + /* 0x05 */ SLOT_BEAN, + /* 0x06 */ SLOT_FARORES_WIND, + /* 0x07 */ SLOT_SLINGSHOT, + /* 0x08 */ SLOT_BOOMERANG, + /* 0x09 */ SLOT_STICK, + /* 0x0A */ SLOT_BOOTS_HOVER, + /* 0x0B */ SLOT_TRADE_CHILD, + /* 0x0C */ SLOT_NAYRUS_LOVE, + /* 0x0D */ SLOT_BOW, + /* 0x0E */ SLOT_HOOKSHOT, /* 0x0F */ SLOT_HAMMER, - /* 0x10 */ SLOT_ARROW_LIGHT, - /* 0x11 */ SLOT_NAYRUS_LOVE, - /* 0x12 */ SLOT_BOTTLE_1, - /* 0x13 */ SLOT_BOTTLE_2, - /* 0x14 */ SLOT_BOTTLE_3, - /* 0x15 */ SLOT_BOTTLE_4, - /* 0x16 */ SLOT_TRADE_ADULT, - /* 0x17 */ SLOT_TRADE_CHILD, - /* 0x18 */ SLOT_TUNIC_KOKIRI, - /* 0x19 */ SLOT_TUNIC_GORON, - /* 0x1A */ SLOT_TUNIC_ZORA, - /* 0x1B */ SLOT_BOOTS_KOKIRI, - /* 0x1C */ SLOT_BOOTS_IRON, - /* 0x1D */ SLOT_BOOTS_HOVER, + /* 0x10 */ SLOT_BOOTS_IRON, + /* 0x11 */ SLOT_TRADE_ADULT, + /* 0x12 */ SLOT_EMPTY_LEFT, + /* 0x13 */ SLOT_BOTTLE_1, + /* 0x14 */ SLOT_BOTTLE_2, + /* 0x15 */ SLOT_BOTTLE_3, + /* 0x16 */ SLOT_BOTTLE_4, + /* 0x17 */ SLOT_EMPTY_RIGHT, + /* 0x18 */ SLOT_OCARINA, + /* 0x19 */ SLOT_ARROW_FIRE, + /* 0x1A */ SLOT_ARROW_ICE, + /* 0x1B */ SLOT_ARROW_LIGHT, + /* 0x1C */ SLOT_TUNIC_KOKIRI, + /* 0x1D */ SLOT_TUNIC_GORON, + /* 0x1E */ SLOT_TUNIC_ZORA, + /* 0x1F */ SLOT_BOOTS_KOKIRI, /* 0xFF */ SLOT_NONE = 0xFF } InventorySlot; diff --git a/soh/include/z64save.h b/soh/include/z64save.h index c7bee045fc1..b3ff798ef81 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -43,7 +43,7 @@ typedef struct { } ItemEquips; // size = 0x0A typedef struct { - /* 0x00 */ u8 items[24]; + /* 0x00 */ u8 items[28]; /* 0x18 */ s8 ammo[16]; /* 0x28 */ u16 equipment; // a mask where each nibble corresponds to a type of equipment `EquipmentType`, and each bit to an owned piece `EquipInv*` /* 0x2C */ u32 upgrades; @@ -389,7 +389,8 @@ typedef enum { typedef enum { /* 0 */ LINK_AGE_ADULT, - /* 1 */ LINK_AGE_CHILD + /* 1 */ LINK_AGE_CHILD, + /* 9 */ LINK_AGE_EITHER = 9 } LinkAge; diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index eb69f3cc852..217ccc35c6e 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -295,6 +295,8 @@ namespace GameControlEditor { "To make the cursor only move a single space during name entry no matter how long a direction is held, manually set gDpadHoldChange to 0"); UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); DrawHelpIcon("Equip items and equipment on the D-pad\nIf used with D-pad on Pause Screen, you must hold C-Up to equip instead of navigate"); + UIWidgets::PaddedEnhancementCheckbox("Toggle minimap with D-pad down", "gMapOnDDown"); + DrawHelpIcon("Toggle the minimap by pressing down on the D-pad\nIf \"D-pad as Equip Items\" is enabled, equipping an item on D-pad down will prevent you from toggling the map"); window->EndGroupPanelPublic(0); } diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 378197bcdd8..a8a3d54acdb 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1328,7 +1328,7 @@ void Draw_Placements(){ ImGui::EndTable(); } } - if (CVarGetInteger("gDpadEquips",0) && ImGui::CollapsingHeader("DPad items position")) { + if (ImGui::CollapsingHeader("DPad items position")) { if (ImGui::BeginTable("tabledpaditems", 1, FlagsTable)) { ImGui::TableSetupColumn("DPad items settings", FlagsCell, TablesCellsWidth); Table_InitHeader(false); diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index d93bae98357..05a79849827 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -54,6 +54,9 @@ typedef enum { TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range + TEXT_FIRE_ARROW = 0x0070, + TEXT_ICE_ARROW = 0x0071, + TEXT_LIGHT_ARROW = 0x0072, } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 9af4eadb7e9..66c8944c0f1 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -639,12 +639,16 @@ void DrawInventoryTab() { ImGui::Checkbox("Restrict to valid items", &restrictToValid); UIWidgets::InsertHelpHoverText("Restricts items and ammo to only what is possible to legally acquire in-game"); - for (int32_t y = 0; y < 4; y++) { + for (int32_t y = 0; y < 5; y++) { for (int32_t x = 0; x < 6; x++) { int32_t index = x + y * 6; static int32_t selectedIndex = -1; static const char* itemPopupPicker = "itemPopupPicker"; + if (index >= ARRAY_COUNT(gSaveContext.inventory.items)) { + break; + } + ImGui::PushID(index); if (x != 0) { @@ -1705,10 +1709,10 @@ void DrawPlayerTab() { ImGui::SameLine(); ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL); + ImGui::NewLine(); + ImGui::Text("Current D-pad Equips"); + ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working if (CVarGetInteger("gDpadEquips", 0)) { - ImGui::NewLine(); - ImGui::Text("Current D-pad Equips"); - ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working ImGui::SameLine(); ImGui::InputScalar("D-pad Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[5], &one, NULL); // Intentionnal to not put everything on the same line, else it's taking too much for lower resolution. diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..78712704cb0 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -173,7 +173,6 @@ const std::vector enhancementsCvars = { "gDisableCritWiggle", "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", - "gSeparateArrows", "gCustomizeShootingGallery", "gInstantShootingGalleryWin", "gConstantAdultGallery", @@ -626,9 +625,6 @@ const std::vector enhancedPresetEntries = { // Skip Magic Arrow Equip Animation PRESET_ENTRY_S32("gSkipArrowAnimation", 1), - // Equip arrows on multiple slots - PRESET_ENTRY_S32("gSeparateArrows", 1), - // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), @@ -750,9 +746,6 @@ const std::vector randomizerPresetEntries = { // Exit Market at Night PRESET_ENTRY_S32("gMarketSneak", 1), - // Equip arrows on multiple slots - PRESET_ENTRY_S32("gSeparateArrows", 1), - // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 4c564afde72..7ceee4215f3 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -246,9 +246,9 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); - if (std::filesystem::exists(mqPath)) { + if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); - } + } std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); @@ -278,7 +278,7 @@ OTRGlobals::OTRGlobals() { ); }); OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end()); - std::unordered_set ValidHashes = { + std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, OOT_NTSC_US_MQ, @@ -865,7 +865,7 @@ void CheckSoHOTRVersion(std::string otrPath) { } // Checks the program version stored in the otr and compares the major value to soh -// For Windows/Mac/Linux if the version doesn't match, offer to +// For Windows/Mac/Linux if the version doesn't match, offer to void DetectOTRVersion(std::string fileName, bool isMQ) { bool isOtrOld = false; std::string otrPath = LUS::Context::LocateFileAcrossAppDirs(fileName, appShortName); @@ -1049,7 +1049,7 @@ extern "C" void InitOTR() { SpeechSynthesizer::Instance = new SAPISpeechSynthesizer(); SpeechSynthesizer::Instance->Init(); #endif - + clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); OTRAudio_Init(); @@ -1084,7 +1084,7 @@ extern "C" void InitOTR() { } #endif - std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); + std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RunVersionUpdates(); @@ -1520,11 +1520,11 @@ std::shared_ptr GetResourceByNameHandlingMQ(const char* path) { extern "C" char* GetResourceDataByNameHandlingMQ(const char* path) { auto res = GetResourceByNameHandlingMQ(path); - + if (res == nullptr) { return nullptr; } - + return (char*)res->GetRawPointer(); } @@ -1611,7 +1611,7 @@ extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); - + return nullptr; } @@ -2185,10 +2185,10 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { extern "C" int Controller_ShouldRumble(size_t slot) { auto controlDeck = LUS::Context::GetInstance()->GetControlDeck(); - + if (slot < controlDeck->GetNumConnectedPorts()) { auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot); - + if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) { return 1; } @@ -2410,7 +2410,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { Player_GetMask(play) == PLAYER_MASK_TRUTH) || (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == RO_GOSSIP_STONES_NEED_STONE && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { - Actor* stone = GET_PLAYER(play)->targetActor; + Actor* stone = GET_PLAYER(play)->targetActor; actorParams = stone->params; // if we're in a generic grotto @@ -2446,7 +2446,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF); } } else if (textId == TEXT_SHEIK_NEED_HOOK || textId == TEXT_SHEIK_HAVE_HOOK) { - messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); + messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) } else if (textId >= TEXT_SCRUB_RANDOM && textId <= TEXT_SCRUB_RANDOM + NUM_SCRUBS) { RandomizerInf randoInf = (RandomizerInf)((textId - TEXT_SCRUB_RANDOM) + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT); @@ -2552,6 +2552,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger("gMarketSneak", 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT); } + if (textId >= TEXT_FIRE_ARROW && textId <= TEXT_LIGHT_ARROW) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + } font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition(); switch (gSaveContext.language) { case LANGUAGE_FRA: @@ -2607,7 +2610,7 @@ void SoH_ProcessDroppedFiles(std::string filePath) { nlohmann::json configJson; configStream >> configJson; - // #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer + // #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer if (configJson.contains("version") && configJson.contains("finalSeed")) { CVarSetString("gRandomizerDroppedFile", filePath.c_str()); CVarSetInteger("gRandomizerNewFileDropped", 1); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index e61cf922354..d75b0b9898f 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -662,6 +662,8 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots); button++) { gSaveContext.childEquips.cButtonSlots[button] = SLOT_NONE; } + gSaveContext.childEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.childEquips.equipment = 0; for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); button++) { gSaveContext.adultEquips.buttonItems[button] = ITEM_NONE; @@ -669,6 +671,8 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots); button++) { gSaveContext.adultEquips.cButtonSlots[button] = SLOT_NONE; } + gSaveContext.adultEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.adultEquips.equipment = 0; gSaveContext.unk_54 = 0; gSaveContext.savedSceneNum = 0x51; @@ -682,19 +686,22 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) { gSaveContext.equips.cButtonSlots[button] = sCButtonSlots[button]; } + gSaveContext.equips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.equips.equipment = 0x1122; // Inventory - static std::array sItems = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_ARROW_FIRE, ITEM_DINS_FIRE, - ITEM_SLINGSHOT, ITEM_OCARINA_FAIRY, ITEM_BOMBCHU, ITEM_HOOKSHOT, ITEM_ARROW_ICE, ITEM_FARORES_WIND, - ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NAYRUS_LOVE, - ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_POCKET_EGG, ITEM_WEIRD_EGG, + static std::array sItems = { + ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, + ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_WEIRD_EGG, + ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, + ITEM_NONE, ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_NONE, + ITEM_OCARINA_FAIRY, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT }; for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { gSaveContext.inventory.items[item] = sItems[item]; } - static std::array sAmmo = { 50, 50, 10, 30, 1, 1, 30, 1, 50, 1, 1, 1, 1, 1, 1, 1 }; + static std::array sAmmo = { 1, 20, 50, 20, 1, 10, 1, 30, 1, 10, 1, 1, 1, 30, 1, 1 }; for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { gSaveContext.inventory.ammo[ammo] = sAmmo[ammo]; } diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..359a90a0928 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -606,8 +606,6 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); - UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); - UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); @@ -878,7 +876,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -887,7 +885,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -1064,8 +1062,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1398,12 +1396,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndDisabled(); @@ -1583,12 +1581,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1644,4 +1642,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index 6bbd1eca9bd..cfe92df1907 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -13,14 +13,14 @@ extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr; extern "C" MessageTableEntry* sFraMessageEntryTablePtr; extern "C" MessageTableEntry* sStaffMessageEntryTablePtr; -//extern "C" MessageTableEntry* _message_0xFFFC_nes; +//extern "C" MessageTableEntry* _message_0xFFFC_nes; MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { auto file = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(filePath)); if (file == nullptr) return nullptr; - + // Allocate room for an additional message // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table is // already null. @@ -160,4 +160,37 @@ extern "C" void OTRMessage_Init() CustomMessage("You look bored. Wanna go out for a&walk?\x1B&%gYes&No%w", "Du siehst gelangweilt aus.&Willst du einen Spaziergang machen?\x1B&%gJa&Nein%w", "Tu as l'air de t'ennuyer. Tu veux&aller faire un tour?\x1B&%gOui&Non%w")); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_FIRE_ARROW, ITEM_ARROW_FIRE, + CustomMessage( + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_ICE_ARROW, ITEM_ARROW_ICE, + CustomMessage( + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_LIGHT_ARROW, ITEM_ARROW_LIGHT, + CustomMessage( + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); } diff --git a/soh/src/code/code_80097A00.c b/soh/src/code/code_80097A00.c index eb83738e360..4068117e7c8 100644 --- a/soh/src/code/code_80097A00.c +++ b/soh/src/code/code_80097A00.c @@ -180,7 +180,9 @@ u8 gItemSlots[] = { SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, - SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, + SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_BOW, SLOT_BOW, SLOT_BOW, SLOT_NONE, + SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, + SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_BOOTS_IRON, SLOT_BOOTS_HOVER, }; void Inventory_ChangeEquipment(s16 equipment, u16 value) { diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 42ea78f90ba..87c43f98af0 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -333,7 +333,9 @@ void EnItem00_SetupAction(EnItem00* this, EnItem00ActionFunc actionFunc) { void EnItem00_SetObjectDependency(EnItem00* this, PlayState* play, s16 objectIndex) { // Remove object dependency for Enemy Randomizer and Crowd Control to allow Like-likes to // drop equipment correctly in rooms where Like-likes normally don't spawn. - if (CVarGetInteger("gRandomizedEnemies", 0) || CVarGetInteger("gCrowdControl", 0)) { + // Also remove object dependency for Master Quest Fire Temple to fix the Like-like there + if (CVarGetInteger("gRandomizedEnemies", 0) || CVarGetInteger("gCrowdControl", 0) || + (ResourceMgr_IsSceneMasterQuest(SCENE_FIRE_TEMPLE) && play->sceneNum == SCENE_FIRE_TEMPLE)) { this->actor.objBankIndex = 0; } else { this->actor.objBankIndex = Object_GetIndex(&play->objectCtx, objectIndex); @@ -1371,7 +1373,7 @@ void EnItem00_DrawCollectible(EnItem00* this, PlayState* play) { Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } - + f32 mtxScale = 10.67f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); EnItem00_CustomItemsParticles(&this->actor, play, this->randoGiEntry); @@ -1532,7 +1534,7 @@ s16 func_8001F404(s16 dropId) { } } - if ((CVarGetInteger("gBombchuDrops", 0) || + if ((CVarGetInteger("gBombchuDrops", 0) || (IS_RANDO && Randomizer_GetSettingValue(RSK_ENABLE_BOMBCHU_DROPS) == 1)) && (dropId == ITEM00_BOMBS_A || dropId == ITEM00_BOMBS_B || dropId == ITEM00_BOMBS_SPECIAL)) { dropId = EnItem00_ConvertBombDropToBombchu(dropId); @@ -1612,7 +1614,7 @@ EnItem00* Item_DropCollectible2(PlayState* play, Vec3f* spawnPos, s16 params) { params &= 0x3FFF; if ((params & 0x00FF) == ITEM00_HEART && CVarGetInteger("gNoHeartDrops", 0)) { return NULL; } - + if (((params & 0x00FF) == ITEM00_FLEXIBLE) && !param4000) { // TODO: Prevent the cast to EnItem00 here since this is a different actor (En_Elf) spawnedActor = (EnItem00*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELF, spawnPos->x, diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index c4db0098b23..99a19316c7d 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -734,10 +734,20 @@ void Minimap_Draw(PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - // If any of these CVars are enabled, disable toggling the minimap with L, unless gEnableMapToggle is set - bool enableMapToggle = - !(CVarGetInteger("gDebugEnabled", 0) || CVarGetInteger("gMoonJumpOnL", 0) || CVarGetInteger("gTurboOnL", 0)) || - CVarGetInteger("gEnableMapToggle", 0); + u16 minimapToggleBtn; + bool enableMapToggle; + if (CVarGetInteger("gMapOnDDown", 0)) { + minimapToggleBtn = BTN_DDOWN; + // If you can use an item with D down, disable toggling the minimap with it + enableMapToggle = !(CVarGetInteger("gDpadEquips", 0) && gSaveContext.equips.buttonItems[5] < 0xF0); + } else { + minimapToggleBtn = BTN_L; + // If any of these CVars are enabled, disable toggling the minimap with L + enableMapToggle = + !(CVarGetInteger("gDebugEnabled", 0) || CVarGetInteger("gMoonJumpOnL", 0) || CVarGetInteger("gTurboOnL", 0)); + } + // If this CVar is set, allow toggling the map despite conflicts + enableMapToggle = enableMapToggle || CVarGetInteger("gEnableMapToggle", 0); if (play->pauseCtx.state < 4) { //Minimap margins @@ -808,7 +818,7 @@ void Minimap_Draw(PlayState* play) { } } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + if (CHECK_BTN_ALL(play->state.input[0].press.button, minimapToggleBtn) && !Play_InCsMode(play) && enableMapToggle) { osSyncPrintf("Game_play_demo_mode_check=%d\n", Play_InCsMode(play)); // clang-format off if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &D_801333D4, 4, @@ -964,7 +974,7 @@ void Minimap_Draw(PlayState* play) { Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + if (CHECK_BTN_ALL(play->state.input[0].press.button, minimapToggleBtn) && !Play_InCsMode(play) && enableMapToggle) { // clang-format off if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a4d61f87769..54326cbce95 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1441,7 +1441,7 @@ void Inventory_SwapAgeEquipment(void) { u16 shieldEquipValue; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (i != 0) { @@ -1472,6 +1472,7 @@ void Inventory_SwapAgeEquipment(void) { Flags_SetInfTable(INFTABLE_SWORDLESS); } + // Nuts on C-left (if present) if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) { gSaveContext.equips.buttonItems[1] = ITEM_NUT; gSaveContext.equips.cButtonSlots[0] = SLOT_NUT; @@ -1479,27 +1480,32 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] = ITEM_NONE; } + // Bombs on C-down gSaveContext.equips.buttonItems[2] = ITEM_BOMB; - gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; - gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; - + + // Nothing on C-right + gSaveContext.equips.buttonItems[3] = ITEM_NONE; + gSaveContext.equips.cButtonSlots[2] = ITEM_NONE; + gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) | (EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) | (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) | (EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4)); - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.equips.buttonItems[0] == ITEM_NONE) { gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); } - // Set the dpad to nothing - gSaveContext.equips.buttonItems[4] = ITEM_NONE; + // Ocarina on D-up + gSaveContext.equips.buttonItems[4] = gSaveContext.inventory.items[SLOT_OCARINA]; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; + + // Set the rest of the d-pad to nothing gSaveContext.equips.buttonItems[5] = ITEM_NONE; gSaveContext.equips.buttonItems[6] = ITEM_NONE; gSaveContext.equips.buttonItems[7] = ITEM_NONE; - gSaveContext.equips.cButtonSlots[3] = SLOT_NONE; gSaveContext.equips.cButtonSlots[4] = SLOT_NONE; gSaveContext.equips.cButtonSlots[5] = SLOT_NONE; gSaveContext.equips.cButtonSlots[6] = SLOT_NONE; @@ -1828,14 +1834,14 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { /** * @brief Adds the given item to Link's inventory. - * + * * NOTE: This function has been edited to be safe to use with a NULL play. * If you need to add to this function, be sure you check if the play is not * NULL before doing any operations requiring it. - * - * @param play - * @param item - * @return u8 + * + * @param play + * @param item + * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { lusprintf(__FILE__, __LINE__, 2, "Item Give - item: %#x", item); @@ -1916,10 +1922,10 @@ u8 Item_Give(PlayState* play, u8 item) { // In rando, when buying Giant's Knife, also check // without the Koriri Sword in case we don't have it - if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_KOKIRI) | (1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | - (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || - (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || + (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)))) { gSaveContext.inventory.equipment ^= OWNED_EQUIP_FLAG_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); @@ -1931,7 +1937,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - + } else if (item == ITEM_SWORD_MASTER) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); @@ -1950,6 +1956,9 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item >= ITEM_BOOTS_KOKIRI) && (item <= ITEM_BOOTS_HOVER)) { gSaveContext.inventory.equipment |= OWNED_EQUIP_FLAG(EQUIP_TYPE_BOOTS, item - ITEM_BOOTS_KOKIRI); + if (item != ITEM_BOOTS_KOKIRI) { + INV_CONTENT(item) = item; + } return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) { gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS]; @@ -2220,6 +2229,14 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_SEEDS); } else if (item == ITEM_OCARINA_FAIRY) { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; + + gSaveContext.equips.buttonItems[4] = item; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; + gSaveContext.childEquips.buttonItems[4] = item; + gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; + gSaveContext.adultEquips.buttonItems[4] = item; + gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; + return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_OCARINA_TIME) { INV_CONTENT(ITEM_OCARINA_TIME) = ITEM_OCARINA_TIME; @@ -2671,7 +2688,7 @@ u8 Item_CheckObtainability(u8 item) { return ITEM_NONE; } } - + if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { return ITEM_NONE; } else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) { @@ -2935,7 +2952,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); } - if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { return 0; } @@ -2974,7 +2991,7 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l } doAction = newName[loadOffset]; } - + char* segment = interfaceCtx->doActionSegment[loadOffset]; interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; @@ -3041,7 +3058,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { } interfaceCtx->unk_1FC = action; - + char* segment = interfaceCtx->doActionSegment[1]; interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); @@ -3066,7 +3083,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3135,7 +3152,7 @@ void Rupees_ChangeBy(s16 rupeeChange) { void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { - switch (item) { + switch (item) { case ITEM_STICK: gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; @@ -3479,7 +3496,7 @@ void Interface_UpdateMagicBar(PlayState* play) { (msgCtx->msgMode == MSGMODE_NONE) && (play->gameOverCtx.state == GAMEOVER_INACTIVE) && (play->sceneLoadFlag == 0) && (play->transitionMode == 0) && !Play_InCsMode(play)) { bool hasLens = false; - for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0) != 0) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 4; buttonIndex++) { + for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0)) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 5; buttonIndex++) { if (gSaveContext.equips.buttonItems[buttonIndex] == ITEM_LENS) { hasLens = true; break; @@ -4321,7 +4338,7 @@ void Interface_DrawItemButtons(PlayState* play) { G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, (C_Up_BTN_Pos[0]-LabelX_Navi + 32) << 2, (C_Up_BTN_Pos[1]+LabelY_Navi + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -4439,7 +4456,7 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, cRightButtonColor.r, cRightButtonColor.g, cRightButtonColor.b, interfaceCtx->cRightAlpha); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, ItemIconPos[temp-1][0], ItemIconPos[temp-1][1], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][1], ItemIconWidthFactor[temp-1][1]); @@ -4514,8 +4531,8 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; u16 ItemsSlotsAlpha[8] = { @@ -4647,10 +4664,17 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { ItemIconPos[3][1] = ItemIconPos_ori[3][1]; } - gDPLoadTextureBlock(OVERLAY_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + // Exception specifically for dungeon map texture since only that appears on a button + bool smallTex = texture == gItemIcons[ITEM_DUNGEON_MAP]; + int texSize = smallTex ? 24 : 32; + int offset = smallTex ? 4 : 0; + + gDPLoadTextureBlock(OVERLAY_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, texSize, texSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, ItemIconPos[button][0] << 2, ItemIconPos[button][1] << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, + (ItemIconPos[button][0] + offset << 2), + (ItemIconPos[button][1] + offset << 2), (ItemIconPos[button][0] + gItemIconWidth[button]) << 2, (ItemIconPos[button][1] + gItemIconWidth[button]) << 2, G_TX_RENDERTILE, 0, 0, gItemIconDD[button] << 1, gItemIconDD[button] << 1); @@ -4891,11 +4915,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, ItemIconPos[button][0], ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, ItemIconPos[button][0] + 6, ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } @@ -5400,7 +5424,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5484,76 +5508,87 @@ void Interface_Draw(PlayState* play) { Interface_DrawAmmoCount(play, 3, interfaceCtx->cRightAlpha); } - if (CVarGetInteger("gDpadEquips", 0) != 0) { - // DPad is only greyed-out when all 4 DPad directions are too - uint16_t dpadAlpha = - MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), - interfaceCtx->dpadRightAlpha); - - // Draw DPad - s16 DpadPosX; - s16 DpadPosY; - s16 X_Margins_Dpad; - s16 Y_Margins_Dpad; - if (CVarGetInteger("gDPadUseMargins", 0) != 0) { - if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; - Y_Margins_Dpad = (Top_HUD_Margin*-1); - } else { - Y_Margins_Dpad = 0; - X_Margins_Dpad = 0; - } - if (CVarGetInteger("gDPadPosType", 0) != 0) { - DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; - if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None - DpadPosX = CVarGetInteger("gDPadPosX", 0); - } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden - DpadPosX = -9999; - } - } else { - DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); - DpadPosY = DPAD_Y+Y_Margins_Dpad; + // DPad is only greyed-out when all 4 DPad directions are too + uint16_t dpadAlpha = + MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), + interfaceCtx->dpadRightAlpha); + + // Draw DPad + s16 DpadPosX; + s16 DpadPosY; + s16 X_Margins_Dpad; + s16 Y_Margins_Dpad; + if (CVarGetInteger("gDPadUseMargins", 0) != 0) { + if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; + Y_Margins_Dpad = (Top_HUD_Margin*-1); + } else { + Y_Margins_Dpad = 0; + X_Margins_Dpad = 0; + } + if (CVarGetInteger("gDPadPosType", 0) != 0) { + DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; + if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None + DpadPosX = CVarGetInteger("gDPadPosX", 0); + } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden + DpadPosX = -9999; } + } else { + DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); + DpadPosY = DPAD_Y+Y_Margins_Dpad; + } - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); - if (fullUi) { - gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, - G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, - (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, - G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); - } + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); + if (fullUi) { + gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, + G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, + (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); + } - // DPad-Up Button Icon & Ammo Count - if (gSaveContext.equips.buttonItems[4] < 0xF0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); - } + bool dpadEquips = CVarGetInteger("gDpadEquips", 0); - // DPad-Down Button Icon & Ammo Count - if (gSaveContext.equips.buttonItems[5] < 0xF0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[5]], 5); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + // DPad-Up Button Icon & Ammo Count + // Ocarina is perma-mapped to D-up, so that part has to be drawn + if (gSaveContext.equips.buttonItems[4] < 0xF0) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); + } + + // DPad-Down Button Icon & Ammo Count + bool itemOnDpad = dpadEquips && gSaveContext.equips.buttonItems[5] < 0xF0; + bool dpadMap = fullUi && CVarGetInteger("gMapOnDDown", 0) && + play->pauseCtx.state < 4 && + ((play->sceneNum >= SCENE_DEKU_TREE && play->sceneNum <= SCENE_ICE_CAVERN) || + (play->sceneNum >= SCENE_HYRULE_FIELD && play->sceneNum <= SCENE_OUTSIDE_GANONS_CASTLE)); + if (itemOnDpad || dpadMap) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + void* texture = gItemIcons[itemOnDpad ? gSaveContext.equips.buttonItems[5] : ITEM_DUNGEON_MAP]; + Interface_DrawItemIconTexture(play, texture, 5); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + if (itemOnDpad) { Interface_DrawAmmoCount(play, 5, interfaceCtx->dpadDownAlpha); } + } + if (dpadEquips) { // DPad-Left Button Icon & Ammo Count if (gSaveContext.equips.buttonItems[6] < 0xF0) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadLeftAlpha); @@ -5718,7 +5753,7 @@ void Interface_Draw(PlayState* play) { CarrotsPosY = CVarGetInteger("gCarrotsPosY", 0); if (CVarGetInteger("gCarrotsPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Left_HUD_Margin;}; - CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); + CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); } else if (CVarGetInteger("gCarrotsPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Right_HUD_Margin;}; CarrotsPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); @@ -6228,7 +6263,7 @@ void Interface_Draw(PlayState* play) { for (svar1 = 0; svar1 < 5; svar1++) { // clang-format off //svar5 = svar5 + 8; - //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); + //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, digitTextures[timerDigits[svar1]], 8, 16, svar5 + timerDigitLeftPos[svar1], svar2, digitWidth[svar1], VREG(42), VREG(43) << 1, @@ -6372,7 +6407,7 @@ void Interface_Update(PlayState* play) { Left_HUD_Margin = CVarGetInteger("gHUDMargin_L", 0); Right_HUD_Margin = CVarGetInteger("gHUDMargin_R", 0); Bottom_HUD_Margin = CVarGetInteger("gHUDMargin_B", 0); - + GameInteractor_ExecuteOnInterfaceUpdate(); if (CHECK_BTN_ALL(debugInput->press.button, BTN_DLEFT)) { diff --git a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c index 93ff272f4d9..cf011c07064 100644 --- a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c +++ b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c @@ -257,9 +257,9 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) { sp60.x = this->unk_1F4.x - (this->unk_1E8.x - this->unk_1F4.x); sp60.y = this->unk_1F4.y - (this->unk_1E8.y - this->unk_1F4.y); sp60.z = this->unk_1F4.z - (this->unk_1E8.z - this->unk_1F4.z); - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (BgCheck_EntityLineTest1(&play->colCtx, &sp60, &this->unk_1E8, &sp78, &poly, true, true, true, true, &bgId) && diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c index 2346b34ffeb..b6a7a85911c 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c @@ -86,6 +86,13 @@ static InitChainEntry sInitChain[] = { void ObjTsubo_SpawnCollectible(ObjTsubo* this, PlayState* play) { s16 dropParams = this->actor.params & 0x1F; + // Avoid spawning a Deku Shield if the item isn't loaded. + // Targeted fix for a crash due to a broken drop from the pot in Spirit + // Temple surrounded by a circling spike trap. + if (dropParams == ITEM00_SHIELD_DEKU && Object_GetIndex(&play->objectCtx, OBJECT_GI_SHIELD_1) == -1) { + return; + } + if ((dropParams >= ITEM00_RUPEE_GREEN) && (dropParams <= ITEM00_BOMBS_SPECIAL)) { Item_DropCollectible(play, &this->actor.world.pos, (dropParams | (((this->actor.params >> 9) & 0x3F) << 8))); diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index ca7333497a0..ec60d8599d3 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2029,7 +2029,7 @@ s32 func_80833C98(s32 item1, s32 actionParam) { } s32 func_80833CDC(PlayState* play, s32 index) { - if (index >= ((CVarGetInteger("gDpadEquips", 0) != 0) ? 8 : 4)) { + if (index >= ((CVarGetInteger("gDpadEquips", 0) != 0) ? 8 : 5)) { return ITEM_NONE; } else if (play->bombchuBowlingStatus != 0) { return (play->bombchuBowlingStatus > 0) ? ITEM_BOMBCHU : ITEM_NONE; @@ -2062,7 +2062,7 @@ void func_80833DF8(Player* this, PlayState* play) { s32 maskItem = this->currentMask - PLAYER_MASK_KEATON + ITEM_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 4; buttonIndex < 8; buttonIndex++) { + for (int buttonIndex = 5; buttonIndex < 8; buttonIndex++) { hasOnDpad |= gSaveContext.equips.buttonItems[buttonIndex] == maskItem; } } @@ -2077,7 +2077,7 @@ void func_80833DF8(Player* this, PlayState* play) { maskActionParam = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 0; buttonIndex < 4; buttonIndex++) { + for (int buttonIndex = 0; buttonIndex < 5; buttonIndex++) { hasOnDpad |= func_80833C98(DPAD_ITEM(buttonIndex), maskActionParam); } } @@ -2088,6 +2088,28 @@ void func_80833DF8(Player* this, PlayState* play) { } } + // Since boots are items now, take them off if not equipped on a button + if (this->currentBoots != PLAYER_BOOTS_KOKIRI) { + s32 bootsItemAction = this->currentBoots + PLAYER_IA_BOOTS_KOKIRI; + + bool hasOnCBtn = false; + bool hasOnDpad = false; + for (int buttonIndex = 0; buttonIndex < 3; buttonIndex++) { + hasOnCBtn |= func_80833C98(C_BTN_ITEM(buttonIndex), bootsItemAction); + } + if (CVarGetInteger("gDpadEquips", 0)) { + for (int buttonIndex = 1; buttonIndex < 4; buttonIndex++) { + hasOnDpad |= func_80833C98(DPAD_ITEM(buttonIndex), bootsItemAction); + } + } + + if (!hasOnCBtn && !hasOnDpad) { + Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, PLAYER_BOOTS_KOKIRI + 1); + Player_SetEquipmentData(play, this); + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + } + } + if (!(this->stateFlags1 & (PLAYER_STATE1_ITEM_OVER_HEAD | PLAYER_STATE1_IN_CUTSCENE)) && !func_8008F128(this)) { if (this->itemAction >= PLAYER_IA_FISHING_POLE) { bool hasOnDpad = false; @@ -2472,9 +2494,9 @@ s32 func_80834E44(PlayState* play) { } s32 func_80834E7C(PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } return (play->shootingGalleryStatus != 0) && ((play->shootingGalleryStatus < 0) || CHECK_BTN_ANY(sControlInput->cur.button, buttonsToCheck)); @@ -4934,7 +4956,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5378,7 +5400,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6106,8 +6128,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6350,8 +6372,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -6482,9 +6504,9 @@ s32 func_8083EAF0(Player* this, Actor* actor) { } s32 func_8083EB44(Player* this, PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) && (this->heldActor != NULL) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -7759,7 +7781,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -8546,9 +8568,9 @@ void func_8084411C(Player* this, PlayState* play) { if (this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) { Actor* heldActor = this->heldActor; - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (!func_80835644(play, this, heldActor) && (heldActor->id == ACTOR_EN_NIW) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -9328,7 +9350,7 @@ void func_80846260(Player* this, PlayState* play) { return; } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } @@ -11194,7 +11216,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11245,7 +11267,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -11597,9 +11619,9 @@ void func_8084B1D8(Player* this, PlayState* play) { func_80836670(this, play); } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->csMode != 0) || (this->unk_6AD == 0) || (this->unk_6AD >= 4) || func_80833B54(this) || (this->unk_664 != NULL) || !func_8083AD4C(play, this) || @@ -13576,7 +13598,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -15003,7 +15025,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15012,7 +15034,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index d255f40d248..3a460d94e82 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -188,7 +188,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, ZREG(39), ZREG(40), ZREG(41), pauseCtx->alpha); gDPSetEnvColor(POLY_KAL_DISP++, ZREG(43), ZREG(44), ZREG(45), 0); - for (i = 0, j = 64; i < 4; i++, j += 4) { + for (i = 0, j = 64; i < 3; i++, j += 4) { if (CUR_EQUIP_VALUE(i) != 0) { gDPPipeSync(POLY_KAL_DISP++); gSPVertex(POLY_KAL_DISP++, &pauseCtx->equipVtx[j], 4, 0); @@ -220,6 +220,12 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorX[PAUSE_EQUIP] -= 1; pauseCtx->cursorPoint[PAUSE_EQUIP] -= 1; + // Kokiri tunic -> scale + if (pauseCtx->cursorY[PAUSE_EQUIP] == 2 && pauseCtx->cursorX[PAUSE_EQUIP] == 0) { + pauseCtx->cursorY[PAUSE_EQUIP] += 1; + pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (pauseCtx->cursorY[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(UPG_BULLET_BAG) != 0) { @@ -260,6 +266,13 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorX[PAUSE_EQUIP] += 1; pauseCtx->cursorPoint[PAUSE_EQUIP] += 1; + // Strength -> Deku shield + // Scale -> Kokiri tunic + if (pauseCtx->cursorX[PAUSE_EQUIP] == 1 && pauseCtx->cursorY[PAUSE_EQUIP] >= 2) { + pauseCtx->cursorY[PAUSE_EQUIP] -= 1; + pauseCtx->cursorPoint[PAUSE_EQUIP] -= 4; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(pauseCtx->cursorY[PAUSE_EQUIP]) != 0) { cursorMoveResult = 1; @@ -328,6 +341,12 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorY[PAUSE_EQUIP] += 1; pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; + // Tunics -> scale + if (pauseCtx->cursorY[PAUSE_EQUIP] == 3 && pauseCtx->cursorX[PAUSE_EQUIP] > 0) { + pauseCtx->cursorPoint[PAUSE_EQUIP] -= pauseCtx->cursorX[PAUSE_EQUIP]; + pauseCtx->cursorX[PAUSE_EQUIP] = 0; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(pauseCtx->cursorY[PAUSE_EQUIP]) != 0) { cursorMoveResult = 1; @@ -506,7 +525,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { u16 buttonsToCheck = BTN_A | BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((pauseCtx->cursorSpecialPos == 0) && (cursorItem != PAUSE_ITEM_NONE) && (pauseCtx->state == 6) && @@ -700,6 +719,11 @@ void KaleidoScope_DrawEquipment(PlayState* play) { gSPGrayscale(POLY_KAL_DISP++, false); } } + + if (i == 3) { + continue; + } + // Draw inventory screen icons for (k = 0, bit = rowStart, point = 4; k < 3; k++, point += 4, temp++, bit++) { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 665c95b81af..a97ebad6635 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -7,8 +7,9 @@ #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" u8 gAmmoItems[] = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, - ITEM_BOMBCHU, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_BEAN, ITEM_NONE, + ITEM_NONE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_NONE, ITEM_BEAN, + ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, ITEM_STICK, ITEM_NONE, ITEM_NONE, + ITEM_NONE, ITEM_BOW, ITEM_NONE, ITEM_NONE, }; static s16 sEquipState = 0; @@ -17,10 +18,23 @@ static s16 sEquipMoveTimer = 10; bool gSelectingMask; bool gSelectingAdultTrade; +ArrowMenuState gArrowMenuState; +static s16 sArrowMenuTimer = 0; + +/* Maps an inventory slot to double the position of its ammo count in sAmmoVtxTableIdx */ static s16 sAmmoVtxOffset[] = { - 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12, + 99, 0, 2, 4, 99, 6, + 99, 8, 99, 10, 99, 99, + 99, 12, 99 }; +typedef enum { + ES_MAGIC_ARROW_GLOWING = 0, + ES_MAGIC_ARROW_APPLYING = 1, + ES_MAGIC_ARROW_EQUIPPING = 2, // Unused in item screen mod + ES_DEFAULT = 3, +} EquipState; + extern const char* _gAmmoDigit0Tex[]; void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) { @@ -41,7 +55,8 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, if (ammo == 0) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 130, 130, 130, pauseCtx->alpha); } else if ((item == ITEM_BOMB && AMMO(item) == CUR_CAPACITY(UPG_BOMB_BAG)) || - (item == ITEM_BOW && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || + ((item == ITEM_BOW || item == ITEM_BOW_ARROW_FIRE || item == ITEM_BOW_ARROW_ICE || item == ITEM_BOW_ARROW_LIGHT) + && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || (item == ITEM_SLINGSHOT && AMMO(item) == CUR_CAPACITY(UPG_BULLET_BAG)) || (item == ITEM_STICK && AMMO(item) == CUR_CAPACITY(UPG_STICKS)) || (item == ITEM_NUT && AMMO(item) == CUR_CAPACITY(UPG_NUTS)) || (item == ITEM_BOMBCHU && ammo == 50) || @@ -220,6 +235,217 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 CLOSE_DISPS(play->state.gfxCtx); } +void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active) { + if (ARROW_SELECT_OPEN == active) + return; + + gArrowMenuState = AMS_CLOSING + active; + pauseCtx->arrowMenuAnimPos = 12; + sArrowMenuTimer = 2; +} + +void KaleidoScope_ArrowSelect(PlayState* play, u16 cursorSlot) { + PauseContext* pauseCtx = &play->pauseCtx; + if (cursorSlot != SLOT_BOW || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + gArrowMenuState = AMS_DISABLED; + pauseCtx->arrowMenuAnimPos = 0; + sArrowMenuTimer = 0; + return; + } + + Input* input = &play->state.input[0]; + + // Allow changing arrows if: + // - Selecting bow slot and pressing A + // - You have an item in the bow slot and any magic arrow + if (CHECK_BTN_ALL(input->press.button, BTN_A) && + INV_CONTENT(ITEM_BOW) != ITEM_NONE && + (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE)) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + KaleidoScope_SetArrowSelectActive(pauseCtx, !ARROW_SELECT_OPEN); + } + + if (!ARROW_SELECT_OPEN) { + return; + } + + pauseCtx->cursorColorSet = 8; + bool dpad = CVarGetInteger("gDpadPause", 0); + + // Select arrow with stick/d-pad + // Up = Fire + // Left = Ice + // Right = Light + // Down = Normal + u8 newBow = ITEM_NONE; + u16 arrowCursorSlot; + if (pauseCtx->stickRelY < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DDOWN))) { + newBow = ITEM_BOW; + arrowCursorSlot = cursorSlot + 6; + } else if (pauseCtx->stickRelY > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) { + newBow = (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE) ? ITEM_BOW_ARROW_FIRE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 6; + } else if (pauseCtx->stickRelX < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) { + newBow = (INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE) ? ITEM_BOW_ARROW_ICE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 1; + } else if (pauseCtx->stickRelX > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) { + newBow = (INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE) ? ITEM_BOW_ARROW_LIGHT : ITEM_NONE; + arrowCursorSlot = cursorSlot + 1; + } + + if (newBow == ITEM_NONE) { + return; + } + + // If you double select an arrow, reset to normal + if (newBow == INV_CONTENT(ITEM_BOW)) { + newBow = ITEM_BOW; + + // If double selecting regular arrows, cancel + if (INV_CONTENT(ITEM_BOW) == ITEM_BOW) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + KaleidoScope_SetArrowSelectActive(pauseCtx, false); + return; + } + } + + u16 sfxId; + if (newBow == ITEM_BOW || CVarGetInteger("gSkipArrowAnimation", 0)) { + sfxId = NA_SE_SY_DECIDE; + pauseCtx->equipTargetItem = newBow; + pauseCtx->equipAnimAlpha = 255; + sEquipState = ES_MAGIC_ARROW_APPLYING; + } else { + sfxId = NA_SE_SY_SET_FIRE_ARROW + (newBow - ITEM_BOW_ARROW_FIRE); + pauseCtx->equipTargetItem = 0xBF - ITEM_BOW_ARROW_FIRE + newBow; + pauseCtx->equipAnimAlpha = 0; + sEquipState = ES_MAGIC_ARROW_GLOWING; + } + + Audio_PlaySoundGeneral(sfxId, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + pauseCtx->equipAnimX = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[0] * 10; + pauseCtx->equipAnimY = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[1] * 10; + sEquipMoveTimer = 6; + sEquipAnimTimer = 0; + pauseCtx->unk_1E4 = 3; +} + +void KaleidoScope_BowMenuSetRect(PauseContext* pauseCtx, s16 xOffset, s16 yOffset, s16 size, u8 vtx) { + s16 bowCenterX = -64 + 16; + s16 bowCenterY = -6 - 16 + pauseCtx->offsetY; + s16 arrowCenterX = bowCenterX + xOffset; + s16 arrowCenterY = bowCenterY + yOffset; + s16 arrowX = arrowCenterX - size / 2; + s16 arrowY = arrowCenterY + size / 2; + + pauseCtx->arrowSelectVtx[vtx].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.ob[0] = arrowX; + pauseCtx->arrowSelectVtx[vtx + 1].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[0] = arrowX + size; + pauseCtx->arrowSelectVtx[vtx].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 1].v.ob[1] = arrowY; + pauseCtx->arrowSelectVtx[vtx + 2].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[1] = arrowY - size; +} + +void KaleidoScope_DrawBowMenuTexture(PlayState* play, s16 xOffset, s16 yOffset, s16 drawSize, u8 vtx, void* tex, u16 texSize) { + PauseContext* pauseCtx = &play->pauseCtx; + + KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, drawSize, vtx); + pauseCtx->arrowSelectVtx[vtx + 1].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.tc[1] = + pauseCtx->arrowSelectVtx[vtx + 3].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.tc[1] = texSize << 5; + + OPEN_DISPS(play->state.gfxCtx); + + gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, tex, texSize, texSize, 0); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_DrawMagicArrowIcon(PlayState* play, s16 offset, u8 itemId) { + if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + return; + } + + s16 xOffset, yOffset, vtx; + char* source; + switch (itemId) { + case ITEM_ARROW_FIRE: + xOffset = 0; + yOffset = offset; + vtx = 0; + source = "__OTR__textures/icon_item_static/gFireArrowPower"; + break; + case ITEM_ARROW_ICE: + xOffset = -offset; + yOffset = 0; + vtx = 4; + source = "__OTR__textures/icon_item_static/gIceArrowPower"; + break; + case ITEM_ARROW_LIGHT: + xOffset = offset; + yOffset = 0; + vtx = 8; + source = "__OTR__textures/icon_item_static/gLightArrowPower"; + break; + default: + return; + } + + KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 12, vtx, source, 16); +} + +void KaleidoScope_DrawSelectableArrow(PlayState* play, s16 offset, u8 itemId) { + if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + return; + } + + s16 xOffset, yOffset, vtx; + char* tex = gItemIcons[itemId]; + switch (itemId) { + case ITEM_ARROW_FIRE: + xOffset = 0; + yOffset = offset; + vtx = 0; + break; + case ITEM_ARROW_ICE: + xOffset = -offset; + yOffset = 0; + vtx = 4; + break; + case ITEM_ARROW_LIGHT: + xOffset = offset; + yOffset = 0; + vtx = 8; + break; + case ITEM_BOW: + xOffset = 0; + yOffset = -offset; + vtx = 12; + tex = "__OTR__textures/icon_item_static/gArrowIconTex"; + break; + default: + return; + } + + if (gArrowMenuState == AMS_ENABLED) { + PauseContext* pauseCtx = &play->pauseCtx; + OPEN_DISPS(play->state.gfxCtx); + gDPPipeSync(POLY_KAL_DISP++); + vtx += 16; + + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 0); + KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, 32, vtx); + gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); + POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); + + vtx -= 16; + CLOSE_DISPS(play->state.gfxCtx); + } + + KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 28, vtx, tex, 32); +} + void KaleidoScope_DrawItemSelect(PlayState* play) { static s16 magicArrowEffectsR[] = { 255, 100, 255 }; static s16 magicArrowEffectsG[] = { 0, 100, 255 }; @@ -260,7 +486,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->nameColorSet = 0; if ((pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM)) { - moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorItem = pauseCtx->cursorItem[PAUSE_ITEM]; @@ -434,7 +660,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorSpecialPos == 0) { if (cursorItem != PAUSE_ITEM_NONE) { if ((ABS(pauseCtx->stickRelY) > 30) || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) { - moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorY = pauseCtx->cursorY[PAUSE_ITEM]; @@ -561,9 +787,12 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT; } + + KaleidoScope_ArrowSelect(play, cursorSlot); + u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (CHECK_BTN_ANY(input->press.button, buttonsToCheck)) { if (CHECK_AGE_REQ_SLOT(cursorSlot) && @@ -602,9 +831,11 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 0); for (i = 0, j = 24 * 4; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++, j += 4) { - if ((gSaveContext.equips.buttonItems[i + 1] != ITEM_NONE) && - !((gSaveContext.equips.buttonItems[i + 1] >= ITEM_SHIELD_DEKU) && - (gSaveContext.equips.buttonItems[i + 1] <= ITEM_BOOTS_HOVER))) { + u8 buttonItem = gSaveContext.equips.buttonItems[i + 1]; + if ((buttonItem != ITEM_NONE) && // equipped + (buttonItem < ARRAY_COUNT(gItemSlots)) && // has an assigned slot + (gItemSlots[buttonItem] < 24) && // assigned slot is on the menu + !((buttonItem >= ITEM_SHIELD_DEKU) && (buttonItem <= ITEM_BOOTS_KOKIRI))) { // not equipment (except boots) gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j], 4, 0); POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); } @@ -616,39 +847,20 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { for (i = j = 0; i < 24; i++, j += 4) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - if (gSaveContext.inventory.items[i] != ITEM_NONE) { - if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && (pauseCtx->cursorSpecialPos == 0)) { - if (CHECK_AGE_REQ_SLOT(i)) { - if ((sEquipState == 2) && (i == 3)) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, magicArrowEffectsR[pauseCtx->equipTargetItem - 0xBF], - magicArrowEffectsG[pauseCtx->equipTargetItem - 0xBF], - magicArrowEffectsB[pauseCtx->equipTargetItem - 0xBF], pauseCtx->alpha); - - pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] - 2; - - pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] + 32; - - pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] + 2; + if ((gSaveContext.inventory.items[i] != ITEM_NONE)) { + if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && + (pauseCtx->cursorSpecialPos == 0) && CHECK_AGE_REQ_SLOT(i) && (i == cursorSlot)) { + pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] - 2; - pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] - 32; - } else if (i == cursorSlot) { - pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] - 2; + pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] + 32; - pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] + 32; + pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] + 2; - pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] + 2; - - pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] - 32; - } - } + pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] - 32; } gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j + 0], 4, 0); @@ -688,6 +900,38 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + if (gArrowMenuState == AMS_DISABLED) { + s16 offset = 14; + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_FIRE); + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_ICE); + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_LIGHT); + } else { + s16 offset; + if (gArrowMenuState == AMS_ENABLED) { + offset = 32; + } else { + offset = pauseCtx->arrowMenuAnimPos / sArrowMenuTimer; + pauseCtx->arrowMenuAnimPos -= offset; + if (gArrowMenuState == AMS_OPENING) { + offset = 32 - pauseCtx->arrowMenuAnimPos; + } else { + offset = 20 + pauseCtx->arrowMenuAnimPos; + } + } + + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_FIRE); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_ICE); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_LIGHT); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_BOW); + + sArrowMenuTimer--; + + if (sArrowMenuTimer == 0) { + gArrowMenuState &= 1; + } + } + CLOSE_DISPS(play->state.gfxCtx); } @@ -696,6 +940,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, PauseContext* pauseCtx = &play->pauseCtx; gSelectingMask = false; gSelectingAdultTrade = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { pauseCtx->equipTargetCBtn = 0; @@ -704,9 +949,10 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } else if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) { pauseCtx->equipTargetCBtn = 2; } else if (CVarGetInteger("gDpadEquips", 0)) { - if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { + // D up is permanently mapped to ocarina + /*if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { pauseCtx->equipTargetCBtn = 3; - } else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { + } else */if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { pauseCtx->equipTargetCBtn = 4; } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT)) { pauseCtx->equipTargetCBtn = 5; @@ -722,7 +968,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, pauseCtx->equipAnimY = animY; pauseCtx->equipAnimAlpha = 255; sEquipAnimTimer = 0; - sEquipState = 3; + sEquipState = ES_DEFAULT; sEquipMoveTimer = 10; if ((pauseCtx->equipTargetItem == ITEM_ARROW_FIRE) || (pauseCtx->equipTargetItem == ITEM_ARROW_ICE) || (pauseCtx->equipTargetItem == ITEM_ARROW_LIGHT)) { @@ -738,7 +984,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } Audio_PlaySoundGeneral(NA_SE_SY_SET_FIRE_ARROW + index, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); pauseCtx->equipTargetItem = 0xBF + index; - sEquipState = 0; + sEquipState = ES_MAGIC_ARROW_GLOWING; pauseCtx->equipAnimAlpha = 0; sEquipMoveTimer = 6; } @@ -813,8 +1059,8 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; s16 DPad_ItemsOffset[4][2] = { @@ -922,35 +1168,18 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { sCButtonPosX[6] = sCButtonPosX[6] - 160; sCButtonPosY[6] = 120 - sCButtonPosY[6]; - if (sEquipState == 0) { + if (sEquipState == ES_MAGIC_ARROW_GLOWING) { pauseCtx->equipAnimAlpha += 14; if (pauseCtx->equipAnimAlpha > 255) { pauseCtx->equipAnimAlpha = 254; - sEquipState++; + sEquipState = ES_MAGIC_ARROW_APPLYING; } sEquipAnimTimer = 5; return; } - if (sEquipState == 2) { - D_8082A488--; - - if (D_8082A488 == 0) { - pauseCtx->equipTargetItem -= 0xBF - ITEM_BOW_ARROW_FIRE; - if (!CVarGetInteger("gSeparateArrows", 0)) { - pauseCtx->equipTargetSlot = SLOT_BOW; - } - sEquipMoveTimer = 6; - WREG(90) = 320; - WREG(87) = WREG(91); - sEquipState++; - Audio_PlaySoundGeneral(NA_SE_SY_SYNTH_MAGIC_ARROW, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - } - return; - } - - if (sEquipState == 1) { - bowItemVtx = &pauseCtx->itemVtx[12]; + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + bowItemVtx = &pauseCtx->itemVtx[52]; offsetX = ABS(pauseCtx->equipAnimX - bowItemVtx->v.ob[0] * 10) / sEquipMoveTimer; offsetY = ABS(pauseCtx->equipAnimY - bowItemVtx->v.ob[1] * 10) / sEquipMoveTimer; } else { @@ -971,14 +1200,14 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { WREG(90) -= WREG(87) / sEquipMoveTimer; WREG(87) -= WREG(87) / sEquipMoveTimer; - if (sEquipState == 1) { - if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[12].v.ob[0] * 10)) { + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[52].v.ob[0] * 10)) { pauseCtx->equipAnimX -= offsetX; } else { pauseCtx->equipAnimX += offsetX; } - if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[12].v.ob[1] * 10)) { + if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[52].v.ob[1] * 10)) { pauseCtx->equipAnimY -= offsetY; } else { pauseCtx->equipAnimY += offsetY; @@ -1000,34 +1229,19 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { sEquipMoveTimer--; if (sEquipMoveTimer == 0) { - if (sEquipState == 1) { - sEquipState++; - D_8082A488 = 4; + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + pauseCtx->unk_1E4 = 0; + s16 magicArrowType = pauseCtx->equipTargetItem - 0xBF; + if (magicArrowType >= 0 && magicArrowType <= 2) { + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE + magicArrowType; + } + Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), pauseCtx->equipTargetItem); + KaleidoScope_SetArrowSelectActive(pauseCtx, false); return; } osSyncPrintf("\n================================\n"); - // Skipping the arrow animation: need to change the item's type and - // slot when it hits the button since it didn't get set earlier - if (pauseCtx->equipTargetItem == ITEM_ARROW_FIRE || pauseCtx->equipTargetItem == ITEM_ARROW_ICE || - pauseCtx->equipTargetItem == ITEM_ARROW_LIGHT) { - switch (pauseCtx->equipTargetItem) { - case ITEM_ARROW_FIRE: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE; - break; - case ITEM_ARROW_ICE: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_ICE; - break; - case ITEM_ARROW_LIGHT: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_LIGHT; - break; - } - if (!CVarGetInteger("gSeparateArrows", 0)) { - pauseCtx->equipTargetSlot = SLOT_BOW; - } - } - // If the item is on another button already, swap the two uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1; for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index 8c214d9b0ae..19caf918f2f 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -12,6 +12,14 @@ extern u8 gSlotAgeReqs[]; extern u8 gItemAgeReqs[]; extern u8 gAreaGsFlags[]; extern bool gSelectingMask; +typedef enum { + AMS_DISABLED, + AMS_ENABLED, + AMS_CLOSING, + AMS_OPENING +} ArrowMenuState; +extern ArrowMenuState gArrowMenuState; +#define ARROW_SELECT_OPEN (gArrowMenuState & 1) #define MAP_48x85_TEX_WIDTH 48 #define MAP_48x85_TEX_HEIGHT 85 @@ -45,6 +53,7 @@ void KaleidoScope_ProcessPlayerPreRender(); void KaleidoScope_SetupPlayerPreRender(PlayState* play); void KaleidoScope_DrawCursor(PlayState* play, u16 pageIndex); void KaleidoScope_UpdateDungeonMap(PlayState* play); +void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active); void PauseMapMark_Draw(PlayState* play); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 877ea7e6f42..09106740d16 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -734,30 +734,10 @@ static u16 D_8082ABEC[] = { }; u8 gSlotAgeReqs[] = { - AGE_REQ_CHILD, // SLOT_DEKU_STICK - AGE_REQ_NONE, // SLOT_DEKU_NUT - AGE_REQ_NONE, // SLOT_BOMB - AGE_REQ_ADULT, // SLOT_BOW - AGE_REQ_ADULT, // SLOT_ARROW_FIRE - AGE_REQ_NONE, // SLOT_DINS_FIRE - AGE_REQ_CHILD, // SLOT_SLINGSHOT - AGE_REQ_NONE, // SLOT_OCARINA - AGE_REQ_NONE, // SLOT_BOMBCHU - AGE_REQ_ADULT, // SLOT_HOOKSHOT - AGE_REQ_ADULT, // SLOT_ARROW_ICE - AGE_REQ_NONE, // SLOT_FARORES_WIND - AGE_REQ_CHILD, // SLOT_BOOMERANG - AGE_REQ_NONE, // SLOT_LENS_OF_TRUTH - AGE_REQ_CHILD, // SLOT_MAGIC_BEAN - AGE_REQ_ADULT, // SLOT_HAMMER - AGE_REQ_ADULT, // SLOT_ARROW_LIGHT - AGE_REQ_NONE, // SLOT_NAYRUS_LOVE - AGE_REQ_NONE, // SLOT_BOTTLE_1 - AGE_REQ_NONE, // SLOT_BOTTLE_2 - AGE_REQ_NONE, // SLOT_BOTTLE_3 - AGE_REQ_NONE, // SLOT_BOTTLE_4 - AGE_REQ_ADULT, // SLOT_TRADE_ADULT - AGE_REQ_CHILD, // SLOT_TRADE_CHILD + LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_CHILD, + LINK_AGE_EITHER, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_ADULT, LINK_AGE_CHILD, + LINK_AGE_EITHER, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, + LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, }; u8 gEquipAgeReqs[][4] = { @@ -1009,6 +989,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { s16 s; s16 i; gSelectingMask = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); switch (pauseCtx->pageIndex) { case PAUSE_ITEM: @@ -1043,6 +1024,7 @@ void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) { pauseCtx->unk_1E4 = 1; pauseCtx->unk_1EA = 0; gSelectingMask = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); if (!pt) { pauseCtx->mode = pauseCtx->pageIndex * 2 + 1; @@ -2230,6 +2212,18 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { } else { osSyncPrintf("zoom_name=%d\n", pauseCtx->namedItem); + switch (sp2A) { + case ITEM_BOW_ARROW_FIRE: + sp2A = ITEM_ARROW_FIRE; + break; + case ITEM_BOW_ARROW_ICE: + sp2A = ITEM_ARROW_ICE; + break; + case ITEM_BOW_ARROW_LIGHT: + sp2A = ITEM_ARROW_LIGHT; + break; + } + if (gSaveContext.language) { sp2A += 123; } @@ -2619,7 +2613,8 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) { return phi_t1; } -static s16 D_8082B11C[] = { 0, 4, 8, 12, 24, 32, 56 }; +/* Maps an ammo item to an inventory slot by 4x its slot number */ +static s16 sAmmoVtxTableIdx[] = { 4, 8, 12, 20, 28, 36, 52 }; static s16 D_8082B12C[] = { -114, 12, 44, 76 }; @@ -2784,7 +2779,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { for (phi_t3 = 1; phi_t3 < ARRAY_COUNT(gSaveContext.equips.buttonItems); phi_t3++, phi_t2 += 4) { if (gSaveContext.equips.cButtonSlots[phi_t3 - 1] != ITEM_NONE && - ((phi_t3 < 4) || CVarGetInteger("gDpadEquips", 0))) { + ((phi_t3 < 5) || CVarGetInteger("gDpadEquips", 0))) { phi_t4 = gSaveContext.equips.cButtonSlots[phi_t3 - 1] * 4; pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = @@ -2834,7 +2829,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { } for (phi_t3 = 0; phi_t3 < 7; phi_t3++) { - phi_t4 = D_8082B11C[phi_t3]; + phi_t4 = sAmmoVtxTableIdx[phi_t3]; pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = pauseCtx->itemVtx[phi_t4].v.ob[0]; @@ -2895,7 +2890,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->equipVtx[phi_t4 + 0].v.ob[0] + 28; pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 1].v.ob[1] = - phi_t5 + pauseCtx->offsetY - 2; + phi_t5 + pauseCtx->offsetY - 2 - (phi_t3 > 0 ? 16 : 0); pauseCtx->equipVtx[phi_t4 + 2].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 3].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] - 28; @@ -3086,6 +3081,34 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->saveVtx = Graph_Alloc(gfxCtx, 80 * sizeof(Vtx)); func_80823A0C(play, pauseCtx->saveVtx, 5, 5); + + pauseCtx->arrowSelectVtx = Graph_Alloc(gfxCtx, 32 * sizeof(Vtx)); + + // All arrow select vertices + for (phi_t2 = 0; phi_t2 < 32; phi_t2++) { + pauseCtx->arrowSelectVtx[phi_t2].v.flag = 0; + + // Z position + pauseCtx->arrowSelectVtx[phi_t2].v.ob[2] = 0; + + // Color + pauseCtx->arrowSelectVtx[phi_t2].v.cn[0] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[1] = + pauseCtx->arrowSelectVtx[phi_t2].v.cn[2] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[3] = 255; + } + + // All arrow select quads + for (phi_t2 = 0; phi_t2 < 32; phi_t2 += 4) { + // Top left UV at (0, 0); + pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[1] = + pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[1] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[0] = 0; + } + + // Background quads + for (phi_t2 = 16; phi_t2 < 32; phi_t2 += 4) { + // Bottom left UV at (32, 32) + pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[1] = + pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[1] = 0x400; + } } void KaleidoScope_DrawGameOver(PlayState* play) { @@ -4438,6 +4461,9 @@ void KaleidoScope_Update(PlayState* play) break; case 0x12: + // OTRTODO: move this somewhere it won't be called repeatedly for several frames + KaleidoScope_SetArrowSelectActive(pauseCtx, false); + if (pauseCtx->unk_1F4 != 160.0f) { pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 += 160.0f / WREG(6); pauseCtx->infoPanelOffsetY -= 40 / WREG(6); From f0ed065ff87ef3bccb3d58ab17ef239baa1c38bc Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sun, 26 Nov 2023 10:49:22 -0600 Subject: [PATCH 10/60] Update some graphics items --- .../icon_item_static/gArrowIconTex.rgba32.png | Bin 0 -> 987 bytes .../gFireArrowPower.rgba32.png | Bin 0 -> 386 bytes .../gIceArrowPower.rgba32.png | Bin 0 -> 410 bytes .../gLightArrowPower.rgba32.png | Bin 0 -> 393 bytes soh/assets/soh_assets.h | 12 +++++ soh/include/z64save.h | 1 - .../misc/ovl_kaleido_scope/z_kaleido_item.c | 46 ++++++++++++++---- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 28 +++++++++-- 8 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 soh/assets/custom/textures/icon_item_static/gArrowIconTex.rgba32.png create mode 100644 soh/assets/custom/textures/icon_item_static/gFireArrowPower.rgba32.png create mode 100644 soh/assets/custom/textures/icon_item_static/gIceArrowPower.rgba32.png create mode 100644 soh/assets/custom/textures/icon_item_static/gLightArrowPower.rgba32.png diff --git a/soh/assets/custom/textures/icon_item_static/gArrowIconTex.rgba32.png b/soh/assets/custom/textures/icon_item_static/gArrowIconTex.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..6e8affade3fbd0a8c0cb321daff3178ea8f917d6 GIT binary patch literal 987 zcmV<110?*3P) zL=qQ`Z_A=FGt1PBs2NVP#l)8|S@__L8QDxmqnX)!lsZs=cVzrt6zKR;CNPWN2Q@ zo2oV3BBwYjDvf)is|7_CUAalpb$T8y@+{=nYaO8CK~rm%OWN>vG=@E--`=s=lW$Hn zZvUp&mpPwbrzPC7!rmBl2mw{GSnQ{y1$eB!;7E3s zy%+&&a$FST7IS`V7+E%eonI)sH>@JmE`-d86{R3f~dJA^ql^TRJ{o` z7Uo#rO-4qe5^xR(0Pg@@nguYM2)Z0b+|##+tt_Jd&j6C_VCo+oAA7G5np6|*exM69 zyaM0v{=O2O!j(xC-Gf-qj1PT8kAIL`5i8&Rc)5Bi5{X+n zf$x?Bj%(2lR8}-Sm**@j3tcOC%aZ`C|~fBPVVt=S~-r zqkVf%j-L5?P(;FtxT^GtJ-fFFmn%2%iJc+||CY0I0efZIHA%y$-e*q002ov JPDHLkV1mHc)HDD9 literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/icon_item_static/gFireArrowPower.rgba32.png b/soh/assets/custom/textures/icon_item_static/gFireArrowPower.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8e2600364000011992483ffae74b040ec291ef GIT binary patch literal 386 zcmV-|0e$|7P)@l08d80T@OfKPW{oXtc?#2tlRBrdnM41rY?%;L>j> zBqCd*CFllyElq6=7SW(C30j~~q&Gq*l?#5{(@=&qTwLqy=e*DGO8*mJ1<3P74|o8U zN0pBNtV)G<Et1=*QfsnL+6q*EYP&16)tEKNv?SeE=3mkPGp8VB`WUL`3yEO>tf`X4U0 z=N?;bNfBIHD?RCLYg@h98HJ`o^2TGf(}L{u(xQC9plnHxLU*7-udC-`NuK#RNy<6} zb^?==S~ZS;B1LSud_F}E4>T4I_a*Jh2_OZ~YBb26ol`kIrCX~F{$bNm9*QJ@Yrq7m gz!k7ClKl7h1oMf^pNYVybN~PV07*qoM6N<$f^&@lD#iO0Tf5id-ak=X;LwiG-6Pb1`&fnB20`X8-GC! z60=c6#9);02k2nYM65)U29XY>NgLl96h)p^>u2zh<_(RNGv9OW9WMM&Buz-#(O11oE>6q8F4+FJvR4fbFFeL+8=fDd5A zFpTK8V>*K2>~oRn$N_JrMJAi$sZd6yi`~;a_jU;&Tq!sM-8+diPiM!N?m9}1ZEU1% zY_k?z7UvH(Kv$(u;|P@Xl5-VK4!|(6{6W&bQ5H871br5MPY0o<`uA!V#0Ppqcs;eC zciyg36f*nRmno7*NjjVB0OHjGa}C~lmS@60kzzK3+j6lmK154{rwq(f4N0?-boZE7 zWNTZI?S!r$?eBk>sw!7Rh9yNMT}ir-v@WUtSMuNE19#rH1JY=XRsaA107*qoM6N<$ Eg2c?H1poj5 literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/icon_item_static/gLightArrowPower.rgba32.png b/soh/assets/custom/textures/icon_item_static/gLightArrowPower.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..79a3dd48423605adbae68d2d4fc2772e432ac5c2 GIT binary patch literal 393 zcmV;40e1e0P)@k}*p{Q5c3_Zx=lxTp)D^@<%19SpO8E!`NAJG z$!C&ho65H&Ih}Sn7?kPz4JtMIZLzq?GNml@?rw+G>M^CfqLkO1Od88bX4SFQ8hK+r zAY}nUD2&HlkUngiFy;xsCjjJw0_lFghE{8gc-(^P&Jm41z;ULCL;$Vd0pM^|u-5{M z;SgK(x`JgXxUP*{?hU3f`0oT1mIJ~z2P(lzSizMm$BYIwiolb>H4VM2<2$WYM n8Iq4ACCNU?dy*#`$$yV;517n|Y~J$800000NkvXXu0mjfdlsXU literal 0 HcmV?d00001 diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h index 2b193053c3b..c3d8216afbc 100644 --- a/soh/assets/soh_assets.h +++ b/soh/assets/soh_assets.h @@ -61,6 +61,18 @@ static const ALIGN_ASSET(2) char gTriforcePieceCompletedDL[] = dgTriforcePieceCo static const ALIGN_ASSET(2) char gOptionsDividerChangeLangVtx[] = dgOptionsDividerChangeLangVtx; // textures +#define dgArrowIconTex "__OTR__textures/icon_item_static/gArrowIconTex" +static const ALIGN_ASSET(2) char gArrowIconTex[] = dgArrowIconTex; + +#define dgFireArrowPower "__OTR__textures/icon_item_static/gFireArrowPower" +static const ALIGN_ASSET(2) char gFireArrowPowerTex[] = dgFireArrowPower; + +#define dgIceArrowPower "__OTR__textures/icon_item_static/gIceArrowPower" +static const ALIGN_ASSET(2) char gIceArrowPowerTex[] = dgIceArrowPower; + +#define dgLightArrowPower "__OTR__textures/icon_item_static/gLightArrowPower" +static const ALIGN_ASSET(2) char gLightArrowPowerTex[] = dgLightArrowPower; + #define dgDPad "__OTR__textures/parameter_static/gDPad" static const ALIGN_ASSET(2) char gDPadTex[] = dgDPad; diff --git a/soh/include/z64save.h b/soh/include/z64save.h index b3ff798ef81..2c31fe672e1 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -390,7 +390,6 @@ typedef enum { typedef enum { /* 0 */ LINK_AGE_ADULT, /* 1 */ LINK_AGE_CHILD, - /* 9 */ LINK_AGE_EITHER = 9 } LinkAge; diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index a97ebad6635..ea46340b59a 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -5,11 +5,25 @@ #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" +#include "soh_assets.h" u8 gAmmoItems[] = { - ITEM_NONE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_NONE, ITEM_BEAN, - ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, ITEM_STICK, ITEM_NONE, ITEM_NONE, - ITEM_NONE, ITEM_BOW, ITEM_NONE, ITEM_NONE, + ITEM_NONE, // SLOT_DINS_FIRE + ITEM_BOMB, // SLOT_BOMB + ITEM_BOMBCHU, // SLOT_BOMBCHU + ITEM_NUT, // SLOT_NUT + ITEM_NONE, // SLOT_LENS + ITEM_BEAN, // SLOT_BEAN + ITEM_NONE, // SLOT_FARORES_WIND + ITEM_SLINGSHOT, // SLOT_SLINGSHOT + ITEM_NONE, // SLOT_BOOMERANG + ITEM_STICK, // SLOT_STICK + ITEM_NONE, // SLOT_BOOTS_HOVER + ITEM_NONE, // SLOT_TRADE_CHILD + ITEM_NONE, // SLOT_NAYRUS_LOVE + ITEM_BOW, // SLOT_BOW + ITEM_NONE, // SLOT_HOOKSHOT + ITEM_NONE, // SLOT_HAMMER }; static s16 sEquipState = 0; @@ -23,9 +37,21 @@ static s16 sArrowMenuTimer = 0; /* Maps an inventory slot to double the position of its ammo count in sAmmoVtxTableIdx */ static s16 sAmmoVtxOffset[] = { - 99, 0, 2, 4, 99, 6, - 99, 8, 99, 10, 99, 99, - 99, 12, 99 + 99, // SLOT_DINS_FIRE + 0, // SLOT_BOMB + 2, // SLOT_BOMBCHU + 4, // SLOT_NUT + 99, // SLOT_LENS + 6, // SLOT_BEAN + 99, // SLOT_FARORES_WIND + 8, // SLOT_SLINGSHOT + 99, // SLOT_BOOMERANG + 10, // SLOT_STICK + 99, // SLOT_BOOTS_HOVER + 99, // SLOT_TRADE_CHILD + 99, // SLOT_NAYRUS_LOVE + 12, // SLOT_BOW + 99 // SLOT_HOOKSHOT }; typedef enum { @@ -373,19 +399,19 @@ void KaleidoScope_DrawMagicArrowIcon(PlayState* play, s16 offset, u8 itemId) { xOffset = 0; yOffset = offset; vtx = 0; - source = "__OTR__textures/icon_item_static/gFireArrowPower"; + source = gFireArrowPowerTex; break; case ITEM_ARROW_ICE: xOffset = -offset; yOffset = 0; vtx = 4; - source = "__OTR__textures/icon_item_static/gIceArrowPower"; + source = gIceArrowPowerTex; break; case ITEM_ARROW_LIGHT: xOffset = offset; yOffset = 0; vtx = 8; - source = "__OTR__textures/icon_item_static/gLightArrowPower"; + source = gLightArrowPowerTex; break; default: return; @@ -421,7 +447,7 @@ void KaleidoScope_DrawSelectableArrow(PlayState* play, s16 offset, u8 itemId) { xOffset = 0; yOffset = -offset; vtx = 12; - tex = "__OTR__textures/icon_item_static/gArrowIconTex"; + tex = gArrowIconTex; break; default: return; diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 09106740d16..1db5ed1578f 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -734,10 +734,30 @@ static u16 D_8082ABEC[] = { }; u8 gSlotAgeReqs[] = { - LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_CHILD, - LINK_AGE_EITHER, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_ADULT, LINK_AGE_CHILD, - LINK_AGE_EITHER, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, - LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, + AGE_REQ_NONE, // SLOT_DINS_FIRE + AGE_REQ_NONE, // SLOT_BOMB + AGE_REQ_NONE, // SLOT_BOMBCHU + AGE_REQ_NONE, // SLOT_NUT + AGE_REQ_NONE, // SLOT_LENS + AGE_REQ_CHILD, // SLOT_BEAN + AGE_REQ_NONE, // SLOT_FARORES_WIND + AGE_REQ_CHILD, // SLOT_SLINGSHOT + AGE_REQ_CHILD, // SLOT_BOOMERANG + AGE_REQ_CHILD, // SLOT_STICK + AGE_REQ_ADULT, // SLOT_BOOTS_HOVER + AGE_REQ_CHILD, // SLOT_TRADE_CHILD + AGE_REQ_NONE, // SLOT_NAYRUS_LOVE + AGE_REQ_ADULT, // SLOT_BOW + AGE_REQ_ADULT, // SLOT_HOOKSHOT + AGE_REQ_ADULT, // SLOT_HAMMER + AGE_REQ_ADULT, // SLOT_BOOTS_IRON + AGE_REQ_ADULT, // SLOT_TRADE_ADULT + AGE_REQ_NONE, // SLOT_EMPTY_LEFT + AGE_REQ_NONE, // SLOT_BOTTLE_1 + AGE_REQ_NONE, // SLOT_BOTTLE_2 + AGE_REQ_NONE, // SLOT_BOTTLE_3 + AGE_REQ_NONE, // SLOT_BOTTLE_4 + AGE_REQ_NONE, // SLOT_EMPTY_RIGHT }; u8 gEquipAgeReqs[][4] = { From b9c0ad3c94c98358b1da85561baee6382cc7797e Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Wed, 20 Dec 2023 23:23:35 -0600 Subject: [PATCH 11/60] Fix save file init with new layout --- soh/soh/Enhancements/boss-rush/BossRush.cpp | 39 ++++++++++++--------- soh/soh/SaveManager.cpp | 19 +++++----- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/soh/soh/Enhancements/boss-rush/BossRush.cpp b/soh/soh/Enhancements/boss-rush/BossRush.cpp index e9d94c503ab..c109df4104c 100644 --- a/soh/soh/Enhancements/boss-rush/BossRush.cpp +++ b/soh/soh/Enhancements/boss-rush/BossRush.cpp @@ -13,7 +13,7 @@ typedef struct BossRushSetting { std::vector> choices; } BossRushSetting; -BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = { +BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = { { { "BOSSES:", "BOSSE:", "BOSS:" }, { @@ -309,7 +309,7 @@ void BossRush_InitSave() { // Set health uint16_t health = 16; - switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { + switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { case BR_CHOICE_HEARTS_7: health *= 7; break; @@ -351,39 +351,44 @@ void BossRush_InitSave() { } // Set items - std::array brItems = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, - ITEM_SLINGSHOT, ITEM_NONE, ITEM_NONE, ITEM_HOOKSHOT, ITEM_NONE, ITEM_NONE, - ITEM_BOOMERANG, ITEM_LENS, ITEM_NONE, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NONE, - ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, + std::array brItems = { + ITEM_NONE, ITEM_BOMB, ITEM_NONE, ITEM_NUT, ITEM_LENS, ITEM_NONE, + ITEM_NONE, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_NONE, ITEM_NONE, + ITEM_NONE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_NONE, ITEM_NONE, + ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, + ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_ARROW_LIGHT, }; if (gSaveContext.bossRushOptions[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { - brItems[9] = ITEM_LONGSHOT; + brItems[SLOT_HOOKSHOT] = ITEM_LONGSHOT; } switch (gSaveContext.bossRushOptions[BR_OPTIONS_BOTTLE]) { case BR_CHOICE_BOTTLE_EMPTY: - brItems[18] = ITEM_BOTTLE; + brItems[SLOT_BOTTLE_1] = ITEM_BOTTLE; break; case BR_CHOICE_BOTTLE_FAIRY: - brItems[18] = ITEM_FAIRY; + brItems[SLOT_BOTTLE_1] = ITEM_FAIRY; break; case BR_CHOICE_BOTTLE_REDPOTION: - brItems[18] = ITEM_POTION_RED; + brItems[SLOT_BOTTLE_1] = ITEM_POTION_RED; break; case BR_CHOICE_BOTTLE_GREENPOTION: - brItems[18] = ITEM_POTION_GREEN; + brItems[SLOT_BOTTLE_1] = ITEM_POTION_GREEN; break; case BR_CHOICE_BOTTLE_BLUEPOTION: - brItems[18] = ITEM_POTION_BLUE; + brItems[SLOT_BOTTLE_1] = ITEM_POTION_BLUE; break; default: break; } if (gSaveContext.bossRushOptions[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { - brItems[23] = ITEM_MASK_BUNNY; + brItems[SLOT_TRADE_CHILD] = ITEM_MASK_BUNNY; + } + + if (gSaveContext.bossRushOptions[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { + brItems[SLOT_BOOTS_HOVER] = ITEM_BOOTS_HOVER; } for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { @@ -391,12 +396,12 @@ void BossRush_InitSave() { } // Set consumable counts - std::array brAmmo = { 5, 5, 10, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + std::array brAmmo = { 0, 10, 0, 5, 0, 0, 0, 10, 0, 5, 0, 0, 0, 10, 0, 0 }; if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { - brAmmo = { 10, 20, 20, 30, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + brAmmo = { 0, 20, 0, 20, 0, 0, 0, 30, 0, 10, 0, 0, 0, 30, 0, 0 }; } else if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { - brAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + brAmmo = { 0, 40, 0, 40, 0, 0, 0, 50, 0, 30, 0, 0, 0, 50, 0, 0 }; } for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index d75b0b9898f..293c1b1dd21 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -692,7 +692,7 @@ void SaveManager::InitFileDebug() { // Inventory static std::array sItems = { - ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, + ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_WEIRD_EGG, ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, ITEM_NONE, ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_NONE, @@ -795,16 +795,17 @@ void SaveManager::InitFileMaxed() { gSaveContext.equips.equipment = 0x1122; // Inventory - static std::array sItems = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_ARROW_FIRE, ITEM_DINS_FIRE, - ITEM_SLINGSHOT, ITEM_OCARINA_TIME, ITEM_BOMBCHU, ITEM_LONGSHOT, ITEM_ARROW_ICE, ITEM_FARORES_WIND, - ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NAYRUS_LOVE, - ITEM_FAIRY, ITEM_FAIRY, ITEM_BUG, ITEM_FISH, ITEM_CLAIM_CHECK, ITEM_MASK_BUNNY, + static std::array sItems = { + ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, + ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_MASK_BUNNY, + ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, + ITEM_NONE, ITEM_FAIRY, ITEM_FAIRY, ITEM_BUG, ITEM_FISH, ITEM_NONE, + ITEM_OCARINA_TIME, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT, }; for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { gSaveContext.inventory.items[item] = sItems[item]; } - static std::array sAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 50, 0, 0, 0, 0, 0, 15, 0 }; + static std::array sAmmo = { 0, 40, 50, 40, 0, 10, 0, 50, 0, 30, 0, 0, 0, 50, 0, 0 }; for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { gSaveContext.inventory.ammo[ammo] = sAmmo[ammo]; } @@ -974,13 +975,13 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int se if (std::filesystem::exists(fileName)) { std::filesystem::remove(fileName); } - + #if defined(__SWITCH__) || defined(__WIIU__) copy_file(tempFile.c_str(), fileName.c_str()); #else std::filesystem::copy_file(tempFile, fileName); #endif - + if (std::filesystem::exists(tempFile)) { std::filesystem::remove(tempFile); } From e6d84e2ddeb242537963827e3ac8aec703e5c5e5 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Wed, 20 Dec 2023 23:50:10 -0600 Subject: [PATCH 12/60] Fix z_en_bom.h include capitalization --- soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c index db1f0fd13bb..f50448348ec 100644 --- a/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c +++ b/soh/src/overlays/actors/ovl_En_Arrow/z_en_arrow.c @@ -5,7 +5,7 @@ */ #include "z_en_arrow.h" -#include "overlays/actors/ovl_en_bom/z_en_bom.h" +#include "overlays/actors/ovl_En_Bom/z_en_bom.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_gi_nuts/object_gi_nuts.h" From ed831a81528eef1c3d6a0cd1ea4130d7e5cc4554 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 21 Dec 2023 00:12:34 -0600 Subject: [PATCH 13/60] Duplicate function in z_en_bom.c to remove implicit declaration --- soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c index 7d53d7942fb..a34ca45ddd2 100644 --- a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c +++ b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c @@ -528,6 +528,12 @@ void ArrowBomb_Charge(EnBom* this, PlayState* play) { } } +void ArrowBomb_80865ECC(Vec3f* unkPos, Vec3f* firePos, f32 scale) { + unkPos->x += ((firePos->x - unkPos->x) * scale); + unkPos->y += ((firePos->y - unkPos->y) * scale); + unkPos->z += ((firePos->z - unkPos->z) * scale); +} + void ArrowBomb_Fly(EnBom* this, PlayState* play) { EnArrow* arrow; f32 distanceScaled; @@ -545,7 +551,7 @@ void ArrowBomb_Fly(EnBom* this, PlayState* play) { if (distanceScaled < 1.0f) { this->unk_158 = 1.0f; } - func_80865ECC(&this->unkPos, &this->actor.world.pos, 0.05f); + ArrowBomb_80865ECC(&this->unkPos, &this->actor.world.pos, 0.05f); if (arrow->hitFlags & 1) { this->timer = 0; From 0d0d59ffc02a26382618870837e98381974c64ea Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 21 Dec 2023 08:26:22 -0600 Subject: [PATCH 14/60] Fix broken messages --- soh/src/code/z_message_PAL.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 7bb3803fcc6..96660c34161 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -470,8 +470,8 @@ void Message_DrawTextboxIcon(PlayState* play, Gfx** p, s16 x, s16 y) { sIconEnvColors[1] = color; } else if (CVarGetInteger("gCosmetics.DefaultColorScheme", COLORSCHEME_N64) == COLORSCHEME_GAMECUBE) { sIconPrimColors[0] = (Color_RGB8){ 0, 200, 80 }; - sIconPrimColors[1] = (Color_RGB8){ 50, 255, 130 }; - sIconEnvColors[1] = (Color_RGB8){ 50, 255, 130 }; + sIconPrimColors[1] = (Color_RGB8){ 50, 255, 130 }; + sIconEnvColors[1] = (Color_RGB8){ 50, 255, 130 }; } static Color_RGB8 sIconPrim = { 0, 80, 200 }; static s16 sIconFlashTimer = 12; @@ -1132,6 +1132,9 @@ void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { interfaceCtx->mapPalette[30] = 0xFF; interfaceCtx->mapPalette[31] = 0xFF; } + if (itemId > ITEM_BOW_ARROW_BOMB) { + itemId += 1; + } if (itemId < ITEM_MEDALLION_FOREST) { R_TEXTBOX_ICON_XPOS = R_TEXT_INIT_XPOS - sIconItem32XOffsets[gSaveContext.language]; R_TEXTBOX_ICON_YPOS = y + 6; @@ -3139,7 +3142,7 @@ void Message_Update(PlayState* play) { if (msgCtx->msgLength == 0) { return; } - + GameInteractor_ExecuteOnDialogMessage(); bool isB_Held = CVarGetInteger("gSkipText", 0) != 0 ? CHECK_BTN_ALL(input->cur.button, BTN_B) && !sTextboxSkipped From 426efee8622a1809406d1560678f87f6459374e6 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 21 Dec 2023 09:06:22 -0600 Subject: [PATCH 15/60] Fix broken custom messages --- soh/soh/Enhancements/custom-message/CustomMessageManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp index e552a9672d9..5309f7d6e41 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp @@ -105,7 +105,8 @@ void CustomMessage::Replace(std::string&& oldStr, std::string&& newEnglish, std: void CustomMessage::Format(ItemID iid) { for (std::string* str : { &english, &french, &german }) { - str->insert(0, ITEM_OBTAINED(iid)); + // HACK: this is so messed up + str->insert(0, ITEM_OBTAINED(iid > ITEM_BOW_ARROW_BOMB ? iid - 1 : iid)); size_t start_pos = 0; std::replace(str->begin(), str->end(), '&', NEWLINE()[0]); while ((start_pos = str->find('^', start_pos)) != std::string::npos) { @@ -253,7 +254,7 @@ bool CustomMessageManager::ClearMessageTable(std::string tableID) { return true; } -bool CustomMessageManager::AddCustomMessageTable(std::string tableID) { +bool CustomMessageManager::AddCustomMessageTable(std::string tableID) { CustomMessageTable newMessageTable; return messageTables.emplace(tableID, newMessageTable).second; } From d3f7e6d8716a833dc236c3e9a1fe6d198904ebbf Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sat, 23 Dec 2023 10:42:42 -0600 Subject: [PATCH 16/60] Fix Forest Medallion message box texture --- soh/src/code/z_message_PAL.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 96660c34161..1ab090ce661 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -1132,10 +1132,10 @@ void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { interfaceCtx->mapPalette[30] = 0xFF; interfaceCtx->mapPalette[31] = 0xFF; } - if (itemId > ITEM_BOW_ARROW_BOMB) { + if (itemId >= ITEM_BOW_ARROW_BOMB) { itemId += 1; } - if (itemId < ITEM_MEDALLION_FOREST) { + if (itemId - 1 < ITEM_MEDALLION_FOREST) { R_TEXTBOX_ICON_XPOS = R_TEXT_INIT_XPOS - sIconItem32XOffsets[gSaveContext.language]; R_TEXTBOX_ICON_YPOS = y + 6; R_TEXTBOX_ICON_SIZE = 32; From 605469798e1fd99b1b521fa96dc6f8762d958f42 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sat, 23 Dec 2023 12:19:14 -0600 Subject: [PATCH 17/60] S&Q: Restore save confirmation --- soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index c6e16daf499..84cc51ddb01 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -4076,7 +4076,7 @@ void KaleidoScope_Update(PlayState* play) Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Play_PerformSave(play); - pauseCtx->unk_1EC = CVarGetInteger("gSaveAndQuit", 0) ? 7 : 4; + pauseCtx->unk_1EC = 4; D_8082B25C = CVarGetInteger("gSkipSaveConfirmation", 0) ? 3 /* 0.1 sec */ : 90 /* 3 secs */; } } else if (CHECK_BTN_ALL(input->press.button, BTN_START) || From 607928e4884bb6acf773a8d7775085c185e30de9 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sat, 23 Dec 2023 12:24:02 -0600 Subject: [PATCH 18/60] S&Q: Don't switch back to confirmation screen --- soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 84cc51ddb01..7864091883f 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -1603,9 +1603,9 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC < 4 || pauseCtx->unk_1EC == 7 || - (CVarGetInteger("gSaveAndQuit", 0) && pauseCtx->unk_1EC == 5))) || + (CVarGetInteger("gSaveAndQuit", 0) && (pauseCtx->unk_1EC == 5 || pauseCtx->unk_1EC == 8)))) || (pauseCtx->state == 0xE)) { - if (pauseCtx->unk_1EC == 7 || pauseCtx->unk_1EC == 5) { + if (pauseCtx->unk_1EC == 5 || pauseCtx->unk_1EC == 7 || pauseCtx->unk_1EC == 8) { POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sContinuePromptTexs[gSaveContext.language], 152, 16, 0); } else { From 9f455c2d1e268f4969da3053306630f095d7ebe1 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sat, 23 Dec 2023 14:57:34 -0600 Subject: [PATCH 19/60] Use quest item cycle for magic arrows Not too happy with how this turned out, but will change later --- soh/include/z64.h | 4 +- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 299 ++++-------------- .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 10 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 35 +- 4 files changed, 61 insertions(+), 287 deletions(-) diff --git a/soh/include/z64.h b/soh/include/z64.h index 5cc757fd535..b431e312503 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -31,7 +31,7 @@ #include "ichain.h" #include "regs.h" -#if defined(__LP64__) +#if defined(__LP64__) #define _SOH64 #endif @@ -914,8 +914,6 @@ typedef struct { /* 0x0266 */ u8 worldMapPoints[20]; // 0 = hidden; 1 = displayed; 2 = highlighted /* 0x027A */ u8 tradeQuestLocation; /* 0x027C */ SkelAnime playerSkelAnime; - Vtx* arrowSelectVtx; - s16 arrowMenuAnimPos; } PauseContext; // size = 0x2C0 typedef enum { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index ea46340b59a..f2da22b6d85 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -31,9 +31,7 @@ static s16 sEquipAnimTimer = 0; static s16 sEquipMoveTimer = 10; bool gSelectingMask; bool gSelectingAdultTrade; - -ArrowMenuState gArrowMenuState; -static s16 sArrowMenuTimer = 0; +bool gSelectingArrow; /* Maps an inventory slot to double the position of its ammo count in sAmmoVtxTableIdx */ static s16 sAmmoVtxOffset[] = { @@ -261,215 +259,41 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 CLOSE_DISPS(play->state.gfxCtx); } -void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active) { - if (ARROW_SELECT_OPEN == active) - return; - - gArrowMenuState = AMS_CLOSING + active; - pauseCtx->arrowMenuAnimPos = 12; - sArrowMenuTimer = 2; -} - -void KaleidoScope_ArrowSelect(PlayState* play, u16 cursorSlot) { - PauseContext* pauseCtx = &play->pauseCtx; - if (cursorSlot != SLOT_BOW || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { - gArrowMenuState = AMS_DISABLED; - pauseCtx->arrowMenuAnimPos = 0; - sArrowMenuTimer = 0; - return; - } - - Input* input = &play->state.input[0]; - - // Allow changing arrows if: - // - Selecting bow slot and pressing A - // - You have an item in the bow slot and any magic arrow - if (CHECK_BTN_ALL(input->press.button, BTN_A) && - INV_CONTENT(ITEM_BOW) != ITEM_NONE && - (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE || - INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE || - INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE)) { - Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - KaleidoScope_SetArrowSelectActive(pauseCtx, !ARROW_SELECT_OPEN); - } - - if (!ARROW_SELECT_OPEN) { - return; - } - - pauseCtx->cursorColorSet = 8; - bool dpad = CVarGetInteger("gDpadPause", 0); - - // Select arrow with stick/d-pad - // Up = Fire - // Left = Ice - // Right = Light - // Down = Normal - u8 newBow = ITEM_NONE; - u16 arrowCursorSlot; - if (pauseCtx->stickRelY < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DDOWN))) { - newBow = ITEM_BOW; - arrowCursorSlot = cursorSlot + 6; - } else if (pauseCtx->stickRelY > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) { - newBow = (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE) ? ITEM_BOW_ARROW_FIRE : ITEM_NONE; - arrowCursorSlot = cursorSlot - 6; - } else if (pauseCtx->stickRelX < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) { - newBow = (INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE) ? ITEM_BOW_ARROW_ICE : ITEM_NONE; - arrowCursorSlot = cursorSlot - 1; - } else if (pauseCtx->stickRelX > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) { - newBow = (INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE) ? ITEM_BOW_ARROW_LIGHT : ITEM_NONE; - arrowCursorSlot = cursorSlot + 1; - } - - if (newBow == ITEM_NONE) { - return; - } +static u8 sBowArrowItems[] = {ITEM_BOW, ITEM_BOW_ARROW_FIRE, ITEM_BOW_ARROW_ICE, ITEM_BOW_ARROW_LIGHT}; +static u8 sArrowItems[] = {ITEM_BOW, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT}; - // If you double select an arrow, reset to normal - if (newBow == INV_CONTENT(ITEM_BOW)) { - newBow = ITEM_BOW; - - // If double selecting regular arrows, cancel - if (INV_CONTENT(ITEM_BOW) == ITEM_BOW) { - Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - KaleidoScope_SetArrowSelectActive(pauseCtx, false); - return; - } - } - - u16 sfxId; - if (newBow == ITEM_BOW || CVarGetInteger("gSkipArrowAnimation", 0)) { - sfxId = NA_SE_SY_DECIDE; - pauseCtx->equipTargetItem = newBow; - pauseCtx->equipAnimAlpha = 255; - sEquipState = ES_MAGIC_ARROW_APPLYING; +u8 KaleidoScope_GetNextBow() { + u8 currentBow = INV_CONTENT(ITEM_BOW); + u8 bowIndex; + if (currentBow == ITEM_BOW) { + bowIndex = 0; } else { - sfxId = NA_SE_SY_SET_FIRE_ARROW + (newBow - ITEM_BOW_ARROW_FIRE); - pauseCtx->equipTargetItem = 0xBF - ITEM_BOW_ARROW_FIRE + newBow; - pauseCtx->equipAnimAlpha = 0; - sEquipState = ES_MAGIC_ARROW_GLOWING; - } - - Audio_PlaySoundGeneral(sfxId, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - pauseCtx->equipAnimX = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[0] * 10; - pauseCtx->equipAnimY = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[1] * 10; - sEquipMoveTimer = 6; - sEquipAnimTimer = 0; - pauseCtx->unk_1E4 = 3; -} - -void KaleidoScope_BowMenuSetRect(PauseContext* pauseCtx, s16 xOffset, s16 yOffset, s16 size, u8 vtx) { - s16 bowCenterX = -64 + 16; - s16 bowCenterY = -6 - 16 + pauseCtx->offsetY; - s16 arrowCenterX = bowCenterX + xOffset; - s16 arrowCenterY = bowCenterY + yOffset; - s16 arrowX = arrowCenterX - size / 2; - s16 arrowY = arrowCenterY + size / 2; - - pauseCtx->arrowSelectVtx[vtx].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.ob[0] = arrowX; - pauseCtx->arrowSelectVtx[vtx + 1].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[0] = arrowX + size; - pauseCtx->arrowSelectVtx[vtx].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 1].v.ob[1] = arrowY; - pauseCtx->arrowSelectVtx[vtx + 2].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[1] = arrowY - size; -} - -void KaleidoScope_DrawBowMenuTexture(PlayState* play, s16 xOffset, s16 yOffset, s16 drawSize, u8 vtx, void* tex, u16 texSize) { - PauseContext* pauseCtx = &play->pauseCtx; - - KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, drawSize, vtx); - pauseCtx->arrowSelectVtx[vtx + 1].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.tc[1] = - pauseCtx->arrowSelectVtx[vtx + 3].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.tc[1] = texSize << 5; - - OPEN_DISPS(play->state.gfxCtx); - - gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); - KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, tex, texSize, texSize, 0); - - CLOSE_DISPS(play->state.gfxCtx); -} - -void KaleidoScope_DrawMagicArrowIcon(PlayState* play, s16 offset, u8 itemId) { - if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { - return; + bowIndex = currentBow - ITEM_BOW_ARROW_FIRE + 1; } - - s16 xOffset, yOffset, vtx; - char* source; - switch (itemId) { - case ITEM_ARROW_FIRE: - xOffset = 0; - yOffset = offset; - vtx = 0; - source = gFireArrowPowerTex; - break; - case ITEM_ARROW_ICE: - xOffset = -offset; - yOffset = 0; - vtx = 4; - source = gIceArrowPowerTex; - break; - case ITEM_ARROW_LIGHT: - xOffset = offset; - yOffset = 0; - vtx = 8; - source = gLightArrowPowerTex; - break; - default: - return; + for (int i = 1; i < ARRAY_COUNT(sBowArrowItems); i++) { + int index = (bowIndex + i) % ARRAY_COUNT(sBowArrowItems); + if (INV_CONTENT(sArrowItems[index] != ITEM_NONE)) { + return sBowArrowItems[index]; + } } - - KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 12, vtx, source, 16); + return ITEM_NONE; } -void KaleidoScope_DrawSelectableArrow(PlayState* play, s16 offset, u8 itemId) { - if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { - return; - } - - s16 xOffset, yOffset, vtx; - char* tex = gItemIcons[itemId]; - switch (itemId) { - case ITEM_ARROW_FIRE: - xOffset = 0; - yOffset = offset; - vtx = 0; - break; - case ITEM_ARROW_ICE: - xOffset = -offset; - yOffset = 0; - vtx = 4; - break; - case ITEM_ARROW_LIGHT: - xOffset = offset; - yOffset = 0; - vtx = 8; - break; - case ITEM_BOW: - xOffset = 0; - yOffset = -offset; - vtx = 12; - tex = gArrowIconTex; - break; - default: - return; +u8 KaleidoScope_GetPrevBow() { + u8 currentBow = INV_CONTENT(ITEM_BOW); + u8 bowIndex; + if (currentBow == ITEM_BOW) { + bowIndex = 0; + } else { + bowIndex = currentBow - ITEM_BOW_ARROW_FIRE + 1; } - - if (gArrowMenuState == AMS_ENABLED) { - PauseContext* pauseCtx = &play->pauseCtx; - OPEN_DISPS(play->state.gfxCtx); - gDPPipeSync(POLY_KAL_DISP++); - vtx += 16; - - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 0); - KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, 32, vtx); - gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); - POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); - - vtx -= 16; - CLOSE_DISPS(play->state.gfxCtx); + for (int i = ARRAY_COUNT(sBowArrowItems) - 1; i > 0; i--) { + int index = (bowIndex + i) % ARRAY_COUNT(sBowArrowItems); + if (INV_CONTENT(sArrowItems[index] != ITEM_NONE)) { + return sBowArrowItems[index]; + } } - - KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 28, vtx, tex, 32); + return ITEM_NONE; } void KaleidoScope_DrawItemSelect(PlayState* play) { @@ -502,6 +326,11 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) && Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD); + bool canArrowSelect = INV_CONTENT(ITEM_BOW) != ITEM_NONE && + (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE); + OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_42Opa(play->state.gfxCtx); @@ -512,7 +341,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->nameColorSet = 0; if ((pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM)) { - moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade || gSelectingArrow; oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorItem = pauseCtx->cursorItem[PAUSE_ITEM]; @@ -686,7 +515,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorSpecialPos == 0) { if (cursorItem != PAUSE_ITEM_NONE) { if ((ABS(pauseCtx->stickRelY) > 30) || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) { - moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade || gSelectingArrow; cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorY = pauseCtx->cursorY[PAUSE_ITEM]; @@ -813,8 +642,23 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT; } - - KaleidoScope_ArrowSelect(play, cursorSlot); + if (canArrowSelect && cursorSlot == SLOT_BOW && CHECK_BTN_ALL(input->press.button, BTN_A)) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + gSelectingArrow = !gSelectingArrow; + } + if (gSelectingArrow) { + pauseCtx->cursorColorSet = 8; + if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) || + dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP))) { + Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), KaleidoScope_GetNextBow()); + } else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) || + dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN))) { + Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), KaleidoScope_GetNextBow()); + } + gSelectingArrow = cursorSlot == SLOT_BOW; + } u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { @@ -925,38 +769,8 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_CHILD, gSelectingMask, canMaskSelect, childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); - - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - if (gArrowMenuState == AMS_DISABLED) { - s16 offset = 14; - KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_FIRE); - KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_ICE); - KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_LIGHT); - } else { - s16 offset; - if (gArrowMenuState == AMS_ENABLED) { - offset = 32; - } else { - offset = pauseCtx->arrowMenuAnimPos / sArrowMenuTimer; - pauseCtx->arrowMenuAnimPos -= offset; - if (gArrowMenuState == AMS_OPENING) { - offset = 32 - pauseCtx->arrowMenuAnimPos; - } else { - offset = 20 + pauseCtx->arrowMenuAnimPos; - } - } - - KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_FIRE); - KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_ICE); - KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_LIGHT); - KaleidoScope_DrawSelectableArrow(play, offset, ITEM_BOW); - - sArrowMenuTimer--; - - if (sArrowMenuTimer == 0) { - gArrowMenuState &= 1; - } - } + KaleidoScope_DrawItemCycleExtras(play, SLOT_BOW, gSelectingArrow, canArrowSelect, + KaleidoScope_GetPrevBow(), KaleidoScope_GetNextBow()); CLOSE_DISPS(play->state.gfxCtx); } @@ -966,7 +780,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, PauseContext* pauseCtx = &play->pauseCtx; gSelectingMask = false; gSelectingAdultTrade = false; - KaleidoScope_SetArrowSelectActive(pauseCtx, false); + gSelectingArrow = false; if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { pauseCtx->equipTargetCBtn = 0; @@ -1262,7 +1076,7 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE + magicArrowType; } Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), pauseCtx->equipTargetItem); - KaleidoScope_SetArrowSelectActive(pauseCtx, false); + gSelectingArrow = false; return; } @@ -1324,4 +1138,5 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { void KaleidoScope_ResetTradeSelect() { gSelectingMask = false; gSelectingAdultTrade = false; + gSelectingArrow = false; } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index 19caf918f2f..afbe40bc331 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -12,14 +12,7 @@ extern u8 gSlotAgeReqs[]; extern u8 gItemAgeReqs[]; extern u8 gAreaGsFlags[]; extern bool gSelectingMask; -typedef enum { - AMS_DISABLED, - AMS_ENABLED, - AMS_CLOSING, - AMS_OPENING -} ArrowMenuState; -extern ArrowMenuState gArrowMenuState; -#define ARROW_SELECT_OPEN (gArrowMenuState & 1) +extern bool gSelectingArrow; #define MAP_48x85_TEX_WIDTH 48 #define MAP_48x85_TEX_HEIGHT 85 @@ -53,7 +46,6 @@ void KaleidoScope_ProcessPlayerPreRender(); void KaleidoScope_SetupPlayerPreRender(PlayState* play); void KaleidoScope_DrawCursor(PlayState* play, u16 pageIndex); void KaleidoScope_UpdateDungeonMap(PlayState* play); -void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active); void PauseMapMark_Draw(PlayState* play); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 1db5ed1578f..5846654fdef 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -1009,7 +1009,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { s16 s; s16 i; gSelectingMask = false; - KaleidoScope_SetArrowSelectActive(pauseCtx, false); + gSelectingArrow = false; switch (pauseCtx->pageIndex) { case PAUSE_ITEM: @@ -1044,7 +1044,7 @@ void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) { pauseCtx->unk_1E4 = 1; pauseCtx->unk_1EA = 0; gSelectingMask = false; - KaleidoScope_SetArrowSelectActive(pauseCtx, false); + gSelectingArrow = false; if (!pt) { pauseCtx->mode = pauseCtx->pageIndex * 2 + 1; @@ -3101,34 +3101,6 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->saveVtx = Graph_Alloc(gfxCtx, 80 * sizeof(Vtx)); func_80823A0C(play, pauseCtx->saveVtx, 5, 5); - - pauseCtx->arrowSelectVtx = Graph_Alloc(gfxCtx, 32 * sizeof(Vtx)); - - // All arrow select vertices - for (phi_t2 = 0; phi_t2 < 32; phi_t2++) { - pauseCtx->arrowSelectVtx[phi_t2].v.flag = 0; - - // Z position - pauseCtx->arrowSelectVtx[phi_t2].v.ob[2] = 0; - - // Color - pauseCtx->arrowSelectVtx[phi_t2].v.cn[0] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[1] = - pauseCtx->arrowSelectVtx[phi_t2].v.cn[2] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[3] = 255; - } - - // All arrow select quads - for (phi_t2 = 0; phi_t2 < 32; phi_t2 += 4) { - // Top left UV at (0, 0); - pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[1] = - pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[1] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[0] = 0; - } - - // Background quads - for (phi_t2 = 16; phi_t2 < 32; phi_t2 += 4) { - // Bottom left UV at (32, 32) - pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[1] = - pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[1] = 0x400; - } } void KaleidoScope_DrawGameOver(PlayState* play) { @@ -4481,9 +4453,6 @@ void KaleidoScope_Update(PlayState* play) break; case 0x12: - // OTRTODO: move this somewhere it won't be called repeatedly for several frames - KaleidoScope_SetArrowSelectActive(pauseCtx, false); - if (pauseCtx->unk_1F4 != 160.0f) { pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 += 160.0f / WREG(6); pauseCtx->infoPanelOffsetY -= 40 / WREG(6); From 572b87b307e8541a558cfce99690ebec2b6791af Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Wed, 27 Dec 2023 17:55:38 -0600 Subject: [PATCH 20/60] Overhaul item menu rearrangement to be toggleable --- soh/include/variables.h | 2 +- soh/include/z64.h | 2 +- soh/include/z64item.h | 60 ++--- soh/include/z64save.h | 4 +- soh/soh/Enhancements/boss-rush/BossRush.cpp | 39 ++- .../controls/GameControlEditor.cpp | 3 +- .../cosmetics/CosmeticsEditor.cpp | 2 +- .../Enhancements/debugger/debugSaveEditor.cpp | 14 +- soh/soh/Enhancements/mods.cpp | 66 +++++ soh/soh/Enhancements/presets.h | 7 + soh/soh/OTRGlobals.cpp | 30 +-- soh/soh/SaveManager.cpp | 36 +-- soh/soh/SohMenuBar.cpp | 34 ++- soh/soh/z_message_OTR.cpp | 4 +- soh/src/code/code_80097A00.c | 4 +- soh/src/code/z_en_item00.c | 6 +- soh/src/code/z_parameter.c | 230 ++++++++-------- .../actors/ovl_Arms_Hook/z_arms_hook.c | 4 +- .../actors/ovl_player_actor/z_player.c | 75 ++++-- .../ovl_kaleido_scope/z_kaleido_equipment.c | 16 +- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 247 ++++++++++++------ .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 19 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 118 +++++++-- 23 files changed, 629 insertions(+), 393 deletions(-) diff --git a/soh/include/variables.h b/soh/include/variables.h index ce1a9dbec95..2bad8335c99 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -102,7 +102,7 @@ extern "C" extern void* gItemIcons[0x82]; extern u8 gItemAgeReqs[]; extern u8 gSlotAgeReqs[]; - extern u8 gItemSlots[71]; + extern u8 gItemSlots[56]; extern void (*gSceneCmdHandlers[SCENE_CMD_ID_MAX])(PlayState*, SceneCmd*); extern s16 gLinkObjectIds[2]; extern u32 gObjectTableSize; diff --git a/soh/include/z64.h b/soh/include/z64.h index b431e312503..23ffcfb1717 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -31,7 +31,7 @@ #include "ichain.h" #include "regs.h" -#if defined(__LP64__) +#if defined(__LP64__) #define _SOH64 #endif diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 9e58b460ea1..1fc919a45f6 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -116,38 +116,36 @@ typedef enum { } DungeonItem; typedef enum { - /* 0x00 */ SLOT_DINS_FIRE, - /* 0x01 */ SLOT_BOMB, - /* 0x02 */ SLOT_BOMBCHU, - /* 0x03 */ SLOT_NUT, - /* 0x04 */ SLOT_LENS, - /* 0x05 */ SLOT_BEAN, - /* 0x06 */ SLOT_FARORES_WIND, - /* 0x07 */ SLOT_SLINGSHOT, - /* 0x08 */ SLOT_BOOMERANG, - /* 0x09 */ SLOT_STICK, - /* 0x0A */ SLOT_BOOTS_HOVER, - /* 0x0B */ SLOT_TRADE_CHILD, - /* 0x0C */ SLOT_NAYRUS_LOVE, - /* 0x0D */ SLOT_BOW, - /* 0x0E */ SLOT_HOOKSHOT, + /* 0x00 */ SLOT_STICK, + /* 0x01 */ SLOT_NUT, + /* 0x02 */ SLOT_BOMB, + /* 0x03 */ SLOT_BOW, + /* 0x04 */ SLOT_ARROW_FIRE, + /* 0x05 */ SLOT_DINS_FIRE, + /* 0x06 */ SLOT_SLINGSHOT, + /* 0x07 */ SLOT_OCARINA, + /* 0x08 */ SLOT_BOMBCHU, + /* 0x09 */ SLOT_HOOKSHOT, + /* 0x0A */ SLOT_ARROW_ICE, + /* 0x0B */ SLOT_FARORES_WIND, + /* 0x0C */ SLOT_BOOMERANG, + /* 0x0D */ SLOT_LENS, + /* 0x0E */ SLOT_BEAN, /* 0x0F */ SLOT_HAMMER, - /* 0x10 */ SLOT_BOOTS_IRON, - /* 0x11 */ SLOT_TRADE_ADULT, - /* 0x12 */ SLOT_EMPTY_LEFT, - /* 0x13 */ SLOT_BOTTLE_1, - /* 0x14 */ SLOT_BOTTLE_2, - /* 0x15 */ SLOT_BOTTLE_3, - /* 0x16 */ SLOT_BOTTLE_4, - /* 0x17 */ SLOT_EMPTY_RIGHT, - /* 0x18 */ SLOT_OCARINA, - /* 0x19 */ SLOT_ARROW_FIRE, - /* 0x1A */ SLOT_ARROW_ICE, - /* 0x1B */ SLOT_ARROW_LIGHT, - /* 0x1C */ SLOT_TUNIC_KOKIRI, - /* 0x1D */ SLOT_TUNIC_GORON, - /* 0x1E */ SLOT_TUNIC_ZORA, - /* 0x1F */ SLOT_BOOTS_KOKIRI, + /* 0x10 */ SLOT_ARROW_LIGHT, + /* 0x11 */ SLOT_NAYRUS_LOVE, + /* 0x12 */ SLOT_BOTTLE_1, + /* 0x13 */ SLOT_BOTTLE_2, + /* 0x14 */ SLOT_BOTTLE_3, + /* 0x15 */ SLOT_BOTTLE_4, + /* 0x16 */ SLOT_TRADE_ADULT, + /* 0x17 */ SLOT_TRADE_CHILD, + /* 0x18 */ SLOT_TUNIC_KOKIRI, + /* 0x19 */ SLOT_TUNIC_GORON, + /* 0x1A */ SLOT_TUNIC_ZORA, + /* 0x1B */ SLOT_BOOTS_KOKIRI, + /* 0x1C */ SLOT_BOOTS_IRON, + /* 0x1D */ SLOT_BOOTS_HOVER, /* 0xFF */ SLOT_NONE = 0xFF } InventorySlot; diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 2c31fe672e1..c7bee045fc1 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -43,7 +43,7 @@ typedef struct { } ItemEquips; // size = 0x0A typedef struct { - /* 0x00 */ u8 items[28]; + /* 0x00 */ u8 items[24]; /* 0x18 */ s8 ammo[16]; /* 0x28 */ u16 equipment; // a mask where each nibble corresponds to a type of equipment `EquipmentType`, and each bit to an owned piece `EquipInv*` /* 0x2C */ u32 upgrades; @@ -389,7 +389,7 @@ typedef enum { typedef enum { /* 0 */ LINK_AGE_ADULT, - /* 1 */ LINK_AGE_CHILD, + /* 1 */ LINK_AGE_CHILD } LinkAge; diff --git a/soh/soh/Enhancements/boss-rush/BossRush.cpp b/soh/soh/Enhancements/boss-rush/BossRush.cpp index c109df4104c..e9d94c503ab 100644 --- a/soh/soh/Enhancements/boss-rush/BossRush.cpp +++ b/soh/soh/Enhancements/boss-rush/BossRush.cpp @@ -13,7 +13,7 @@ typedef struct BossRushSetting { std::vector> choices; } BossRushSetting; -BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = { +BossRushSetting BossRushOptions[BOSSRUSH_OPTIONS_AMOUNT] = { { { "BOSSES:", "BOSSE:", "BOSS:" }, { @@ -309,7 +309,7 @@ void BossRush_InitSave() { // Set health uint16_t health = 16; - switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { + switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { case BR_CHOICE_HEARTS_7: health *= 7; break; @@ -351,44 +351,39 @@ void BossRush_InitSave() { } // Set items - std::array brItems = { - ITEM_NONE, ITEM_BOMB, ITEM_NONE, ITEM_NUT, ITEM_LENS, ITEM_NONE, - ITEM_NONE, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_NONE, ITEM_NONE, - ITEM_NONE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_NONE, ITEM_NONE, - ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, - ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_ARROW_LIGHT, + std::array brItems = { + ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, + ITEM_SLINGSHOT, ITEM_NONE, ITEM_NONE, ITEM_HOOKSHOT, ITEM_NONE, ITEM_NONE, + ITEM_BOOMERANG, ITEM_LENS, ITEM_NONE, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NONE, + ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, }; if (gSaveContext.bossRushOptions[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { - brItems[SLOT_HOOKSHOT] = ITEM_LONGSHOT; + brItems[9] = ITEM_LONGSHOT; } switch (gSaveContext.bossRushOptions[BR_OPTIONS_BOTTLE]) { case BR_CHOICE_BOTTLE_EMPTY: - brItems[SLOT_BOTTLE_1] = ITEM_BOTTLE; + brItems[18] = ITEM_BOTTLE; break; case BR_CHOICE_BOTTLE_FAIRY: - brItems[SLOT_BOTTLE_1] = ITEM_FAIRY; + brItems[18] = ITEM_FAIRY; break; case BR_CHOICE_BOTTLE_REDPOTION: - brItems[SLOT_BOTTLE_1] = ITEM_POTION_RED; + brItems[18] = ITEM_POTION_RED; break; case BR_CHOICE_BOTTLE_GREENPOTION: - brItems[SLOT_BOTTLE_1] = ITEM_POTION_GREEN; + brItems[18] = ITEM_POTION_GREEN; break; case BR_CHOICE_BOTTLE_BLUEPOTION: - brItems[SLOT_BOTTLE_1] = ITEM_POTION_BLUE; + brItems[18] = ITEM_POTION_BLUE; break; default: break; } if (gSaveContext.bossRushOptions[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { - brItems[SLOT_TRADE_CHILD] = ITEM_MASK_BUNNY; - } - - if (gSaveContext.bossRushOptions[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { - brItems[SLOT_BOOTS_HOVER] = ITEM_BOOTS_HOVER; + brItems[23] = ITEM_MASK_BUNNY; } for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { @@ -396,12 +391,12 @@ void BossRush_InitSave() { } // Set consumable counts - std::array brAmmo = { 0, 10, 0, 5, 0, 0, 0, 10, 0, 5, 0, 0, 0, 10, 0, 0 }; + std::array brAmmo = { 5, 5, 10, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { - brAmmo = { 0, 20, 0, 20, 0, 0, 0, 30, 0, 10, 0, 0, 0, 30, 0, 0 }; + brAmmo = { 10, 20, 20, 30, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; } else if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { - brAmmo = { 0, 40, 0, 40, 0, 0, 0, 50, 0, 30, 0, 0, 0, 50, 0, 0 }; + brAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; } for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index 217ccc35c6e..3788dafa980 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -296,7 +296,8 @@ namespace GameControlEditor { UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); DrawHelpIcon("Equip items and equipment on the D-pad\nIf used with D-pad on Pause Screen, you must hold C-Up to equip instead of navigate"); UIWidgets::PaddedEnhancementCheckbox("Toggle minimap with D-pad down", "gMapOnDDown"); - DrawHelpIcon("Toggle the minimap by pressing down on the D-pad\nIf \"D-pad as Equip Items\" is enabled, equipping an item on D-pad down will prevent you from toggling the map"); + DrawHelpIcon("Toggle the minimap by pressing down on the D-pad\nIf \"D-pad as Equip Items\" is enabled, equipping an item on D-pad down will prevent " + "you from toggling the map, but you can clear the item on D-pad down by re-equipping it over itself."); window->EndGroupPanelPublic(0); } diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index a8a3d54acdb..f38a98a715b 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1328,7 +1328,7 @@ void Draw_Placements(){ ImGui::EndTable(); } } - if (ImGui::CollapsingHeader("DPad items position")) { + if ((CVarGetInteger("gDpadEquips",0) || CVarGetInteger("gAltItemMenu", 0)) && ImGui::CollapsingHeader("DPad items position")) { if (ImGui::BeginTable("tabledpaditems", 1, FlagsTable)) { ImGui::TableSetupColumn("DPad items settings", FlagsCell, TablesCellsWidth); Table_InitHeader(false); diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 66c8944c0f1..19ca9f96980 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -639,16 +639,12 @@ void DrawInventoryTab() { ImGui::Checkbox("Restrict to valid items", &restrictToValid); UIWidgets::InsertHelpHoverText("Restricts items and ammo to only what is possible to legally acquire in-game"); - for (int32_t y = 0; y < 5; y++) { + for (int32_t y = 0; y < 4; y++) { for (int32_t x = 0; x < 6; x++) { int32_t index = x + y * 6; static int32_t selectedIndex = -1; static const char* itemPopupPicker = "itemPopupPicker"; - if (index >= ARRAY_COUNT(gSaveContext.inventory.items)) { - break; - } - ImGui::PushID(index); if (x != 0) { @@ -1709,9 +1705,11 @@ void DrawPlayerTab() { ImGui::SameLine(); ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL); - ImGui::NewLine(); - ImGui::Text("Current D-pad Equips"); - ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working + if (CVarGetInteger("gDpadEquips", 0) || CVarGetInteger("gAltItemMenu", 0)) { + ImGui::NewLine(); + ImGui::Text("Current D-pad Equips"); + ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working + } if (CVarGetInteger("gDpadEquips", 0)) { ImGui::SameLine(); ImGui::InputScalar("D-pad Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[5], &one, NULL); diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 6692dd5c971..9a3108676d1 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1067,6 +1067,71 @@ void RegisterRandomizedEnemySizes() { }); } +void AltItemMenu_Update() { + if (CVarGetInteger("gAltItemMenu", 0)) { // Enabled: force equip ocarina on D-up and match equipped bow, if any + uint16_t targetCBtn = 3; + uint16_t targetButtonIndex = targetCBtn + 1; + for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); otherSlotIndex++) { + uint16_t otherButtonIndex = otherSlotIndex + 1; + if (otherSlotIndex == targetCBtn) { + continue; + } + + if (gSaveContext.equips.cButtonSlots[otherSlotIndex] == SLOT_OCARINA) { + // Assign the other button to the target's current item + if (gSaveContext.equips.buttonItems[targetButtonIndex] != ITEM_NONE) { + gSaveContext.equips.buttonItems[otherButtonIndex] = + gSaveContext.equips.buttonItems[targetButtonIndex]; + gSaveContext.equips.cButtonSlots[otherSlotIndex] = + gSaveContext.equips.cButtonSlots[targetCBtn]; + Interface_LoadItemIcon2(gPlayState, otherButtonIndex); + } else { + gSaveContext.equips.buttonItems[otherButtonIndex] = ITEM_NONE; + gSaveContext.equips.cButtonSlots[otherSlotIndex] = SLOT_NONE; + } + //break; // 'Assume there is only one possible pre-existing equip' + } + + if (gSaveContext.equips.cButtonSlots[otherSlotIndex] == SLOT_BOW) { + switch (gSaveContext.equips.buttonItems[otherButtonIndex]) { + case ITEM_BOW_ARROW_FIRE: + case ITEM_BOW_ARROW_ICE: + case ITEM_BOW_ARROW_LIGHT: + INV_CONTENT(ITEM_BOW) = gSaveContext.equips.buttonItems[otherButtonIndex]; + break; + } + } + } + + gSaveContext.equips.buttonItems[targetButtonIndex] = INV_CONTENT(ITEM_OCARINA_FAIRY); + gSaveContext.equips.cButtonSlots[targetCBtn] = SLOT_OCARINA; + Interface_LoadItemIcon1(gPlayState, targetButtonIndex); + } else { // Disabled: reset bow item to Fairy Bow if some magic arrow is equipped + switch (INV_CONTENT(ITEM_BOW)) { + case ITEM_BOW_ARROW_FIRE: + case ITEM_BOW_ARROW_ICE: + case ITEM_BOW_ARROW_LIGHT: + INV_CONTENT(ITEM_BOW) = ITEM_BOW; + break; + } + } +} + +void AltItemMenu_Register() { + static int altItemMenuOld = -1; + GameInteractor::Instance->RegisterGameHook([]() { + int altItemMenu = CVarGetInteger("gAltItemMenu", 0); + if (altItemMenu != altItemMenuOld) { + AltItemMenu_Update(); + } + altItemMenuOld = altItemMenu; + }); + + GameInteractor::Instance->RegisterGameHook([](int16_t _) { + AltItemMenu_Update(); + }); +} + void InitMods() { RegisterTTS(); RegisterInfiniteMoney(); @@ -1096,4 +1161,5 @@ void InitMods() { RegisterRandomizerSheikSpawn(); RegisterRandomizedEnemySizes(); NameTag_RegisterHooks(); + AltItemMenu_Register(); } diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 78712704cb0..22c9dd7db3d 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -173,6 +173,7 @@ const std::vector enhancementsCvars = { "gDisableCritWiggle", "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", + "gSeparateArrows", "gCustomizeShootingGallery", "gInstantShootingGalleryWin", "gConstantAdultGallery", @@ -625,6 +626,9 @@ const std::vector enhancedPresetEntries = { // Skip Magic Arrow Equip Animation PRESET_ENTRY_S32("gSkipArrowAnimation", 1), + // Equip arrows on multiple slots + PRESET_ENTRY_S32("gSeparateArrows", 1), + // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), @@ -746,6 +750,9 @@ const std::vector randomizerPresetEntries = { // Exit Market at Night PRESET_ENTRY_S32("gMarketSneak", 1), + // Equip arrows on multiple slots + PRESET_ENTRY_S32("gSeparateArrows", 1), + // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7ceee4215f3..f918416ece1 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -246,9 +246,9 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); - if (std::filesystem::exists(mqPath)) { + if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); - } + } std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); @@ -278,7 +278,7 @@ OTRGlobals::OTRGlobals() { ); }); OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end()); - std::unordered_set ValidHashes = { + std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, OOT_NTSC_US_MQ, @@ -865,7 +865,7 @@ void CheckSoHOTRVersion(std::string otrPath) { } // Checks the program version stored in the otr and compares the major value to soh -// For Windows/Mac/Linux if the version doesn't match, offer to +// For Windows/Mac/Linux if the version doesn't match, offer to void DetectOTRVersion(std::string fileName, bool isMQ) { bool isOtrOld = false; std::string otrPath = LUS::Context::LocateFileAcrossAppDirs(fileName, appShortName); @@ -1049,7 +1049,7 @@ extern "C" void InitOTR() { SpeechSynthesizer::Instance = new SAPISpeechSynthesizer(); SpeechSynthesizer::Instance->Init(); #endif - + clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); OTRAudio_Init(); @@ -1084,7 +1084,7 @@ extern "C" void InitOTR() { } #endif - std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); + std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RunVersionUpdates(); @@ -1520,11 +1520,11 @@ std::shared_ptr GetResourceByNameHandlingMQ(const char* path) { extern "C" char* GetResourceDataByNameHandlingMQ(const char* path) { auto res = GetResourceByNameHandlingMQ(path); - + if (res == nullptr) { return nullptr; } - + return (char*)res->GetRawPointer(); } @@ -1611,7 +1611,7 @@ extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); - + return nullptr; } @@ -2185,10 +2185,10 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { extern "C" int Controller_ShouldRumble(size_t slot) { auto controlDeck = LUS::Context::GetInstance()->GetControlDeck(); - + if (slot < controlDeck->GetNumConnectedPorts()) { auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot); - + if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) { return 1; } @@ -2410,7 +2410,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { Player_GetMask(play) == PLAYER_MASK_TRUTH) || (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == RO_GOSSIP_STONES_NEED_STONE && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { - Actor* stone = GET_PLAYER(play)->targetActor; + Actor* stone = GET_PLAYER(play)->targetActor; actorParams = stone->params; // if we're in a generic grotto @@ -2446,7 +2446,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF); } } else if (textId == TEXT_SHEIK_NEED_HOOK || textId == TEXT_SHEIK_HAVE_HOOK) { - messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); + messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) } else if (textId >= TEXT_SCRUB_RANDOM && textId <= TEXT_SCRUB_RANDOM + NUM_SCRUBS) { RandomizerInf randoInf = (RandomizerInf)((textId - TEXT_SCRUB_RANDOM) + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT); @@ -2552,7 +2552,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger("gMarketSneak", 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT); } - if (textId >= TEXT_FIRE_ARROW && textId <= TEXT_LIGHT_ARROW) { + if (textId >= TEXT_FIRE_ARROW && textId <= TEXT_LIGHT_ARROW && CVarGetInteger("gAltItemMenu", 0)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); } font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition(); @@ -2610,7 +2610,7 @@ void SoH_ProcessDroppedFiles(std::string filePath) { nlohmann::json configJson; configStream >> configJson; - // #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer + // #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer if (configJson.contains("version") && configJson.contains("finalSeed")) { CVarSetString("gRandomizerDroppedFile", filePath.c_str()); CVarSetInteger("gRandomizerNewFileDropped", 1); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 293c1b1dd21..e61cf922354 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -662,8 +662,6 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots); button++) { gSaveContext.childEquips.cButtonSlots[button] = SLOT_NONE; } - gSaveContext.childEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; - gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.childEquips.equipment = 0; for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); button++) { gSaveContext.adultEquips.buttonItems[button] = ITEM_NONE; @@ -671,8 +669,6 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots); button++) { gSaveContext.adultEquips.cButtonSlots[button] = SLOT_NONE; } - gSaveContext.adultEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; - gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.adultEquips.equipment = 0; gSaveContext.unk_54 = 0; gSaveContext.savedSceneNum = 0x51; @@ -686,22 +682,19 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) { gSaveContext.equips.cButtonSlots[button] = sCButtonSlots[button]; } - gSaveContext.equips.buttonItems[4] = ITEM_OCARINA_FAIRY; - gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.equips.equipment = 0x1122; // Inventory - static std::array sItems = { - ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, - ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_WEIRD_EGG, - ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, - ITEM_NONE, ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_NONE, - ITEM_OCARINA_FAIRY, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT + static std::array sItems = { + ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_ARROW_FIRE, ITEM_DINS_FIRE, + ITEM_SLINGSHOT, ITEM_OCARINA_FAIRY, ITEM_BOMBCHU, ITEM_HOOKSHOT, ITEM_ARROW_ICE, ITEM_FARORES_WIND, + ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NAYRUS_LOVE, + ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_POCKET_EGG, ITEM_WEIRD_EGG, }; for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { gSaveContext.inventory.items[item] = sItems[item]; } - static std::array sAmmo = { 1, 20, 50, 20, 1, 10, 1, 30, 1, 10, 1, 1, 1, 30, 1, 1 }; + static std::array sAmmo = { 50, 50, 10, 30, 1, 1, 30, 1, 50, 1, 1, 1, 1, 1, 1, 1 }; for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { gSaveContext.inventory.ammo[ammo] = sAmmo[ammo]; } @@ -795,17 +788,16 @@ void SaveManager::InitFileMaxed() { gSaveContext.equips.equipment = 0x1122; // Inventory - static std::array sItems = { - ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, - ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_MASK_BUNNY, - ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, - ITEM_NONE, ITEM_FAIRY, ITEM_FAIRY, ITEM_BUG, ITEM_FISH, ITEM_NONE, - ITEM_OCARINA_TIME, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT, + static std::array sItems = { + ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_ARROW_FIRE, ITEM_DINS_FIRE, + ITEM_SLINGSHOT, ITEM_OCARINA_TIME, ITEM_BOMBCHU, ITEM_LONGSHOT, ITEM_ARROW_ICE, ITEM_FARORES_WIND, + ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NAYRUS_LOVE, + ITEM_FAIRY, ITEM_FAIRY, ITEM_BUG, ITEM_FISH, ITEM_CLAIM_CHECK, ITEM_MASK_BUNNY, }; for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { gSaveContext.inventory.items[item] = sItems[item]; } - static std::array sAmmo = { 0, 40, 50, 40, 0, 10, 0, 50, 0, 30, 0, 0, 0, 50, 0, 0 }; + static std::array sAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 50, 0, 0, 0, 0, 0, 15, 0 }; for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { gSaveContext.inventory.ammo[ammo] = sAmmo[ammo]; } @@ -975,13 +967,13 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int se if (std::filesystem::exists(fileName)) { std::filesystem::remove(fileName); } - + #if defined(__SWITCH__) || defined(__WIIU__) copy_file(tempFile.c_str(), fileName.c_str()); #else std::filesystem::copy_file(tempFile, fileName); #endif - + if (std::filesystem::exists(tempFile)) { std::filesystem::remove(tempFile); } diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 359a90a0928..5a30d5657ae 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -606,6 +606,10 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); + bool disableSeparateArrows = CVarGetInteger("gAltItemMenu", 0); + static const char* disableSeparateArrowsText = "This setting is diabled because \"Rearrange Item Menu\" is on."; + UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false, disableSeparateArrows, disableSeparateArrowsText); + UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); @@ -856,6 +860,10 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble"); UIWidgets::PaddedEnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots", true, false); UIWidgets::Tooltip("Allows equipping the tunic and boots to c-buttons"); + UIWidgets::PaddedEnhancementCheckbox("Rearrange Item Menu", "gAltItemMenu", true, false); + UIWidgets::Tooltip("Change the organization of the item subscreen so that boots behave as regular items without the need for " + "\"Assignable Tunics and Boots\". Magic arrows are now accessed from the bow's slot, and the ocarina is always " + "equipped on D-pad up."); UIWidgets::PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false); UIWidgets::Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen."); UIWidgets::PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false); @@ -876,7 +884,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -885,7 +893,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -1062,8 +1070,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1396,12 +1404,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndDisabled(); @@ -1581,12 +1589,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1642,4 +1650,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index cfe92df1907..fe4c65cefb8 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -13,14 +13,14 @@ extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr; extern "C" MessageTableEntry* sFraMessageEntryTablePtr; extern "C" MessageTableEntry* sStaffMessageEntryTablePtr; -//extern "C" MessageTableEntry* _message_0xFFFC_nes; +//extern "C" MessageTableEntry* _message_0xFFFC_nes; MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { auto file = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(filePath)); if (file == nullptr) return nullptr; - + // Allocate room for an additional message // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table is // already null. diff --git a/soh/src/code/code_80097A00.c b/soh/src/code/code_80097A00.c index 4068117e7c8..eb83738e360 100644 --- a/soh/src/code/code_80097A00.c +++ b/soh/src/code/code_80097A00.c @@ -180,9 +180,7 @@ u8 gItemSlots[] = { SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, - SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_BOW, SLOT_BOW, SLOT_BOW, SLOT_NONE, - SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, - SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_BOOTS_IRON, SLOT_BOOTS_HOVER, + SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, }; void Inventory_ChangeEquipment(s16 equipment, u16 value) { diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 87c43f98af0..de5b91d8a85 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -1373,7 +1373,7 @@ void EnItem00_DrawCollectible(EnItem00* this, PlayState* play) { Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } - + f32 mtxScale = 10.67f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); EnItem00_CustomItemsParticles(&this->actor, play, this->randoGiEntry); @@ -1534,7 +1534,7 @@ s16 func_8001F404(s16 dropId) { } } - if ((CVarGetInteger("gBombchuDrops", 0) || + if ((CVarGetInteger("gBombchuDrops", 0) || (IS_RANDO && Randomizer_GetSettingValue(RSK_ENABLE_BOMBCHU_DROPS) == 1)) && (dropId == ITEM00_BOMBS_A || dropId == ITEM00_BOMBS_B || dropId == ITEM00_BOMBS_SPECIAL)) { dropId = EnItem00_ConvertBombDropToBombchu(dropId); @@ -1614,7 +1614,7 @@ EnItem00* Item_DropCollectible2(PlayState* play, Vec3f* spawnPos, s16 params) { params &= 0x3FFF; if ((params & 0x00FF) == ITEM00_HEART && CVarGetInteger("gNoHeartDrops", 0)) { return NULL; } - + if (((params & 0x00FF) == ITEM00_FLEXIBLE) && !param4000) { // TODO: Prevent the cast to EnItem00 here since this is a different actor (En_Elf) spawnedActor = (EnItem00*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELF, spawnPos->x, diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 54326cbce95..97af52105ce 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1441,7 +1441,7 @@ void Inventory_SwapAgeEquipment(void) { u16 shieldEquipValue; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (i != 0) { @@ -1472,7 +1472,6 @@ void Inventory_SwapAgeEquipment(void) { Flags_SetInfTable(INFTABLE_SWORDLESS); } - // Nuts on C-left (if present) if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) { gSaveContext.equips.buttonItems[1] = ITEM_NUT; gSaveContext.equips.cButtonSlots[0] = SLOT_NUT; @@ -1480,32 +1479,27 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] = ITEM_NONE; } - // Bombs on C-down gSaveContext.equips.buttonItems[2] = ITEM_BOMB; + gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; - - // Nothing on C-right - gSaveContext.equips.buttonItems[3] = ITEM_NONE; - gSaveContext.equips.cButtonSlots[2] = ITEM_NONE; - + gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; + gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) | (EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) | (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) | (EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4)); - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.equips.buttonItems[0] == ITEM_NONE) { gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); } - // Ocarina on D-up - gSaveContext.equips.buttonItems[4] = gSaveContext.inventory.items[SLOT_OCARINA]; - gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; - - // Set the rest of the d-pad to nothing + // Set the dpad to nothing + gSaveContext.equips.buttonItems[4] = ITEM_NONE; gSaveContext.equips.buttonItems[5] = ITEM_NONE; gSaveContext.equips.buttonItems[6] = ITEM_NONE; gSaveContext.equips.buttonItems[7] = ITEM_NONE; + gSaveContext.equips.cButtonSlots[3] = SLOT_NONE; gSaveContext.equips.cButtonSlots[4] = SLOT_NONE; gSaveContext.equips.cButtonSlots[5] = SLOT_NONE; gSaveContext.equips.cButtonSlots[6] = SLOT_NONE; @@ -1834,14 +1828,14 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { /** * @brief Adds the given item to Link's inventory. - * + * * NOTE: This function has been edited to be safe to use with a NULL play. * If you need to add to this function, be sure you check if the play is not * NULL before doing any operations requiring it. - * - * @param play - * @param item - * @return u8 + * + * @param play + * @param item + * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { lusprintf(__FILE__, __LINE__, 2, "Item Give - item: %#x", item); @@ -1922,10 +1916,10 @@ u8 Item_Give(PlayState* play, u8 item) { // In rando, when buying Giant's Knife, also check // without the Koriri Sword in case we don't have it - if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_KOKIRI) | (1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | - (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || - (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || + (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)))) { gSaveContext.inventory.equipment ^= OWNED_EQUIP_FLAG_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); @@ -1937,7 +1931,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - + } else if (item == ITEM_SWORD_MASTER) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); @@ -1956,9 +1950,6 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item >= ITEM_BOOTS_KOKIRI) && (item <= ITEM_BOOTS_HOVER)) { gSaveContext.inventory.equipment |= OWNED_EQUIP_FLAG(EQUIP_TYPE_BOOTS, item - ITEM_BOOTS_KOKIRI); - if (item != ITEM_BOOTS_KOKIRI) { - INV_CONTENT(item) = item; - } return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) { gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS]; @@ -2229,14 +2220,6 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_SEEDS); } else if (item == ITEM_OCARINA_FAIRY) { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; - - gSaveContext.equips.buttonItems[4] = item; - gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; - gSaveContext.childEquips.buttonItems[4] = item; - gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; - gSaveContext.adultEquips.buttonItems[4] = item; - gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; - return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_OCARINA_TIME) { INV_CONTENT(ITEM_OCARINA_TIME) = ITEM_OCARINA_TIME; @@ -2688,7 +2671,7 @@ u8 Item_CheckObtainability(u8 item) { return ITEM_NONE; } } - + if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { return ITEM_NONE; } else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) { @@ -2952,7 +2935,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); } - if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { return 0; } @@ -2991,7 +2974,7 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l } doAction = newName[loadOffset]; } - + char* segment = interfaceCtx->doActionSegment[loadOffset]; interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; @@ -3058,7 +3041,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { } interfaceCtx->unk_1FC = action; - + char* segment = interfaceCtx->doActionSegment[1]; interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); @@ -3083,7 +3066,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3152,7 +3135,7 @@ void Rupees_ChangeBy(s16 rupeeChange) { void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { - switch (item) { + switch (item) { case ITEM_STICK: gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; @@ -3496,7 +3479,7 @@ void Interface_UpdateMagicBar(PlayState* play) { (msgCtx->msgMode == MSGMODE_NONE) && (play->gameOverCtx.state == GAMEOVER_INACTIVE) && (play->sceneLoadFlag == 0) && (play->transitionMode == 0) && !Play_InCsMode(play)) { bool hasLens = false; - for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0)) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 5; buttonIndex++) { + for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0) != 0) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 4; buttonIndex++) { if (gSaveContext.equips.buttonItems[buttonIndex] == ITEM_LENS) { hasLens = true; break; @@ -4338,7 +4321,7 @@ void Interface_DrawItemButtons(PlayState* play) { G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, (C_Up_BTN_Pos[0]-LabelX_Navi + 32) << 2, (C_Up_BTN_Pos[1]+LabelY_Navi + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -4456,7 +4439,7 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, cRightButtonColor.r, cRightButtonColor.g, cRightButtonColor.b, interfaceCtx->cRightAlpha); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, ItemIconPos[temp-1][0], ItemIconPos[temp-1][1], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][1], ItemIconWidthFactor[temp-1][1]); @@ -4531,8 +4514,8 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; u16 ItemsSlotsAlpha[8] = { @@ -4915,11 +4898,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, ItemIconPos[button][0], ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, ItemIconPos[button][0] + 6, ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } @@ -5424,7 +5407,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5508,83 +5491,86 @@ void Interface_Draw(PlayState* play) { Interface_DrawAmmoCount(play, 3, interfaceCtx->cRightAlpha); } - // DPad is only greyed-out when all 4 DPad directions are too - uint16_t dpadAlpha = - MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), - interfaceCtx->dpadRightAlpha); - - // Draw DPad - s16 DpadPosX; - s16 DpadPosY; - s16 X_Margins_Dpad; - s16 Y_Margins_Dpad; - if (CVarGetInteger("gDPadUseMargins", 0) != 0) { - if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; - Y_Margins_Dpad = (Top_HUD_Margin*-1); - } else { - Y_Margins_Dpad = 0; - X_Margins_Dpad = 0; - } - if (CVarGetInteger("gDPadPosType", 0) != 0) { - DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; - if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None - DpadPosX = CVarGetInteger("gDPadPosX", 0); - } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden - DpadPosX = -9999; + bool altItemMenu = CVarGetInteger("gAltItemMenu", 0); + bool dpadEquips = CVarGetInteger("gDpadEquips", 0); + if (dpadEquips || altItemMenu) { + // DPad is only greyed-out when all 4 DPad directions are too + uint16_t dpadAlpha = + MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), + interfaceCtx->dpadRightAlpha); + + // Draw DPad + s16 DpadPosX; + s16 DpadPosY; + s16 X_Margins_Dpad; + s16 Y_Margins_Dpad; + if (CVarGetInteger("gDPadUseMargins", 0) != 0) { + if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; + Y_Margins_Dpad = (Top_HUD_Margin*-1); + } else { + Y_Margins_Dpad = 0; + X_Margins_Dpad = 0; + } + if (CVarGetInteger("gDPadPosType", 0) != 0) { + DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; + if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None + DpadPosX = CVarGetInteger("gDPadPosX", 0); + } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden + DpadPosX = -9999; + } + } else { + DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); + DpadPosY = DPAD_Y+Y_Margins_Dpad; } - } else { - DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); - DpadPosY = DPAD_Y+Y_Margins_Dpad; - } - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); - if (fullUi) { - gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, - G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, - (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, - G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); + if (fullUi) { + gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, + G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, + (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); + } } - bool dpadEquips = CVarGetInteger("gDpadEquips", 0); + if (dpadEquips || altItemMenu) { + // DPad-Up Button Icon & Ammo Count + if (gSaveContext.equips.buttonItems[4] < 0xF0) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); + } - // DPad-Up Button Icon & Ammo Count - // Ocarina is perma-mapped to D-up, so that part has to be drawn - if (gSaveContext.equips.buttonItems[4] < 0xF0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); - } - - // DPad-Down Button Icon & Ammo Count - bool itemOnDpad = dpadEquips && gSaveContext.equips.buttonItems[5] < 0xF0; - bool dpadMap = fullUi && CVarGetInteger("gMapOnDDown", 0) && - play->pauseCtx.state < 4 && - ((play->sceneNum >= SCENE_DEKU_TREE && play->sceneNum <= SCENE_ICE_CAVERN) || - (play->sceneNum >= SCENE_HYRULE_FIELD && play->sceneNum <= SCENE_OUTSIDE_GANONS_CASTLE)); - if (itemOnDpad || dpadMap) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - void* texture = gItemIcons[itemOnDpad ? gSaveContext.equips.buttonItems[5] : ITEM_DUNGEON_MAP]; - Interface_DrawItemIconTexture(play, texture, 5); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - if (itemOnDpad) { - Interface_DrawAmmoCount(play, 5, interfaceCtx->dpadDownAlpha); + // DPad-Down Button Icon & Ammo Count + bool itemOnDpad = dpadEquips && gSaveContext.equips.buttonItems[5] < 0xF0; + bool dpadMap = fullUi && CVarGetInteger("gMapOnDDown", 0) && + play->pauseCtx.state < 4 && + ((play->sceneNum >= SCENE_DEKU_TREE && play->sceneNum <= SCENE_ICE_CAVERN) || + (play->sceneNum >= SCENE_HYRULE_FIELD && play->sceneNum <= SCENE_OUTSIDE_GANONS_CASTLE)); + if (itemOnDpad || dpadMap) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + void* texture = gItemIcons[itemOnDpad ? gSaveContext.equips.buttonItems[5] : ITEM_DUNGEON_MAP]; + Interface_DrawItemIconTexture(play, texture, 5); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + if (itemOnDpad) { + Interface_DrawAmmoCount(play, 5, interfaceCtx->dpadDownAlpha); + } } } @@ -5753,7 +5739,7 @@ void Interface_Draw(PlayState* play) { CarrotsPosY = CVarGetInteger("gCarrotsPosY", 0); if (CVarGetInteger("gCarrotsPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Left_HUD_Margin;}; - CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); + CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); } else if (CVarGetInteger("gCarrotsPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Right_HUD_Margin;}; CarrotsPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); @@ -6263,7 +6249,7 @@ void Interface_Draw(PlayState* play) { for (svar1 = 0; svar1 < 5; svar1++) { // clang-format off //svar5 = svar5 + 8; - //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); + //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, digitTextures[timerDigits[svar1]], 8, 16, svar5 + timerDigitLeftPos[svar1], svar2, digitWidth[svar1], VREG(42), VREG(43) << 1, @@ -6407,7 +6393,7 @@ void Interface_Update(PlayState* play) { Left_HUD_Margin = CVarGetInteger("gHUDMargin_L", 0); Right_HUD_Margin = CVarGetInteger("gHUDMargin_R", 0); Bottom_HUD_Margin = CVarGetInteger("gHUDMargin_B", 0); - + GameInteractor_ExecuteOnInterfaceUpdate(); if (CHECK_BTN_ALL(debugInput->press.button, BTN_DLEFT)) { diff --git a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c index cf011c07064..93ff272f4d9 100644 --- a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c +++ b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c @@ -257,9 +257,9 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) { sp60.x = this->unk_1F4.x - (this->unk_1E8.x - this->unk_1F4.x); sp60.y = this->unk_1F4.y - (this->unk_1E8.y - this->unk_1F4.y); sp60.z = this->unk_1F4.z - (this->unk_1E8.z - this->unk_1F4.z); - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (BgCheck_EntityLineTest1(&play->colCtx, &sp60, &this->unk_1E8, &sp78, &poly, true, true, true, true, &bgId) && diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index ec60d8599d3..77b5e65680a 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2029,7 +2029,15 @@ s32 func_80833C98(s32 item1, s32 actionParam) { } s32 func_80833CDC(PlayState* play, s32 index) { - if (index >= ((CVarGetInteger("gDpadEquips", 0) != 0) ? 8 : 5)) { + int buttons; + if (CVarGetInteger("gDpadEquips", 0)) { + buttons = 8; + } else if (CVarGetInteger("gAltItemMenu", 0)) { + buttons = 5; + } else { + buttons = 4; + } + if (index >= buttons) { return ITEM_NONE; } else if (play->bombchuBowlingStatus != 0) { return (play->bombchuBowlingStatus > 0) ? ITEM_BOMBCHU : ITEM_NONE; @@ -2062,7 +2070,7 @@ void func_80833DF8(Player* this, PlayState* play) { s32 maskItem = this->currentMask - PLAYER_MASK_KEATON + ITEM_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 5; buttonIndex < 8; buttonIndex++) { + for (int buttonIndex = 4; buttonIndex < 8; buttonIndex++) { hasOnDpad |= gSaveContext.equips.buttonItems[buttonIndex] == maskItem; } } @@ -2077,7 +2085,7 @@ void func_80833DF8(Player* this, PlayState* play) { maskActionParam = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 0; buttonIndex < 5; buttonIndex++) { + for (int buttonIndex = 0; buttonIndex < 4; buttonIndex++) { hasOnDpad |= func_80833C98(DPAD_ITEM(buttonIndex), maskActionParam); } } @@ -2088,8 +2096,8 @@ void func_80833DF8(Player* this, PlayState* play) { } } - // Since boots are items now, take them off if not equipped on a button - if (this->currentBoots != PLAYER_BOOTS_KOKIRI) { + // Alt item menu: Since boots are items, take them off if not equipped on a button + if (CVarGetInteger("gAltItemMenu", 0) && this->currentBoots != PLAYER_BOOTS_KOKIRI) { s32 bootsItemAction = this->currentBoots + PLAYER_IA_BOOTS_KOKIRI; bool hasOnCBtn = false; @@ -2494,9 +2502,12 @@ s32 func_80834E44(PlayState* play) { } s32 func_80834E7C(PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + if (CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } return (play->shootingGalleryStatus != 0) && ((play->shootingGalleryStatus < 0) || CHECK_BTN_ANY(sControlInput->cur.button, buttonsToCheck)); @@ -4956,7 +4967,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5400,7 +5411,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6128,8 +6139,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6372,8 +6383,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -6504,9 +6515,12 @@ s32 func_8083EAF0(Player* this, Actor* actor) { } s32 func_8083EB44(Player* this, PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + if (CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) && (this->heldActor != NULL) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -7781,7 +7795,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -8568,9 +8582,12 @@ void func_8084411C(Player* this, PlayState* play) { if (this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) { Actor* heldActor = this->heldActor; - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + if (CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (!func_80835644(play, this, heldActor) && (heldActor->id == ACTOR_EN_NIW) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -9350,7 +9367,10 @@ void func_80846260(Player* this, PlayState* play) { return; } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + if (CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } if (CVarGetInteger("gDpadEquips", 0) != 0) { buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } @@ -11216,7 +11236,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11267,7 +11287,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -11619,9 +11639,12 @@ void func_8084B1D8(Player* this, PlayState* play) { func_80836670(this, play); } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + if (CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->csMode != 0) || (this->unk_6AD == 0) || (this->unk_6AD >= 4) || func_80833B54(this) || (this->unk_664 != NULL) || !func_8083AD4C(play, this) || @@ -13598,7 +13621,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -15025,7 +15048,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15034,7 +15057,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index 3a460d94e82..939030f99d3 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -181,6 +181,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP)); bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) || (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON); + bool altItems = CVarGetInteger("gAltItemMenu", 0); OPEN_DISPS(play->state.gfxCtx); @@ -188,7 +189,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, ZREG(39), ZREG(40), ZREG(41), pauseCtx->alpha); gDPSetEnvColor(POLY_KAL_DISP++, ZREG(43), ZREG(44), ZREG(45), 0); - for (i = 0, j = 64; i < 3; i++, j += 4) { + for (i = 0, j = 64; i < (altItems ? 3 : 4); i++, j += 4) { if (CUR_EQUIP_VALUE(i) != 0) { gDPPipeSync(POLY_KAL_DISP++); gSPVertex(POLY_KAL_DISP++, &pauseCtx->equipVtx[j], 4, 0); @@ -221,7 +222,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorPoint[PAUSE_EQUIP] -= 1; // Kokiri tunic -> scale - if (pauseCtx->cursorY[PAUSE_EQUIP] == 2 && pauseCtx->cursorX[PAUSE_EQUIP] == 0) { + if (altItems && pauseCtx->cursorY[PAUSE_EQUIP] == 2 && pauseCtx->cursorX[PAUSE_EQUIP] == 0) { pauseCtx->cursorY[PAUSE_EQUIP] += 1; pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; } @@ -268,7 +269,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { // Strength -> Deku shield // Scale -> Kokiri tunic - if (pauseCtx->cursorX[PAUSE_EQUIP] == 1 && pauseCtx->cursorY[PAUSE_EQUIP] >= 2) { + if (altItems && pauseCtx->cursorX[PAUSE_EQUIP] == 1 && pauseCtx->cursorY[PAUSE_EQUIP] >= 2) { pauseCtx->cursorY[PAUSE_EQUIP] -= 1; pauseCtx->cursorPoint[PAUSE_EQUIP] -= 4; } @@ -342,7 +343,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; // Tunics -> scale - if (pauseCtx->cursorY[PAUSE_EQUIP] == 3 && pauseCtx->cursorX[PAUSE_EQUIP] > 0) { + if (altItems && pauseCtx->cursorY[PAUSE_EQUIP] == 3 && pauseCtx->cursorX[PAUSE_EQUIP] > 0) { pauseCtx->cursorPoint[PAUSE_EQUIP] -= pauseCtx->cursorX[PAUSE_EQUIP]; pauseCtx->cursorX[PAUSE_EQUIP] = 0; } @@ -525,6 +526,9 @@ void KaleidoScope_DrawEquipment(PlayState* play) { u16 buttonsToCheck = BTN_A | BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { + if (!CVarGetInteger("gAltItemMenu", 0)) { + buttonsToCheck |= BTN_DUP; + } buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } @@ -692,7 +696,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { point = CUR_UPG_VALUE(sChildUpgrades[i]); if ((point != 0) && (CUR_UPG_VALUE(sChildUpgrades[i]) != 0)) { if (drawGreyItems && - ((sChildUpgradeItemBases[i] + CUR_UPG_VALUE(sChildUpgrades[i]) - 1) == ITEM_GAUNTLETS_SILVER || + ((sChildUpgradeItemBases[i] + CUR_UPG_VALUE(sChildUpgrades[i]) - 1) == ITEM_GAUNTLETS_SILVER || (sChildUpgradeItemBases[i] + CUR_UPG_VALUE(sChildUpgrades[i]) - 1) == ITEM_GAUNTLETS_GOLD)) { // Grey Out the Gauntlets gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255); gSPGrayscale(POLY_KAL_DISP++, true); @@ -720,7 +724,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { } } - if (i == 3) { + if (altItems && i == 3) { continue; } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index f2da22b6d85..d4dd9876894 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -8,22 +8,8 @@ #include "soh_assets.h" u8 gAmmoItems[] = { - ITEM_NONE, // SLOT_DINS_FIRE - ITEM_BOMB, // SLOT_BOMB - ITEM_BOMBCHU, // SLOT_BOMBCHU - ITEM_NUT, // SLOT_NUT - ITEM_NONE, // SLOT_LENS - ITEM_BEAN, // SLOT_BEAN - ITEM_NONE, // SLOT_FARORES_WIND - ITEM_SLINGSHOT, // SLOT_SLINGSHOT - ITEM_NONE, // SLOT_BOOMERANG - ITEM_STICK, // SLOT_STICK - ITEM_NONE, // SLOT_BOOTS_HOVER - ITEM_NONE, // SLOT_TRADE_CHILD - ITEM_NONE, // SLOT_NAYRUS_LOVE - ITEM_BOW, // SLOT_BOW - ITEM_NONE, // SLOT_HOOKSHOT - ITEM_NONE, // SLOT_HAMMER + ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, + ITEM_BOMBCHU, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_BEAN, ITEM_NONE, }; static s16 sEquipState = 0; @@ -35,21 +21,7 @@ bool gSelectingArrow; /* Maps an inventory slot to double the position of its ammo count in sAmmoVtxTableIdx */ static s16 sAmmoVtxOffset[] = { - 99, // SLOT_DINS_FIRE - 0, // SLOT_BOMB - 2, // SLOT_BOMBCHU - 4, // SLOT_NUT - 99, // SLOT_LENS - 6, // SLOT_BEAN - 99, // SLOT_FARORES_WIND - 8, // SLOT_SLINGSHOT - 99, // SLOT_BOOMERANG - 10, // SLOT_STICK - 99, // SLOT_BOOTS_HOVER - 99, // SLOT_TRADE_CHILD - 99, // SLOT_NAYRUS_LOVE - 12, // SLOT_BOW - 99 // SLOT_HOOKSHOT + 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12, }; typedef enum { @@ -61,17 +33,36 @@ typedef enum { extern const char* _gAmmoDigit0Tex[]; +u8 KaleidoScope_ItemInSlot(u8 slot) { + if (CVarGetInteger("gAltItemMenu", 0)) { + slot = gAltToMainSlot[slot]; + } + if (slot < 24) { + return gSaveContext.inventory.items[slot]; + } else if ((slot == SLOT_BOOTS_IRON) && (gSaveContext.inventory.equipment & 1 << 13)) { + return ITEM_BOOTS_IRON; + } else if ((slot == SLOT_BOOTS_HOVER) && (gSaveContext.inventory.equipment & 1 << 14)) { + return ITEM_BOOTS_HOVER; + } else { + return ITEM_NONE; + } +} + void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) { s16 ammo; s16 i; OPEN_DISPS(gfxCtx); + if (item == ITEM_BOW_ARROW_FIRE || item == ITEM_BOW_ARROW_ICE || item == ITEM_BOW_ARROW_LIGHT) { + item = ITEM_BOW; + } + ammo = AMMO(item); gDPPipeSync(POLY_KAL_DISP++); - if (!CHECK_AGE_REQ_SLOT(SLOT(item))) { + if (!CHECK_AGE_REQ_SLOT(KALEIDO_SLOT(item))) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 100, 100, 100, pauseCtx->alpha); } else { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); @@ -79,8 +70,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, if (ammo == 0) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 130, 130, 130, pauseCtx->alpha); } else if ((item == ITEM_BOMB && AMMO(item) == CUR_CAPACITY(UPG_BOMB_BAG)) || - ((item == ITEM_BOW || item == ITEM_BOW_ARROW_FIRE || item == ITEM_BOW_ARROW_ICE || item == ITEM_BOW_ARROW_LIGHT) - && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || + (item == ITEM_BOW && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || (item == ITEM_SLINGSHOT && AMMO(item) == CUR_CAPACITY(UPG_BULLET_BAG)) || (item == ITEM_STICK && AMMO(item) == CUR_CAPACITY(UPG_STICKS)) || (item == ITEM_NUT && AMMO(item) == CUR_CAPACITY(UPG_NUTS)) || (item == ITEM_BOMBCHU && ammo == 50) || @@ -182,7 +172,7 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 } } - u8 slotItem = gSaveContext.inventory.items[slot]; + u8 slotItem = KaleidoScope_ItemInSlot(slot); u8 showLeftItem = leftItem != ITEM_NONE && slotItem != leftItem; u8 showRightItem = rightItem != ITEM_NONE && slotItem != rightItem && leftItem != rightItem; @@ -315,6 +305,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP)); bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) || (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON); + bool altItemMenu = CVarGetInteger("gAltItemMenu", 0); // only allow mask select when: // the shop is open: @@ -326,7 +317,8 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) && Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD); - bool canArrowSelect = INV_CONTENT(ITEM_BOW) != ITEM_NONE && + bool canArrowSelect = altItemMenu && + INV_CONTENT(ITEM_BOW) != ITEM_NONE && (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE || INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE || INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE); @@ -363,14 +355,14 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { // Seem necessary to match if (pauseCtx->cursorX[PAUSE_ITEM]) {} - if (gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]]) {} + if (KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM])) {} while (moveCursorResult == 0) { if ((pauseCtx->stickRelX < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) { if (pauseCtx->cursorX[PAUSE_ITEM] != 0) { pauseCtx->cursorX[PAUSE_ITEM] -= 1; pauseCtx->cursorPoint[PAUSE_ITEM] -= 1; - if ((gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE) || + if ((KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) != ITEM_NONE) || pauseAnyCursor) { moveCursorResult = 1; } @@ -402,7 +394,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorX[PAUSE_ITEM] < 5) { pauseCtx->cursorX[PAUSE_ITEM] += 1; pauseCtx->cursorPoint[PAUSE_ITEM] += 1; - if ((gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE) || + if ((KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) != ITEM_NONE) || pauseAnyCursor) { moveCursorResult = 1; } @@ -434,7 +426,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } if (moveCursorResult == 1) { - cursorItem = gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]]; + cursorItem = KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]); } osSyncPrintf("【X cursor=%d(%) (cur_xpt=%d)(ok_fg=%d)(ccc=%d)(key_angle=%d)】 ", @@ -450,7 +442,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { cursorPoint = cursorX = cursorY = 0; while (true) { - if (gSaveContext.inventory.items[cursorPoint] != ITEM_NONE) { + if (KaleidoScope_ItemInSlot(cursorPoint) != ITEM_NONE) { pauseCtx->cursorPoint[PAUSE_ITEM] = cursorPoint; pauseCtx->cursorX[PAUSE_ITEM] = cursorX; pauseCtx->cursorY[PAUSE_ITEM] = cursorY; @@ -485,7 +477,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { cursorPoint = cursorX = 5; cursorY = 0; while (true) { - if (gSaveContext.inventory.items[cursorPoint] != ITEM_NONE) { + if (KaleidoScope_ItemInSlot(cursorPoint) != ITEM_NONE) { pauseCtx->cursorPoint[PAUSE_ITEM] = cursorPoint; pauseCtx->cursorX[PAUSE_ITEM] = cursorX; pauseCtx->cursorY[PAUSE_ITEM] = cursorY; @@ -524,7 +516,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorY[PAUSE_ITEM] != 0) { pauseCtx->cursorY[PAUSE_ITEM] -= 1; pauseCtx->cursorPoint[PAUSE_ITEM] -= 6; - if ((gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE) || + if ((KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) != ITEM_NONE) || pauseAnyCursor) { moveCursorResult = 1; } @@ -538,7 +530,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorY[PAUSE_ITEM] < 3) { pauseCtx->cursorY[PAUSE_ITEM] += 1; pauseCtx->cursorPoint[PAUSE_ITEM] += 6; - if ((gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE) || + if ((KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) != ITEM_NONE) || pauseAnyCursor) { moveCursorResult = 1; } @@ -563,9 +555,9 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->cursorColorSet = 4; if (moveCursorResult == 1) { - cursorItem = gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]]; + cursorItem = KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]); } else if (moveCursorResult != 2) { - cursorItem = gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]]; + cursorItem = KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]); } pauseCtx->cursorItem[PAUSE_ITEM] = cursorItem; @@ -580,7 +572,9 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { KaleidoScope_SetCursorVtx(pauseCtx, index, pauseCtx->itemVtx); if ((pauseCtx->debugState == 0) && (pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0)) { - if (canMaskSelect && cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A)) { + if (canMaskSelect && cursorSlot == (altItemMenu ? SLOT_ALT_TRADE_CHILD : SLOT_TRADE_CHILD) && + CHECK_BTN_ALL(input->press.button, BTN_A) + ) { Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); gSelectingMask = !gSelectingMask; } @@ -616,7 +610,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } } } - gSelectingMask = cursorSlot == SLOT_TRADE_CHILD; + gSelectingMask = cursorSlot == (altItemMenu ? SLOT_ALT_TRADE_CHILD : SLOT_TRADE_CHILD); gSlotAgeReqs[SLOT_TRADE_CHILD] = gItemAgeReqs[ITEM_MASK_BUNNY] = ((((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) || CVarGetInteger("gTimelessEquipment", 0)) && @@ -625,7 +619,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { : AGE_REQ_CHILD; } if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) && - cursorSlot == SLOT_TRADE_ADULT && CHECK_BTN_ALL(input->press.button, BTN_A)) { + cursorSlot == (altItemMenu ? SLOT_ALT_TRADE_ADULT : SLOT_TRADE_ADULT) && CHECK_BTN_ALL(input->press.button, BTN_A)) { Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); gSelectingAdultTrade = !gSelectingAdultTrade; } @@ -640,9 +634,9 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Inventory_ReplaceItem(play, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetPrevAdultTradeItem()); } - gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT; + gSelectingAdultTrade = cursorSlot == (altItemMenu ? SLOT_ALT_TRADE_ADULT : SLOT_TRADE_ADULT); } - if (canArrowSelect && cursorSlot == SLOT_BOW && CHECK_BTN_ALL(input->press.button, BTN_A)) { + if (canArrowSelect && cursorSlot == SLOT_ALT_BOW && CHECK_BTN_ALL(input->press.button, BTN_A)) { Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); gSelectingArrow = !gSelectingArrow; } @@ -657,11 +651,14 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), KaleidoScope_GetNextBow()); } - gSelectingArrow = cursorSlot == SLOT_BOW; + gSelectingArrow = cursorSlot == SLOT_ALT_BOW; } u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { + if (!altItemMenu) { + buttonsToCheck |= BTN_DUP; + } buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (CHECK_BTN_ANY(input->press.button, buttonsToCheck)) { @@ -702,10 +699,13 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { for (i = 0, j = 24 * 4; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++, j += 4) { u8 buttonItem = gSaveContext.equips.buttonItems[i + 1]; - if ((buttonItem != ITEM_NONE) && // equipped - (buttonItem < ARRAY_COUNT(gItemSlots)) && // has an assigned slot - (gItemSlots[buttonItem] < 24) && // assigned slot is on the menu - !((buttonItem >= ITEM_SHIELD_DEKU) && (buttonItem <= ITEM_BOOTS_KOKIRI))) { // not equipment (except boots) + u8 drawBg = (buttonItem != ITEM_NONE) && // equipped + !((buttonItem >= ITEM_SHIELD_DEKU) && (buttonItem <= ITEM_BOOTS_HOVER)); // not equipment + u8 drawBgAlt = (buttonItem != ITEM_NONE) && // equipped + (buttonItem < ARRAY_COUNT(gAltItemSlots)) && // has an assigned slot + (gAltItemSlots[buttonItem] < 24) && // assigned slot is on the menu + !((buttonItem >= ITEM_SHIELD_DEKU) && (buttonItem <= ITEM_BOOTS_KOKIRI)); // not equipment (except boots) + if (altItemMenu ? drawBgAlt : drawBg) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j], 4, 0); POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); } @@ -717,24 +717,43 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { for (i = j = 0; i < 24; i++, j += 4) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - if ((gSaveContext.inventory.items[i] != ITEM_NONE)) { - if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && - (pauseCtx->cursorSpecialPos == 0) && CHECK_AGE_REQ_SLOT(i) && (i == cursorSlot)) { - pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] - 2; + if (KaleidoScope_ItemInSlot(i) != ITEM_NONE) { + if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && (pauseCtx->cursorSpecialPos == 0)) { + if (CHECK_AGE_REQ_SLOT(i)) { + if ((sEquipState == ES_MAGIC_ARROW_EQUIPPING) && (i == SLOT_BOW) && !altItemMenu) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, magicArrowEffectsR[pauseCtx->equipTargetItem - 0xBF], + magicArrowEffectsG[pauseCtx->equipTargetItem - 0xBF], + magicArrowEffectsB[pauseCtx->equipTargetItem - 0xBF], pauseCtx->alpha); - pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] + 32; + pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] - 2; - pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] + 2; + pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] + 32; - pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] - 32; + pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] + 2; + + pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] - 32; + } else if (i == cursorSlot) { + pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] - 2; + + pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] + 32; + + pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] + 2; + + pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] - 32; + } + } } gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j + 0], 4, 0); - int itemId = gSaveContext.inventory.items[i]; + int itemId = KaleidoScope_ItemInSlot(i); bool not_acquired = !CHECK_AGE_REQ_ITEM(itemId); if (not_acquired) { gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255); @@ -761,15 +780,17 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } // Adult trade item cycle - KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_ADULT, gSelectingAdultTrade, + KaleidoScope_DrawItemCycleExtras(play, altItemMenu ? SLOT_ALT_TRADE_ADULT : SLOT_TRADE_ADULT, + gSelectingAdultTrade, IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), Randomizer_GetPrevAdultTradeItem(), Randomizer_GetNextAdultTradeItem()); // Child mask item cycle (mimics the left/right item behavior from the cycling logic above) u8 childTradeItem = INV_CONTENT(ITEM_TRADE_CHILD); - KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_CHILD, gSelectingMask, canMaskSelect, + KaleidoScope_DrawItemCycleExtras(play, altItemMenu ? SLOT_ALT_TRADE_CHILD : SLOT_TRADE_CHILD, + gSelectingMask, canMaskSelect, childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); - KaleidoScope_DrawItemCycleExtras(play, SLOT_BOW, gSelectingArrow, canArrowSelect, + KaleidoScope_DrawItemCycleExtras(play, SLOT_ALT_BOW, gSelectingArrow, canArrowSelect, KaleidoScope_GetPrevBow(), KaleidoScope_GetNextBow()); CLOSE_DISPS(play->state.gfxCtx); @@ -781,6 +802,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, gSelectingMask = false; gSelectingAdultTrade = false; gSelectingArrow = false; + int altItemMenu = CVarGetInteger("gAltItemMenu", 0); if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { pauseCtx->equipTargetCBtn = 0; @@ -789,10 +811,9 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } else if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) { pauseCtx->equipTargetCBtn = 2; } else if (CVarGetInteger("gDpadEquips", 0)) { - // D up is permanently mapped to ocarina - /*if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { + if (CHECK_BTN_ALL(input->press.button, BTN_DUP) && !altItemMenu) { pauseCtx->equipTargetCBtn = 3; - } else */if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { + } else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { pauseCtx->equipTargetCBtn = 4; } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT)) { pauseCtx->equipTargetCBtn = 5; @@ -802,7 +823,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } pauseCtx->equipTargetItem = item; - pauseCtx->equipTargetSlot = slot; + pauseCtx->equipTargetSlot = altItemMenu ? gAltToMainSlot[slot] : slot; pauseCtx->unk_1E4 = 3; pauseCtx->equipAnimX = animX; pauseCtx->equipAnimY = animY; @@ -899,8 +920,8 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; s16 DPad_ItemsOffset[4][2] = { @@ -1018,8 +1039,27 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { return; } + int altItemMenu = CVarGetInteger("gAltItemMenu", 0); + int vtx = 4 * (altItemMenu ? SLOT_ALT_BOW : SLOT_BOW); + if (sEquipState == ES_MAGIC_ARROW_EQUIPPING && !altItemMenu) { + D_8082A488--; + + if (D_8082A488 == 0) { + pauseCtx->equipTargetItem -= 0xBF - ITEM_BOW_ARROW_FIRE; + if (!CVarGetInteger("gSeparateArrows", 0)) { + pauseCtx->equipTargetSlot = SLOT_BOW; + } + sEquipMoveTimer = 6; + WREG(90) = 320; + WREG(87) = WREG(91); + sEquipState++; + Audio_PlaySoundGeneral(NA_SE_SY_SYNTH_MAGIC_ARROW, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } + return; + } + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { - bowItemVtx = &pauseCtx->itemVtx[52]; + bowItemVtx = &pauseCtx->itemVtx[vtx]; offsetX = ABS(pauseCtx->equipAnimX - bowItemVtx->v.ob[0] * 10) / sEquipMoveTimer; offsetY = ABS(pauseCtx->equipAnimY - bowItemVtx->v.ob[1] * 10) / sEquipMoveTimer; } else { @@ -1041,13 +1081,13 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { WREG(87) -= WREG(87) / sEquipMoveTimer; if (sEquipState == ES_MAGIC_ARROW_APPLYING) { - if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[52].v.ob[0] * 10)) { + if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[vtx].v.ob[0] * 10)) { pauseCtx->equipAnimX -= offsetX; } else { pauseCtx->equipAnimX += offsetX; } - if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[52].v.ob[1] * 10)) { + if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[vtx].v.ob[1] * 10)) { pauseCtx->equipAnimY -= offsetY; } else { pauseCtx->equipAnimY += offsetY; @@ -1070,18 +1110,43 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { if (sEquipMoveTimer == 0) { if (sEquipState == ES_MAGIC_ARROW_APPLYING) { - pauseCtx->unk_1E4 = 0; - s16 magicArrowType = pauseCtx->equipTargetItem - 0xBF; - if (magicArrowType >= 0 && magicArrowType <= 2) { - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE + magicArrowType; + if (altItemMenu) { + pauseCtx->unk_1E4 = 0; + s16 magicArrowType = pauseCtx->equipTargetItem - 0xBF; + if (magicArrowType >= 0 && magicArrowType <= 2) { + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE + magicArrowType; + } + Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), pauseCtx->equipTargetItem); + gSelectingArrow = false; + } else { + sEquipState = ES_MAGIC_ARROW_EQUIPPING; + D_8082A488 = 4; } - Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), pauseCtx->equipTargetItem); - gSelectingArrow = false; return; } osSyncPrintf("\n================================\n"); + // Skipping the arrow animation: need to change the item's type and + // slot when it hits the button since it didn't get set earlier + if (pauseCtx->equipTargetItem == ITEM_ARROW_FIRE || pauseCtx->equipTargetItem == ITEM_ARROW_ICE || + pauseCtx->equipTargetItem == ITEM_ARROW_LIGHT) { + switch (pauseCtx->equipTargetItem) { + case ITEM_ARROW_FIRE: + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE; + break; + case ITEM_ARROW_ICE: + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_ICE; + break; + case ITEM_ARROW_LIGHT: + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_LIGHT; + break; + } + if (!CVarGetInteger("gSeparateArrows", 0)) { + pauseCtx->equipTargetSlot = SLOT_BOW; + } + } + // If the item is on another button already, swap the two uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1; for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); @@ -1118,6 +1183,16 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { } } + const bool ddown = 5; + if (CVarGetInteger("gMapOnDDown", 0) && + pauseCtx->equipTargetCBtn == ddown && + gSaveContext.equips.buttonItems[ddown + 1] == pauseCtx->equipTargetItem && + gSaveContext.equips.cButtonSlots[ddown] == pauseCtx->equipTargetSlot + ) { + pauseCtx->equipTargetItem = ITEM_NONE; + pauseCtx->equipTargetSlot = SLOT_NONE; + } + gSaveContext.equips.buttonItems[targetButtonIndex] = pauseCtx->equipTargetItem; gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn] = pauseCtx->equipTargetSlot; Interface_LoadItemIcon1(play, targetButtonIndex); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index afbe40bc331..3dc7a53b396 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -23,7 +23,6 @@ extern bool gSelectingArrow; #define AGE_REQ_NONE 9 #define CHECK_AGE_REQ_EQUIP(i, j) (CVarGetInteger("gTimelessEquipment", 0) || (gEquipAgeReqs[i][j] == AGE_REQ_NONE) || (gEquipAgeReqs[i][j] == ((void)0, gSaveContext.linkAge))) -#define CHECK_AGE_REQ_SLOT(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqs[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge)) #define CHECK_AGE_REQ_ITEM(itemIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gItemAgeReqs[itemIndex] == AGE_REQ_NONE) || (gItemAgeReqs[itemIndex] == gSaveContext.linkAge)) void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx); @@ -53,4 +52,22 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx); void KaleidoScope_ResetTradeSelect(); +/* Alternate item menu */ +typedef enum { + SLOT_ALT_DINS_FIRE, SLOT_ALT_BOMB, SLOT_ALT_BOMBCHU, SLOT_ALT_NUT, SLOT_ALT_LENS, SLOT_ALT_BEAN, + SLOT_ALT_FARORES_WIND, SLOT_ALT_SLINGSHOT, SLOT_ALT_BOOMERANG, SLOT_ALT_STICK, SLOT_ALT_BOOTS_HOVER, SLOT_ALT_TRADE_CHILD, + SLOT_ALT_NAYRUS_LOVE, SLOT_ALT_BOW, SLOT_ALT_HOOKSHOT, SLOT_ALT_HAMMER, SLOT_ALT_BOOTS_IRON, SLOT_ALT_TRADE_ADULT, + SLOT_ALT_EMPTY_LEFT, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_2, SLOT_ALT_BOTTLE_3, SLOT_ALT_BOTTLE_4, SLOT_ALT_EMPTY_RIGHT, + SLOT_ALT_NONE = 0xFF +} InventorySlotAlt; + +u8 gSlotAgeReqsAlt[24]; +u8 gAltItemSlots[71]; +u8 gAltToMainSlot[24]; +#define _CHECK_AGE_REQ_SLOT_MAIN(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqs[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge)) +#define _CHECK_AGE_REQ_SLOT_ALT(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqsAlt[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqsAlt[slotIndex] == ((void)0, gSaveContext.linkAge)) +#define CHECK_AGE_REQ_SLOT(slotIndex) (CVarGetInteger("gAltItemMenu", 0) ? _CHECK_AGE_REQ_SLOT_ALT(slotIndex) : _CHECK_AGE_REQ_SLOT_MAIN(slotIndex)) +#define KALEIDO_SLOT(item) (CVarGetInteger("gAltItemMenu", 0) ? gAltItemSlots[item] : SLOT(item)) +u8 KaleidoScope_ItemInSlot(u8 slot); + #endif diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 5846654fdef..1a4be09888c 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -734,30 +734,57 @@ static u16 D_8082ABEC[] = { }; u8 gSlotAgeReqs[] = { - AGE_REQ_NONE, // SLOT_DINS_FIRE + AGE_REQ_CHILD, // SLOT_DEKU_STICK + AGE_REQ_NONE, // SLOT_DEKU_NUT AGE_REQ_NONE, // SLOT_BOMB + AGE_REQ_ADULT, // SLOT_BOW + AGE_REQ_ADULT, // SLOT_ARROW_FIRE + AGE_REQ_NONE, // SLOT_DINS_FIRE + AGE_REQ_CHILD, // SLOT_SLINGSHOT + AGE_REQ_NONE, // SLOT_OCARINA AGE_REQ_NONE, // SLOT_BOMBCHU - AGE_REQ_NONE, // SLOT_NUT - AGE_REQ_NONE, // SLOT_LENS - AGE_REQ_CHILD, // SLOT_BEAN + AGE_REQ_ADULT, // SLOT_HOOKSHOT + AGE_REQ_ADULT, // SLOT_ARROW_ICE AGE_REQ_NONE, // SLOT_FARORES_WIND - AGE_REQ_CHILD, // SLOT_SLINGSHOT AGE_REQ_CHILD, // SLOT_BOOMERANG - AGE_REQ_CHILD, // SLOT_STICK - AGE_REQ_ADULT, // SLOT_BOOTS_HOVER - AGE_REQ_CHILD, // SLOT_TRADE_CHILD - AGE_REQ_NONE, // SLOT_NAYRUS_LOVE - AGE_REQ_ADULT, // SLOT_BOW - AGE_REQ_ADULT, // SLOT_HOOKSHOT + AGE_REQ_NONE, // SLOT_LENS_OF_TRUTH + AGE_REQ_CHILD, // SLOT_MAGIC_BEAN AGE_REQ_ADULT, // SLOT_HAMMER - AGE_REQ_ADULT, // SLOT_BOOTS_IRON - AGE_REQ_ADULT, // SLOT_TRADE_ADULT - AGE_REQ_NONE, // SLOT_EMPTY_LEFT + AGE_REQ_ADULT, // SLOT_ARROW_LIGHT + AGE_REQ_NONE, // SLOT_NAYRUS_LOVE AGE_REQ_NONE, // SLOT_BOTTLE_1 AGE_REQ_NONE, // SLOT_BOTTLE_2 AGE_REQ_NONE, // SLOT_BOTTLE_3 AGE_REQ_NONE, // SLOT_BOTTLE_4 - AGE_REQ_NONE, // SLOT_EMPTY_RIGHT + AGE_REQ_ADULT, // SLOT_TRADE_ADULT + AGE_REQ_CHILD, // SLOT_TRADE_CHILD +}; + +u8 gSlotAgeReqsAlt[] = { + AGE_REQ_NONE, // SLOT_ALT_DINS_FIRE + AGE_REQ_NONE, // SLOT_ALT_BOMB + AGE_REQ_NONE, // SLOT_ALT_BOMBCHU + AGE_REQ_NONE, // SLOT_ALT_NUT + AGE_REQ_NONE, // SLOT_ALT_LENS + AGE_REQ_CHILD, // SLOT_ALT_BEAN + AGE_REQ_NONE, // SLOT_ALT_FARORES_WIND + AGE_REQ_CHILD, // SLOT_ALT_SLINGSHOT + AGE_REQ_CHILD, // SLOT_ALT_BOOMERANG + AGE_REQ_CHILD, // SLOT_ALT_STICK + AGE_REQ_ADULT, // SLOT_ALT_BOOTS_HOVER + AGE_REQ_CHILD, // SLOT_ALT_TRADE_CHILD + AGE_REQ_NONE, // SLOT_ALT_NAYRUS_LOVE + AGE_REQ_ADULT, // SLOT_ALT_BOW + AGE_REQ_ADULT, // SLOT_ALT_HOOKSHOT + AGE_REQ_ADULT, // SLOT_ALT_HAMMER + AGE_REQ_ADULT, // SLOT_ALT_BOOTS_IRON + AGE_REQ_ADULT, // SLOT_ALT_TRADE_ADULT + AGE_REQ_NONE, // SLOT_ALT_EMPTY_LEFT + AGE_REQ_NONE, // SLOT_ALT_BOTTLE_1 + AGE_REQ_NONE, // SLOT_ALT_BOTTLE_2 + AGE_REQ_NONE, // SLOT_ALT_BOTTLE_3 + AGE_REQ_NONE, // SLOT_ALT_BOTTLE_4 + AGE_REQ_NONE, // SLOT_ALT_EMPTY_RIGHT }; u8 gEquipAgeReqs[][4] = { @@ -877,6 +904,38 @@ u8 gItemAgeReqs[] = { AGE_REQ_ADULT, // ITEM_GIANTS_KNIFE }; +u8 gMainToAltSlot[] = { + SLOT_ALT_STICK, SLOT_ALT_NUT, SLOT_ALT_BOMB, SLOT_ALT_BOW, SLOT_ALT_NONE, SLOT_ALT_DINS_FIRE, + SLOT_ALT_SLINGSHOT, SLOT_ALT_NONE, SLOT_ALT_BOMBCHU, SLOT_ALT_HOOKSHOT, SLOT_ALT_NONE, SLOT_ALT_FARORES_WIND, + SLOT_ALT_BOOMERANG, SLOT_ALT_LENS, SLOT_ALT_BEAN, SLOT_ALT_HAMMER, SLOT_ALT_NONE, SLOT_ALT_NAYRUS_LOVE, + SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_2, SLOT_ALT_BOTTLE_3, SLOT_ALT_BOTTLE_4, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_CHILD, +}; + +u8 gAltToMainSlot[] = { + SLOT_DINS_FIRE, SLOT_BOMB, SLOT_BOMBCHU, SLOT_NUT, SLOT_LENS, SLOT_BEAN, + SLOT_FARORES_WIND, SLOT_SLINGSHOT, SLOT_BOOMERANG, SLOT_STICK, SLOT_BOOTS_IRON, SLOT_TRADE_CHILD, + SLOT_NAYRUS_LOVE, SLOT_BOW, SLOT_HOOKSHOT, SLOT_HAMMER, SLOT_BOOTS_HOVER, SLOT_TRADE_ADULT, + SLOT_NONE, SLOT_BOTTLE_1, SLOT_BOTTLE_2, SLOT_BOTTLE_3, SLOT_BOTTLE_4, SLOT_NONE, +}; + +u8 gAltItemSlots[] = { + SLOT_ALT_STICK, SLOT_ALT_NUT, SLOT_ALT_BOMB, SLOT_ALT_BOW, SLOT_ALT_NONE, + SLOT_ALT_DINS_FIRE, SLOT_ALT_SLINGSHOT, SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_BOMBCHU, + SLOT_ALT_HOOKSHOT, SLOT_ALT_HOOKSHOT, SLOT_ALT_NONE, SLOT_ALT_FARORES_WIND, SLOT_ALT_BOOMERANG, + SLOT_ALT_LENS, SLOT_ALT_BEAN, SLOT_ALT_HAMMER, SLOT_ALT_NONE, SLOT_ALT_NAYRUS_LOVE, + SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, + SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, + SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_BOTTLE_1, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, + SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, + SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, SLOT_ALT_TRADE_CHILD, + SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, + SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, SLOT_ALT_TRADE_ADULT, + SLOT_ALT_TRADE_ADULT, SLOT_ALT_BOW, SLOT_ALT_BOW, SLOT_ALT_BOW, SLOT_ALT_NONE, + SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_NONE, + SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_NONE, SLOT_ALT_BOOTS_IRON, + SLOT_ALT_BOOTS_HOVER, +}; + u8 gAreaGsFlags[] = { 0x0F, 0x1F, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x07, 0x07, 0x03, 0x0F, 0x07, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0x1F, 0x0F, 0x03, 0x0F, @@ -1014,10 +1073,10 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { switch (pauseCtx->pageIndex) { case PAUSE_ITEM: s = pauseCtx->cursorSlot[PAUSE_ITEM]; - if (gSaveContext.inventory.items[s] == ITEM_NONE) { + if (KaleidoScope_ItemInSlot(s) == ITEM_NONE) { i = s + 1; while (true) { - if (gSaveContext.inventory.items[i] != ITEM_NONE) { + if (KaleidoScope_ItemInSlot(i) != ITEM_NONE) { break; } i++; @@ -1029,7 +1088,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { return; } } - pauseCtx->cursorItem[PAUSE_ITEM] = gSaveContext.inventory.items[i]; + pauseCtx->cursorItem[PAUSE_ITEM] = KaleidoScope_ItemInSlot(i); pauseCtx->cursorSlot[PAUSE_ITEM] = i; } break; @@ -2065,7 +2124,7 @@ void KaleidoScope_DrawInfoPanel(PlayState* play) { bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) || (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON); - if (!pauseCtx->pageIndex && (!pauseAnyCursor || (gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE))) { // pageIndex == PAUSE_ITEM + if (!pauseCtx->pageIndex && (!pauseAnyCursor || (KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) != ITEM_NONE))) { // pageIndex == PAUSE_ITEM pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = WREG(49 + gSaveContext.language); @@ -2214,7 +2273,7 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { if (pauseAnyCursor && ((pauseCtx->pageIndex == PAUSE_EQUIP && pauseCtx->cursorX[PAUSE_EQUIP] != 0 && !CHECK_OWNED_EQUIP(pauseCtx->cursorY[PAUSE_EQUIP], pauseCtx->cursorX[PAUSE_EQUIP] - 1)) || - (pauseCtx->pageIndex == PAUSE_ITEM && gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] == ITEM_NONE))) { + (pauseCtx->pageIndex == PAUSE_ITEM && KaleidoScope_ItemInSlot(pauseCtx->cursorPoint[PAUSE_ITEM]) == ITEM_NONE))) { pauseCtx->namedItem = PAUSE_ITEM_NONE; } @@ -2634,7 +2693,8 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) { } /* Maps an ammo item to an inventory slot by 4x its slot number */ -static s16 sAmmoVtxTableIdx[] = { 4, 8, 12, 20, 28, 36, 52 }; +static s16 sAmmoVtxTableIdx[] = { 0, 4, 8, 12, 24, 32, 56 }; +static s16 sAmmoVtxTableIdxAlt[] = { 36, 12, 4, 52, 28, 8, 20 }; static s16 D_8082B12C[] = { -114, 12, 44, 76 }; @@ -2799,8 +2859,12 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { for (phi_t3 = 1; phi_t3 < ARRAY_COUNT(gSaveContext.equips.buttonItems); phi_t3++, phi_t2 += 4) { if (gSaveContext.equips.cButtonSlots[phi_t3 - 1] != ITEM_NONE && - ((phi_t3 < 5) || CVarGetInteger("gDpadEquips", 0))) { - phi_t4 = gSaveContext.equips.cButtonSlots[phi_t3 - 1] * 4; + ((phi_t3 < 4) || CVarGetInteger("gDpadEquips", 0))) { + int slot = gSaveContext.equips.cButtonSlots[phi_t3 - 1]; + if (CVarGetInteger("gAltItemMenu", 0)) { + slot = gMainToAltSlot[slot]; + } + phi_t4 = slot * 4; pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = pauseCtx->itemVtx[phi_t4].v.ob[0] - 2; @@ -2849,7 +2913,11 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { } for (phi_t3 = 0; phi_t3 < 7; phi_t3++) { - phi_t4 = sAmmoVtxTableIdx[phi_t3]; + if (CVarGetInteger("gAltItemMenu", 0)) { + phi_t4 = sAmmoVtxTableIdxAlt[phi_t3]; + } else { + phi_t4 = sAmmoVtxTableIdx[phi_t3]; + } pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = pauseCtx->itemVtx[phi_t4].v.ob[0]; @@ -2910,7 +2978,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->equipVtx[phi_t4 + 0].v.ob[0] + 28; pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 1].v.ob[1] = - phi_t5 + pauseCtx->offsetY - 2 - (phi_t3 > 0 ? 16 : 0); + phi_t5 + pauseCtx->offsetY - 2 - ((CVarGetInteger("gAltItemMenu", 0) && phi_t3 > 0) ? 16 : 0); pauseCtx->equipVtx[phi_t4 + 2].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 3].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] - 28; From 1d4a405ac1f20e8a65ca3535728a882ab1144df3 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Wed, 27 Dec 2023 19:26:58 -0600 Subject: [PATCH 21/60] Make alt slot conversion arrays extern --- soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index 3dc7a53b396..364d491312a 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -61,9 +61,9 @@ typedef enum { SLOT_ALT_NONE = 0xFF } InventorySlotAlt; -u8 gSlotAgeReqsAlt[24]; -u8 gAltItemSlots[71]; -u8 gAltToMainSlot[24]; +extern u8 gSlotAgeReqsAlt[24]; +extern u8 gAltItemSlots[71]; +extern u8 gAltToMainSlot[24]; #define _CHECK_AGE_REQ_SLOT_MAIN(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqs[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge)) #define _CHECK_AGE_REQ_SLOT_ALT(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqsAlt[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqsAlt[slotIndex] == ((void)0, gSaveContext.linkAge)) #define CHECK_AGE_REQ_SLOT(slotIndex) (CVarGetInteger("gAltItemMenu", 0) ? _CHECK_AGE_REQ_SLOT_ALT(slotIndex) : _CHECK_AGE_REQ_SLOT_MAIN(slotIndex)) From dccd4efb4518599aba95bbda8965f257fd341197 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Wed, 27 Dec 2023 19:28:40 -0600 Subject: [PATCH 22/60] Account for new item menu in presets --- soh/soh/Enhancements/presets.h | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..60a63b9be92 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -242,6 +242,7 @@ const std::vector enhancementsCvars = { "gAddTraps.Speed", "gAddTraps.Tele", "gAddTraps.Void", + "gAltItemMenu", }; const std::vector cheatCvars = { From d03471d3b31eb6f0e65f41af084500a091a396fc Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 28 Dec 2023 12:23:25 -0600 Subject: [PATCH 23/60] Re-add four-directional arrow selection --- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 272 +++++++++++++++--- 1 file changed, 235 insertions(+), 37 deletions(-) diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index d4dd9876894..5de84a23002 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -252,38 +252,192 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 static u8 sBowArrowItems[] = {ITEM_BOW, ITEM_BOW_ARROW_FIRE, ITEM_BOW_ARROW_ICE, ITEM_BOW_ARROW_LIGHT}; static u8 sArrowItems[] = {ITEM_BOW, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT}; -u8 KaleidoScope_GetNextBow() { - u8 currentBow = INV_CONTENT(ITEM_BOW); - u8 bowIndex; - if (currentBow == ITEM_BOW) { - bowIndex = 0; +// Vertices for the extra items +static Vtx sArrowSelectExtraItemVtx[] = { + // Fire Arrow + VTX(-16, 48, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(16, 48, 0, 32 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-16, 16, 0, 0 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(16, 16, 0, 32 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Ice Arrow + VTX(-48, 16, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-16, 16, 0, 32 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-48, -16, 0, 0 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-16, -16, 0, 32 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Light Arrow + VTX(16, 16, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(48, 16, 0, 32 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(16, -16, 0, 0 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(48, -16, 0, 32 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Arrow + VTX(-16, -16, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(16, -16, 0, 32 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-16, -48, 0, 0 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(16, -48, 0, 32 << 5, 32 << 5, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +// Vertices for the circle behind the items +static Vtx sArrowSelectCircleVtx[] = { + // Fire Arrow + VTX(-24, 56, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(24, 56, 0, 48 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-24, 8, 0, 0 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(24, 8, 0, 48 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Ice Arrow + VTX(-56, 24, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-8, 24, 0, 48 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-56, -24, 0, 0 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-8, -24, 0, 48 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Light Arrow + VTX(8, 24, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(56, 24, 0, 48 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(8, -24, 0, 0 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(56, -24, 0, 48 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Arrow + VTX(-24, -8, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(24, -8, 0, 48 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-24, -56, 0, 0 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(24, -56, 0, 48 << 5, 48 << 5, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +static Vtx sArrowSelectIndicatorVtx[] = { + // Fire Arrow + VTX(-18, 56, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(18, 56, 0, 16 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-18, 20, 0, 0 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(18, 20, 0, 16 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Ice Arrow + VTX(-56, 18, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-20, 18, 0, 16 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-56, -18, 0, 0 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-20, -18, 0, 16 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + // Light Arrow + VTX(20, 18, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(56, 18, 0, 16 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(20, -18, 0, 0 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(56, -18, 0, 16 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +// Vertices for A button indicator (coordinates 1.5x larger than texture size) +static Vtx sArrowSelectAButtonVtx[] = { + VTX(-18, -20, 0, 0 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(18, -20, 0, 24 << 5, 0 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(-18, -44, 0, 0 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), + VTX(18, -44, 0, 24 << 5, 16 << 5, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +void KaleidoScope_DrawArrowSelectExtras(PlayState* play, u8 slot, u8 isSelecting, u8 canSelect) { + PauseContext* pauseCtx = &play->pauseCtx; + + OPEN_DISPS(play->state.gfxCtx); + + // Update active cycling animation timer + if (isSelecting) { + if (sSlotCycleActiveAnimTimer[slot] < 5) { + sSlotCycleActiveAnimTimer[slot]++; + } } else { - bowIndex = currentBow - ITEM_BOW_ARROW_FIRE + 1; - } - for (int i = 1; i < ARRAY_COUNT(sBowArrowItems); i++) { - int index = (bowIndex + i) % ARRAY_COUNT(sBowArrowItems); - if (INV_CONTENT(sArrowItems[index] != ITEM_NONE)) { - return sBowArrowItems[index]; + if (sSlotCycleActiveAnimTimer[slot] > 0) { + sSlotCycleActiveAnimTimer[slot]--; } } - return ITEM_NONE; -} -u8 KaleidoScope_GetPrevBow() { - u8 currentBow = INV_CONTENT(ITEM_BOW); - u8 bowIndex; - if (currentBow == ITEM_BOW) { - bowIndex = 0; - } else { - bowIndex = currentBow - ITEM_BOW_ARROW_FIRE + 1; - } - for (int i = ARRAY_COUNT(sBowArrowItems) - 1; i > 0; i--) { - int index = (bowIndex + i) % ARRAY_COUNT(sBowArrowItems); - if (INV_CONTENT(sArrowItems[index] != ITEM_NONE)) { - return sBowArrowItems[index]; + u8 slotItem = KaleidoScope_ItemInSlot(slot); + u8 showFire = INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE; + u8 showIce = INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE; + u8 showLight = INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE; + + if (canSelect && slotItem != ITEM_NONE && (showFire || showIce || showLight)) { + Matrix_Push(); + + Vtx* itemTopLeft = &pauseCtx->itemVtx[slot * 4]; + Vtx* itemBottomRight = &itemTopLeft[3]; + + s16 halfX = (itemBottomRight->v.ob[0] - itemTopLeft->v.ob[0]) / 2; + s16 halfY = (itemBottomRight->v.ob[1] - itemTopLeft->v.ob[1]) / 2; + + Matrix_Translate(itemTopLeft->v.ob[0] + halfX, itemTopLeft->v.ob[1] + halfY, 0, MTXMODE_APPLY); + + f32 animScale = (f32)(5 - sSlotCycleActiveAnimTimer[slot]) / 5; + + // When not selecting or actively animating, shrink and move the items under the main slot item + if (!isSelecting || sSlotCycleActiveAnimTimer[slot] < 5) { + f32 finalScale = 1.0f - (0.675f * animScale); + Matrix_Scale(finalScale, finalScale, 1.0f, MTXMODE_APPLY); } + + gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + // Render A button indicator when hovered and not cycling + if (!isSelecting && sSlotCycleActiveAnimTimer[slot] == 0 && pauseCtx->cursorSlot[PAUSE_ITEM] == slot && + pauseCtx->cursorSpecialPos == 0) { + Color_RGB8 aButtonColor = { 0, 100, 255 }; + if (CVarGetInteger("gCosmetics.Hud_AButton.Changed", 0)) { + aButtonColor = CVarGetColor24("gCosmetics.Hud_AButton.Value", aButtonColor); + } else if (CVarGetInteger("gCosmetics.DefaultColorScheme", COLORSCHEME_N64) == COLORSCHEME_GAMECUBE) { + aButtonColor = (Color_RGB8){ 0, 255, 100 }; + } + + gSPVertex(POLY_KAL_DISP++, sArrowSelectAButtonVtx, 4, 0); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, aButtonColor.r, aButtonColor.g, aButtonColor.b, pauseCtx->alpha); + gDPLoadTextureBlock(POLY_KAL_DISP++, gABtnSymbolTex, G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); + gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); + } + + // Render a dark circle behind the arrows when selecting + if (isSelecting) { + gSPVertex(POLY_KAL_DISP++, sArrowSelectCircleVtx, 16, 0); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 0, 0, 0, pauseCtx->alpha * (1.0f - animScale)); + gDPLoadTextureBlock_4b(POLY_KAL_DISP++, gPausePromptCursorTex, G_IM_FMT_I, 48, 48, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + + if (showFire) { + gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); + } + if (showIce) { + gSP1Quadrangle(POLY_KAL_DISP++, 4, 6, 7, 5, 0); + } + if (showLight) { + gSP1Quadrangle(POLY_KAL_DISP++, 8, 10, 11, 9, 0); + } + gSP1Quadrangle(POLY_KAL_DISP++, 12, 14, 15, 13, 0); + } + + if (isSelecting || sSlotCycleActiveAnimTimer[slot] != 0) { + // Render arrows + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + gSPVertex(POLY_KAL_DISP++, sArrowSelectExtraItemVtx, 16, 0); + if (showFire) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[ITEM_ARROW_FIRE], 32, 32, 0); + } + if (showIce) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[ITEM_ARROW_ICE], 32, 32, 4); + } + if (showLight) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[ITEM_ARROW_LIGHT], 32, 32, 8); + } + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gArrowIconTex, 32, 32, 12); + } else { + // Render arrows + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + gSPVertex(POLY_KAL_DISP++, sArrowSelectIndicatorVtx, 12, 0); + if (showFire) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gFireArrowPowerTex, 16, 16, 0); + } + if (showIce) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gIceArrowPowerTex, 16, 16, 4); + } + if (showLight) { + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gLightArrowPowerTex, 16, 16, 8); + } + } + + Matrix_Pop(); } - return ITEM_NONE; + + CLOSE_DISPS(play->state.gfxCtx); } void KaleidoScope_DrawItemSelect(PlayState* play) { @@ -642,16 +796,61 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } if (gSelectingArrow) { pauseCtx->cursorColorSet = 8; - if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP))) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), KaleidoScope_GetNextBow()); - } else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN))) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), KaleidoScope_GetNextBow()); + + // Select arrow with stick/d-pad + // Up = Fire + // Left = Ice + // Right = Light + // Down = Normal + u8 newBow = ITEM_NONE; + u16 arrowCursorSlot; + if (pauseCtx->stickRelY < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DDOWN))) { + newBow = ITEM_BOW; + arrowCursorSlot = cursorSlot + 6; + } else if (pauseCtx->stickRelY > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) { + newBow = (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE) ? ITEM_BOW_ARROW_FIRE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 6; + } else if (pauseCtx->stickRelX < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) { + newBow = (INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE) ? ITEM_BOW_ARROW_ICE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 1; + } else if (pauseCtx->stickRelX > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) { + newBow = (INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE) ? ITEM_BOW_ARROW_LIGHT : ITEM_NONE; + arrowCursorSlot = cursorSlot + 1; + } + + // If you double select an arrow, reset to normal + if (newBow == INV_CONTENT(ITEM_BOW)) { + newBow = ITEM_BOW; + } + + // If double selecting regular arrows, cancel + if (newBow == ITEM_BOW && INV_CONTENT(ITEM_BOW) == ITEM_BOW) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + gSelectingArrow = false; + newBow = ITEM_NONE; + } + + if (newBow != ITEM_NONE) { + u16 sfxId; + if (newBow == ITEM_BOW || CVarGetInteger("gSkipArrowAnimation", 0)) { + sfxId = NA_SE_SY_DECIDE; + pauseCtx->equipTargetItem = newBow; + pauseCtx->equipAnimAlpha = 255; + sEquipState = ES_MAGIC_ARROW_APPLYING; + } else { + sfxId = NA_SE_SY_SET_FIRE_ARROW + (newBow - ITEM_BOW_ARROW_FIRE); + pauseCtx->equipTargetItem = 0xBF - ITEM_BOW_ARROW_FIRE + newBow; + pauseCtx->equipAnimAlpha = 0; + sEquipState = ES_MAGIC_ARROW_GLOWING; + } + + Audio_PlaySoundGeneral(sfxId, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + pauseCtx->equipAnimX = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[0] * 10; + pauseCtx->equipAnimY = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[1] * 10; + sEquipMoveTimer = 6; + sEquipAnimTimer = 0; + pauseCtx->unk_1E4 = 3; } - gSelectingArrow = cursorSlot == SLOT_ALT_BOW; } u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; @@ -790,8 +989,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { gSelectingMask, canMaskSelect, childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); - KaleidoScope_DrawItemCycleExtras(play, SLOT_ALT_BOW, gSelectingArrow, canArrowSelect, - KaleidoScope_GetPrevBow(), KaleidoScope_GetNextBow()); + KaleidoScope_DrawArrowSelectExtras(play, SLOT_ALT_BOW, gSelectingArrow, canArrowSelect); CLOSE_DISPS(play->state.gfxCtx); } From c6e0c789e5577f7f6214007f4d57a7aec5d1f9fa Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Fri, 29 Dec 2023 08:59:42 -0600 Subject: [PATCH 24/60] Allow cycling bomb arrows to normal arrows --- .../actors/ovl_player_actor/z_player.c | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 204fc34cda4..d8cbf7dd267 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2281,7 +2281,7 @@ bool Player_CanSwitchArrows(Player* this) { return false; } - if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_LIGHT) { + if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_BOMB) { return false; } @@ -2292,27 +2292,34 @@ bool Player_SwitchArrowsIfEnabled(Player* this) { if (!CVarGetInteger("gArrowSwitching", 0)) { return false; } - if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_LIGHT) { + if (this->heldItemAction < PLAYER_IA_BOW || this->heldItemAction > PLAYER_IA_BOW_BOMB) { return false; } if (!CHECK_BTN_ANY(sControlInput->press.button, CVarGetInteger("gArrowSwitchBtnMap", BTN_R))) { return false; } - u8 i, newItem, newItemAction; - const u8 arrowCount = ARRAY_COUNT(arrowTypeToItem); - u8 heldArrowAP = this->heldItemAction - PLAYER_IA_BOW; - for (i = 1; i < arrowCount; i++) { - u8 arrowAP = (heldArrowAP + i) % arrowCount; - ArrowItems items = arrowTypeToItem[arrowAP]; - if (INV_CONTENT(items.asArrow) != ITEM_NONE) { - newItem = items.asBowArrow; - newItemAction = PLAYER_IA_BOW + arrowAP; - break; + u8 newItem, newItemAction; + // Cycle bomb arrow to bow, but not light arrow to bomb arrow + if (this->heldItemAction == PLAYER_IA_BOW_BOMB) { + newItem = ITEM_BOW; + newItemAction = PLAYER_IA_BOW; + } else { + u8 i; + const u8 arrowCount = ARRAY_COUNT(arrowTypeToItem); + u8 heldArrowAP = this->heldItemAction - PLAYER_IA_BOW; + for (i = 1; i < arrowCount; i++) { + u8 arrowAP = (heldArrowAP + i) % arrowCount; + ArrowItems items = arrowTypeToItem[arrowAP]; + if (INV_CONTENT(items.asArrow) != ITEM_NONE) { + newItem = items.asBowArrow; + newItemAction = PLAYER_IA_BOW + arrowAP; + break; + } + } + if (i == arrowCount) { + return false; } - } - if (i == arrowCount) { - return false; } gSaveContext.equips.buttonItems[this->heldItemButton] = newItem; From fa8a0e2a7686ab3b120d767e477f016da715b417 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 31 Dec 2023 11:58:31 -0700 Subject: [PATCH 25/60] [Rando] Fix Check Tracker Area Totals (#3758) * Fix the calculation of `areaChecksGotten` to account for flags functionality setting invisible checks. Change `areaChecksTotal` to dynamic calculation based on tracker visibility, now that all checks are being added to `checksByArea`. Both are updated in realtime when either "Show all GS locations" or "Hide right side shop items" are toggled. Reformat all remaining unencapsulated if statements. * Changed helper variable change and call to `RecalculateAreaTotals()` to when the options are toggled instead of checking every frame. Removed redundant if...else. Clarified areaChecksGotten increment/decrement functionality based on current status and incoming status change. * Removed unused code. --- .../randomizer/randomizer_check_tracker.cpp | 179 ++++++++++++------ 1 file changed, 118 insertions(+), 61 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index d9c2424af51..39418485f57 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -107,8 +107,9 @@ std::map> checksByArea; bool areasFullyChecked[RCAREA_INVALID]; u32 areasSpoiled = 0; bool showVOrMQ; -s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)" -bool optCollapseAll; // A bool that will collapse all checks once +s8 areaChecksGotten[RCAREA_INVALID]; //| "Kokiri Forest (4/9)" +s8 areaCheckTotals[RCAREA_INVALID]; +bool optCollapseAll; // A bool that will collapse all checks once bool optExpandAll; // A bool that will expand all checks once RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK; RandomizerCheckArea previousArea = RCAREA_INVALID; @@ -225,6 +226,26 @@ void TrySetAreas() { } } +void RecalculateAreaTotals() { + for (auto [rcArea, rcObjects] : checksByArea) { + if (rcArea == RCAREA_INVALID) { + return; + } + areaChecksGotten[rcArea] = 0; + areaCheckTotals[rcArea] = 0; + for (auto rcObj : rcObjects) { + if (!IsVisibleInCheckTracker(rcObj)) { + continue; + } + areaCheckTotals[rcArea]++; + if (gSaveContext.checkTrackerData[rcObj.rc].skipped || gSaveContext.checkTrackerData[rcObj.rc].status == RCSHOW_COLLECTED + || gSaveContext.checkTrackerData[rcObj.rc].status == RCSHOW_SAVED) { + areaChecksGotten[rcArea]++; + } + } + } +} + void SetCheckCollected(RandomizerCheck rc) { gSaveContext.checkTrackerData[rc].status = RCSHOW_COLLECTED; RandomizerCheckObject rcObj; @@ -233,10 +254,12 @@ void SetCheckCollected(RandomizerCheck rc) { } else { rcObj = RandomizerCheckObjects::GetAllRCObjects().find(rc)->second; } - if (!gSaveContext.checkTrackerData[rc].skipped) { - areaChecksGotten[rcObj.rcArea]++; - } else { - gSaveContext.checkTrackerData[rc].skipped = false; + if (IsVisibleInCheckTracker(rcObj)) { + if (!gSaveContext.checkTrackerData[rc].skipped) { + areaChecksGotten[rcObj.rcArea]++; + } else { + gSaveContext.checkTrackerData[rc].skipped = false; + } } SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); @@ -346,6 +369,7 @@ void ClearAreaChecksAndTotals() { for (auto& [rcArea, vec] : checksByArea) { vec.clear(); areaChecksGotten[rcArea] = 0; + areaCheckTotals[rcArea] = 0; } } @@ -425,9 +449,9 @@ void CheckTrackerLoadGame(int32_t fileNum) { TrySetAreas(); for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) { RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc]; - if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET || - !RandomizerCheckObjects::GetAllRCObjects().contains(rc)) + if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET || !RandomizerCheckObjects::GetAllRCObjects().contains(rc)) { continue; + } RandomizerCheckObject realRcObj; if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) { @@ -437,8 +461,11 @@ void CheckTrackerLoadGame(int32_t fileNum) { } checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj); - if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) { - areaChecksGotten[realRcObj.rcArea]++; + if (IsVisibleInCheckTracker(realRcObj)) { + areaCheckTotals[realRcObj.rcArea]++; + if (rcTrackerData.status == RCSHOW_COLLECTED || rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) { + areaChecksGotten[realRcObj.rcArea]++; + } } if (areaChecksGotten[realRcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(realRcObj.rcArea)) { @@ -463,6 +490,7 @@ void CheckTrackerLoadGame(int32_t fileNum) { checksByArea.find(startingArea)->second.push_back(linksPocket); areaChecksGotten[startingArea]++; + areaCheckTotals[startingArea]++; } showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER || @@ -514,10 +542,6 @@ void CheckTrackerTransition(uint32_t sceneNum) { } void CheckTrackerFrame() { - if (IS_RANDO) { - hideShopRightChecks = CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1); - alwaysShowGS = CVarGetInteger("gCheckTrackerOptionAlwaysShowGSLocs", 0); - } if (!GameInteractor::IsSaveLoaded()) { return; } @@ -787,9 +811,13 @@ void Teardown() { void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) { auto area = RandomizerCheckObjects::GetAllRCObjects().find(static_cast(check))->second.rcArea; - if (!gSaveContext.checkTrackerData[check].skipped && data.skipped) { + if ((!gSaveContext.checkTrackerData[check].skipped && data.skipped) || + ((gSaveContext.checkTrackerData[check].status != RCSHOW_COLLECTED && gSaveContext.checkTrackerData[check].status != RCSHOW_SAVED) && + (data.status == RCSHOW_COLLECTED || data.status == RCSHOW_SAVED))) { areaChecksGotten[area]++; - } else if (gSaveContext.checkTrackerData[check].skipped && !data.skipped) { + } else if ((gSaveContext.checkTrackerData[check].skipped && !data.skipped) || + ((gSaveContext.checkTrackerData[check].status == RCSHOW_COLLECTED || gSaveContext.checkTrackerData[check].status == RCSHOW_SAVED) && + (data.status != RCSHOW_COLLECTED && data.status != RCSHOW_SAVED))) { areaChecksGotten[area]--; } gSaveContext.checkTrackerData[check] = data; @@ -902,8 +930,7 @@ void CheckTrackerWindow::DrawElement() { for (auto& [rcArea, objs] : checksByArea) { RandomizerCheckArea thisArea = currentArea; - const int areaChecksTotal = static_cast(objs.size()); - thisAreaFullyChecked = (areaChecksGotten[rcArea] == areaChecksTotal); + thisAreaFullyChecked = (areaChecksGotten[rcArea] == areaCheckTotals[rcArea]); //Last Area needs to be cleaned up if (lastArea != RCAREA_INVALID && doDraw) { UIWidgets::PaddedSeparator(); @@ -940,10 +967,11 @@ void CheckTrackerWindow::DrawElement() { stemp = RandomizerCheckObjects::GetRCAreaName(rcArea) + "##TreeNode"; ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f, mainColor.b / 255.0f, mainColor.a / 255.0f)); - if (doingCollapseOrExpand) + if (doingCollapseOrExpand) { ImGui::SetNextItemOpen(collapseLogic, ImGuiCond_Always); - else + } else { ImGui::SetNextItemOpen(!thisAreaFullyChecked, ImGuiCond_Once); + } doDraw = ImGui::TreeNode(stemp.c_str()); ImGui::PopStyleColor(); ImGui::SameLine(); @@ -958,12 +986,14 @@ void CheckTrackerWindow::DrawElement() { if (isThisAreaSpoiled) { if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) { - if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(DungeonSceneLookupByArea(rcArea))) - ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaChecksTotal); - else - ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaChecksTotal); + if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains( + DungeonSceneLookupByArea(rcArea))) { + ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaCheckTotals[rcArea]); + } else { + ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaCheckTotals[rcArea]); + } } else { - ImGui::Text("(%d/%d)", areaChecksGotten[rcArea], areaChecksTotal); + ImGui::Text("(%d/%d)", areaChecksGotten[rcArea], areaCheckTotals[rcArea]); } } else { ImGui::Text("???"); @@ -977,11 +1007,13 @@ void CheckTrackerWindow::DrawElement() { doAreaScroll = false; } for (auto rco : objs) { - if (doDraw && isThisAreaSpoiled && IsVisibleInCheckTracker(rco)) + if (IsVisibleInCheckTracker(rco) && doDraw && isThisAreaSpoiled) { DrawLocation(rco); + } } - if (doDraw) + if (doDraw) { ImGui::TreePop(); + } } areaMask <<= 1; } @@ -1200,8 +1232,9 @@ void UpdateAreaFullyChecked(RandomizerCheckArea area) { void UpdateAreas(RandomizerCheckArea area) { areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size(); - if (areaChecksGotten[area] != 0 || RandomizerCheckObjects::AreaIsOverworld(area)) + if (areaChecksGotten[area] != 0 || RandomizerCheckObjects::AreaIsOverworld(area)) { areasSpoiled |= (1 << area); + } } void UpdateAllOrdering() { @@ -1229,30 +1262,36 @@ bool CompareChecks(RandomizerCheckObject i, RandomizerCheckObject j) { bool iSaved = iShow.status == RCSHOW_SAVED; bool jCollected = jShow.status == RCSHOW_COLLECTED || jShow.status == RCSHOW_SAVED; bool jSaved = jShow.status == RCSHOW_SAVED; - if (!iCollected && jCollected) + + if (!iCollected && jCollected) { return true; - else if (iCollected && !jCollected) + } else if (iCollected && !jCollected) { return false; + } - if (!iSaved && jSaved) + if (!iSaved && jSaved) { return true; - else if (iSaved && !jSaved) + } else if (iSaved && !jSaved) { return false; + } - if (!iShow.skipped && jShow.skipped) + if (!iShow.skipped && jShow.skipped) { return true; - else if (iShow.skipped && !jShow.skipped) + } else if (iShow.skipped && !jShow.skipped) { return false; + } - if (!IsEoDCheck(i.rcType) && IsEoDCheck(j.rcType)) + if (!IsEoDCheck(i.rcType) && IsEoDCheck(j.rcType)) { return true; - else if (IsEoDCheck(i.rcType) && !IsEoDCheck(j.rcType)) + } else if (IsEoDCheck(i.rcType) && !IsEoDCheck(j.rcType)) { return false; + } - if (i.rc < j.rc) + if (i.rc < j.rc) { return true; - else if (i.rc > j.rc) + } else if (i.rc > j.rc) { return false; + } return false; } @@ -1270,47 +1309,54 @@ void DrawLocation(RandomizerCheckObject rcObj) { RandomizerCheckStatus status = checkData.status; bool skipped = checkData.skipped; if (status == RCSHOW_COLLECTED) { - if (!showHidden && CVarGetInteger("gCheckTrackerCollectedHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerCollectedHide", 0)) { return; + } mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default) : - CVarGetColor("gCheckTrackerCollectedMainColor", Color_Main_Default); + CVarGetColor("gCheckTrackerCollectedMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default); } else if (status == RCSHOW_SAVED) { - if (!showHidden && CVarGetInteger("gCheckTrackerSavedHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerSavedHide", 0)) { return; - mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default) : - CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default); + } + mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default) : + CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default); } else if (skipped) { - if (!showHidden && CVarGetInteger("gCheckTrackerSkippedHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerSkippedHide", 0)) { return; - mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default) : - CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default); + } + mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default) : + CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default); } else if (status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED) { - if (!showHidden && CVarGetInteger("gCheckTrackerSeenHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerSeenHide", 0)) { return; - mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default) : - CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default); + } + mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default) : + CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default); } else if (status == RCSHOW_SCUMMED) { - if (!showHidden && CVarGetInteger("gCheckTrackerKnownHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerKnownHide", 0)) { return; - mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default) : - CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default); + } + mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default) : + CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default); } else if (status == RCSHOW_UNCHECKED) { - if (!showHidden && CVarGetInteger("gCheckTrackerUncheckedHide", 0)) + if (!showHidden && CVarGetInteger("gCheckTrackerUncheckedHide", 0)) { return; - mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default) : - CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default); + } + mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default) : + CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default); } //Main Text txt = rcObj.rcShortName; - if (lastLocationChecked == rcObj.rc) + if (lastLocationChecked == rcObj.rc) { txt = "* " + txt; + } // Draw button - for Skipped/Seen/Scummed/Unchecked only if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) { @@ -1385,8 +1431,9 @@ void DrawLocation(RandomizerCheckObject rcObj) { break; } } - if (txt == "" && skipped) - txt = "Skipped"; //TODO language + if (txt == "" && skipped) { + txt = "Skipped"; // TODO language + } if (txt != "") { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f)); @@ -1412,8 +1459,9 @@ int hue = 0; void RainbowTick() { float freqHue = hue * 2 * M_PI / (360 * CVarGetFloat("gCosmetics.RainbowSpeed", 0.6f)); for (auto& cvar : rainbowCVars) { - if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0) + if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0) { continue; + } Color_RGBA8 newColor; newColor.r = sin(freqHue + 0) * 127 + 128; @@ -1520,9 +1568,15 @@ void CheckTrackerSettingsWindow::DrawElement() { } UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers"); UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked."); - UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true); + if (UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true)) { + hideShopRightChecks = !hideShopRightChecks; + RecalculateAreaTotals(); + } UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops."); - UIWidgets::EnhancementCheckbox("Always show gold skulltulas", "gCheckTrackerOptionAlwaysShowGSLocs", false, ""); + if (UIWidgets::EnhancementCheckbox("Always show gold skulltulas", "gCheckTrackerOptionAlwaysShowGSLocs", false, "")) { + alwaysShowGS = !alwaysShowGS; + RecalculateAreaTotals(); + } UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings."); ImGui::TableNextColumn(); @@ -1577,6 +1631,9 @@ void CheckTrackerWindow::InitElement() { GameInteractor::Instance->RegisterGameHook(CheckTrackerSceneFlagSet); GameInteractor::Instance->RegisterGameHook(CheckTrackerFlagSet); + hideShopRightChecks = CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1); + alwaysShowGS = CVarGetInteger("gCheckTrackerOptionAlwaysShowGSLocs", 0); + LocationTable_Init(); } From 96abadd904d6f5eaa2bd947c2d0fbe43bdba5f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaro=20Mart=C3=ADnez?= Date: Sun, 31 Dec 2023 16:06:47 -0500 Subject: [PATCH 26/60] Update Boost download URL (#3776) --- soh/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index fd0c6ac250a..9bf8b973d7d 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -328,7 +328,7 @@ endif() include(FetchContent) FetchContent_Declare( Boost - URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz + URL https://sourceforge.net/projects/boost/files/boost/1.81.0/boost_1_81_0.tar.gz URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6 SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it) DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change From 6cb3a830bdbfb09e228c073cdf61f8dc8f7b28d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaro=20Mart=C3=ADnez?= Date: Fri, 5 Jan 2024 18:41:09 -0500 Subject: [PATCH 27/60] Restore previous Boost download URL (#3809) This reverts commit 96abadd904d6f5eaa2bd947c2d0fbe43bdba5f8c. --- soh/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 9bf8b973d7d..fd0c6ac250a 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -328,7 +328,7 @@ endif() include(FetchContent) FetchContent_Declare( Boost - URL https://sourceforge.net/projects/boost/files/boost/1.81.0/boost_1_81_0.tar.gz + URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6 SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it) DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change From 37b2fc0745a149d039b0944ce4e35c0bddc6d1e8 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 6 Jan 2024 01:51:48 +0000 Subject: [PATCH 28/60] Make noclip only effect player (#3788) --- soh/src/code/z_bgcheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/code/z_bgcheck.c b/soh/src/code/z_bgcheck.c index 4acc68e55c2..7c99e7ca28c 100644 --- a/soh/src/code/z_bgcheck.c +++ b/soh/src/code/z_bgcheck.c @@ -1902,7 +1902,7 @@ s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResul s32 bgId2; f32 nx, ny, nz; // unit normal of polygon - if (CVarGetInteger("gNoClip", 0) != 0) { + if (CVarGetInteger("gNoClip", 0) && actor != NULL && actor->id == ACTOR_PLAYER) { return false; } From 02938cfba20911dc95f68d60ff66b85901ecef44 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 5 Jan 2024 18:53:18 -0700 Subject: [PATCH 29/60] Fix Starting Triforce Piece Count (#3797) * Move zeroing of triforcePiecesCollected to the beginning of `Randomizer_InitSaveFile()` to fix starting TFP count issues. --- soh/soh/Enhancements/randomizer/savefile.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 33278d0b757..fb04eca0c61 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -207,6 +207,9 @@ extern "C" void Randomizer_InitSaveFile() { gSaveContext.randomizerInf[i] = 0; } + // Reset triforce pieces collected + gSaveContext.triforcePiecesCollected = 0; + gSaveContext.cutsceneIndex = 0; // no intro cutscene // Starts pending ice traps out at 0 before potentially incrementing them down the line. gSaveContext.pendingIceTrapCount = 0; @@ -442,8 +445,5 @@ extern "C" void Randomizer_InitSaveFile() { gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth } - // Reset triforce pieces collected - gSaveContext.triforcePiecesCollected = 0; - SetStartingItems(); } From 321c258d6912f8bac7ad04be8cd6a9f947aa4024 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:55:09 +0000 Subject: [PATCH 30/60] Fix Fire Temple Boss Door Logic (#3774) * Fix Fire Temple Boss Door Logic * Update soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp Co-authored-by: Adam Bird --------- Co-authored-by: Adam Bird --- .../randomizer/3drando/location_access/locacc_fire_temple.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp index 440483af64f..ff2fb885c53 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp @@ -40,7 +40,7 @@ void AreaTable_Init_FireTemple() { }, { //Exits Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), - Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}}), + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && (LogicFireBossDoorJump || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}))) || CanUse(HOVER_BOOTS));}}), }); areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { From 21796367a0fcde197d94dcfa5d72f50c54192770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaro=20Mart=C3=ADnez?= Date: Mon, 8 Jan 2024 13:39:49 -0500 Subject: [PATCH 31/60] Use temporary mirror for Boost download URL (#3822) --- soh/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index fd0c6ac250a..5c239ae132f 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -328,7 +328,7 @@ endif() include(FetchContent) FetchContent_Declare( Boost - URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz + URL https://archives.boost.io/release/1.81.0/source/boost_1_81_0.tar.gz URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6 SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it) DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change From 8426cc93e597a734160460544c6b1f8869d637ad Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 15 Jan 2024 10:25:57 -0500 Subject: [PATCH 32/60] Fix: Tektite texture not loading for death animation (#3808) * fix tektite death texture loading * add string header --- soh/src/overlays/actors/ovl_En_Part/z_en_part.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Part/z_en_part.c b/soh/src/overlays/actors/ovl_En_Part/z_en_part.c index e1b65efcad0..be1143ff115 100644 --- a/soh/src/overlays/actors/ovl_En_Part/z_en_part.c +++ b/soh/src/overlays/actors/ovl_En_Part/z_en_part.c @@ -8,6 +8,8 @@ #include "objects/object_tite/object_tite.h" #include "objects/object_ik/object_ik.h" +#include // strcmp + #define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED void EnPart_Init(Actor* thisx, PlayState* play); @@ -297,11 +299,11 @@ void EnPart_Draw(Actor* thisx, PlayState* play) { gSPSegment(POLY_OPA_DISP++, 0x08, func_80ACEAC0(play->state.gfxCtx, 255, 255, 255, 180, 180, 180)); gSPSegment(POLY_OPA_DISP++, 0x09, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0)); gSPSegment(POLY_OPA_DISP++, 0x0A, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0)); - } else if ((thisx->params == 9) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) { + } else if ((thisx->params == 9) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) { gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001300); gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001700); gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_001900); - } else if ((thisx->params == 10) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) { + } else if ((thisx->params == 10) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) { gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001B00); gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001F00); gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_002100); From 861bd09848b7653e747105f26d532fb57c2ca9c2 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 15 Jan 2024 08:26:19 -0700 Subject: [PATCH 33/60] Adds a log statement to show the SoH version at startup, in case crashes don't produce a stack trace from which to glean that information. (#3786) --- soh/soh/OTRGlobals.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 4c564afde72..4f2e4ee7edf 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -297,6 +297,7 @@ OTRGlobals::OTRGlobals() { }; // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3); + SPDLOG_INFO("Starting Ship of Harkinian version {}", (char*)gBuildVersion); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared()); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared()); From db02870a05461a09159a6b9e302056211f1ac625 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:30:20 +0000 Subject: [PATCH 34/60] Restore Original Scene Command Object List Behaviour (MacReady) (#3827) * Restore Original Scene_CommandObjectList Behaviour * remove some vrom stuff * add some comments --- soh/soh/z_scene_otr.cpp | 50 ++++++++++++++++------------------------- soh/src/code/z_actor.c | 6 +++-- soh/src/code/z_scene.c | 7 ++++-- 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index ef98a4b3af2..54065e27e64 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -149,6 +149,13 @@ bool Scene_CommandMeshHeader(PlayState* play, LUS::ISceneCommand* cmd) { extern "C" void* func_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId); +bool OTRfunc_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId) { + + objectCtx->status[bankIndex].id = -objectId; + + return false; +} + bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) { // LUS::SetObjectList* cmdObj = static_pointer_cast(cmd); LUS::SetObjectList* cmdObj = (LUS::SetObjectList*)cmd; @@ -164,49 +171,30 @@ bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) { void* nextPtr; k = 0; - // i = play->objectCtx.unk_09; - i = 0; + i = play->objectCtx.unk_09; firstStatus = &play->objectCtx.status[0]; status = &play->objectCtx.status[i]; - for (int i = 0; i < cmdObj->objects.size(); i++) { - bool alreadyIncluded = false; - - for (int j = 0; j < play->objectCtx.num; j++) { - if (play->objectCtx.status[j].id == cmdObj->objects[i]) { - alreadyIncluded = true; - break; + // Loop until a mismatch in the object lists + // Then clear all object ids past that in the context object list and kill actors for those objects + for (i = play->objectCtx.unk_09, k = 0; i < play->objectCtx.num; i++, k++) { + if (play->objectCtx.status[i].id != cmdObj->objects[k]) { + for (j = i; j < play->objectCtx.num; j++) { + play->objectCtx.status[j].id = OBJECT_INVALID; } - } - - if (!alreadyIncluded) { - play->objectCtx.status[play->objectCtx.num++].id = cmdObj->objects[i]; func_80031A28(play, &play->actorCtx); + break; } } - /* - while (i < play->objectCtx.num) { - if (status->id != *objectEntry) { - status2 = &play->objectCtx.status[i]; - for (j = i; j < play->objectCtx.num; j++) { - status2->id = OBJECT_INVALID; - status2++; - } - play->objectCtx.num = i; - func_80031A28(play, &play->actorCtx); - - continue; + // Continuing from the last index, add the remaining object ids from the command object list + for (; k < cmdObj->objects.size(); k++, i++) { + if (i < OBJECT_EXCHANGE_BANK_MAX - 1) { + OTRfunc_800982FC(&play->objectCtx, i, cmdObj->objects[k]); } - - i++; - k++; - objectEntry++; - status++; } play->objectCtx.num = i; - */ return false; } diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 79a3c8ace21..dfb3e440718 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -1219,8 +1219,7 @@ void Actor_Init(Actor* actor, PlayState* play) { CollisionCheck_InitInfo(&actor->colChkInfo); actor->floorBgId = BGCHECK_SCENE; ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f); - //if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) - { + if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) { //Actor_SetObjectDependency(play, actor); actor->init(actor, play); actor->init = NULL; @@ -3129,6 +3128,9 @@ void Actor_FreeOverlay(ActorDBEntry* dbEntry) { osSyncPrintf(VT_RST); } +// SoH: Flag to check if actors are being spawned from the actor entry list +// This flag is checked against to allow actors which dont have an objectBankIndex in the objectCtx slot/status array to spawn +// An example of what this fixes, is that it allows hookshot to be used as child int gMapLoading = 0; Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 posX, f32 posY, f32 posZ, diff --git a/soh/src/code/z_scene.c b/soh/src/code/z_scene.c index 2a0a5d5d782..579e84eda37 100644 --- a/soh/src/code/z_scene.c +++ b/soh/src/code/z_scene.c @@ -83,9 +83,10 @@ void Object_UpdateBank(ObjectContext* objectCtx) { RomFile* objectFile; size_t size; - /* + for (i = 0; i < objectCtx->num; i++) { if (status->id < 0) { + /* if (status->dmaRequest.vromAddr == 0) { osCreateMesgQueue(&status->loadQueue, &status->loadMsg, 1); objectFile = &gObjectTable[-status->id]; @@ -96,10 +97,12 @@ void Object_UpdateBank(ObjectContext* objectCtx) { } else if (!osRecvMesg(&status->loadQueue, NULL, OS_MESG_NOBLOCK)) { status->id = -status->id; } + */ + status->id = -status->id; } status++; } - */ + } s32 Object_GetIndex(ObjectContext* objectCtx, s16 objectId) { From 1da1b1a2bb5b453a111ea42512d1c9869c0b0541 Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 15 Jan 2024 10:39:54 -0500 Subject: [PATCH 35/60] Tweak: Improve pause menu dungeon map performance (#3773) * add map palettes per pulse to leverage shader caching * use unregister blended with kaleido maps * use Gfx_TextureCacheDelete for KD lava * bump lus * add miss tex clears for KD --- libultraship | 2 +- soh/include/z64.h | 5 ++- soh/soh/OTRGlobals.cpp | 18 ++++++++++ soh/soh/OTRGlobals.h | 2 ++ soh/src/code/z_map_exp.c | 1 - .../actors/ovl_Boss_Dodongo/z_boss_dodongo.c | 33 +++++++++---------- .../ovl_kaleido_scope/z_kaleido_map_PAL.c | 13 +++++--- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 32 +++++++++--------- 8 files changed, 66 insertions(+), 40 deletions(-) diff --git a/libultraship b/libultraship index b4abd7c366b..96c8a8929c1 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit b4abd7c366b1fb38b2cd80ffb91e129035bee0ea +Subproject commit 96c8a8929c18c1bffd7d92a35a589f74cf16fc59 diff --git a/soh/include/z64.h b/soh/include/z64.h index 23ffcfb1717..f790dddc759 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -744,7 +744,6 @@ typedef struct { /* 0x0134 */ char** doActionSegment; /* 0x0138 */ u8* iconItemSegment; /* 0x013C */ char** mapSegment; - char** mapSegmentName; /* 0x0140 */ u8 mapPalette[32]; /* 0x0160 */ DmaRequest dmaRequest_160; /* 0x0180 */ DmaRequest dmaRequest_180; @@ -815,6 +814,10 @@ typedef struct { /* 0x026C */ u8 dinsNayrus; // "m_magic"; din's fire and nayru's love /* 0x026D */ u8 all; // "another"; enables all item restrictions } restrictions; + // #region SOH [General] + /* */ char* mapSegmentName[2]; // Tracks the map segment texture by OTR sig name + /* */ u8 mapPalettesPulse[40][32]; // Used to have unique pointers per map pulse color for the shader backend. 40 for map pulse timer x2 + // #endregion } InterfaceContext; // size = 0x270 typedef struct { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 4f2e4ee7edf..6543c5b8c20 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2598,6 +2598,24 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla gfx_register_blended_texture(name, mask, replacement); } +extern "C" void Gfx_UnregisterBlendedTexture(const char* name) { + gfx_unregister_blended_texture(name); +} + +extern "C" void Gfx_TextureCacheDelete(const uint8_t* texAddr) { + char* imgName = (char*)texAddr; + + if (texAddr == nullptr) { + return; + } + + if (ResourceMgr_OTRSigCheck(imgName)) { + texAddr = (const uint8_t*)GetResourceDataByNameHandlingMQ(imgName); + } + + gfx_texture_cache_delete(texAddr); +} + void SoH_ProcessDroppedFiles(std::string filePath) { try { std::ifstream configStream(filePath); diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 9b42e689550..a93df7efbf2 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -173,6 +173,8 @@ void Entrance_InitEntranceTrackingData(void); void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex); void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex); void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); +void Gfx_UnregisterBlendedTexture(const char* name); +void Gfx_TextureCacheDelete(const uint8_t* addr); void SaveManager_ThreadPoolWait(); void CheckTracker_OnMessageClose(); diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index c4db0098b23..213ee018d54 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -524,7 +524,6 @@ void Map_Init(PlayState* play) { interfaceCtx->unk_25A = -1; interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*)); - interfaceCtx->mapSegmentName = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*)); // "MAP texture initialization scene_data_ID=%d mapSegment=%x" osSyncPrintf("\n\n\nMAP テクスチャ初期化 scene_data_ID=%d\nmapSegment=%x\n\n", play->sceneNum, interfaceCtx->mapSegment, play); diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index deb761641de..1f279154070 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -10,10 +10,6 @@ #include // malloc #include // memcpy -// OTRTODO: Replace usage of this method when we can clear the cache -// for a single texture without the need of a DL opcode in the render code -void gfx_texture_cache_clear(); - #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED) #define LAVA_TEX_WIDTH 32 @@ -123,7 +119,9 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { sMaskTexLava[i] = maskVal; } } + Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, NULL); + Gfx_TextureCacheDelete(sMaskTexLava); return; } @@ -165,7 +163,9 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { } } - gfx_texture_cache_clear(); + Gfx_TextureCacheDelete(sMaskTexLava); + Gfx_TextureCacheDelete(sLavaWavyTex); + Gfx_TextureCacheDelete(sLavaFloorModifiedTex); } void func_808C12C4(u8* arg1, s16 arg2) { @@ -228,6 +228,7 @@ void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) { } free(sp54); + Gfx_TextureCacheDelete(sLavaWavyTexRaw); } // Modified to support CPU modified texture with the resource system @@ -255,6 +256,8 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) { temp_s3[i + temp2] = sp54[i + i2]; } } + + Gfx_TextureCacheDelete(sLavaWavyTex); } void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) { @@ -373,6 +376,13 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) { Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL); Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL); + // Clear cache for masks + Gfx_TextureCacheDelete(sMaskTex8x16); + Gfx_TextureCacheDelete(sMaskTex8x32); + Gfx_TextureCacheDelete(sMaskTex16x16); + Gfx_TextureCacheDelete(sMaskTex16x32); + Gfx_TextureCacheDelete(sMaskTex32x16); + BossDodongo_RegisterBlendedLavaTextureUpdate(); // Register alt listener to update the blended lava for the replacement texture based on alt path @@ -1206,6 +1216,7 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) { } } else { sMaskTexLava[new_var] = 1; + Gfx_TextureCacheDelete(sMaskTexLava); } this->unk_1C2 += 37; @@ -1345,18 +1356,6 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) { gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16); } - gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava); - - // Using WORK_DISP to invalidate these textures as they are used in drawing the scene textures which happens - // before actors are drawn. WORK_DISP comes before POLAY_OPA_DISP. It is probably not meant for this, but it - // at least works for now. - // Alternatively, having a way to invalidate just these pointers from the Update func should be sufficient. - if (sLavaFloorModifiedTexRaw != NULL) { - gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTexRaw); - } else { - gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTex); - } - if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) { POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099); } else { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c index 28723d3d029..34dc47aa900 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c @@ -312,6 +312,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { KaleidoScope_DrawQuadTextureRGBA32(gfxCtx, gQuestIconGoldSkulltulaTex, 24, 24, 8); } + // Unique index for both pulse phases + uint8_t palettePulseIdx = (mapBgPulseStage ? 40 : 20) - mapBgPulseTimer; + if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) { stepR = (mapBgPulseR - mapBgPulseColors[mapBgPulseStage][0]) / mapBgPulseTimer; stepG = (mapBgPulseG - mapBgPulseColors[mapBgPulseStage][1]) / mapBgPulseTimer; @@ -324,6 +327,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { interfaceCtx->mapPalette[28] = (rgba16 & 0xFF00) >> 8; interfaceCtx->mapPalette[29] = rgba16 & 0xFF; + interfaceCtx->mapPalettesPulse[palettePulseIdx][28] = (rgba16 & 0xFF00) >> 8; + interfaceCtx->mapPalettesPulse[palettePulseIdx][29] = rgba16 & 0xFF; + mapBgPulseTimer--; if (mapBgPulseTimer == 0) { mapBgPulseStage ^= 1; @@ -335,7 +341,8 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gDPSetTextureFilter(POLY_KAL_DISP++, G_TF_POINT); gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalette); + // Use a unique palette address per frame so the renderer/shader can cache all variations + gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalettesPulse[palettePulseIdx]); gDPSetTextureLUT(POLY_KAL_DISP++, G_TT_RGBA16); u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0); @@ -349,10 +356,6 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[60], 8, 0); - // The dungeon map textures are recreated each frame, so always invalidate them - gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]); - gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]); - gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH, MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 877ea7e6f42..1475472a9af 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -1205,8 +1205,6 @@ Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, void** textures) { return gfx; } -static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT]; - void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { static Color_RGB8 D_8082ACF4[12] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 }, @@ -1375,10 +1373,6 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { } } - // Need to invalidate the blend mask every frame. Ideally this would be done in KaleidoScope_DrawDungeonMap - // but the reference is not shared between files - gSPInvalidateTexCache(POLY_KAL_DISP++, mapBlendMask); - if (pauseCtx->pageIndex) { // pageIndex != PAUSE_ITEM gDPPipeSync(OVERLAY_DISP++); gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA); @@ -3326,6 +3320,7 @@ static uint8_t mapLeftTexModified[MAP_48x85_TEX_SIZE]; static uint8_t mapRightTexModified[MAP_48x85_TEX_SIZE]; static uint8_t* mapLeftTexModifiedRaw = NULL; static uint8_t* mapRightTexModifiedRaw = NULL; +static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT]; // Load dungeon maps into the interface context // SoH [General] - Modified to account for our resource system and HD textures @@ -3357,19 +3352,16 @@ void KaleidoScope_LoadDungeonMap(PlayState* play) { size_t size = (width * height) / 2; // account for CI4 size // Resource size being larger than the calculated CI size means it is most likely not a CI4 texture - // Abort early end undo the blended effect by clearing the mask to avoid crashing + // Abort early and unregister the blended effect to avoid crashing if (size < ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0])) { - if (mapBlendMask[0] != 0) { - for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) { - mapBlendMask[i] = 0; - } - } - interfaceCtx->mapSegment[0] = NULL; interfaceCtx->mapSegment[1] = NULL; - Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, NULL); - Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, NULL); + Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[0]); + Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[1]); + + Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]); + Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]); return; } @@ -3404,6 +3396,11 @@ void KaleidoScope_LoadDungeonMap(PlayState* play) { Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]); Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]); + + Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]); + Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]); + Gfx_TextureCacheDelete(interfaceCtx->mapSegment[0]); + Gfx_TextureCacheDelete(interfaceCtx->mapSegment[1]); } static uint8_t registeredDungeonMapTextureHook = false; @@ -3444,6 +3441,11 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) { KaleidoScope_LoadDungeonMap(play); Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3); + // Copy the map palette values to all pulse palettes + for (uint8_t i = 0; i < ARRAY_COUNT(interfaceCtx->mapPalettesPulse); i++) { + memcpy(interfaceCtx->mapPalettesPulse[i], interfaceCtx->mapPalette, sizeof(interfaceCtx->mapPalette)); + } + s32 size = MAP_48x85_TEX_SIZE; if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) { From dd5d8088f6b7fcf545459454ae29bd51119c7343 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:31:06 +0000 Subject: [PATCH 36/60] Revert actor uncullZone related checks back to match decomp (#3828) --- soh/src/code/z_actor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index dfb3e440718..df9b6c75833 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -2860,9 +2860,9 @@ s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) { if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) { var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3; - if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 2.0f) && - (((arg2->y + actor->uncullZoneDownward) * var) > -2.0f) && - (((arg2->y - actor->uncullZoneScale) * var) < 2.0f)) { + if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 1.0f) && + (((arg2->y + actor->uncullZoneDownward) * var) > -1.0f) && + (((arg2->y - actor->uncullZoneScale) * var) < 1.0f)) { return true; } } From 63cf3610e5f2483b9da25be3858ac05f671174dc Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 15 Jan 2024 11:31:33 -0500 Subject: [PATCH 37/60] Fix: Move Ruto earring fix to graphic patch and fix Ganon fight rubble DL reference (#3810) * move ruto earing fix to real patch * use stringpath for ganon rubble --- .../cosmetics/authenticGfxPatches.cpp | 16 ++++++++++++++++ soh/src/overlays/actors/ovl_Demo_Gj/z_demo_gj.c | 6 +++--- soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c | 13 ------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp b/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp index de97f3840b2..709854c3569 100644 --- a/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp +++ b/soh/soh/Enhancements/cosmetics/authenticGfxPatches.cpp @@ -8,6 +8,7 @@ extern "C" { #include "objects/object_gi_soldout/object_gi_soldout.h" #include "objects/object_ik/object_ik.h" #include "objects/object_link_child/object_link_child.h" +#include "objects/object_ru2/object_ru2.h" uint32_t ResourceMgr_GameHasMasterQuest(); uint32_t ResourceMgr_GameHasOriginal(); @@ -187,10 +188,25 @@ void PatchIronKnuckleTextureOverflow() { } } +void PatchPrincessRutoEaring() { + // FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings. + // Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so + // it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the + // earring texture loads into the same place in TMEM as the brick texture, so when it comes to rendering, TEXEL1 + // uses the earring texture with different clamp settings, and it displays without noticeable error. However, both + // texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses + // our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces + // TEXEL1 with TEXEL0, which is most likely the original intention, and all is well. + ResourceMgr_PatchGfxByName(gAdultRutoHeadDL, "RutoEaringTileFix", 162, + gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, + TEXEL0, 0, PRIM_LOD_FRAC, COMBINED)); +} + void ApplyAuthenticGfxPatches() { PatchDekuStickTextureOverflow(); PatchFreezardTextureOverflow(); PatchIronKnuckleTextureOverflow(); + PatchPrincessRutoEaring(); } // Patches the Sold Out GI DL to render the texture in the mirror boundary diff --git a/soh/src/overlays/actors/ovl_Demo_Gj/z_demo_gj.c b/soh/src/overlays/actors/ovl_Demo_Gj/z_demo_gj.c index 5f3737b44d9..357b2c0ca92 100644 --- a/soh/src/overlays/actors/ovl_Demo_Gj/z_demo_gj.c +++ b/soh/src/overlays/actors/ovl_Demo_Gj/z_demo_gj.c @@ -192,11 +192,11 @@ void DemoGj_Explode(DemoGj* this, PlayState* play, Vec3f* initialPos, Vec3f* dir phi_s0 = 0x21; } - Gfx* gfx = ResourceMgr_LoadGfxByName(gGanonRubbleDL); - + // SoH [Port] Changed from &gGanonsCastleRubbleAroundArenaDL[28] to gGanonRubbleDL as it seems this was an error in the original rom/decomp + // Other calls to EffectSsKakera_Spawn with OBJECT_GEFF use gGanonRubbleDL, so this change is to match that EffectSsKakera_Spawn(play, &explosionPos, &velocity, initialPos, -200, phi_s0, 10, 10, 0, Rand_ZeroOne() * 20.0f + 20.0f, 20, 300, (s32)(Rand_ZeroOne() * 30.0f) + 30, -1, - OBJECT_GEFF, gfx); + OBJECT_GEFF, gGanonRubbleDL); theta += 0x2AAA; } diff --git a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c index 6be42b42dad..fe4a7772490 100644 --- a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c +++ b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c @@ -821,19 +821,6 @@ void func_80AF3F20(EnRu2* this, PlayState* play) { void EnRu2_Draw(Actor* thisx, PlayState* play) { EnRu2* this = (EnRu2*)thisx; - // FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings. - // Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so - // it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the - // earring texture loads into the same place in tmem as the brick texture, so when it comes to rendering, TEXEL1 - // uses the earring texture with diffrent clamp settings, and it displays without noticeable error. However, both - // texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses - // our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces - // TEXEL1 with TEXEL0, which is most likely the original intention, and all is well. - Gfx* gfx = ResourceMgr_LoadGfxByName(gAdultRutoHeadDL); - Gfx patch = gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, TEXEL0, 0, - PRIM_LOD_FRAC, COMBINED); - gfx[0xA2] = patch; - if ((this->drawConfig < 0) || (this->drawConfig >= ARRAY_COUNT(sDrawFuncs)) || (sDrawFuncs[this->drawConfig] == 0)) { // "Draw Mode is improper!" From cb82e77e407ca80dc23c61cfce78fa8ea174a221 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Fri, 2 Feb 2024 01:15:13 +0000 Subject: [PATCH 38/60] fix bombchu logic bugs (#3720) --- soh/soh/Enhancements/randomizer/3drando/logic.cpp | 2 +- soh/soh/OTRGlobals.cpp | 3 +-- soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c | 7 +++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.cpp b/soh/soh/Enhancements/randomizer/3drando/logic.cpp index 580c687d096..df127e69931 100644 --- a/soh/soh/Enhancements/randomizer/3drando/logic.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/logic.cpp @@ -536,7 +536,7 @@ namespace Logic { Fish = HasBottle && FishAccess; Fairy = HasBottle && FairyAccess; - FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20); + FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20) && (BombBag || BombchusInLogic); CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag); HasBombchus = (BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus)); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 6543c5b8c20..391db3b8c9d 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2487,8 +2487,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { randoInf = RAND_INF_MERCHANTS_CARPET_SALESMAN; } messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(randoInf, textId, Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_ON_HINT); - } else if (Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) && - (textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT)) { + } else if (textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); } else if (textId == TEXT_CURSED_SKULLTULA_PEOPLE) { actorParams = GET_PLAYER(play)->targetActor->params; 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 037b4b59438..6aa1b7d412d 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 @@ -1027,8 +1027,8 @@ void EnGirlA_BuyEvent_ObtainBombchuPack(PlayState* play, EnGirlA* this) { Rupees_ChangeBy(-this->basePrice); // Normally, buying a bombchu pack sets a flag indicating the pack is now sold out - // If they're in logic for rando, skip setting that flag so they can be purchased repeatedly - if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC)) { + // If we're in rando, skip setting that flag so they can be purchased repeatedly + if (IS_RANDO) { return; } @@ -1255,8 +1255,7 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, PlayState* play) { this->itemGiveFunc = itemEntry->itemGiveFunc; this->buyEventFunc = itemEntry->buyEventFunc; // If chus are in logic, make the 10 pack affordable without a wallet upgrade - if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) && - this->getItemId == GI_BOMBCHUS_10) { + if (IS_RANDO && this->getItemId == GI_BOMBCHUS_10) { this->basePrice = 99; } else { this->basePrice = itemEntry->price; From e3825ec2630c50335d809102e5a9febc53972031 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 1 Feb 2024 18:23:06 -0700 Subject: [PATCH 39/60] Unify defaults for reward count sliders with Greg As Reward so they need to register changes. (#3875) --- soh/soh/Enhancements/randomizer/randomizer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4b9a84eff2d..ab3554174b2 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -4207,7 +4207,7 @@ void RandomizerSettingsWindow::DrawElement() { break; case RO_LACS_GREG_REWARD: UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount", - "gRandomizeLacsStoneCount", 1, 4, "", 4, true, true, false); + "gRandomizeLacsStoneCount", 1, 4, "", 3, true, true, false); break; case RO_LACS_WILDCARD_REWARD: UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount", @@ -4236,7 +4236,7 @@ void RandomizerSettingsWindow::DrawElement() { break; case RO_LACS_GREG_REWARD: UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount", - "gRandomizeLacsMedallionCount", 1, 7, "", 7, true, true, false); + "gRandomizeLacsMedallionCount", 1, 7, "", 6, true, true, false); break; case RO_LACS_WILDCARD_REWARD: UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount", @@ -4265,7 +4265,7 @@ void RandomizerSettingsWindow::DrawElement() { break; case RO_LACS_GREG_REWARD: UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount", - "gRandomizeLacsRewardCount", 1, 10, "", 10, true, true, false); + "gRandomizeLacsRewardCount", 1, 10, "", 9, true, true, false); break; case RO_LACS_WILDCARD_REWARD: UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount", @@ -4294,7 +4294,7 @@ void RandomizerSettingsWindow::DrawElement() { break; case RO_LACS_GREG_REWARD: UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount", - "gRandomizeLacsDungeonCount", 1, 9, "", 9, true, true, false); + "gRandomizeLacsDungeonCount", 1, 9, "", 8, true, true, false); break; case RO_LACS_WILDCARD_REWARD: UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount", From 7ef6a434f92c6529952aef3e0848daf246f149bf Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 1 Feb 2024 20:25:57 -0500 Subject: [PATCH 40/60] fix timestamp truncation (#3874) --- soh/soh/OTRGlobals.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 391db3b8c9d..64d70da8806 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1144,8 +1144,7 @@ extern "C" uint64_t GetUnixTimestamp() { auto time = std::chrono::system_clock::now(); auto since_epoch = time.time_since_epoch(); auto millis = std::chrono::duration_cast(since_epoch); - long now = millis.count(); - return now; + return (uint64_t)millis.count(); } // C->C++ Bridge From 16ee20c2a8c7ec6bcb7076d4a962a206387acc90 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 1 Feb 2024 18:26:36 -0700 Subject: [PATCH 41/60] Renames Freecam to Free Look. (#3771) Adds helper info for invert, distance, and transition speed options. --- .../controls/GameControlEditor.cpp | 24 +++++++++++-------- soh/src/code/z_camera.c | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index eb69f3cc852..976912b63a7 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -258,24 +258,28 @@ namespace GameControlEditor { window->EndGroupPanelPublic(0); UIWidgets::Spacer(0); - window->BeginGroupPanelPublic("Third-Person Camera", ImGui::GetContentRegionAvail()); + window->BeginGroupPanelPublic("Free Look/Third-person Camera", ImGui::GetContentRegionAvail()); - UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera"); - DrawHelpIcon("Enables free camera control\nNote: You must remap C buttons off of the right stick in the " + UIWidgets::PaddedEnhancementCheckbox("Enable Free Look", "gFreeCamera"); + DrawHelpIcon("Enables free look camera control\nNote: You must remap C buttons off of the right stick in the " "controller config menu, and map the camera stick to the right stick."); - UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis"); - DrawHelpIcon("Inverts the Camera X Axis in:\n-Free camera"); - UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true); - DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free camera"); + UIWidgets::PaddedEnhancementCheckbox("Invert X Axis", "gInvertXAxis"); + DrawHelpIcon("Inverts the Camera X Axis in:\n-Free Look"); + UIWidgets::PaddedEnhancementCheckbox("Invert Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true); + DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free Look"); UIWidgets::Spacer(0); - UIWidgets::PaddedEnhancementSliderFloat("Third-Person Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal", + UIWidgets::PaddedEnhancementSliderFloat("Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal", "gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true); - UIWidgets::PaddedEnhancementSliderFloat("Third-Person Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical", + DrawHelpIcon("Changes the sensitivity of the X axis control for Free Look"); + UIWidgets::PaddedEnhancementSliderFloat("Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical", "gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true); + DrawHelpIcon("Changes the sensitivity of the Y axis control for Free Look"); UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist", "gFreeCameraDistMax", 100, 900, "", 185, true, false, true); - UIWidgets::PaddedEnhancementSliderInt("Camera Transition Speed: %d", "##CamTranSpeed", + DrawHelpIcon("How far the camera sits from Link while in Free Look mode"); + UIWidgets::PaddedEnhancementSliderInt("Transition Speed: %d", "##CamTranSpeed", "gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true); + DrawHelpIcon("How quickly the camera changes to the distance specified above"); window->EndGroupPanelPublic(0); } diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c index a177e29e7b2..4353d397e6c 100644 --- a/soh/src/code/z_camera.c +++ b/soh/src/code/z_camera.c @@ -7887,7 +7887,7 @@ s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags) { } } - // Clear free camera if an action is performed that would move the camera (targeting, first person, talking) + // Clear free look if an action is performed that would move the camera (targeting, first person, talking) if (CVarGetInteger("gFreeCamera", 0) && SetCameraManual(camera) == 1 && ((mode >= CAM_MODE_TARGET && mode <= CAM_MODE_BATTLE) || (mode >= CAM_MODE_FIRSTPERSON && mode <= CAM_MODE_CLIMBZ) || mode == CAM_MODE_HANGZ || From 61cf2bd323e8e31d416d9d2e325b02fb2c6a2260 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 1 Feb 2024 18:29:24 -0700 Subject: [PATCH 42/60] No Magic Numbers for Preset Location Exclusions (#3801) * Adds `FormatLocations` and `PRESET_ENTRY_TYPE_CPP_STRING` to allow for feeding `RandomizerCheck` values directly in presets instead of a string with magic numbers. * Switch to concatenation with `std::to_string`. * Forgot to remove include XD --- soh/soh/Enhancements/presets.cpp | 11 +++++++++++ soh/soh/Enhancements/presets.h | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/presets.cpp b/soh/soh/Enhancements/presets.cpp index 7b2ca659584..726863e0550 100644 --- a/soh/soh/Enhancements/presets.cpp +++ b/soh/soh/Enhancements/presets.cpp @@ -12,6 +12,14 @@ void clearCvars(std::vector cvarsToClear) { } } +std::string FormatLocations(std::vector locs) { + std::string locString = ""; + for (auto loc: locs) { + locString += std::to_string(loc) + ","; + } + return locString; +} + void applyPreset(std::vector entries) { for(auto& [cvar, type, value] : entries) { switch (type) { @@ -24,6 +32,9 @@ void applyPreset(std::vector entries) { case PRESET_ENTRY_TYPE_STRING: CVarSetString(cvar, std::get(value)); break; + case PRESET_ENTRY_TYPE_CPP_STRING: + CVarSetString(cvar, std::get(value).c_str()); + break; } } } diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..cac60cdefe0 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -11,6 +12,7 @@ enum PresetEntryType { PRESET_ENTRY_TYPE_S32, PRESET_ENTRY_TYPE_FLOAT, PRESET_ENTRY_TYPE_STRING, + PRESET_ENTRY_TYPE_CPP_STRING, }; enum PresetType { @@ -36,15 +38,19 @@ enum RandomizerPreset { typedef struct PresetEntry { const char* cvar; PresetEntryType type; - std::variant value; + std::variant value; } PresetEntry; +std::string FormatLocations(std::vector locs); + #define PRESET_ENTRY_S32(cvar, value) \ { cvar, PRESET_ENTRY_TYPE_S32, value } #define PRESET_ENTRY_FLOAT(cvar, value) \ { cvar, PRESET_ENTRY_TYPE_FLOAT, value } #define PRESET_ENTRY_STRING(cvar, value) \ { cvar, PRESET_ENTRY_TYPE_STRING, value } +#define PRESET_ENTRY_CPP_STRING(cvar, value) \ + { cvar, PRESET_ENTRY_TYPE_CPP_STRING, value } void DrawPresetSelector(PresetType presetType); void clearCvars(std::vector cvarsToClear); @@ -866,7 +872,8 @@ const std::vector spockRacePresetEntries = { PRESET_ENTRY_S32("gRandomizeDampeHint", 1), PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN), PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1), - PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"), + PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations( + { RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })), PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN), PRESET_ENTRY_S32("gRandomizeFullWallets", 1), PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP), @@ -958,7 +965,8 @@ const std::vector spockRaceNoLogicPresetEntries = { PRESET_ENTRY_S32("gRandomizeDampeHint", 1), PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN), PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1), - PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"), + PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations( + { RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })), PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN), PRESET_ENTRY_S32("gRandomizeFullWallets", 1), PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP), @@ -1011,7 +1019,7 @@ const std::vector s6PresetEntries = { PRESET_ENTRY_S32("gRandomizeBigPoeTargetCount", 1), PRESET_ENTRY_S32("gRandomizeCuccosToReturn", 4), PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN), - PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "48,"), + PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations({ RC_DEKU_THEATER_MASK_OF_TRUTH })), PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_CLOSED_DEKU), PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP), PRESET_ENTRY_S32("gRandomizeGerudoFortress", RO_GF_FAST), From 2529dc59bd5ab3be95ed7d5530cde90bc48758de Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Fri, 2 Feb 2024 01:58:08 +0000 Subject: [PATCH 43/60] Increase Door Cull range (#3888) * cullzone * better cvar name * Update soh/src/code/z_actor.c * Update soh/src/code/z_actor.c --------- Co-authored-by: Garrett Cox --- soh/src/code/z_actor.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index df9b6c75833..c1dc66e23bf 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -2860,11 +2860,19 @@ s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) { if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) { var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3; - if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 1.0f) && - (((arg2->y + actor->uncullZoneDownward) * var) > -1.0f) && - (((arg2->y - actor->uncullZoneScale) * var) < 1.0f)) { + // #region SoH [Widescreen support] + // Doors will cull quite noticeably on wider screens. For these actors the zone is increased + f32 limit = 1.0f; + if (((actor->id == ACTOR_EN_DOOR) || (actor->id == ACTOR_DOOR_SHUTTER)) && CVarGetInteger("gIncreaseDoorUncullZones", 1)) { + limit = 2.0f; + } + + if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < limit) && + (((arg2->y + actor->uncullZoneDownward) * var) > -limit) && + (((arg2->y - actor->uncullZoneScale) * var) < limit)) { return true; } + // #endregion } return false; From bb1078e99ca1789a2de696a4229dd27b1ec5da3c Mon Sep 17 00:00:00 2001 From: Rozelette Date: Thu, 1 Feb 2024 19:58:22 -0600 Subject: [PATCH 44/60] Account for removed object dependency in Deku Scrub Leader (#3878) * Account for removed object dependency in Deku Scrub Leader * Update soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c --------- Co-authored-by: Garrett Cox --- soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c b/soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c index ae09cb4384d..9ce27f4c1ea 100644 --- a/soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c +++ b/soh/src/overlays/actors/ovl_En_Dnt_Jiji/z_en_dnt_jiji.c @@ -101,6 +101,9 @@ void EnDntJiji_Destroy(Actor* thisx, PlayState* play) { } void EnDntJiji_SetFlower(EnDntJiji* this, PlayState* play) { + // SOH: Due to removed object dependencies, parent was still NULL when Init was called. In order to properly set + // stage, redo it here now that we are a frame later. + this->stage = (EnDntDemo*)this->actor.parent; if (this->actor.bgCheckFlags & 1) { this->flowerPos = this->actor.world.pos; this->actionFunc = EnDntJiji_SetupWait; From 107a365b71f8330559e667495174ba0ebc253e22 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:38:54 +0000 Subject: [PATCH 45/60] Add safety measure to Scene_CommandObjectList to prevent crash (#3904) * dont let k overflow * Update soh/soh/z_scene_otr.cpp Co-authored-by: Archez --------- Co-authored-by: Archez --- soh/soh/z_scene_otr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index 54065e27e64..33104326e3a 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -178,7 +178,7 @@ bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) { // Loop until a mismatch in the object lists // Then clear all object ids past that in the context object list and kill actors for those objects for (i = play->objectCtx.unk_09, k = 0; i < play->objectCtx.num; i++, k++) { - if (play->objectCtx.status[i].id != cmdObj->objects[k]) { + if (i >= cmdObj->objects.size() || play->objectCtx.status[i].id != cmdObj->objects[k]) { for (j = i; j < play->objectCtx.num; j++) { play->objectCtx.status[j].id = OBJECT_INVALID; } From 11a0a0063352018660467edaf0e66e38fb6b192b Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 15 Feb 2024 18:50:31 -0700 Subject: [PATCH 46/60] Add `CVarClear` to appropriate sections of randomizer Locations and Tricks tabs to get around issue with saving blank CVar strings. (#3916) --- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index ab3554174b2..835621fd35f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -4689,7 +4689,11 @@ void RandomizerSettingsWindow::DrawElement() { excludedLocationString += std::to_string(excludedLocationIt); excludedLocationString += ","; } - CVarSetString("gRandomizeExcludedLocations", excludedLocationString.c_str()); + if (excludedLocationString == "") { + CVarClear("gRandomizeExcludedLocations"); + } else { + CVarSetString("gRandomizeExcludedLocations", excludedLocationString.c_str()); + } LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } ImGui::SameLine(); @@ -4866,7 +4870,7 @@ void RandomizerSettingsWindow::DrawElement() { enabledTrickString += std::to_string(enabledTrickIt); enabledTrickString += ","; } - CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str()); + CVarClear("gRandomizeEnabledTricks"); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } ImGui::SameLine(); @@ -5070,7 +5074,7 @@ void RandomizerSettingsWindow::DrawElement() { enabledTrickString += std::to_string(enabledTrickIt); enabledTrickString += ","; } - CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str()); + CVarClear("gRandomizeEnabledTricks"); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } @@ -5108,7 +5112,11 @@ void RandomizerSettingsWindow::DrawElement() { enabledTrickString += std::to_string(enabledTrickIt); enabledTrickString += ","; } - CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str()); + if (enabledTrickString == "") { + CVarClear("gRandomizeEnabledTricks"); + } else { + CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str()); + } LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } DrawTagChips(*rtObject.rtTags); From 43fed2d77e7efe1c187c2fe5ae5794e95d5c8893 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:51:31 -0500 Subject: [PATCH 47/60] ci: pin switch docker image to known working version (#3917) --- .github/workflows/generate-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml index cd8a6fd9b0f..38cc4c9ad69 100644 --- a/.github/workflows/generate-builds.yml +++ b/.github/workflows/generate-builds.yml @@ -191,7 +191,7 @@ jobs: needs: generate-soh-otr runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }} container: - image: devkitpro/devkita64:latest + image: devkitpro/devkita64:20240120 steps: - name: Install dependencies run: | From 0cb4cd158aa1243cbec697fff6e663551764b39b Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 15 Feb 2024 18:53:18 -0700 Subject: [PATCH 48/60] Adds reset function to z_en_si (GS Token) to set getItemId to vanilla after resetting SoH. (#3925) --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 49e88f90345..f6c87074db9 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -16,6 +16,7 @@ void EnSi_Init(Actor* thisx, PlayState* play); void EnSi_Destroy(Actor* thisx, PlayState* play); void EnSi_Update(Actor* thisx, PlayState* play); void EnSi_Draw(Actor* thisx, PlayState* play); +void EnSi_Reset(); s32 func_80AFB748(EnSi* this, PlayState* play); void func_80AFB768(EnSi* this, PlayState* play); @@ -61,7 +62,7 @@ const ActorInit En_Si_InitVars = { (ActorFunc)EnSi_Destroy, (ActorFunc)EnSi_Update, (ActorFunc)EnSi_Draw, - NULL, + (ActorResetFunc)EnSi_Reset, }; void EnSi_Init(Actor* thisx, PlayState* play) { @@ -224,6 +225,11 @@ void EnSi_Draw(Actor* thisx, PlayState* play) { } } +void EnSi_Reset() { + textId = 0xB4; + giveItemId = ITEM_SKULL_TOKEN; +} + void Randomizer_UpdateSkullReward(EnSi* this, PlayState* play) { Player* player = GET_PLAYER(play); From 3d3b8bfc5b22fdc056cea448738fe904a8523f02 Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 15 Feb 2024 20:54:35 -0500 Subject: [PATCH 49/60] Allow IsSaveLoaded to consider debug saves (#3929) --- .../game-interactor/GameInteractor.cpp | 11 ++++++-- .../game-interactor/GameInteractor.h | 2 +- soh/soh/Enhancements/mods.cpp | 27 ++++++++++--------- soh/soh/Enhancements/tts/tts.cpp | 2 +- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor.cpp index eb330947bbb..5a0d0efd302 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.cpp @@ -37,12 +37,19 @@ GameInteractionEffectQueryResult GameInteractor::RemoveEffect(GameInteractionEff // MARK: - Helpers -bool GameInteractor::IsSaveLoaded() { +bool GameInteractor::IsSaveLoaded(bool allowDbgSave) { Player* player; if (gPlayState != NULL) { player = GET_PLAYER(gPlayState); } - return (gPlayState == NULL || player == NULL || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) ? false : true; + + // Checking for normal game mode prevents debug saves from reporting true on title screen + if (gPlayState == NULL || player == NULL || gSaveContext.gameMode != GAMEMODE_NORMAL) { + return false; + } + + // Valid save file or debug save + return (gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2) || (allowDbgSave && gSaveContext.fileNum == 0xFF); } bool GameInteractor::IsGameplayPaused() { diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 4f8ef259b4d..b56a001d206 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -198,7 +198,7 @@ class GameInteractor { DEFINE_HOOK(OnAssetAltChange, void()); // Helpers - static bool IsSaveLoaded(); + static bool IsSaveLoaded(bool allowDbgSave = false); static bool IsGameplayPaused(); static bool CanSpawnActor(); static bool CanAddOrTakeAmmo(int16_t amount, int16_t item); diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 6692dd5c971..258fbba4232 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -47,7 +47,7 @@ void ReloadSceneTogglingLinkAge() { void RegisterInfiniteMoney() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gInfiniteMoney", 0) != 0) { if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) { gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET); @@ -58,7 +58,7 @@ void RegisterInfiniteMoney() { void RegisterInfiniteHealth() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gInfiniteHealth", 0) != 0) { if (gSaveContext.health < gSaveContext.healthCapacity) { gSaveContext.health = gSaveContext.healthCapacity; @@ -69,7 +69,7 @@ void RegisterInfiniteHealth() { void RegisterInfiniteAmmo() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gInfiniteAmmo", 0) != 0) { // Deku Sticks if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) { @@ -106,7 +106,7 @@ void RegisterInfiniteAmmo() { void RegisterInfiniteMagic() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gInfiniteMagic", 0) != 0) { if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) { gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30; @@ -117,7 +117,7 @@ void RegisterInfiniteMagic() { void RegisterInfiniteNayrusLove() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gInfiniteNayru", 0) != 0) { gSaveContext.nayrusLoveTimer = 0x44B; } @@ -126,7 +126,7 @@ void RegisterInfiniteNayrusLove() { void RegisterMoonJumpOnL() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gMoonJumpOnL", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -141,7 +141,7 @@ void RegisterMoonJumpOnL() { void RegisterInfiniteISG() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gEzISG", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -153,7 +153,7 @@ void RegisterInfiniteISG() { //Permanent quick put away (QPA) glitched damage value void RegisterEzQPA() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gEzQPA", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -165,7 +165,7 @@ void RegisterEzQPA() { void RegisterUnrestrictedItems() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; if (CVarGetInteger("gNoRestrictItems", 0) != 0) { u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong; @@ -193,11 +193,14 @@ void RegisterFreezeTime() { /// Switches Link's age and respawns him at the last entrance he entered. void RegisterSwitchAge() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) { + static bool warped = false; + + if (!GameInteractor::IsSaveLoaded(true)) { CVarClear("gSwitchAge"); + warped = false; return; } - static bool warped = false; + static Vec3f playerPos; static int16_t playerYaw; static RoomContext* roomCtx; @@ -231,7 +234,7 @@ void RegisterSwitchAge() { void RegisterOcarinaTimeTravel() { GameInteractor::Instance->RegisterGameHook([]() { - if (!GameInteractor::IsSaveLoaded()) { + if (!GameInteractor::IsSaveLoaded(true)) { CVarClear("gTimeTravel"); return; } diff --git a/soh/soh/Enhancements/tts/tts.cpp b/soh/soh/Enhancements/tts/tts.cpp index 0b46cd18fcd..9e5ff4a42ae 100644 --- a/soh/soh/Enhancements/tts/tts.cpp +++ b/soh/soh/Enhancements/tts/tts.cpp @@ -168,7 +168,7 @@ void RegisterOnInterfaceUpdateHook() { prevTimer = timer; - if (!GameInteractor::IsSaveLoaded()) return; + if (!GameInteractor::IsSaveLoaded(true)) return; static int16_t lostHealth = 0; static int16_t prevHealth = 0; From cf6101f4daeb8591c65b8a3d0262b4888e000d06 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Fri, 16 Feb 2024 02:03:58 +0000 Subject: [PATCH 50/60] Logic bug: child cannot climb forest temple to the straight hallway either (#3934) --- .../randomizer/3drando/location_access/locacc_forest_temple.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp index fea9fda6f76..5e64aee6ce9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp @@ -172,7 +172,7 @@ void AreaTable_Init_ForestTemple() { Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}), Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && CanJumpslash && GoronBracelet);}}), Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}), - Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}), + Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return IsAdult && (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}), }); areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { From 30a063b75d504aaecec4b44a6f7d81f15fe778ff Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 15 Feb 2024 19:44:40 -0700 Subject: [PATCH 51/60] [Tweak] Move Personal Notes to Save File (#3909) * Moves personal notes to the save file under a new itemTracker save section. * Update soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp --------- Co-authored-by: Archez --- .../randomizer/randomizer_item_tracker.cpp | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index f24ab818b9d..f63b37b628b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -30,6 +30,8 @@ void DrawBottle(ItemTrackerItem item); void DrawQuest(ItemTrackerItem item); void DrawSong(ItemTrackerItem item); +int itemTrackerSectionId; + bool shouldUpdateVectors = true; std::vector mainWindowItems = {}; @@ -282,11 +284,6 @@ void ItemTrackerOnFrame() { } } -void SaveNotes(uint32_t fileNum) { - CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str()); - LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); -} - bool IsValidSaveFile() { bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2; return validSave; @@ -734,7 +731,7 @@ void DrawNotes(bool resizeable = false) { } if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) { notesNeedSave = false; - SaveNotes(gSaveContext.fileNum); + SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true); } ImGui::EndGroup(); } @@ -959,6 +956,26 @@ void UpdateVectors() { shouldUpdateVectors = false; } +void ItemTrackerInitFile(bool isDebug) { + itemTrackerNotes.clear(); + itemTrackerNotes.push_back(0); +} + +void ItemTrackerSaveFile(SaveContext* saveContext, int sectionID, bool fullSave) { + SaveManager::Instance->SaveData("personalNotes", std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str()); +} + +void ItemTrackerLoadFile() { + std::string initialTrackerNotes = ""; + SaveManager::Instance->LoadData("personalNotes", initialTrackerNotes); + itemTrackerNotes.resize(initialTrackerNotes.length() + 1); + if (initialTrackerNotes != "") { + SohUtils::CopyStringToCharArray(itemTrackerNotes.Data, initialTrackerNotes.c_str(), itemTrackerNotes.size()); + } else { + itemTrackerNotes.push_back(0); + } +} + void ItemTrackerWindow::DrawElement() { UpdateVectors(); @@ -1223,14 +1240,9 @@ void ItemTrackerWindow::InitElement() { itemTrackerNotes.push_back(0); } - GameInteractor::Instance->RegisterGameHook([](uint32_t fileNum) { - const char* initialTrackerNotes = CVarGetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), ""); - itemTrackerNotes.resize(strlen(initialTrackerNotes) + 1); - strcpy(itemTrackerNotes.Data, initialTrackerNotes); - }); - GameInteractor::Instance->RegisterGameHook([](uint32_t fileNum) { - CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), ""); - LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); - }); + SaveManager::Instance->AddInitFunction(ItemTrackerInitFile); + itemTrackerSectionId = SaveManager::Instance->AddSaveFunction("itemTrackerData", 1, ItemTrackerSaveFile, true, -1); + SaveManager::Instance->AddLoadFunction("itemTrackerData", 1, ItemTrackerLoadFile); + GameInteractor::Instance->RegisterGameHook(ItemTrackerOnFrame); } From 19af4481c08d44fe4bff85eb4662bfb559c4dbfb Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 20 Feb 2024 09:31:24 -0500 Subject: [PATCH 52/60] fix object unload using wrong index (#3949) --- soh/soh/z_scene_otr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index 33104326e3a..be1840ecdba 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -178,7 +178,7 @@ bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) { // Loop until a mismatch in the object lists // Then clear all object ids past that in the context object list and kill actors for those objects for (i = play->objectCtx.unk_09, k = 0; i < play->objectCtx.num; i++, k++) { - if (i >= cmdObj->objects.size() || play->objectCtx.status[i].id != cmdObj->objects[k]) { + if (k >= cmdObj->objects.size() || play->objectCtx.status[i].id != cmdObj->objects[k]) { for (j = i; j < play->objectCtx.num; j++) { play->objectCtx.status[j].id = OBJECT_INVALID; } From ef9fc0a9ec8716201dfaeb2d28d059171a066b7a Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 20 Feb 2024 09:38:10 -0500 Subject: [PATCH 53/60] fix endianess issue with camera setting data (#3950) --- soh/src/code/z_camera_data.inc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/soh/src/code/z_camera_data.inc b/soh/src/code/z_camera_data.inc index b9e0ba864ac..90b1874c73a 100644 --- a/soh/src/code/z_camera_data.inc +++ b/soh/src/code/z_camera_data.inc @@ -16,9 +16,11 @@ typedef struct { union { u32 unk_00; struct { - u32 unk_bit0 : 1; - u32 unk_bit1 : 1; - u32 validModes : 30; + // SoH [Port] These bitfield values are unused and led to shifting in validModes for little endian systems + // Removing those so that validModes can be a complete 32 bit value + // u32 unk_bit0 : 1; + // u32 unk_bit1 : 1; + u32 validModes; }; }; CameraMode* cameraModes; From ea1ffdd041651e3cf7caca70459891ff38465156 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 28 Feb 2024 19:04:44 -0700 Subject: [PATCH 54/60] Adds messageboxes to `no_ui` handling so they don't show if you have it on. (#3977) --- soh/src/code/z_message_PAL.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 7bb3803fcc6..87cff43da7c 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -8,6 +8,7 @@ #include "textures/message_static/message_static.h" #include "textures/message_texture_static/message_texture_static.h" #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/OTRGlobals.h" @@ -3069,7 +3070,9 @@ void Message_Draw(PlayState* play) { POLY_OPA_DISP = plusOne; } plusOne = Graph_GfxPlusOne(polyOpaP = POLY_OPA_DISP); - gSPDisplayList(OVERLAY_DISP++, plusOne); + if (!GameInteractor_NoUIActive()) { + gSPDisplayList(OVERLAY_DISP++, plusOne); + } Message_DrawMain(play, &plusOne); gSPEndDisplayList(plusOne++); Graph_BranchDlist(polyOpaP, plusOne); From 358dd47da7542efdc4fa7f768a4b1fe9be350368 Mon Sep 17 00:00:00 2001 From: Archez Date: Wed, 28 Feb 2024 22:03:08 -0500 Subject: [PATCH 55/60] remove zapd extraction from mac launch script (#3981) --- soh/macosx/soh-macos.sh.in | 234 ------------------------------------- 1 file changed, 234 deletions(-) diff --git a/soh/macosx/soh-macos.sh.in b/soh/macosx/soh-macos.sh.in index 0983f63b1b0..217496cf104 100755 --- a/soh/macosx/soh-macos.sh.in +++ b/soh/macosx/soh-macos.sh.in @@ -7,68 +7,6 @@ export RESPATH="${SNAME%/MacOS*}/Resources" export LIBPATH="${SNAME%/MacOS*}/Frameworks" export DYLD_FALLBACK_LIBRARY_PATH="$LIBPATH" -remap_hashes () -{ - # Remap v64 and n64 hashes to their z64 hash equivalent - # ZAPD will handle converting the data into z64 format - case "$ROMHASH" in - a9059b56e761c9034fbe02fe4c24985aaa835dac) # v64 - ROMHASH=cee6bc3c2a634b41728f2af8da54d9bf8cc14099 - ;; - 24708102dc504d3f375a37f4ae4e149c167dc515) # n64 - ROMHASH=cee6bc3c2a634b41728f2af8da54d9bf8cc14099 - ;; - 580dd0bd1b6d2c51cc20a764eece84dba558964c) # v64 - ROMHASH=0227d7c0074f2d0ac935631990da8ec5914597b4 - ;; - d6342c59007e57c1194661ec6880b2f078403f4e) # n64 - ROMHASH=0227d7c0074f2d0ac935631990da8ec5914597b4 - ;; - d0bdc2eb320668b4ba6893b9aefe4040a73123ff) # v64 - ROMHASH=328a1f1beba30ce5e178f031662019eb32c5f3b5 - ;; - 4946ab250f6ac9b32d76b21f309ebb8ebc8103d2) # n64 - ROMHASH=328a1f1beba30ce5e178f031662019eb32c5f3b5 - ;; - 663c34f1b2c05a09e5beffe4d0dcd440f7d49dc7) # v64 - ROMHASH=cfbb98d392e4a9d39da8285d10cbef3974c2f012 - ;; - 24c73d378b0620a380ce5ef9f2b186c6c157a68b) # n64 - ROMHASH=cfbb98d392e4a9d39da8285d10cbef3974c2f012 - ;; - 8ebf2e29313f44f2d49e5b4191971d09919e8e48) # v64 - ROMHASH=f46239439f59a2a594ef83cf68ef65043b1bffe2 - ;; - 4264bf7b875737b8fae77d52322a5099d051fc11) # n64 - ROMHASH=f46239439f59a2a594ef83cf68ef65043b1bffe2 - ;; - 973bc6fe56010a8d646166a1182a81b4f13b8cf9) # v64 - ROMHASH=50bebedad9e0f10746a52b07239e47fa6c284d03 - ;; - d327752c46edc70ff3668b9514083dbbee08927c) # v64 - ROMHASH=50bebedad9e0f10746a52b07239e47fa6c284d03 - ;; - ecdeb1747560834e079c22243febea7f6f26ba3b) # v64 - ROMHASH=079b855b943d6ad8bd1eb026c0ed169ecbdac7da - ;; - f19f8662ec7abee29484a272a6fda53e39efe0f1) # n64 - ROMHASH=079b855b943d6ad8bd1eb026c0ed169ecbdac7da - ;; - ab519ce04a33818ce2c39b3c514a751d807a494a) # v64 - ROMHASH=cfecfdc58d650e71a200c81f033de4e6d617a9f6 - ;; - c19a34f7646305e1755249fca2071e178bd7cd00) # n64 - ROMHASH=cfecfdc58d650e71a200c81f033de4e6d617a9f6 - ;; - 25e8ae79ea0839ca5c984473f7460d8040c36f9c) # v64 - ROMHASH=517bd9714c73cb96c21e7c2ef640d7b55186102f - ;; - 166c02770d67fcc3954c443eb400a6a3573d3fc0) # n64 - ROMHASH=517bd9714c73cb96c21e7c2ef640d7b55186102f - ;; - esac -} - if [ ! -e "$SHIP_HOME" ]; then mkdir "$SHIP_HOME"; fi if [ ! -e "$SHIP_HOME"/mods ]; then @@ -76,178 +14,6 @@ if [ ! -e "$SHIP_HOME"/mods ]; then touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt fi -# If either OTR doesn't exist kick off the OTR gen process -if [ ! -e "$SHIP_HOME"/oot.otr ] || [ ! -e "$SHIP_HOME"/oot-mq.otr ]; then - - # If no ROMs exist kick off the file selection prompts - while [ ! -e "$SHIP_HOME"/*.*64 ] && [ ! -e "$SHIP_HOME"/oot*.otr ]; do - - SHOULD_PROMPT_FOR_ROM=1 - while [ $SHOULD_PROMPT_FOR_ROM -eq 1 ]; do - SHOULD_PROMPT_FOR_ROM=0 - # Use osascript to prompt the user to chose a file - DROPROM=`osascript <<-EOF - set romFile to choose file of type {"b64","n64","v64","z64"} with prompt "Please select your ROM:" - return POSIX path of romFile - EOF` - - # If no rom was selected, the user cancelled, so exit - if [[ -z $DROPROM ]] && [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then - echo "No ROM selected. Exiting..." - exit 1 - elif [[ -z $DROPROM ]]; then - break; - fi - - # If an invalid rom was selected, let the user know and ask to try again - ROMHASH="$(shasum "$DROPROM" | awk '{ print $1 }')" - - remap_hashes - - case "$ROMHASH" in - cee6bc3c2a634b41728f2af8da54d9bf8cc14099) - ROM_TYPE=0;; - 0227d7c0074f2d0ac935631990da8ec5914597b4) - ROM_TYPE=0;; - 328a1f1beba30ce5e178f031662019eb32c5f3b5) - ROM_TYPE=0;; - cfbb98d392e4a9d39da8285d10cbef3974c2f012) - ROM_TYPE=0;; - f46239439f59a2a594ef83cf68ef65043b1bffe2) - ROM_TYPE=1;; - 50bebedad9e0f10746a52b07239e47fa6c284d03) - ROM_TYPE=1;; - 079b855b943d6ad8bd1eb026c0ed169ecbdac7da) - ROM_TYPE=1;; - cfecfdc58d650e71a200c81f033de4e6d617a9f6) - ROM_TYPE=1;; - 517bd9714c73cb96c21e7c2ef640d7b55186102f) - ROM_TYPE=1;; - *) - TRY_AGAIN_RESULT=`osascript <<-EOF - set alertText to "Incompatible ROM hash" - set alertMessage to "Incompatible ROM provided, would you like to try again?" - return display alert alertText \ - message alertMessage \ - as critical \ - buttons {"Cancel", "Try Again"} - EOF` - if [[ "$TRY_AGAIN_RESULT" == "button returned:Try Again" ]]; then - SHOULD_PROMPT_FOR_ROM=1 - continue; - else - echo "No ROM selected. Exiting..." - exit 1 - fi - esac - - cp "$DROPROM" "$SHIP_HOME" - - # Ask user if they would also like to select the other variant (MQ/Vanilla) - if [ $ROM_TYPE -eq 0 ] && [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then - UPLOAD_ANOTHER_RESULT=`osascript <<-EOF - set alertText to "Success" - set alertMessage to "Would you also like to provide a Master Quest ROM?" - return display alert alertText \ - message alertMessage \ - buttons {"No", "Yes"} - EOF` - elif [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then - UPLOAD_ANOTHER_RESULT=`osascript <<-EOF - set alertText to "Success" - set alertMessage to "Would you also like to provide a Vanilla (Non Master Quest) ROM?" - return display alert alertText \ - message alertMessage \ - buttons {"No", "Yes"} - EOF` - fi - - if [[ "$UPLOAD_ANOTHER_RESULT" == "button returned:Yes" ]]; then - UPLOAD_ANOTHER_RESULT="button returned:No" - SHOULD_PROMPT_FOR_ROM=1 - continue; - fi - break - done - done - - # At this point we should now have 1 or more valid roms in $SHIP_HOME directory - - # Prepare tmp dir - for ROMPATH in "$SHIP_HOME"/*.*64 - do - ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" - export ASSETDIR - cp -r "$RESPATH/assets" "$ASSETDIR" - mkdir -p "$ASSETDIR"/tmp - cp "$ROMPATH" "$ASSETDIR"/tmp/rom.z64 - cd "$ASSETDIR" || return - - # If an invalid rom was detected, let the user know - ROMHASH="$(shasum "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')" - - remap_hashes - - case "$ROMHASH" in - cee6bc3c2a634b41728f2af8da54d9bf8cc14099) - ROM=GC_NMQ_D - OTRNAME="oot.otr";; - 0227d7c0074f2d0ac935631990da8ec5914597b4) - ROM=GC_NMQ_PAL_F - OTRNAME="oot.otr";; - 328a1f1beba30ce5e178f031662019eb32c5f3b5) - ROM=N64_PAL_10 - OTRNAME="oot.otr";; - cfbb98d392e4a9d39da8285d10cbef3974c2f012) - ROM=N64_PAL_11 - OTRNAME="oot.otr";; - f46239439f59a2a594ef83cf68ef65043b1bffe2) - ROM=GC_MQ_PAL_F - OTRNAME="oot-mq.otr";; - 50bebedad9e0f10746a52b07239e47fa6c284d03) - ROM=GC_MQ_D - OTRNAME="oot-mq.otr";; - 079b855b943d6ad8bd1eb026c0ed169ecbdac7da) - ROM=GC_MQ_D - OTRNAME="oot-mq.otr";; - cfecfdc58d650e71a200c81f033de4e6d617a9f6) - ROM=GC_MQ_D - OTRNAME="oot-mq.otr";; - 517bd9714c73cb96c21e7c2ef640d7b55186102f) - ROM=GC_MQ_D - OTRNAME="oot-mq.otr";; - *) - osascript -e 'display notification "One or more invalid ROM provided" with title "Ship Of Harkinian"' - rm -r "$ASSETDIR" - cd "$SNAME" - continue; - esac - - # Only generate OTR if we don't have on of this type yet - if [ -e "$SHIP_HOME"/"$OTRNAME" ]; then - rm -r "$ASSETDIR" - cd "$SNAME" - continue; - fi - - osascript -e 'display notification "Generating OTR..." with title "Ship Of Harkinian"' - assets/extractor/ZAPD.out ed -i assets/extractor/xmls/"${ROM}" -b tmp/rom.z64 -fl assets/extractor/filelists -o placeholder -osf placeholder -gsf 1 -rconf assets/extractor/Config_"${ROM}".xml -se OTR --portVer "@CMAKE_PROJECT_VERSION@" - if [ -e "$ASSETDIR"/oot.otr ]; then - osascript -e 'display notification "OTR successfully generated" with title "Ship Of Harkinian"' - cp "$ASSETDIR"/oot.otr "$SHIP_HOME"/"$OTRNAME" - rm -r "$ASSETDIR" - cd "$SNAME" - fi - done - - if [ ! -e "$SHIP_HOME"/oot*.otr ]; then - osascript -e 'display notification "OTR failed to generate" with title "Ship Of Harkinian"' - exit 1; - fi -fi - -cd "$SNAME" - arch_name="$(uname -m)" launch_arch="arm64" if [ "${arch_name}" = "x86_64" ] && [ "$(sysctl -in sysctl.proc_translated)" != "1" ]; then From b26f2b21da3768b4caca370d5b3e6165849b4478 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 28 Feb 2024 20:12:23 -0700 Subject: [PATCH 56/60] [UX Improvement] Catch save loading errors and notify user (#3979) * Add `SohModalWindow` and `SohModal`. Runs as window, always "visible", but not drawing if no popups are registered. Adds error catching for save file corruption (malformed json) that renames the file in question to prevent future loading issues and uses `SohModalWindow` to inform the user of the error. * Apply suggestions from code review --------- Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com> --- soh/soh/SaveManager.cpp | 100 ++++++++++++++++++++++++---------------- soh/soh/SohGui.cpp | 9 ++++ soh/soh/SohGui.hpp | 2 + soh/soh/SohModals.cpp | 54 ++++++++++++++++++++++ soh/soh/SohModals.h | 15 ++++++ 5 files changed, 139 insertions(+), 41 deletions(-) create mode 100644 soh/soh/SohModals.cpp create mode 100644 soh/soh/SohModals.h diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index e61cf922354..10d40396fab 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -9,6 +9,7 @@ #include #include "soh/Enhancements/boss-rush/BossRush.h" #include +#include "SohGui.hpp" #define NOGDI // avoid various windows defines that conflict with things in z64.h #include @@ -1023,53 +1024,70 @@ void SaveManager::SaveGlobal() { output << std::setw(4) << globalBlock << std::endl; } + void SaveManager::LoadFile(int fileNum) { SPDLOG_INFO("Load File - fileNum: {}", fileNum); - assert(std::filesystem::exists(GetFileName(fileNum))); + std::filesystem::path fileName = GetFileName(fileNum); + assert(std::filesystem::exists(fileName)); InitFile(false); - std::ifstream input(GetFileName(fileNum)); - - saveBlock = nlohmann::json::object(); - input >> saveBlock; - if (!saveBlock.contains("version")) { - SPDLOG_ERROR("Save at " + GetFileName(fileNum).string() + " contains no version"); - assert(false); - } - switch (saveBlock["version"].get()) { - case 1: - for (auto& block : saveBlock["sections"].items()) { - int sectionVersion = block.value()["version"]; - std::string sectionName = block.key(); - if (!sectionLoadHandlers.contains(sectionName)) { - // Unloadable sections aren't necessarily errors, they are probably mods that were unloaded - // TODO report in a more noticeable manner - SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + sectionName); - continue; - } - SectionLoadHandler& handler = sectionLoadHandlers[sectionName]; - if (!handler.contains(sectionVersion)) { - // A section that has a loader without a handler for the specific version means that the user has a mod - // at an earlier version than the save has. In this case, the user probably wants to load the save. - // Report the error so that the user can rectify the error. - // TODO report in a more noticeable manner - SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName + - " with an unloadable version " + std::to_string(sectionVersion)); - assert(false); - continue; - } - currentJsonContext = &block.value()["data"]; - handler[sectionVersion](); - } - break; - default: - SPDLOG_ERROR("Unrecognized save version " + std::to_string(saveBlock["version"].get()) + " in " + - GetFileName(fileNum).string()); + std::ifstream input(fileName); + + try { + saveBlock = nlohmann::json::object(); + input >> saveBlock; + if (!saveBlock.contains("version")) { + SPDLOG_ERROR("Save at " + fileName.string() + " contains no version"); assert(false); - break; + } + switch (saveBlock["version"].get()) { + case 1: + for (auto& block : saveBlock["sections"].items()) { + int sectionVersion = block.value()["version"]; + std::string sectionName = block.key(); + if (!sectionLoadHandlers.contains(sectionName)) { + // Unloadable sections aren't necessarily errors, they are probably mods that were unloaded + // TODO report in a more noticeable manner + SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + + sectionName); + continue; + } + SectionLoadHandler& handler = sectionLoadHandlers[sectionName]; + if (!handler.contains(sectionVersion)) { + // A section that has a loader without a handler for the specific version means that the user + // has a mod at an earlier version than the save has. In this case, the user probably wants to + // load the save. Report the error so that the user can rectify the error. + // TODO report in a more noticeable manner + SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName + + " with an unloadable version " + std::to_string(sectionVersion)); + assert(false); + continue; + } + currentJsonContext = &block.value()["data"]; + handler[sectionVersion](); + } + break; + default: + SPDLOG_ERROR("Unrecognized save version " + std::to_string(saveBlock["version"].get()) + " in " + + GetFileName(fileNum).string()); + assert(false); + break; + } + InitMeta(fileNum); + GameInteractor::Instance->ExecuteHooks(fileNum); + } catch (const std::exception& e) { + input.close(); + std::filesystem::path newFile(LUS::Context::GetPathRelativeToAppDirectory("Save") + ("/file" + std::to_string(fileNum + 1) + ".bak")); +#if defined(__SWITCH__) || defined(__WIIU__) + copy_file(fileName.c_str(), newFile.c_str()); +#else + std::filesystem::copy_file(fileName, newFile); +#endif + + std::filesystem::remove(fileName); + SohGui::RegisterPopup("Error loading save file", "A problem occurred loading the save in slot " + std::to_string(fileNum + 1) + ".\nSave file corruption is suspected.\n" + + "The file has been renamed to prevent further issues."); } - InitMeta(fileNum); - GameInteractor::Instance->ExecuteHooks(fileNum); } void SaveManager::ThreadPoolWait() { diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index 94b9e690d5c..90f6e59e5ea 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -125,6 +125,7 @@ namespace SohGui { std::shared_ptr mItemTrackerSettingsWindow; std::shared_ptr mItemTrackerWindow; std::shared_ptr mRandomizerSettingsWindow; + std::shared_ptr mModalWindow; void SetupGuiElements() { auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); @@ -183,9 +184,13 @@ namespace SohGui { gui->AddGuiWindow(mItemTrackerSettingsWindow); mRandomizerSettingsWindow = std::make_shared("gRandomizerSettingsEnabled", "Randomizer Settings"); gui->AddGuiWindow(mRandomizerSettingsWindow); + mModalWindow = std::make_shared("gOpenWindows.modalWindowEnabled", "Modal Window"); + gui->AddGuiWindow(mModalWindow); + mModalWindow->Show(); } void Destroy() { + mModalWindow = nullptr; mRandomizerSettingsWindow = nullptr; mItemTrackerWindow = nullptr; mItemTrackerSettingsWindow = nullptr; @@ -205,4 +210,8 @@ namespace SohGui { mConsoleWindow = nullptr; mSohMenuBar = nullptr; } + + void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function button1callback, std::function button2callback) { + mModalWindow->RegisterPopup(title, message, button1, button2, button1callback, button2callback); + } } diff --git a/soh/soh/SohGui.hpp b/soh/soh/SohGui.hpp index 59333fd4249..dead44b51f3 100644 --- a/soh/soh/SohGui.hpp +++ b/soh/soh/SohGui.hpp @@ -22,6 +22,7 @@ #include "Enhancements/randomizer/randomizer_entrance_tracker.h" #include "Enhancements/randomizer/randomizer_item_tracker.h" #include "Enhancements/randomizer/randomizer_settings_window.h" +#include "SohModals.h" #ifdef __cplusplus extern "C" { @@ -37,6 +38,7 @@ namespace SohGui { void SetupGuiElements(); void Draw(); void Destroy(); + void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "", std::function button1callback = nullptr, std::function button2callback = nullptr); } #endif /* SohGui_hpp */ diff --git a/soh/soh/SohModals.cpp b/soh/soh/SohModals.cpp new file mode 100644 index 00000000000..087bc8ab12b --- /dev/null +++ b/soh/soh/SohModals.cpp @@ -0,0 +1,54 @@ +#include "SohModals.h" +#include "ImGui/imgui.h" +#include +#include +#include +#include +#include "UIWidgets.hpp" +#include "OTRGlobals.h" +#include "z64.h" + +extern "C" PlayState* gPlayState; +struct SohModal { + std::string title_; + std::string message_; + std::string button1_; + std::string button2_; + std::function button1callback_; + std::function button2callback_; +}; +std::vector modals; + +void SohModalWindow::DrawElement() { + if (modals.size() > 0) { + SohModal curModal = modals.at(0); + if (!ImGui::IsPopupOpen(curModal.title_.c_str())) { + ImGui::OpenPopup(curModal.title_.c_str()); + } + if (ImGui::BeginPopupModal(curModal.title_.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) { + ImGui::Text(curModal.message_.c_str()); + if (ImGui::Button(curModal.button1_.c_str())) { + if (curModal.button1callback_ != nullptr) { + curModal.button1callback_(); + } + ImGui::CloseCurrentPopup(); + modals.erase(modals.begin()); + } + ImGui::SameLine(); + if (curModal.button2_ != "") { + if (ImGui::Button(curModal.button2_.c_str())) { + if (curModal.button2callback_ != nullptr) { + curModal.button2callback_(); + } + ImGui::CloseCurrentPopup(); + modals.erase(modals.begin()); + } + } + } + ImGui::EndPopup(); + } +} + +void SohModalWindow::RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function button1callback, std::function button2callback) { + modals.push_back({ title, message, button1, button2, button1callback, button2callback }); +} \ No newline at end of file diff --git a/soh/soh/SohModals.h b/soh/soh/SohModals.h new file mode 100644 index 00000000000..6f5acb2c0be --- /dev/null +++ b/soh/soh/SohModals.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include "window/gui/GuiMenuBar.h" +#include "window/gui/GuiElement.h" + +class SohModalWindow : public LUS::GuiWindow { + public: + using LUS::GuiWindow::GuiWindow; + + void InitElement() override {}; + void DrawElement() override; + void UpdateElement() override {}; + void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "", std::function button1callback = nullptr, std::function button2callback = nullptr); +}; \ No newline at end of file From fb6ea4256072b75e6d70a24948fd2120c47e247e Mon Sep 17 00:00:00 2001 From: Archez Date: Wed, 28 Feb 2024 22:33:51 -0500 Subject: [PATCH 57/60] prevent remember save location in dungeons/boss rooms (#3983) --- .../randomizer/randomizer_entrance.c | 5 + soh/soh/SohMenuBar.cpp | 2 +- soh/src/code/z_sram.c | 117 +++++++++--------- .../ovl_file_choose/z_file_choose.c | 6 +- 4 files changed, 67 insertions(+), 63 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index e6ec3fef3fa..eda97647345 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -398,6 +398,11 @@ void Entrance_SetSavewarpEntrance(void) { gSaveContext.entranceIndex = 0x0486; // Gerudo Fortress -> Thieve's Hideout spawn 0 } else if (scene == SCENE_LINKS_HOUSE) { gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); + } else if (CVarGetInteger("gRememberSaveLocation", 0) && scene != SCENE_FAIRYS_FOUNTAIN && scene != SCENE_GROTTOS && + // Use the saved entrance value with remember save location, except when in grottos/fairy fountains or if + // the entrance index is -1 (new save) + gSaveContext.entranceIndex != -1) { + return; } else if (LINK_IS_CHILD) { gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); // Child Overworld Spawn } else { diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..0917b0c6d9b 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -558,7 +558,7 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false); UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n" - "This doesn't work if the save was made in a grotto."); + "This doesn't work if the save was made in grottos/fairy fountains or dungeons."); UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", "gSkipArrowAnimation", true, false); UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", "gSkipSaveConfirmation", true, false); UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen"); diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 1ce20abc3f9..0152ecf2ec1 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -59,65 +59,68 @@ void Sram_OpenSave() { Save_LoadFile(); - if (!CVarGetInteger("gRememberSaveLocation", 0) || gSaveContext.savedSceneNum == SCENE_FAIRYS_FOUNTAIN || - gSaveContext.savedSceneNum == SCENE_GROTTOS) { - switch (gSaveContext.savedSceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_GANONS_TOWER: - case SCENE_GERUDO_TRAINING_GROUND: - case SCENE_THIEVES_HIDEOUT: - case SCENE_INSIDE_GANONS_CASTLE: - gSaveContext.entranceIndex = dungeonEntrances[gSaveContext.savedSceneNum]; - break; - case SCENE_DEKU_TREE_BOSS: - gSaveContext.entranceIndex = 0; - break; - case SCENE_DODONGOS_CAVERN_BOSS: - gSaveContext.entranceIndex = 4; - break; - case SCENE_JABU_JABU_BOSS: - gSaveContext.entranceIndex = 0x28; - break; - case SCENE_FOREST_TEMPLE_BOSS: - gSaveContext.entranceIndex = 0x169; - break; - case SCENE_FIRE_TEMPLE_BOSS: - gSaveContext.entranceIndex = 0x165; - break; - case SCENE_WATER_TEMPLE_BOSS: - gSaveContext.entranceIndex = 0x10; - break; - case SCENE_SPIRIT_TEMPLE_BOSS: - gSaveContext.entranceIndex = 0x82; - break; - case SCENE_SHADOW_TEMPLE_BOSS: - gSaveContext.entranceIndex = 0x37; - break; - case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR: - case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE: - case SCENE_GANONDORF_BOSS: - case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR: - case SCENE_GANON_BOSS: - gSaveContext.entranceIndex = 0x41B; + switch (gSaveContext.savedSceneNum) { + case SCENE_DEKU_TREE: + case SCENE_DODONGOS_CAVERN: + case SCENE_JABU_JABU: + case SCENE_FOREST_TEMPLE: + case SCENE_FIRE_TEMPLE: + case SCENE_WATER_TEMPLE: + case SCENE_SPIRIT_TEMPLE: + case SCENE_SHADOW_TEMPLE: + case SCENE_BOTTOM_OF_THE_WELL: + case SCENE_ICE_CAVERN: + case SCENE_GANONS_TOWER: + case SCENE_GERUDO_TRAINING_GROUND: + case SCENE_THIEVES_HIDEOUT: + case SCENE_INSIDE_GANONS_CASTLE: + gSaveContext.entranceIndex = dungeonEntrances[gSaveContext.savedSceneNum]; + break; + case SCENE_DEKU_TREE_BOSS: + gSaveContext.entranceIndex = 0; + break; + case SCENE_DODONGOS_CAVERN_BOSS: + gSaveContext.entranceIndex = 4; + break; + case SCENE_JABU_JABU_BOSS: + gSaveContext.entranceIndex = 0x28; + break; + case SCENE_FOREST_TEMPLE_BOSS: + gSaveContext.entranceIndex = 0x169; + break; + case SCENE_FIRE_TEMPLE_BOSS: + gSaveContext.entranceIndex = 0x165; + break; + case SCENE_WATER_TEMPLE_BOSS: + gSaveContext.entranceIndex = 0x10; + break; + case SCENE_SPIRIT_TEMPLE_BOSS: + gSaveContext.entranceIndex = 0x82; + break; + case SCENE_SHADOW_TEMPLE_BOSS: + gSaveContext.entranceIndex = 0x37; + break; + case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR: + case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE: + case SCENE_GANONDORF_BOSS: + case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR: + case SCENE_GANON_BOSS: + gSaveContext.entranceIndex = 0x41B; + break; + + default: + // Use the saved entrance value with remember save location, except when in grottos/fairy fountains + if (CVarGetInteger("gRememberSaveLocation", 0) && gSaveContext.savedSceneNum != SCENE_FAIRYS_FOUNTAIN && + gSaveContext.savedSceneNum != SCENE_GROTTOS) { break; + } - default: - if (gSaveContext.savedSceneNum != SCENE_LINKS_HOUSE) { - gSaveContext.entranceIndex = (LINK_AGE_IN_YEARS == YEARS_CHILD) ? 0xBB : 0x5F4; - } else { - gSaveContext.entranceIndex = 0xBB; - } - break; - } + if (gSaveContext.savedSceneNum != SCENE_LINKS_HOUSE) { + gSaveContext.entranceIndex = (LINK_AGE_IN_YEARS == YEARS_CHILD) ? 0xBB : 0x5F4; + } else { + gSaveContext.entranceIndex = 0xBB; + } + break; } osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex); diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index bb8dd14d41c..59b6367f96b 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -3036,11 +3036,7 @@ void FileChoose_LoadGame(GameState* thisx) { Entrance_Init(); // Handle randomized spawn positions after the save context has been setup from load - // When remeber save location is on, set save warp if the save was in an a grotto, or - // the entrance index is -1 from shuffle overwarld spawn - if (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) && ((!CVarGetInteger("gRememberSaveLocation", 0) || - gSaveContext.savedSceneNum == SCENE_FAIRYS_FOUNTAIN || gSaveContext.savedSceneNum == SCENE_GROTTOS) || - (CVarGetInteger("gRememberSaveLocation", 0) && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && gSaveContext.entranceIndex == -1))) { + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Entrance_SetSavewarpEntrance(); } } From ed9cb1dfd257712dda6fc304b361f2c862321788 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 28 Feb 2024 20:45:16 -0700 Subject: [PATCH 58/60] Fix CVar evaluation for scummed checks being hidden. (#3985) --- soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 39418485f57..b9ca97a9b2a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1337,7 +1337,7 @@ void DrawLocation(RandomizerCheckObject rcObj) { CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default); extraColor = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default); } else if (status == RCSHOW_SCUMMED) { - if (!showHidden && CVarGetInteger("gCheckTrackerKnownHide", 0)) { + if (!showHidden && CVarGetInteger("gCheckTrackerScummedHide", 0)) { return; } mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default) : From 368a9015ac3610f68d9ddd4d18ac0d7573788581 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 28 Feb 2024 20:46:32 -0700 Subject: [PATCH 59/60] Add Unix timestamp to renamed corrupted file to prevent trying to copy over existing file. (#3984) --- soh/soh/SaveManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 10d40396fab..d8003988fcd 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1024,7 +1024,6 @@ void SaveManager::SaveGlobal() { output << std::setw(4) << globalBlock << std::endl; } - void SaveManager::LoadFile(int fileNum) { SPDLOG_INFO("Load File - fileNum: {}", fileNum); std::filesystem::path fileName = GetFileName(fileNum); @@ -1077,7 +1076,7 @@ void SaveManager::LoadFile(int fileNum) { GameInteractor::Instance->ExecuteHooks(fileNum); } catch (const std::exception& e) { input.close(); - std::filesystem::path newFile(LUS::Context::GetPathRelativeToAppDirectory("Save") + ("/file" + std::to_string(fileNum + 1) + ".bak")); + std::filesystem::path newFile(LUS::Context::GetPathRelativeToAppDirectory("Save") + ("/file" + std::to_string(fileNum + 1) + "-" + std::to_string(GetUnixTimestamp()) + ".bak")); #if defined(__SWITCH__) || defined(__WIIU__) copy_file(fileName.c_str(), newFile.c_str()); #else From 612da023f0f9da864c2830d2539e49b660ed2ff4 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 29 Feb 2024 03:46:55 +0000 Subject: [PATCH 60/60] Bump version to MacReady Foxtrot 8.0.5 (#3982) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3b85024ba4..2c8644af4a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,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") -project(Ship VERSION 8.0.4 LANGUAGES C CXX) -set(PROJECT_BUILD_NAME "MacReady Echo" CACHE STRING "") +project(Ship VERSION 8.0.5 LANGUAGES C CXX) +set(PROJECT_BUILD_NAME "MacReady Foxtrot" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)