diff options
| author | Adam Bird <archez39@me.com> | 2023-12-18 00:34:59 -0500 |
|---|---|---|
| committer | Adam Bird <archez39@me.com> | 2023-12-18 00:34:59 -0500 |
| commit | 03da69d7b745c4e6131555a2bfaa0c140a91f79e (patch) | |
| tree | 1a109a21f8b5271bb0274fc8e168e3a94ac45889 /soh/src | |
| parent | 86044a1c5071c9a0e00699939fa26946aeefbaff (diff) | |
| parent | 60faf3f750e29643ffa688b9b5fe752a9d2162c0 (diff) | |
Merge tag '8.0.4' into HEAD
MacReady Echo
Diffstat (limited to 'soh/src')
11 files changed, 235 insertions, 49 deletions
diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 3bc7c9c6a..46a87d649 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1521,6 +1521,13 @@ void Inventory_SwapAgeEquipment(void) { } } + // In Rando, when switching to adult for the second+ time, if a sword was not previously + // equiped in MS shuffle, then we need to set the swordless flag again + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + gSaveContext.equips.buttonItems[0] == ITEM_NONE) { + Flags_SetInfTable(INFTABLE_SWORDLESS); + } + gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment; } } else { @@ -1589,6 +1596,13 @@ void Inventory_SwapAgeEquipment(void) { } } + // In Rando, when switching to child from a swordless adult, and child Link previously had a + // sword equiped, then we need to unset the swordless flag to match + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + gSaveContext.equips.buttonItems[0] != ITEM_NONE) { + Flags_UnsetInfTable(INFTABLE_SWORDLESS); + } + gSaveContext.equips.equipment = gSaveContext.childEquips.equipment; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4); 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 f4c46d952..b077d8ef7 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 @@ -69,7 +69,7 @@ static u8 sMaskTex16x32[16 * 32] = { { 0 } }; static u8 sMaskTex32x16[32 * 16] = { { 0 } }; static u8 sMaskTex8x8[8 * 8] = { { 0 } }; static u8 sMaskTex8x32[8 * 32] = { { 0 } }; -static u8 sMaskTexLava[32 * 64] = { { 0 } }; +static u8 sMaskTexLava[LAVA_TEX_WIDTH * LAVA_TEX_HEIGHT] = { { 0 } }; static u32* sLavaFloorModifiedTexRaw = NULL; static u32* sLavaWavyTexRaw = NULL; @@ -112,6 +112,20 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex); size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex); size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex); + size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex); + + // If the sizes don't match, then don't bother with the blended effect to avoid crashing + if (floorSize != lavaSize || floorSize != rockSize) { + uint8_t maskVal = !!Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num); + + if (sMaskTexLava[0] != maskVal) { + for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) { + sMaskTexLava[i] = maskVal; + } + } + Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, NULL); + return; + } sLavaFloorModifiedTexRaw = malloc(lavaSize); sLavaWavyTexRaw = malloc(floorSize); @@ -121,7 +135,6 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { // When KD is dead, just immediately copy the rock texture if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) { u32* rockTex = ResourceGetDataByName(sLavaFloorRockTex); - size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex); memcpy(sLavaFloorModifiedTexRaw, rockTex, rockSize); } @@ -145,6 +158,13 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTex); } + // Set all true for the lava as it will always replace the scene texture + if (sMaskTexLava[0] == 0) { + for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) { + sMaskTexLava[i] = 1; + } + } + gfx_texture_cache_clear(); } @@ -170,6 +190,11 @@ void func_808C12C4(u8* arg1, s16 arg2) { // Same as func_808C1554 but works with u32 values for RGBA32 raw textures void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) { + // Raw lava not registered, so abort the wave modification + if (sLavaWavyTexRaw == NULL || sLavaFloorModifiedTexRaw == NULL) { + return; + } + u16 width = ResourceGetTexWidthByName(arg0); s32 size = ResourceGetTexHeightByName(arg0) * width; @@ -203,9 +228,6 @@ void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) { } free(sp54); - - // Need to clear the cache after updating sLavaWavyTexRaw - gfx_texture_cache_clear(); } // Modified to support CPU modified texture with the resource system @@ -233,9 +255,6 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) { temp_s3[i + temp2] = sp54[i + i2]; } } - - // Need to clear the cache after updating sLavaWavyTex - gfx_texture_cache_clear(); } void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) { @@ -325,7 +344,7 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) { this->actor.flags &= ~ACTOR_FLAG_TARGETABLE; // #region SOH [General] - // Init mask values for all blended textures + // Init mask values for all KD blended textures for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) { sMaskTex8x16[i] = 0; } @@ -341,10 +360,6 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) { for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) { sMaskTex32x16[i] = 0; } - // Set all true for the lava as it will always replace the scene texture - for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) { - sMaskTexLava[i] = 1; - } // Register all blended textures Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL); @@ -1174,15 +1189,23 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) { for (i2 = 0; i2 < 20; i2++) { s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1); - // Compute the index to a scaled position (scaling pseudo x,y as a 1D value) - s32 indexStart = ((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale); - - // From the starting index, apply extra pixels right/down based on the scale - for (size_t j = 0; j < heightScale; j++) { - for (size_t i3 = 0; i3 < widthScale; i3++) { - s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1); - ptr1[scaledIndex] = ptr2[scaledIndex]; + + // Raw lava must be registered, otherwise skip the effect for incompatible texture pack + // and instead set the mask to simulate the lava disappearing by turning black + if (sLavaFloorModifiedTexRaw != NULL) { + // Compute the index to a scaled position (scaling pseudo x,y as a 1D value) + s32 indexStart = + ((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale); + + // From the starting index, apply extra pixels right/down based on the scale + for (size_t j = 0; j < heightScale; j++) { + for (size_t i3 = 0; i3 < widthScale; i3++) { + s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1); + ptr1[scaledIndex] = ptr2[scaledIndex]; + } } + } else { + sMaskTexLava[new_var] = 1; } this->unk_1C2 += 37; @@ -1322,8 +1345,16 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) { gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16); } - if (this->unk_1C6 != 0) { - gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava); + 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)) { diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index e4cccb501..a4d86ff61 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -75,7 +75,6 @@ static InitChainEntry sInitChain[] = { }; static UNK_TYPE sUnused; -GetItemEntry sItem; Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0}; Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0}; @@ -472,7 +471,7 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) { func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos); if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f && Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) { - sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F); + GetItemEntry sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F); GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); // RANDOTODO treasure chest game rando @@ -628,7 +627,7 @@ void EnBox_Update(Actor* thisx, PlayState* play) { } if (((!IS_RANDO && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) || - (IS_RANDO && ABS(sItem.getItemId) == RG_ICE_TRAP)) && + (IS_RANDO && this->getItemEntry.getItemId == RG_ICE_TRAP)) && this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) { if (!CVarGetInteger("gAddTraps.enabled", 0)) { EnBox_SpawnIceSmoke(this, play); diff --git a/soh/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c b/soh/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c index 888b0ef34..6ab91ddc0 100644 --- a/soh/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c +++ b/soh/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c @@ -3,6 +3,7 @@ #include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h" #include "objects/object_ossan/object_ossan.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h" +#include "soh/Enhancements/custom-message/CustomMessageTypes.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON) @@ -371,7 +372,8 @@ void EnSyatekiMan_EndGame(EnSyatekiMan* this, PlayState* play) { this->getItemId = GI_RUPEE_PURPLE; } } else { - if(IS_RANDO && !Flags_GetTreasure(play, 0x1F)) { + // Only give the adult rando reward when the player has a quiver + if (IS_RANDO && !Flags_GetTreasure(play, 0x1F) && CUR_UPG_VALUE(UPG_QUIVER) > 0) { this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_SHOOTING_GALLERY_REWARD, GI_QUIVER_50); this->getItemId = this->getItemEntry.getItemId; Flags_SetTreasure(play, 0x1F); @@ -448,6 +450,9 @@ void EnSyatekiMan_FinishPrize(EnSyatekiMan* this, PlayState* play) { Flags_SetItemGetInf(ITEMGETINF_0D); } else if ((this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)) { Flags_SetItemGetInf(ITEMGETINF_0E); + } else if (IS_RANDO && LINK_IS_ADULT && CUR_UPG_VALUE(UPG_QUIVER) == 0) { + // In Rando without a quiver, display a message reminding the player to come back with a bow + Message_StartTextbox(play, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW, NULL); } this->gameResult = SYATEKI_RESULT_NONE; this->actor.parent = this->tempGallery; 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 c0bb84212..64429ed03 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -11003,7 +11003,14 @@ void Player_UseTunicBoots(Player* this, PlayState* play) { s32 i; s32 item; s32 itemAction; - if (!(this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED || this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS || this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE || this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN || this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING)) { + if (!( + this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED || + this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS || + this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE || + this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN || + this->stateFlags1 & PLAYER_STATE1_DEAD || + this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING + )) { for (i = 0; i < ARRAY_COUNT(sItemButtons); i++) { if (CHECK_BTN_ALL(sControlInput->press.button, sItemButtons[i])) { break; 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 61645de1e..f50106291 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 @@ -1030,18 +1030,18 @@ void FileChoose_UpdateRandomizer() { fileSelectSpoilerFileLoaded = false; } - if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) || + if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) || (!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) { - if (CVarGetInteger("gNewFileDropped", 0) != 0) { - CVarSetString("gSpoilerLog", CVarGetString("gDroppedFile", "None")); + if (CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) { + CVarSetString("gSpoilerLog", CVarGetString("gRandomizerDroppedFile", "None")); } bool silent = true; - if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) { + if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) { silent = false; } CVarSetInteger("gNewSeedGenerated", 0); - CVarSetInteger("gNewFileDropped", 0); - CVarSetString("gDroppedFile", ""); + CVarSetInteger("gRandomizerNewFileDropped", 0); + CVarSetString("gRandomizerDroppedFile", ""); fileSelectSpoilerFileLoaded = false; const char* fileLoc = CVarGetString("gSpoilerLog", ""); Randomizer_LoadSettings(fileLoc); @@ -1076,7 +1076,6 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { Input* input = &this->state.input[0]; bool dpad = CVarGetInteger("gDpadText", 0); - SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) { @@ -1267,7 +1266,6 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { s8 i = 0; bool dpad = CVarGetInteger("gDpadText", 0); - SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c index 377c23eb3..5c5cb3e6d 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_nameset_PAL.c @@ -456,7 +456,6 @@ void FileChoose_DrawNameEntry(GameState* thisx) { this->prevConfigMode = CM_MAIN_MENU; this->configMode = CM_NAME_ENTRY_TO_MAIN; CVarSetInteger("gOnFileSelectNameEntry", 0); - CVarSetInteger("gNewFileDropped", 0); this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200; this->connectorAlpha[this->buttonIndex] = 255; func_800AA000(300.0f, 0xB4, 0x14, 0x64); 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 238a1e4e2..28723d3d0 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 @@ -343,7 +343,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { // Offset the U value of each vertex to be in the mirror boundary for the map textures if (mirroredWorld) { for (size_t i = 0; i < 8; i++) { - pauseCtx->mapPageVtx[60 + i].v.tc[0] += 48 << 5; + pauseCtx->mapPageVtx[60 + i].v.tc[0] += MAP_48x85_TEX_WIDTH << 5; } } @@ -353,8 +353,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { 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, 48, 85, 0, G_TX_WRAP | mirrorMode, - G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + 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); // Swap vertices to render left half on the right and vice-versa if (mirroredWorld) { @@ -363,9 +364,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); } - gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 0, - G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOLOD); + gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], 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); if (mirroredWorld) { gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); 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 6f4ed7ad2..8c214d9b0 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 @@ -13,6 +13,10 @@ extern u8 gItemAgeReqs[]; extern u8 gAreaGsFlags[]; extern bool gSelectingMask; +#define MAP_48x85_TEX_WIDTH 48 +#define MAP_48x85_TEX_HEIGHT 85 +#define MAP_48x85_TEX_SIZE ((MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT) / 2) // 48x85 CI4 texture + #define AGE_REQ_ADULT LINK_AGE_ADULT #define AGE_REQ_CHILD LINK_AGE_CHILD #define AGE_REQ_NONE 9 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 8fe817f2f..4167324d7 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,6 +1205,8 @@ 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 }, @@ -1373,6 +1375,10 @@ 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); @@ -3315,13 +3321,118 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx) { pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16; } +// Modifed map texture buffers for registered blend effects and the room indicator color +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; + +// Load dungeon maps into the interface context +// SoH [General] - Modified to account for our resource system and HD textures void KaleidoScope_LoadDungeonMap(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; + // Free old textures + if (mapLeftTexModifiedRaw != NULL) { + free(mapLeftTexModifiedRaw); + mapLeftTexModifiedRaw = NULL; + } + if (mapRightTexModifiedRaw != NULL) { + free(mapRightTexModifiedRaw); + mapRightTexModifiedRaw = NULL; + } + + // Unload original textures to bypass cache result for lookups + ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX]); + ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]); + interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX]; interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1]; - interfaceCtx->mapSegment[0] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX]); - interfaceCtx->mapSegment[1] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]); + + // When the texture is HD (raw) we need to copy a dynamic amount of data + // Otherwise the original asset has a static size + if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) { + u32 width = ResourceGetTexWidthByName(interfaceCtx->mapSegmentName[0]); + u32 height = ResourceGetTexHeightByName(interfaceCtx->mapSegmentName[0]); + 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 + 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); + return; + } + + u8* map1TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]); + u8* map2TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]); + + mapLeftTexModifiedRaw = malloc(size); + mapRightTexModifiedRaw = malloc(size); + + memcpy(mapLeftTexModifiedRaw, map1TexRaw, size); + memcpy(mapRightTexModifiedRaw, map2TexRaw, size); + + interfaceCtx->mapSegment[0] = mapLeftTexModifiedRaw; + interfaceCtx->mapSegment[1] = mapRightTexModifiedRaw; + } else { + u8* map1Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]); + u8* map2Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]); + + memcpy(mapLeftTexModified, map1Tex, MAP_48x85_TEX_SIZE); + memcpy(mapRightTexModified, map2Tex, MAP_48x85_TEX_SIZE); + + interfaceCtx->mapSegment[0] = mapLeftTexModified; + interfaceCtx->mapSegment[1] = mapRightTexModified; + } + + // Mark and register the blend mask for the copied textures + if (mapBlendMask[0] != 1) { + for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) { + mapBlendMask[i] = 1; + } + } + + Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]); + Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]); +} + +static uint8_t registeredDungeonMapTextureHook = false; + +void KaleidoScope_RegisterUpdatedDungeonMapTexture() { + if (gPlayState == NULL) { + return; + } + + PauseContext* pauseCtx = &gPlayState->pauseCtx; + + // Kaleido is not open in a dungeon so there is nothing to do + if (R_PAUSE_MENU_MODE < 3 || pauseCtx->state < 4 || pauseCtx->state > 7 || !sInDungeonScene) { + return; + } + + KaleidoScope_UpdateDungeonMap(gPlayState); + + // KaleidoScope_UpdateDungeonMap will update the palette index for the current floor if the cursor is on the floor + // If the player toggles alt assets while the cursor is not in the floor level, then we handle the palette index here + if (gPlayState->sceneNum >= SCENE_DEKU_TREE && gPlayState->sceneNum <= SCENE_TREASURE_BOX_SHOP && + (VREG(30) + 3) == pauseCtx->dungeonMapSlot && (VREG(30) + 3) != pauseCtx->cursorPoint[PAUSE_MAP]) { + + InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx; + int32_t size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]); + + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14); + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14); + } } void KaleidoScope_UpdateDungeonMap(PlayState* play) { @@ -3333,19 +3444,29 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) { KaleidoScope_LoadDungeonMap(play); Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3); + s32 size = MAP_48x85_TEX_SIZE; + + if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) { + size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]); + } + if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { - // HDTODO: Handle Runtime Modified Textures (HD) - KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], 2040, interfaceCtx->mapPaletteIndex, 14); + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14); } } if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { - // HDTODO: Handle Runtime Modified Textures (HD) - KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], 2040, interfaceCtx->mapPaletteIndex, 14); + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14); } } + + // Register alt listener to update the blended dungeon map textures on alt toggle + if (!registeredDungeonMapTextureHook) { + registeredDungeonMapTextureHook = true; + GameInteractor_RegisterOnAssetAltChange(KaleidoScope_RegisterUpdatedDungeonMapTexture); + } } void KaleidoScope_Update(PlayState* play) diff --git a/soh/src/overlays/misc/ovl_map_mark_data/z_map_mark_data.c b/soh/src/overlays/misc/ovl_map_mark_data/z_map_mark_data.c index a73ca8265..fec1d8033 100644 --- a/soh/src/overlays/misc/ovl_map_mark_data/z_map_mark_data.c +++ b/soh/src/overlays/misc/ovl_map_mark_data/z_map_mark_data.c @@ -1762,6 +1762,13 @@ static MapMarkData sMapMarkJabuJabuBellyMq[] = { } }, { MAP_MARK_NONE, 0, { 0 } }, }, + // Jabu-Jabu's Belly minimap 16 + // SoH [General] - This entry corresponds to Big Octorok's room and is missing in the MQ game + // N64 hardware does an OoB read and lands on MQ Forest Temple room 0 + // To avoid UB with OoB for SoH, the correct entry is now added below + { + { MAP_MARK_NONE, 0, { 0 } }, + }, }; static MapMarkData sMapMarkForestTempleMq[] = { |
