From 2c680efa9169eaaddae97330fa3ea9586a273b57 Mon Sep 17 00:00:00 2001 From: mzxrules Date: Thu, 20 Jun 2024 21:21:37 -0400 Subject: z_map decompiled (#1032) * First batch of functions * more ok * z_map_data OK * More OKs, MinimapList ZAPD breaking change * func_80103A58 improvements, more OK * func_80106D5C and func_801091F0 decomped * func_801031D0 decomped and some fixes * house cleaning, more OKs more decomp * Even more OKs * func_80105C40 almost OK, more OKs * func_80108AF8 OK and more * All functions attempted * func_8010534C OK * Start documentation, rename DoorCtx * More OKs, split map_data.data, more doc * incremental clean-up, more function names * more function names * func_801068FC OK * old uncommitted changes * minor tweaks * implement easy fixes * more fixes * z_map_disp OK, implement more suggestions * delete utility program * migrate data * TransiActor ->TransitionActor * Major documentation pass * first pass of changes * warning fix attempt, revert ZFile.cpp * Fix FAKE match * Easy fixes * implement gDPLoadTextureBlock_Runtime * z_demo bss patch * Extract white square texture * Implement more suggestions * rework MapIndex/DungeonIndex * revert dungeonSceneIndex -> mapIndex in some spots, implement suggestions * more suggestions * minor nits * fix #include --- src/code/gDPLoadTextureBlock_Runtime.inc.c | 62 + src/code/title_setup.c | 2 +- src/code/z_actor.c | 6 +- src/code/z_kaleido_setup.c | 6 +- src/code/z_map_data.c | 699 +++++++++-- src/code/z_map_disp.c | 1827 +++++++++++++++++++++++++++- src/code/z_map_exp.c | 199 +-- src/code/z_message.c | 28 +- src/code/z_message_nes.c | 23 +- src/code/z_parameter.c | 2 +- src/code/z_play.c | 4 +- src/code/z_room.c | 8 +- src/code/z_scene.c | 32 +- 13 files changed, 2628 insertions(+), 270 deletions(-) create mode 100644 src/code/gDPLoadTextureBlock_Runtime.inc.c (limited to 'src/code') diff --git a/src/code/gDPLoadTextureBlock_Runtime.inc.c b/src/code/gDPLoadTextureBlock_Runtime.inc.c new file mode 100644 index 000000000..f90841564 --- /dev/null +++ b/src/code/gDPLoadTextureBlock_Runtime.inc.c @@ -0,0 +1,62 @@ +#ifndef GDP_LOADTEXTUREBLOCK_RUNTIME_INC_C +#define GDP_LOADTEXTUREBLOCK_RUNTIME_INC_C + +#include "gfx.h" + +static u32 sLoadTextureBlock_siz[] = { + G_IM_SIZ_4b, + G_IM_SIZ_8b, + G_IM_SIZ_16b, + G_IM_SIZ_32b, +}; +static u32 sLoadTextureBlock_siz_LOAD_BLOCK[] = { + G_IM_SIZ_4b_LOAD_BLOCK, + G_IM_SIZ_8b_LOAD_BLOCK, + G_IM_SIZ_16b_LOAD_BLOCK, + G_IM_SIZ_32b_LOAD_BLOCK, +}; +static u32 sLoadTextureBlock_siz_INCR[] = { + G_IM_SIZ_4b_INCR, + G_IM_SIZ_8b_INCR, + G_IM_SIZ_16b_INCR, + G_IM_SIZ_32b_INCR, +}; +static u32 sLoadTextureBlock_siz_SHIFT[] = { + G_IM_SIZ_4b_SHIFT, + G_IM_SIZ_8b_SHIFT, + G_IM_SIZ_16b_SHIFT, + G_IM_SIZ_32b_SHIFT, +}; +static u32 sLoadTextureBlock_siz_BYTES[] = { + G_IM_SIZ_4b_BYTES, + G_IM_SIZ_8b_BYTES, + G_IM_SIZ_16b_BYTES, + G_IM_SIZ_32b_BYTES, +}; +static u32 sLoadTextureBlock_siz_LINE_BYTES[] = { + G_IM_SIZ_4b_LINE_BYTES, + G_IM_SIZ_8b_LINE_BYTES, + G_IM_SIZ_16b_LINE_BYTES, + G_IM_SIZ_32b_LINE_BYTES, +}; + +/** + * Implements a version of gDPLoadTextureBlock using table lookups instead of token pasting, to allow values to be + * passed into `siz` during runtime. + */ +#define gDPLoadTextureBlock_Runtime(pkt, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, sLoadTextureBlock_siz_LOAD_BLOCK[siz], 1, timg); \ + gDPSetTile(pkt, fmt, sLoadTextureBlock_siz_LOAD_BLOCK[siz], 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width) * (height) + sLoadTextureBlock_siz_INCR[siz]) >> sLoadTextureBlock_siz_SHIFT[siz]) - 1, \ + CALC_DXT(width, sLoadTextureBlock_siz_BYTES[siz])); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, sLoadTextureBlock_siz[siz], (((width)*sLoadTextureBlock_siz_LINE_BYTES[siz]) + 7) >> 3, \ + 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) +#endif diff --git a/src/code/title_setup.c b/src/code/title_setup.c index 0859c52d4..336d08be8 100644 --- a/src/code/title_setup.c +++ b/src/code/title_setup.c @@ -32,7 +32,7 @@ void Setup_InitRegs(void) { XREG(90) = 0x1C2; R_STORY_FILL_SCREEN_ALPHA = 0; - R_REVERSE_FLOOR_INDEX = 0; + R_PLAYER_FLOOR_REVERSE_INDEX = 0; R_MINIMAP_DISABLED = false; R_PICTO_FOCUS_BORDER_TOPLEFT_X = 80; diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 3b6b48fda..f47b5146e 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -3413,9 +3413,9 @@ Actor* Actor_SpawnAsChild(ActorContext* actorCtx, Actor* parent, PlayState* play } void Actor_SpawnTransitionActors(PlayState* play, ActorContext* actorCtx) { - TransitionActorEntry* transitionActorList = play->doorCtx.transitionActorList; + TransitionActorEntry* transitionActorList = play->transitionActors.list; s32 i; - s16 numTransitionActors = play->doorCtx.numTransitionActors; + s16 numTransitionActors = play->transitionActors.count; for (i = 0; i < numTransitionActors; transitionActorList++, i++) { if (transitionActorList->id >= 0) { @@ -3434,7 +3434,7 @@ void Actor_SpawnTransitionActors(PlayState* play, ActorContext* actorCtx) { transitionActorList->rotY & 0x7F, HALFDAYBIT_ALL, 0) != NULL) { transitionActorList->id = -transitionActorList->id; } - numTransitionActors = play->doorCtx.numTransitionActors; + numTransitionActors = play->transitionActors.count; } } } diff --git a/src/code/z_kaleido_setup.c b/src/code/z_kaleido_setup.c index d19f96059..9d74d6d46 100644 --- a/src/code/z_kaleido_setup.c +++ b/src/code/z_kaleido_setup.c @@ -160,18 +160,18 @@ void KaleidoSetup_Init(PlayState* play) { pauseCtx->unk_20C = 936.0f; pauseCtx->roll = -314.0f; - pauseCtx->cursorPoint[PAUSE_MAP] = R_REVERSE_FLOOR_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); + pauseCtx->cursorPoint[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); pauseCtx->cursorSpecialPos = PAUSE_CURSOR_PAGE_RIGHT; pauseCtx->pageSwitchInputTimer = 0; pauseCtx->cursorItem[PAUSE_ITEM] = PAUSE_ITEM_NONE; - pauseCtx->cursorItem[PAUSE_MAP] = R_REVERSE_FLOOR_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); + pauseCtx->cursorItem[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); pauseCtx->cursorItem[PAUSE_QUEST] = PAUSE_ITEM_NONE; pauseCtx->cursorItem[PAUSE_MASK] = PAUSE_ITEM_NONE; pauseCtx->cursorSlot[PAUSE_ITEM] = 0; - pauseCtx->cursorSlot[PAUSE_MAP] = R_REVERSE_FLOOR_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); + pauseCtx->cursorSlot[PAUSE_MAP] = R_PLAYER_FLOOR_REVERSE_INDEX + (DUNGEON_FLOOR_INDEX_4 - 1); pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_YELLOW; pauseCtx->ocarinaSongIndex = -1; diff --git a/src/code/z_map_data.c b/src/code/z_map_data.c index a854a37e7..571613a0d 100644 --- a/src/code/z_map_data.c +++ b/src/code/z_map_data.c @@ -1,79 +1,622 @@ #include "global.h" - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801094A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801094C8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801094F8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109528.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010954C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010956C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010958C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801095AC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801095DC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010960C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109630.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109650.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109670.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801096D4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109714.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109754.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801097C8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010983C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801098A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109908.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109964.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_8010997C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801099AC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_801099DC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109A00.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109A20.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109A40.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109A98.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109AD8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109B38.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109BA0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109BF4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109C38.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109CBC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109D40.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109DD8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109E70.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109EF8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_data/func_80109F78.s") +#include "z64map.h" +#include "assets/objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h" + +typedef struct { + /* 0x0 */ u8 texWidth; + /* 0x1 */ u8 texHeight; + /* 0x2 */ s16 offsetX; + /* 0x4 */ s16 offsetY; + /* 0x6 */ u8 drawType; + /* 0x7 */ u8 colorIndex; + /* 0x8 */ s16 scale; +} MapSpriteInfo; // size = 0xA + +typedef struct { + /* 0x0 */ TexturePtr spriteTex; + /* 0x4 */ u8 width; + /* 0x5 */ u8 height; + /* 0x6 */ u8 offsetX; + /* 0x7 */ u8 offsetY; + /* 0x8 */ u8 drawType; + /* 0x9 */ u8 colorIndex; + /* 0xA */ s16 scale; +} MapSpriteInfo2; // size = 0xC + +static Color_RGBA8 sMapColorTable[] = { + { 255, 255, 255, 255 }, + { 0, 255, 255, 160 }, // Blue + { 100, 255, 255, 255 }, +}; + +static MapSpriteInfo2 sGameplayDangeonKeepInfo[5] = { + { gameplay_dangeon_keep_Tex_0022C8, 96, 85, 48, 42, MAPDATA_DRAW_0, 0, 20 }, + { gameplay_dangeon_keep_Tex_0042C8, 96, 85, 48, 62, MAPDATA_DRAW_0, 0, 20 }, + { gameplay_dangeon_keep_Tex_0052C8, 96, 85, 68, 42, MAPDATA_DRAW_0, 0, 20 }, + { gameplay_dangeon_keep_Tex_0032C8, 96, 85, 48, 62, MAPDATA_DRAW_0, 0, 20 }, + { gameplay_dangeon_keep_Tex_0062C8, 96, 85, 68, 62, MAPDATA_DRAW_0, 0, 20 }, +}; + +static MapSpriteInfo sMapGrandStaticInfo[98] = { + { 96, 85, 48, 42, MAPDATA_DRAW_0, 0, 20 }, { 96, 85, 48, 62, MAPDATA_DRAW_0, 0, 20 }, + { 96, 85, 68, 42, MAPDATA_DRAW_0, 0, 20 }, { 96, 85, 48, 62, MAPDATA_DRAW_0, 0, 20 }, + { 96, 85, 68, 62, MAPDATA_DRAW_0, 0, 20 }, { 80, 72, 40, 35, MAPDATA_DRAW_1, 1, 52 }, + { 96, 85, 49, 43, MAPDATA_DRAW_3, 2, 20 }, { 96, 85, 49, 43, MAPDATA_DRAW_3, 2, 20 }, + { 96, 85, 49, 43, MAPDATA_DRAW_3, 2, 20 }, { 96, 85, 49, 49, MAPDATA_DRAW_3, 2, 20 }, + { 48, 44, 25, 23, MAPDATA_DRAW_3, 2, 20 }, { 96, 85, 49, 43, MAPDATA_DRAW_3, 2, 20 }, + { 48, 46, 25, 24, MAPDATA_DRAW_3, 2, 20 }, { 64, 61, 32, 31, MAPDATA_DRAW_3, 2, 20 }, + { 96, 85, 49, 50, MAPDATA_DRAW_3, 2, 20 }, { 96, 85, 49, 62, MAPDATA_DRAW_3, 2, 20 }, + { 96, 85, 49, 43, MAPDATA_DRAW_3, 2, 20 }, { 48, 80, 21, 41, MAPDATA_DRAW_1, 1, 198 }, + { 32, 128, 17, 87, MAPDATA_DRAW_1, 1, 138 }, { 80, 53, 40, 27, MAPDATA_DRAW_1, 1, 54 }, + { 32, 81, 16, 15, MAPDATA_DRAW_3, 2, 20 }, { 80, 45, 35, 23, MAPDATA_DRAW_3, 2, 20 }, + { 64, 87, 36, 44, MAPDATA_DRAW_3, 2, 20 }, { 64, 51, 31, 23, MAPDATA_DRAW_3, 2, 20 }, + { 80, 79, 40, 40, MAPDATA_DRAW_3, 2, 20 }, { 96, 75, 36, 26, MAPDATA_DRAW_3, 2, 20 }, + { 48, 41, 24, 20, MAPDATA_DRAW_3, 2, 20 }, { 64, 45, 31, 20, MAPDATA_DRAW_3, 2, 20 }, + { 80, 52, 38, 28, MAPDATA_DRAW_3, 2, 20 }, { 48, 45, 23, 20, MAPDATA_DRAW_3, 2, 20 }, + { 48, 59, 25, 37, MAPDATA_DRAW_3, 2, 20 }, { 48, 60, 21, 38, MAPDATA_DRAW_3, 2, 20 }, + { 48, 81, 24, 40, MAPDATA_DRAW_3, 2, 20 }, { 48, 81, 24, 40, MAPDATA_DRAW_3, 2, 20 }, + { 80, 89, 41, 26, MAPDATA_DRAW_3, 2, 20 }, { 80, 53, 39, 26, MAPDATA_DRAW_3, 2, 20 }, + { 64, 78, 37, 36, MAPDATA_DRAW_3, 2, 20 }, { 64, 68, 33, 33, MAPDATA_DRAW_3, 2, 20 }, + { 48, 68, 23, 35, MAPDATA_DRAW_3, 2, 20 }, { 48, 36, 25, 17, MAPDATA_DRAW_3, 2, 20 }, + { 48, 25, 24, 12, MAPDATA_DRAW_3, 2, 20 }, { 64, 75, 24, 37, MAPDATA_DRAW_3, 2, 20 }, + { 32, 53, 17, 26, MAPDATA_DRAW_3, 2, 20 }, { 80, 62, 35, 27, MAPDATA_DRAW_1, 1, 105 }, + { 64, 76, 31, 31, MAPDATA_DRAW_1, 1, 133 }, { 96, 85, 47, 43, MAPDATA_DRAW_3, 2, 20 }, + { 80, 71, 48, 33, MAPDATA_DRAW_1, 1, 180 }, { 80, 87, 44, 44, MAPDATA_DRAW_1, 1, 72 }, + { 64, 65, 31, 36, MAPDATA_DRAW_1, 1, 57 }, { 48, 41, 28, 20, MAPDATA_DRAW_1, 1, 60 }, + { 64, 76, 17, 36, MAPDATA_DRAW_1, 1, 58 }, { 80, 60, 27, 22, MAPDATA_DRAW_1, 1, 83 }, + { 80, 47, 38, 23, MAPDATA_DRAW_1, 1, 69 }, { 80, 60, 40, 38, MAPDATA_DRAW_1, 1, 29 }, + { 48, 19, 17, 8, MAPDATA_DRAW_1, 1, 25 }, { 32, 99, 17, 16, MAPDATA_DRAW_1, 1, 88 }, + { 48, 69, 19, 28, MAPDATA_DRAW_1, 1, 76 }, { 48, 83, 34, 47, MAPDATA_DRAW_1, 1, 104 }, + { 80, 54, 45, 27, MAPDATA_DRAW_1, 1, 61 }, { 80, 92, 35, 50, MAPDATA_DRAW_1, 1, 60 }, + { 48, 75, 24, 37, MAPDATA_DRAW_3, 2, 20 }, { 64, 49, 32, 23, MAPDATA_DRAW_3, 2, 20 }, + { 64, 49, 25, 24, MAPDATA_DRAW_3, 2, 20 }, { 64, 52, 32, 24, MAPDATA_DRAW_3, 2, 34 }, + { 64, 49, 31, 24, MAPDATA_DRAW_3, 2, 34 }, { 32, 33, 18, 14, MAPDATA_DRAW_3, 2, 34 }, + { 48, 50, 25, 25, MAPDATA_DRAW_3, 2, 34 }, { 64, 52, 32, 25, MAPDATA_DRAW_3, 2, 34 }, + { 48, 35, 24, 18, MAPDATA_DRAW_3, 2, 34 }, { 64, 51, 32, 26, MAPDATA_DRAW_3, 2, 34 }, + { 48, 35, 24, 18, MAPDATA_DRAW_3, 2, 34 }, { 48, 53, 24, 28, MAPDATA_DRAW_3, 2, 34 }, + { 64, 53, 33, 25, MAPDATA_DRAW_3, 2, 34 }, { 64, 47, 31, 24, MAPDATA_DRAW_3, 2, 34 }, + { 64, 52, 32, 35, MAPDATA_DRAW_3, 2, 34 }, { 48, 48, 24, 23, MAPDATA_DRAW_3, 2, 34 }, + { 64, 87, 32, 26, MAPDATA_DRAW_3, 2, 34 }, { 48, 30, 24, 14, MAPDATA_DRAW_3, 2, 34 }, + { 80, 74, 40, 36, MAPDATA_DRAW_1, 1, 50 }, { 80, 87, 6, 41, MAPDATA_DRAW_1, 1, 42 }, + { 80, 56, 19, 27, MAPDATA_DRAW_1, 1, 40 }, { 80, 65, 25, 33, MAPDATA_DRAW_1, 1, 40 }, + { 16, 38, 8, 12, MAPDATA_DRAW_1, 1, 47 }, { 80, 78, 46, 33, MAPDATA_DRAW_1, 1, 142 }, + { 80, 55, 32, 29, MAPDATA_DRAW_1, 1, 155 }, { 80, 98, 67, 48, MAPDATA_DRAW_1, 1, 51 }, + { 80, 62, 47, 19, MAPDATA_DRAW_1, 1, 55 }, { 32, 123, 15, 83, MAPDATA_DRAW_1, 1, 140 }, + { 80, 60, 47, 14, MAPDATA_DRAW_1, 1, 170 }, { 48, 77, 18, 59, MAPDATA_DRAW_1, 1, 79 }, + { 80, 64, 35, 30, MAPDATA_DRAW_1, 1, 33 }, { 64, 50, 29, 22, MAPDATA_DRAW_1, 1, 40 }, + { 80, 65, 39, 5, MAPDATA_DRAW_1, 1, 37 }, { 32, 61, 8, 56, MAPDATA_DRAW_1, 1, 35 }, + { 80, 83, 37, 42, MAPDATA_DRAW_1, 1, 95 }, { 80, 27, 30, 21, MAPDATA_DRAW_1, 1, 134 }, + { 80, 23, 122, -18, MAPDATA_DRAW_1, 1, 53 }, { 80, 60, 27, 22, MAPDATA_DRAW_1, 1, 83 }, +}; + +static s32 D_801BF15C[5] = { + 0x50, 0x50, 0x8D, 0x50, 0x50, +}; + +static MapSpriteInfo sMapIStaticInfo[MAPDATA_MAP_I_MAX] = { + { 96, 85, 73, 67, MAPDATA_DRAW_0, 0, 60 }, { 96, 85, 73, 74, MAPDATA_DRAW_0, 0, 60 }, + { 96, 85, 80, 67, MAPDATA_DRAW_0, 0, 60 }, { 96, 85, 73, 67, MAPDATA_DRAW_0, 0, 60 }, + { 96, 85, 80, 74, MAPDATA_DRAW_0, 0, 60 }, { 32, 29, 17, 14, MAPDATA_DRAW_2, 0, 50 }, + { 32, 27, 16, 13, MAPDATA_DRAW_2, 0, 50 }, { 32, 30, 16, 15, MAPDATA_DRAW_2, 0, 50 }, + { 16, 32, 8, 20, MAPDATA_DRAW_2, 0, 50 }, { 16, 12, 8, 6, MAPDATA_DRAW_2, 0, 50 }, + { 32, 27, 16, 13, MAPDATA_DRAW_2, 0, 50 }, { 16, 14, 8, 7, MAPDATA_DRAW_2, 0, 50 }, + { 32, 19, 16, 9, MAPDATA_DRAW_2, 0, 50 }, { 32, 26, 16, 16, MAPDATA_DRAW_2, 0, 50 }, + { 16, 32, 8, 22, MAPDATA_DRAW_2, 0, 50 }, { 32, 27, 16, 13, MAPDATA_DRAW_2, 0, 50 }, + { 16, 35, 9, 5, MAPDATA_DRAW_2, 0, 45 }, { 32, 18, 14, 9, MAPDATA_DRAW_2, 0, 45 }, + { 32, 38, 18, 19, MAPDATA_DRAW_2, 0, 45 }, { 32, 21, 16, 9, MAPDATA_DRAW_2, 0, 45 }, + { 32, 34, 16, 17, MAPDATA_DRAW_2, 0, 45 }, { 48, 32, 19, 11, MAPDATA_DRAW_2, 0, 45 }, + { 32, 17, 16, 8, MAPDATA_DRAW_2, 0, 45 }, { 32, 17, 16, 7, MAPDATA_DRAW_2, 0, 45 }, + { 32, 21, 16, 11, MAPDATA_DRAW_2, 0, 45 }, { 32, 18, 16, 8, MAPDATA_DRAW_2, 0, 45 }, + { 16, 24, 9, 15, MAPDATA_DRAW_2, 0, 45 }, { 16, 25, 7, 16, MAPDATA_DRAW_2, 0, 45 }, + { 32, 35, 16, 17, MAPDATA_DRAW_2, 0, 45 }, { 16, 19, 5, 9, MAPDATA_DRAW_2, 0, 80 }, + { 32, 28, 17, 7, MAPDATA_DRAW_2, 0, 66 }, { 32, 16, 16, 8, MAPDATA_DRAW_2, 0, 66 }, + { 32, 24, 18, 11, MAPDATA_DRAW_2, 0, 66 }, { 32, 21, 16, 10, MAPDATA_DRAW_2, 0, 66 }, + { 16, 21, 8, 11, MAPDATA_DRAW_2, 0, 66 }, { 16, 10, 8, 4, MAPDATA_DRAW_2, 0, 66 }, + { 16, 7, 8, 3, MAPDATA_DRAW_2, 0, 66 }, { 32, 23, 13, 11, MAPDATA_DRAW_2, 0, 66 }, + { 16, 16, 8, 8, MAPDATA_DRAW_2, 0, 66 }, { 16, 17, 8, 7, MAPDATA_DRAW_2, 0, 50 }, + { 16, 23, 9, 10, MAPDATA_DRAW_2, 0, 66 }, { 16, 15, 8, 7, MAPDATA_DRAW_2, 0, 66 }, + { 32, 15, 15, 7, MAPDATA_DRAW_2, 0, 66 }, { 32, 17, 16, 8, MAPDATA_DRAW_2, 0, 90 }, + { 32, 16, 16, 8, MAPDATA_DRAW_2, 0, 90 }, { 16, 10, 8, 5, MAPDATA_DRAW_2, 0, 90 }, + { 16, 17, 8, 8, MAPDATA_DRAW_2, 0, 90 }, { 32, 17, 17, 8, MAPDATA_DRAW_2, 0, 90 }, + { 16, 11, 8, 5, MAPDATA_DRAW_2, 0, 90 }, { 32, 17, 15, 9, MAPDATA_DRAW_2, 0, 90 }, + { 16, 12, 8, 6, MAPDATA_DRAW_2, 0, 90 }, { 16, 18, 9, 9, MAPDATA_DRAW_2, 0, 90 }, + { 32, 17, 17, 8, MAPDATA_DRAW_2, 0, 90 }, { 32, 15, 16, 8, MAPDATA_DRAW_2, 0, 90 }, + { 16, 18, 9, 13, MAPDATA_DRAW_2, 0, 90 }, { 16, 16, 8, 7, MAPDATA_DRAW_2, 0, 90 }, + { 16, 30, 9, 8, MAPDATA_DRAW_2, 0, 90 }, { 16, 9, 9, 4, MAPDATA_DRAW_2, 0, 90 }, +}; + +static s32 sMapIForGameplayDangeonKeep[5] = { + 0x00, 0x01, 0x02, 0x03, 0x04, +}; + +static s32 sMapIForMapGrand[98] = { + MAPDATA_MAP_I_MAX, + 0x01, + 0x02, + 0x03, + 0x04, + MAPDATA_MAP_I_MAX, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + MAPDATA_MAP_I_MAX, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + 0x27, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, + MAPDATA_MAP_I_MAX, +}; + +void MapData_GetMapColor(s32 colorIndex, Color_RGBA8* color) { + *color = sMapColorTable[colorIndex]; +} + +void MapData_GetMapTexDimGameplayDangeonKeep(s32 mapId, s32* width, s32* height) { + *width = sGameplayDangeonKeepInfo[mapId].width; + *height = sGameplayDangeonKeepInfo[mapId].height; +} + +void MapData_GetMapTexOffsetGameplayDangeonKeep(s32 mapId, s32* offsetX, s32* offsetY) { + *offsetX = sGameplayDangeonKeepInfo[mapId].offsetX; + *offsetY = sGameplayDangeonKeepInfo[mapId].offsetY; +} + +void MapData_GetMapDrawTypeGameplayDangeonKeep(s32 mapId, s32* drawType) { + *drawType = sGameplayDangeonKeepInfo[mapId].drawType; +} + +u8 MapData_GetMapColorIndexGameplayDangeonKeep(s32 mapId) { + return sGameplayDangeonKeepInfo[mapId].colorIndex; +} + +s16 MapData_GetMapGameplayDangeonKeepScale(s32 mapId) { + return sGameplayDangeonKeepInfo[mapId].scale; +} + +TexturePtr MapData_GetMapTexGameplayDangeonKeep(s32 mapId) { + return sGameplayDangeonKeepInfo[mapId].spriteTex; +} + +void MapData_GetMapTexGameplayDangeonKeepDim(s32 mapId, s32* width, s32* height) { + *width = sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].texWidth; + *height = sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].texHeight; +} + +void MapData_GetMapTexGameplayDangeonKeepOffset(s32 mapId, s32* offsetX, s32* offsetY) { + *offsetX = sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].offsetX; + *offsetY = sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].offsetY; +} + +void MapData_GetMapGrandDrawType(s32 mapId, s32* drawType) { + *drawType = sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].drawType; +} + +u8 MapData_GetMapGrandColorIndex(s32 mapId) { + return sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].colorIndex; +} + +s16 MapData_GetMapGrandScale(s32 mapId) { + return sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].scale; +} + +s32 MapData_MapGrandTexSizeTest(s32 mapId) { + s32 endMap = mapId - MAPDATA_MAP_GRAND; + s32 size = 0; + s32 i; + + for (i = 1; i < endMap + 1; i++) { + size += MapData_GetSizeOfMapGrandTex((i - 1) + MAPDATA_MAP_GRAND); + } + return size; +} + +s32 MapData_GetSizeOfMapGrandTex(s32 mapId) { + return (sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].texWidth * + sMapGrandStaticInfo[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)].texHeight) / + 2; +} + +s32 MapData_MID_GetType(s32 mapId) { + if ((mapId >= 0) && (mapId < 5)) { + return MAPDATA_MID_GAMEPLAY_DANGEON_KEEP; + } + if ((mapId >= 0x100) && (mapId < 0x162)) { + return MAPDATA_MID_MAP_GRAND_STATIC; + } + return MAPDATA_MID_MAP_I_STATIC; +} + +void MapData_GetMapTexDim(s32 mapId, s32* width, s32* height) { + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + MapData_GetMapTexDimGameplayDangeonKeep(mapId, width, height); + return; + + case MAPDATA_MID_MAP_GRAND_STATIC: + MapData_GetMapTexGameplayDangeonKeepDim(mapId, width, height); + return; + + default: + *width = *height = 0; + return; + } +} + +void MapData_GetMapTexOffset(s32 mapId, s32* offsetX, s32* offsetY) { + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + MapData_GetMapTexOffsetGameplayDangeonKeep(mapId, offsetX, offsetY); + return; + + case MAPDATA_MID_MAP_GRAND_STATIC: + MapData_GetMapTexGameplayDangeonKeepOffset(mapId, offsetX, offsetY); + return; + + default: + *offsetX = *offsetY = 0; + return; + } +} + +void MapData_GetMapScale(s32 mapId, s32* scale) { + switch (MapData_MID_GetType(mapId)) { + default: + *scale = 0; + return; + + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + *scale = MapData_GetMapGameplayDangeonKeepScale(mapId); + return; + + case MAPDATA_MID_MAP_GRAND_STATIC: + *scale = MapData_GetMapGrandScale(mapId); + return; + } +} + +void MapData_GetDrawType(s32 mapId, s32* drawType) { + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + MapData_GetMapDrawTypeGameplayDangeonKeep(mapId, drawType); + return; + + case MAPDATA_MID_MAP_GRAND_STATIC: + MapData_GetMapGrandDrawType(mapId, drawType); + return; + + default: + *drawType = 0; + return; + } +} + +s32 MapData_GetMapColorIndex(s32 mapId) { + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + return MapData_GetMapColorIndexGameplayDangeonKeep(mapId); + + case MAPDATA_MID_MAP_GRAND_STATIC: + return MapData_GetMapGrandColorIndex(mapId); + + default: + return 0; + } +} + +s32 func_80109964(s32 arg0) { + return D_801BF15C[arg0]; +} + +void MapData_GetMapITexDim(s32 mapId, s32* width, s32* height) { + *width = sMapIStaticInfo[mapId].texWidth; + *height = sMapIStaticInfo[mapId].texHeight; +} + +void MapData_GetMapITexOffset(s32 mapId, s32* offsetX, s32* offsetY) { + *offsetX = sMapIStaticInfo[mapId].offsetX; + *offsetY = sMapIStaticInfo[mapId].offsetY; +} + +void MapData_GetMapIDrawType(s32 mapId, s32* drawType) { + *drawType = sMapIStaticInfo[mapId].drawType; +} + +u8 MapData_GetMapIColorIndex(s32 mapId) { + return sMapIStaticInfo[mapId].colorIndex; +} + +s16 MapData_GetMapIScale(s32 mapId) { + return sMapIStaticInfo[mapId].scale; +} + +s32 MapData_MapITexSizeTest(s32 mapId) { + s32 i; + s32 size = 0; + + for (i = 1; i < mapId + 1; i++) { + size += MapDisp_GetSizeOfMapITex(i - 1); + } + + return size; +} + +s32 MapDisp_GetSizeOfMapITex(s32 mapCompactId) { + return (sMapIStaticInfo[mapCompactId].texWidth * sMapIStaticInfo[mapCompactId].texHeight) / 2; +} + +s32 MapData_GetMapIId(s32 mapId) { + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + return sMapIForGameplayDangeonKeep[mapId]; + + case MAPDATA_MID_MAP_GRAND_STATIC: + return sMapIForMapGrand[MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(mapId)]; + + default: + return 0; + } +} + +s32 func_80109B38(s32 mapId) { + if (MapData_GetMapIId(mapId) != MAPDATA_MAP_I_MAX) { + return 1; + } + switch (MapData_MID_GetType(mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + return 2; + + case MAPDATA_MID_MAP_GRAND_STATIC: + return 0; + + default: + return 0; + } +} + +s32 MapData_GetMapCompactId(s32 mapId) { + s32 mapI = MapData_GetMapIId(mapId); + + if (mapI != MAPDATA_MAP_I_MAX) { + return mapI; + } + if ((mapId >= 0x100) && (mapId < 0x162)) { + return mapId - 0xC6; + } + return -1; +} + +s32 MapData_CPID_GetType(s32 mapCompactId) { + if (mapCompactId == -1) { + return MAPDATA_CPID_2; + } + if (mapCompactId < MAPDATA_MAP_I_MAX) { + return MAPDATA_CPID_MAP_I_STATIC; + } + if (mapCompactId >= MAPDATA_MAP_I_MAX) { + return MAPDATA_CPID_MAP_GRAND_STATIC; + } + return MAPDATA_CPID_2; +} + +// Unused +s32 func_80109C38(s32 mapCompactId) { + if (mapCompactId == -1) { + return 0; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + return MapData_MapGrandTexSizeTest(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId)); + + case MAPDATA_CPID_MAP_I_STATIC: + return MapData_MapITexSizeTest(mapCompactId); + + case MAPDATA_CPID_2: + return 0; + + default: + return 0; + } +} + +s32 MapData_CPID_GetSizeOfMapTex(s32 mapCompactId) { + if (mapCompactId == -1) { + return 0; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + return MapData_GetSizeOfMapGrandTex(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId)); + + case MAPDATA_CPID_MAP_I_STATIC: + return MapDisp_GetSizeOfMapITex(mapCompactId); + + case MAPDATA_CPID_2: + return 0; + + default: + return 0; + } +} + +void MapData_CPID_GetTexDim(s32 mapCompactId, s32* width, s32* height) { + if (mapCompactId == -1) { + *width = *height = 0; + return; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + MapData_GetMapTexGameplayDangeonKeepDim(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId), width, + height); + return; + + case MAPDATA_CPID_MAP_I_STATIC: + MapData_GetMapITexDim(mapCompactId, width, height); + return; + + case MAPDATA_CPID_2: + default: + *width = *height = 0; + return; + } +} + +void MapData_CPID_GetTexOffset(s32 mapCompactId, s32* offsetX, s32* offsetY) { + if (mapCompactId == -1) { + *offsetX = *offsetY = 0; + return; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + MapData_GetMapTexGameplayDangeonKeepOffset(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId), offsetX, + offsetY); + return; + + case MAPDATA_CPID_MAP_I_STATIC: + MapData_GetMapITexOffset(mapCompactId, offsetX, offsetY); + return; + + case MAPDATA_CPID_2: + default: + *offsetX = *offsetY = 0; + return; + } +} + +// Unused +void MapData_CPID_GetDrawType(s32 mapCompactId, s32* drawType) { + if (mapCompactId == -1) { + *drawType = MAPDATA_DRAW_0; + return; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + MapData_GetMapGrandDrawType(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId), drawType); + return; + + case MAPDATA_CPID_MAP_I_STATIC: + MapData_GetMapIDrawType(mapCompactId, drawType); + return; + + case MAPDATA_CPID_2: + default: + *drawType = MAPDATA_DRAW_0; + return; + } +} + +// Unused +u8 MapData_CPID_GetMapColorIndex(s32 mapCompactId) { + if (mapCompactId == -1) { + return 0; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + return MapData_GetMapGrandColorIndex(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId)); + + case MAPDATA_CPID_MAP_I_STATIC: + return MapData_GetMapIColorIndex(mapCompactId); + + case MAPDATA_CPID_2: + default: + return 0; + } +} + +s16 MapData_CPID_GetMapScale(s32 mapCompactId) { + if (mapCompactId == -1) { + return 0; + } + switch (MapData_CPID_GetType(mapCompactId)) { + case MAPDATA_CPID_MAP_GRAND_STATIC: + return MapData_GetMapGrandScale(MAPDATA_GET_MAP_GRAND_ID_FROM_COMPACT_ID(mapCompactId)); + + case MAPDATA_CPID_MAP_I_STATIC: + return MapData_GetMapIScale(mapCompactId); + + case MAPDATA_CPID_2: + default: + return 0; + } +} diff --git a/src/code/z_map_disp.c b/src/code/z_map_disp.c index d1f09f440..6ab61fcf7 100644 --- a/src/code/z_map_disp.c +++ b/src/code/z_map_disp.c @@ -1,109 +1,1828 @@ #include "global.h" +#include "gfx.h" +#include "sys_cmpdma.h" +#include "assets/interface/icon_item_dungeon_static/icon_item_dungeon_static.h" +#include "assets/interface/parameter_static/parameter_static.h" +#include "assets/objects/gameplay_keep/gameplay_keep.h" +#include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h" +#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102E40.s") +void MapDisp_DestroyMapI(PlayState* play); +void MapDisp_InitMapI(PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102E90.s") +#include "gDPLoadTextureBlock_Runtime.inc.c" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102EA4.s") +static UNK_TYPE4 D_801BEB30[2] = { 0, 0 }; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102EB4.s") +static u64 sWhiteSquareTex[] = { +#include "assets/code/z_map_disp/white_square.i4.inc.c" +}; +static MapDisp sMapDisp = { + NULL, -1, 210, 140, 0, 0, NULL, -1, NULL, 0, 0, 0, 0, NULL, NULL, 0, + 0, 0, 0, 0, 0, NULL, 0, 0, 0, NULL, 0, 0, NULL, 0, 0, +}; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102ED0.s") +MapDataRoom sMapDataRooms[ROOM_MAX]; +MapDataChest sMapDataChests[32]; +static MapDataScene sMapDataScene = { + sMapDataRooms, + 80, +}; +static s32 sSceneNumRooms = 0; // current scene's no. of rooms +static s32 sNumChests = 0; // MinimapChest count +static TransitionActorList sTransitionActorList = { 0, NULL }; +static Color_RGBA8 sMinimapActorCategoryColors[12] = { + { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 0, 255, 0, 255 }, { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, { 255, 0, 0, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, { 255, 0, 0, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, +}; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102EF0.s") +TransitionActorEntry sTransitionActors[ROOM_TRANSITION_MAX]; +PauseDungeonMap sPauseDungeonMap; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80102F9C.s") +void MapDisp_GetMapITexture(void* dst, s32 mapCompactId) { + if (MapDisp_GetSizeOfMapITex(mapCompactId) != 0) { + CmpDma_LoadFile(SEGMENT_ROM_START(map_i_static), mapCompactId, dst, MapDisp_GetSizeOfMapITex(mapCompactId)); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80103090.s") +void MapDisp_InitRoomStoreyRecord(PlayState* play, s16* roomStorey) { + *roomStorey = -1; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801030B4.s") +void MapDisp_DestroyRoomStoreyRecord(PlayState* play, s16* roomStory) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801030F4.s") +void func_80102EB4(u32 flag) { + sMapDisp.unk20 |= flag; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801031D0.s") +void func_80102ED0(u32 flag) { + sMapDisp.unk20 &= ~flag; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801039EC.s") +s32 MapDisp_CurRoomHasMapI(PlayState* play) { + MapDataRoom* mapDataRoom; + s8 curRoom; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80103A10.s") + if (Map_IsInBossScene(play) == true) { + return true; + } + curRoom = play->roomCtx.curRoom.num; + if (curRoom == -1) { + return false; + } + mapDataRoom = &sMapDisp.mapDataScene->rooms[curRoom]; + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + return false; + } + if (MapData_GetMapIId(mapDataRoom->mapId) == MAPDATA_MAP_I_MAX) { + return false; + } + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80103A58.s") +/** + * Computes the storey containing checkY and returns the floor Y value. + * @note Only used to check if a chest is on the same storey as the player. + */ +f32 MapDisp_GetStoreyY(f32 checkY) { + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010439C.s") + if ((sMapDisp.storeyYList[sMapDisp.numStoreys - 1] - 80.0f) < checkY) { + return sMapDisp.storeyYList[sMapDisp.numStoreys - 1]; + } + for (i = sMapDisp.numStoreys - 2; i >= 0; i--) { + if (((sMapDisp.storeyYList[i] - 80.0f) < checkY) && (checkY < (sMapDisp.storeyYList[i + 1] + 80.0f))) { + return sMapDisp.storeyYList[i]; + } + } + if (checkY < (sMapDisp.storeyYList[0] + 80.0f)) { + return sMapDisp.storeyYList[0]; + } + return 0.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801045AC.s") +void MapDisp_GetMapTexDim(MapDataRoom* mapDataRoom, s32* width, s32* height) { + MapData_GetMapTexDim(mapDataRoom->mapId, width, height); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80104AE8.s") +void MapDisp_GetMapScale(MapDataRoom* mapDataRoom, s32* scale) { + MapData_GetMapScale(mapDataRoom->mapId, scale); + if (*scale == 0) { + *scale = 20; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80104C80.s") +void MapDisp_GetMapOffset(MapDataRoom* mapDataRoom, s32* offsetX, s32* offsetY) { + s32 width; + s32 height; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80104CF4.s") + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + *offsetX = 0; + *offsetY = 0; + return; + } + MapDisp_GetMapTexDim(mapDataRoom, &width, &height); + MapData_GetMapTexOffset(mapDataRoom->mapId, offsetX, offsetY); + if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) { + s32 temp = (width / 2); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80104F34.s") + *offsetX = ((width / 2) - *offsetX) + (width / 2); + } + if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) { + s32 temp = (height / 2); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105294.s") + *offsetY = (temp - *offsetY) + temp; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105318.s") +void MapDisp_DrawMinimapRoom(PlayState* play, TexturePtr texture, s32 x, s32 y, s32 room, f32 intensity) { + MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[room]; + s32 texWidth; + s32 texHeight; + s32 dtdy; + s32 dsdx; + s32 t; + s32 s; + s16 dsdx_temp; + s16 dtdy_temp; + Color_RGBA8 color; + s32 drawType; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105328.s") + if ((mapDataRoom->mapId == MAP_DATA_NO_MAP) || (texture == NULL)) { + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010534C.s") + MapDisp_GetMapTexDim(mapDataRoom, &texWidth, &texHeight); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010549C.s") + OPEN_DISPS(play->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010565C.s") + Gfx_SetupDL39_Overlay(play->state.gfxCtx); + MapData_GetMapColor(MapData_GetMapColorIndex(mapDataRoom->mapId), &color); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, color.r, color.g, color.b, + (s32)(play->interfaceCtx.minimapAlpha * intensity * color.a / 255.0f)); + MapData_GetDrawType(mapDataRoom->mapId, &drawType); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105818.s") + switch (drawType) { + case MAPDATA_DRAW_1: + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPLoadTextureBlock_4b(OVERLAY_DISP++, texture, G_IM_FMT_IA, texWidth, texHeight, 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); + break; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105A40.s") + case MAPDATA_DRAW_3: + gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0, 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0); + gDPLoadTextureBlock_4b(OVERLAY_DISP++, texture, G_IM_FMT_I, texWidth, texHeight, 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); + break; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105B34.s") + default: + case MAPDATA_DRAW_0: + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPLoadTextureBlock_4b(OVERLAY_DISP++, texture, G_IM_FMT_I, texWidth, texHeight, 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); + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105C40.s") + s = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) ? (texWidth - 1) << 5 : 0; + t = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) ? 0 : (texHeight - 1) << 5; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80105FE0.s") + dsdx_temp = ((mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) ? -1 : 1) * (1 << 10); + dtdy_temp = ((mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) ? 1 : -1) * (1 << 10); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106408.s") + dsdx = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) ? dsdx_temp & 0xFFFF : dsdx_temp; + dtdy = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) ? dtdy_temp : dtdy_temp & 0xFFFF; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106450.s") + gSPTextureRectangle(OVERLAY_DISP++, x << 2, y << 2, (texWidth + x) << 2, (y + texHeight) << 2, G_TX_RENDERTILE, s, + t, dsdx, dtdy); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801064CC.s") + CLOSE_DISPS(play->state.gfxCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106530.s") +// Tests if the map data should be rotated 180 degrees +// SCENE_35TAKI is the only scene with data flipped in this manner. +s32 MapDisp_IsDataRotated(PlayState* play) { + if (play->sceneId == SCENE_35TAKI) { + return true; + } + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010657C.s") +s32 MapDisp_CanDrawDoors(PlayState* play) { + if ((gSaveContext.save.entrance == ENTRANCE(ROMANI_RANCH, 0)) && (Cutscene_GetSceneLayer(play) != 0)) { + return false; + } + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106644.s") +void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) { + MapDataRoom* mapDataRoom; + s32 posX; + s32 posY; + s32 texOffsetX; + s32 texOffsetY; + s32 texWidth; + s32 texHeight; + f32 scaleFrac; + f32 unused1; + f32 unused2; + Player* player = GET_PLAYER(play); + s32 scale; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_8010683C.s") + // inferred from `MapDisp_Minimap_DrawDoorActor` + unused1 = fabsf(player->actor.world.pos.y - actor->world.pos.y); + unused2 = 1.0f - (1 / 350.0f) * unused1; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801068B4.s") + if (unused2 < 0.0f) { + unused2 = 0.0f; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801068D8.s") + mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801068FC.s") + MapDisp_GetMapOffset(mapDataRoom, &texOffsetX, &texOffsetY); + MapDisp_GetMapTexDim(mapDataRoom, &texWidth, &texHeight); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106BEC.s") + scale = sMapDisp.mapDataScene->scale; + if (sMapDisp.mapDataScene->scale == 0) { + scale = 20; + } else if (sMapDisp.mapDataScene->scale == -1) { + s32 scaleTemp; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106D08.s") + MapDisp_GetMapScale(mapDataRoom, &scaleTemp); + scale = scaleTemp; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80106D5C.s") + scaleFrac = 1.0f / scale; + if (!MapDisp_IsDataRotated(play)) { + posX = (s32)((actor->world.pos.x - mapDataRoom->centerX) * scaleFrac) + sMapDisp.minimapBaseX + + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + texOffsetX; + posY = (s32)((actor->world.pos.z - mapDataRoom->centerZ) * scaleFrac) + sMapDisp.minimapBaseY + + sMapDisp.minimapCurY - sMapDisp.minimapBaseY + texOffsetY; + } else { + posX = -(s32)((actor->world.pos.x - mapDataRoom->centerX) * scaleFrac) + sMapDisp.minimapBaseX + + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + texOffsetX; + posY = -(s32)((actor->world.pos.z - mapDataRoom->centerZ) * scaleFrac) + sMapDisp.minimapBaseY + + sMapDisp.minimapCurY - sMapDisp.minimapBaseY + texOffsetY; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80107B78.s") + if ((posX > 0) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { + OPEN_DISPS(play->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80108124.s") + if ((actor->category == ACTORCAT_PLAYER) && (actor->flags & ACTOR_FLAG_80000000)) { + s16 compassRot; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80108558.s") + Gfx_SetupDL42_Overlay(play->state.gfxCtx); + gSPMatrix(OVERLAY_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, play->interfaceCtx.minimapAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPSetRenderMode(OVERLAY_DISP++, G_RM_AA_DEC_LINE, G_RM_NOOP2); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80108A10.s") + Matrix_Translate(posX - 160.0f, 120.0f - posY, 0.0f, MTXMODE_NEW); + Matrix_RotateXFApply(-1.6f); + compassRot = (s32)(0x7FFF - actor->focus.rot.y) / 1024; + if (MapDisp_IsDataRotated(play)) { + compassRot += 0x7FFF; + } + Matrix_RotateYF(compassRot / 10.0f, MTXMODE_APPLY); + Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); + gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 255, 0, play->interfaceCtx.minimapAlpha); + gSPDisplayList(OVERLAY_DISP++, gCompassArrowDL); + } else if ((actor->id == ACTOR_EN_BOX) && !Flags_GetTreasure(play, actor->params & 0x1F) && + (MapDisp_GetStoreyY(player->actor.world.pos.y) == MapDisp_GetStoreyY(actor->world.pos.y))) { + Gfx_SetupDL39_Overlay(play->state.gfxCtx); + gDPPipeSync(OVERLAY_DISP++); + gDPSetTextureLUT(OVERLAY_DISP++, G_TT_NONE); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, play->interfaceCtx.minimapAlpha); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, play->interfaceCtx.minimapAlpha); + gDPPipeSync(OVERLAY_DISP++); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80108A64.s") + gDPLoadTextureBlock_Runtime(OVERLAY_DISP++, gMapChestIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 8, 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); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80108AF8.s") + gSPTextureRectangle(OVERLAY_DISP++, (posX - 4) << 2, (posY - 4) << 2, (posX + 4) << 2, (posY + 4) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } else { + Gfx_SetupDL39_Overlay(play->state.gfxCtx); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + if (actor->flags & ACTOR_FLAG_80000000) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, sMinimapActorCategoryColors[actor->category].r, + sMinimapActorCategoryColors[actor->category].g, + sMinimapActorCategoryColors[actor->category].b, play->interfaceCtx.minimapAlpha); + gSPTextureRectangle(OVERLAY_DISP++, (posX - 1) << 2, (posY - 1) << 2, (posX + 1) << 2, (posY + 1) << 2, + G_TX_RENDERTILE, 0, 0, 0x0001, 0x0001); + } + } + CLOSE_DISPS(play->state.gfxCtx); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801090B0.s") +void MapDisp_Minimap_DrawActors(PlayState* play) { + ActorContext* actorCtx; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80109124.s") + if (play->roomCtx.curRoom.num != -1) { + OPEN_DISPS(play->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_801091F0.s") + gDPLoadTextureBlock_4b(OVERLAY_DISP++, &sWhiteSquareTex, G_IM_FMT_I, 16, 16, 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); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_map_disp/func_80109428.s") + actorCtx = &play->actorCtx; + for (i = 0; i < ACTORCAT_MAX; i++) { + Actor* actor = actorCtx->actorLists[i].first; + + while (actor != NULL) { + if ((actor->update != NULL) && (actor->init == NULL) && + Object_IsLoaded(&play->objectCtx, actor->objectSlot) && + ((actor->id == ACTOR_EN_BOX) || (i == ACTORCAT_PLAYER) || (actor->flags & ACTOR_FLAG_80000000)) && + ((sMapDisp.curRoom == actor->room) || (actor->room == -1))) { + MapDisp_Minimap_DrawActorIcon(play, actor); + } + actor = actor->next; + } + } + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +void MapDisp_Minimap_DrawDoorActor(PlayState* play, Actor* actor) { + MapDataRoom* mapDataRoom; + s32 posX; + s32 posY; + s32 texOffsetX; + s32 texOffsetY; + s32 texWidth; + s32 texHeight; + Player* player = GET_PLAYER(play); + f32 scaleFrac; + f32 yDistFromPlayer = fabsf(player->actor.world.pos.y - actor->world.pos.y); + s32 scale; + f32 yDistAlpha = 1.0f - (1.0f / 350.0f) * yDistFromPlayer; + + if (yDistAlpha < 0.0f) { + yDistAlpha = 0.0f; + } + mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; + if (mapDataRoom->mapId != MAP_DATA_NO_MAP) { + MapDisp_GetMapOffset(mapDataRoom, &texOffsetX, &texOffsetY); + MapDisp_GetMapTexDim(mapDataRoom, &texWidth, &texHeight); + + scale = sMapDisp.mapDataScene->scale; + if (sMapDisp.mapDataScene->scale == 0) { + scale = 20; + } else if (sMapDisp.mapDataScene->scale == -1) { + s32 scaleTemp; + + MapDisp_GetMapScale(mapDataRoom, &scaleTemp); + scale = scaleTemp; + } + scaleFrac = 1.0f / scale; + if (!MapDisp_IsDataRotated(play)) { + posX = (((s32)((actor->world.pos.x - mapDataRoom->centerX) * scaleFrac) + sMapDisp.minimapBaseX + + sMapDisp.minimapCurX) - + sMapDisp.minimapBaseX) + + texOffsetX; + posY = (((s32)((actor->world.pos.z - mapDataRoom->centerZ) * scaleFrac) + sMapDisp.minimapBaseY + + sMapDisp.minimapCurY) - + sMapDisp.minimapBaseY) + + texOffsetY; + } else { + posX = (((sMapDisp.minimapBaseX - (s32)((actor->world.pos.x - mapDataRoom->centerX) * scaleFrac)) + + sMapDisp.minimapCurX) - + sMapDisp.minimapBaseX) + + texOffsetX; + posY = (((sMapDisp.minimapBaseY - (s32)((actor->world.pos.z - mapDataRoom->centerZ) * scaleFrac)) + + sMapDisp.minimapCurY) - + sMapDisp.minimapBaseY) + + texOffsetY; + } + if ((posX > 0) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL39_Overlay(play->state.gfxCtx); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + + if ((actor->category == ACTORCAT_DOOR) && MapDisp_CanDrawDoors(play)) { + s32 pad; + + gDPSetPrimColor( + OVERLAY_DISP++, 0, 0, sMinimapActorCategoryColors[actor->category].r, + sMinimapActorCategoryColors[actor->category].g, sMinimapActorCategoryColors[actor->category].b, + (s32)((sMinimapActorCategoryColors[actor->category].a * (1.0f - sMapDisp.swapAnimTimer * 0.05f) * + yDistAlpha * play->interfaceCtx.minimapAlpha) / + 255.0f)); + + scale = sMapDisp.mapDataScene->scale; + if (sMapDisp.mapDataScene->scale == 0) { + scale = 20; + } else if (sMapDisp.mapDataScene->scale == -1) { + s32 scaleTemp; + + MapDisp_GetMapScale(mapDataRoom, &scaleTemp); + scale = scaleTemp; + } + if (scale <= 50) { + gSPTextureRectangle(OVERLAY_DISP++, (posX - 2) << 2, (posY - 2) << 2, (posX + 2) << 2, + (posY + 2) << 2, G_TX_RENDERTILE, 0, 0, 0x0001, 0x0001); + } else { + gSPTextureRectangle(OVERLAY_DISP++, (posX - 1) << 2, (posY - 1) << 2, (posX + 1) << 2, + (posY + 1) << 2, G_TX_RENDERTILE, 0, 0, 0x0001, 0x0001); + } + } + + CLOSE_DISPS(play->state.gfxCtx); + } + } +} + +void MapDisp_Minimap_DrawDoorActors(PlayState* play) { + s32 i; + Actor* actor; + + if (play->roomCtx.curRoom.num != -1) { + OPEN_DISPS(play->state.gfxCtx); + + gDPLoadTextureBlock_4b(OVERLAY_DISP++, &sWhiteSquareTex, G_IM_FMT_I, 16, 16, 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); + + actor = play->actorCtx.actorLists[ACTORCAT_DOOR].first; + while (actor != NULL) { + if ((actor->update != NULL) && (actor->init == NULL) && + Object_IsLoaded(&play->objectCtx, actor->objectSlot) && + ((sMapDisp.curRoom == actor->room) || (actor->room == -1))) { + MapDisp_Minimap_DrawDoorActor(play, actor); + } + actor = actor->next; + } + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +/** + * @brief Waits for GAMEPLAY_DANGEON_KEEP to load, if it is a current object depenency + * + * @param play + */ +void MapDisp_AwaitGameplayDangeonKeep(PlayState* play) { + s32 objectSlot = Object_GetSlot(&play->objectCtx, GAMEPLAY_DANGEON_KEEP); + + if (objectSlot <= OBJECT_SLOT_NONE) { + sMapDisp.unk20 |= 1; + return; + } + + while (true) { + if (Object_IsLoaded(&play->objectCtx, objectSlot)) { + break; + } + } +} + +void MapDisp_Init(PlayState* play) { + s32 i; + + sMapDisp.mapDataScene = NULL; + sMapDisp.curRoom = -1; + sMapDisp.minimapBaseX = 210; + sMapDisp.minimapBaseY = 140; + sMapDisp.minimapCurX = 210; + sMapDisp.minimapCurY = 140; + sMapDisp.minimapCurTex = NULL; + sMapDisp.prevRoom = -1; + sMapDisp.minimapPrevTex = NULL; + sMapDisp.minimapPrevX = 0; + sMapDisp.minimapPrevY = 0; + sMapDisp.unk20 = 0; + sMapDisp.swapAnimTimer = 0; + + if (!Map_IsInBossScene(play)) { + sSceneNumRooms = play->numRooms; + } + sMapDisp.texBuff0 = THA_AllocTailAlign16(&play->state.tha, 0x4000); + sMapDisp.texBuff1 = THA_AllocTailAlign16(&play->state.tha, 0x4000); + MapDisp_AwaitGameplayDangeonKeep(play); + if (!Map_IsInBossScene(play)) { + sMapDisp.sceneMinX = 0; + sMapDisp.sceneMinZ = 0; + sMapDisp.sceneWidth = 100; + sMapDisp.sceneHeight = 100; + sMapDisp.sceneMidX = TRUNCF_BINANG((f32)sMapDisp.sceneMinX + ((f32)sMapDisp.sceneWidth * 0.5f)); + sMapDisp.sceneMidZ = TRUNCF_BINANG((f32)sMapDisp.sceneMinZ + ((f32)sMapDisp.sceneHeight * 0.5f)); + } + sMapDisp.roomStoreyList = THA_AllocTailAlign16(&play->state.tha, sSceneNumRooms * sizeof(s16)); + + for (i = 0; i < sSceneNumRooms; i++) { + MapDisp_InitRoomStoreyRecord(play, &sMapDisp.roomStoreyList[i]); + } + sMapDisp.storeyYList = THA_AllocTailAlign16(&play->state.tha, ROOM_MAX * sizeof(s16)); + + for (i = 0; i < ROOM_MAX; i++) { + sMapDisp.storeyYList[i] = FLOOR_MIN_Y; + } + MapDisp_InitMapI(play); + sMapDisp.bossRoomStorey = 0; + sMapDisp.unk5A = 0; + if (Map_IsInBossScene(play)) { + MapDisp_InitMapData(play, NULL); + MapDisp_InitChestData(play, 0, NULL); + } +} + +typedef struct { + /* 0x0 */ s16 sceneId; + /* 0x2 */ s16 bottomStorey; +} MapCustomBottomStorey; // size = 0x4 + +void MapDisp_InitSceneFloorData(PlayState* play) { + static MapCustomBottomStorey sCustomBottomStorey[] = { + { SCENE_HAKUGIN, -1 }, { SCENE_HAKUGIN_BS, -1 }, { SCENE_SEA, -2 }, + { SCENE_SEA_BS, -2 }, { SCENE_INISIE_N, -1 }, + }; + s32 i1; + s32 i2; + s32 i3; + s32 storey; + + // init table + for (i1 = 0; i1 < ROOM_MAX; i1++) { + sMapDisp.storeyYList[i1] = FLOOR_MIN_Y; + } + + // for all rooms in scene + for (i2 = 0; i2 < sSceneNumRooms; i2++) { + MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[i2]; + + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + continue; + } + // add item to the table if it is a newish value + for (i1 = 0; i1 < ROOM_MAX; i1++) { + if (sMapDisp.storeyYList[i1] == FLOOR_MIN_Y) { + sMapDisp.storeyYList[i1] = mapDataRoom->floorY; + break; + } else if (fabsf((f32)sMapDisp.storeyYList[i1] - (f32)mapDataRoom->floorY) < 5.0f) { + break; + } + } + } + + // sort the table in ascending order + for (i2 = 0; i2 < sSceneNumRooms; i2++) { + if (sMapDisp.storeyYList[i2] == FLOOR_MIN_Y) { + break; + } + for (i3 = i2 + 1; i3 < sSceneNumRooms; i3++) { + if (sMapDisp.storeyYList[i3] == FLOOR_MIN_Y) { + break; + } + if (sMapDisp.storeyYList[i3] < sMapDisp.storeyYList[i2]) { + s16 swap = sMapDisp.storeyYList[i2]; + + sMapDisp.storeyYList[i2] = sMapDisp.storeyYList[i3]; + sMapDisp.storeyYList[i3] = swap; + } + } + } + + for (i2 = 0; i2 < sSceneNumRooms; i2++) { + MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[i2]; + + sMapDisp.roomStoreyList[i2] = -1; + + for (storey = 0; storey < sSceneNumRooms; storey++) { + if (sMapDisp.storeyYList[storey] != FLOOR_MIN_Y) { + if (fabsf((f32)sMapDisp.storeyYList[storey] - (f32)mapDataRoom->floorY) < 5.0f) { + sMapDisp.roomStoreyList[i2] = storey; + break; + } + } + } + } + sMapDisp.numStoreys = 0; + for (i2 = 0; i2 < sSceneNumRooms; i2++) { + if (sMapDisp.storeyYList[i2] != FLOOR_MIN_Y) { + sMapDisp.numStoreys++; + } + } + sMapDisp.bottomStorey = 0; + for (i2 = 0; i2 < ARRAY_COUNT(sCustomBottomStorey); i2++) { + if (play->sceneId == sCustomBottomStorey[i2].sceneId) { + sMapDisp.bottomStorey = sCustomBottomStorey[i2].bottomStorey; + } + } +} + +/** + * Unused result + * @returns the y position to place the boss room skull icon on the pause map. + * The result position is the inverse of what it should be, stacking lower rooms above higher ones + */ +s32 MapDisp_GetBossIconY(void) { + s32 dungeonMapFloorIconPosY[5] = { 67, 81, 95, 109, 123 }; + + if ((sMapDisp.mapDataScene == NULL) || (sMapDisp.bossRoomStorey < 0) || (sMapDisp.bossRoomStorey >= 5) || + (sSceneNumRooms == 0)) { + return 123; + } + return dungeonMapFloorIconPosY[sMapDisp.bossRoomStorey]; +} + +s16 MapDisp_GetBossRoomStorey(void) { + return sMapDisp.bossRoomStorey; +} + +// TransitionActor params test +s32 MapDisp_IsBossDoor(s32 params) { + if (DOORSHUTTER_PARAMS_GET_TYPE((u16)params) == DOORSHUTTER_TYPE_BOSS_DOOR) { + return true; + } + return false; +} + +void MapDisp_InitBossRoomStorey(PlayState* play) { + TransitionActorList* transitionActors = &sTransitionActorList; + s32 storey; + s32 i; + + for (i = 0; i < transitionActors->count; i++) { + if (MapDisp_IsBossDoor(sTransitionActors[i].params)) { + if (ABS_ALT(sTransitionActors[i].id) != ACTOR_EN_HOLL) { + for (storey = 0; storey < sMapDisp.numStoreys; storey++) { + //! FAKE: needed for matching + s32 temp = (sMapDisp.storeyYList[storey] - 5); + + if (((storey == sMapDisp.numStoreys - 1) && + (sTransitionActors[i].pos.y >= (sMapDisp.storeyYList[storey] - 5))) || + ((storey != sMapDisp.numStoreys - 1) && + (sTransitionActors[i].pos.y >= (sMapDisp.storeyYList[storey] - 5)) && + (sTransitionActors[i].pos.y < (sMapDisp.storeyYList[storey + 1] - 5)))) { + sMapDisp.bossRoomStorey = storey; + return; + } + } + } + } + } + sMapDisp.bossRoomStorey = 0; +} + +/** + * @brief Initializes the MapData for the current scene + * + * @param play + * @param segmentAddress + */ +void MapDisp_InitMapData(PlayState* play, void* segmentAddress) { + MapDataScene* mapDataScene; + MapDataRoom* mapDataRooms; + s32 i; + + if (!Map_IsInBossScene(play)) { + sSceneNumRooms = play->numRooms; + mapDataScene = Lib_SegmentedToVirtual(segmentAddress); + sMapDataScene = *mapDataScene; + mapDataRooms = Lib_SegmentedToVirtual(mapDataScene->rooms); + + for (i = 0; i < sSceneNumRooms; i++) { + sMapDataRooms[i] = *mapDataRooms++; + } + + sMapDataScene.rooms = sMapDataRooms; + if (play->colCtx.colHeader != NULL) { + sMapDisp.sceneMinX = play->colCtx.colHeader->minBounds.x; + sMapDisp.sceneMinZ = play->colCtx.colHeader->minBounds.z; + sMapDisp.sceneWidth = play->colCtx.colHeader->maxBounds.x - play->colCtx.colHeader->minBounds.x; + sMapDisp.sceneHeight = play->colCtx.colHeader->maxBounds.z - play->colCtx.colHeader->minBounds.z; + sMapDisp.sceneMidX = sMapDisp.sceneMinX + (sMapDisp.sceneWidth * 0.5f); + sMapDisp.sceneMidZ = sMapDisp.sceneMinZ + (sMapDisp.sceneHeight * 0.5f); + } + } + sMapDisp.mapDataScene = &sMapDataScene; + MapDisp_InitSceneFloorData(play); + MapDisp_InitBossRoomStorey(play); +} + +/** + * @brief Creates a deep copy of chest data from the scene data. + * + * @param play + * @param num + * @param segmentAddress + * @note If a boss scene is loaded, no data is copied. This allows the scene to borrow the main dungeon scene data + * instead. + */ +void MapDisp_InitChestData(PlayState* play, s32 num, void* segmentAddress) { + MapDataChest* mapDataChests; + s32 i; + + if (!Map_IsInBossScene(play)) { + mapDataChests = Lib_SegmentedToVirtual(segmentAddress); + for (i = 0; i < num; mapDataChests++, i++) { + sMapDataChests[i] = *mapDataChests; + } + sNumChests = num; + } + sMapDisp.mapDataChests = sMapDataChests; + sMapDisp.numChests = sNumChests; +} + +/** + * @brief Creates a deep copy of transition actors from the scene data. + * + * @param play + * @param num number of transition actors within the list + * @param transitionActorList pointer to the list of transition actors + * @note If a boss scene is loaded, no data is copied. This allows the scene to borrow the main dungeon scene data + * instead. + */ +void MapDisp_InitTransitionActorData(PlayState* play, s32 num, TransitionActorEntry* transitionActorList) { + s32 i; + + if (!Map_IsInBossScene(play)) { + sTransitionActorList.count = num; + for (i = 0; i < num; i++) { + sTransitionActors[i] = transitionActorList[i]; + } + sTransitionActorList.list = sTransitionActors; + } +} + +void MapDisp_Destroy(PlayState* play) { + s32 i; + + sMapDisp.mapDataScene = NULL; + sMapDisp.curRoom = -1; + sMapDisp.minimapCurX = 210; + sMapDisp.minimapCurY = 140; + sMapDisp.minimapCurTex = NULL; + sMapDisp.prevRoom = -1; + sMapDisp.minimapPrevTex = NULL; + sMapDisp.minimapPrevX = 0; + sMapDisp.minimapPrevY = 0; + sMapDisp.unk20 = 0; + sMapDisp.swapAnimTimer = 0; + sMapDisp.texBuff0 = NULL; + sMapDisp.texBuff1 = NULL; + + for (i = 0; i < sSceneNumRooms; i++) { + MapDisp_DestroyRoomStoreyRecord(play, &sMapDisp.roomStoreyList[i]); + } + + sMapDisp.roomStoreyList = NULL; + sMapDisp.numStoreys = 0; + sMapDisp.pauseMapCurStorey = 0; + sMapDisp.bottomStorey = 0; + sMapDisp.timer = 0; + sMapDisp.storeyYList = NULL; + sMapDisp.numChests = 0; + sMapDisp.mapDataChests = NULL; + MapDisp_DestroyMapI(play); + sMapDisp.unk5A = 0; +} + +void MapDisp_Update(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + s16 currentX; + s16 currentY; + s16 targetX; + s16 targetY; + + if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0)) { + sMapDisp.pauseMapCurStorey = DUNGEON_FLOOR_INDEX_0 - pauseCtx->cursorMapDungeonItem; + if (sMapDisp.prevRoom != -1) { + if (sMapDisp.swapAnimTimer > 0) { + targetX = sMapDisp.minimapBaseX; + currentX = sMapDisp.minimapCurX; + if (targetX != currentX) { + sMapDisp.minimapCurX = + TRUNCF_BINANG(((f32)(targetX - currentX) / (f32)sMapDisp.swapAnimTimer) + (f32)currentX); + } + targetY = sMapDisp.minimapBaseY; + currentY = sMapDisp.minimapCurY; + if (targetY != currentY) { + sMapDisp.minimapCurY = + TRUNCF_BINANG(((f32)(targetY - currentY) / (f32)sMapDisp.swapAnimTimer) + (f32)currentY); + } + sMapDisp.swapAnimTimer--; + } else { + sMapDisp.prevRoom = -1; + sMapDisp.swapAnimTimer = 0; + sMapDisp.minimapCurX = sMapDisp.minimapBaseX; + sMapDisp.minimapCurY = sMapDisp.minimapBaseY; + } + } else { + sMapDisp.swapAnimTimer = 0; + } + } +} + +void MapDisp_SwapRooms(s16 nextRoom) { + MapDataRoom* nextMapDataRoom; + MapDataRoom* prevMapDataRoom; + s32 minimapBaseX; + s32 minimapBaseY; + s32 width; + s32 height; + s32 offsetX; + s32 offsetY; + + if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0) && (nextRoom != -1)) { + nextMapDataRoom = &sMapDisp.mapDataScene->rooms[nextRoom]; + if ((nextMapDataRoom->mapId < MAPDATA_GAMEPLAY_DANGEON_KEEP_MAX) || + ((nextMapDataRoom->mapId >= MAPDATA_MAP_GRAND) && (nextMapDataRoom->mapId < MAPDATA_MAP_GRAND_MAX)) || + nextMapDataRoom->mapId == MAP_DATA_NO_MAP) { + + sMapDisp.prevRoom = sMapDisp.curRoom; + sMapDisp.curRoom = nextRoom; + sMapDisp.swapAnimTimer = 20; + + sMapDisp.minimapPrevTex = sMapDisp.minimapCurTex; + minimapBaseX = sMapDisp.minimapBaseX; + minimapBaseY = sMapDisp.minimapBaseY; + + nextMapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; + + if (nextMapDataRoom->mapId == MAP_DATA_NO_MAP) { + sMapDisp.minimapPrevY = 0; + sMapDisp.minimapBaseX = 210; + sMapDisp.minimapBaseY = 140; + sMapDisp.minimapCurX = 210; + sMapDisp.minimapCurY = 140; + sMapDisp.minimapCurTex = NULL; + sMapDisp.minimapPrevX = sMapDisp.minimapPrevY; + return; + } + MapDisp_GetMapOffset(nextMapDataRoom, &offsetX, &offsetY); + MapDisp_GetMapTexDim(nextMapDataRoom, &width, &height); + sMapDisp.minimapBaseX = 295 - width; + sMapDisp.minimapBaseY = 220 - height; + if (sMapDisp.prevRoom != -1) { + prevMapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.prevRoom]; + if (prevMapDataRoom->mapId == MAP_DATA_NO_MAP) { + sMapDisp.minimapCurTex = NULL; + sMapDisp.minimapPrevX = sMapDisp.minimapPrevY = 0; + sMapDisp.minimapCurX = sMapDisp.minimapBaseX; + sMapDisp.minimapCurY = sMapDisp.minimapBaseY; + return; + } else { + s32 prevOffsetX; + s32 prevOffsetY; + s32 scale; + s32 pad; + + MapDisp_GetMapOffset(prevMapDataRoom, &prevOffsetX, &prevOffsetY); + scale = sMapDisp.mapDataScene->scale; + if (sMapDisp.mapDataScene->scale == 0) { + scale = 20; + } else if (sMapDisp.mapDataScene->scale == -1) { + s32 scaleTemp; + + MapDisp_GetMapScale(nextMapDataRoom, &scaleTemp); + scale = scaleTemp; + } + sMapDisp.minimapPrevX = + TRUNCF_BINANG(((f32)offsetX + (((f32)prevMapDataRoom->centerX - (f32)nextMapDataRoom->centerX) * + (1.0f / scale))) - + (f32)prevOffsetX); + sMapDisp.minimapPrevY = + TRUNCF_BINANG(((f32)offsetY + (((f32)prevMapDataRoom->centerZ - (f32)nextMapDataRoom->centerZ) * + (1.0f / scale))) - + (f32)prevOffsetY); + sMapDisp.minimapCurX = minimapBaseX - sMapDisp.minimapPrevX; + sMapDisp.minimapCurY = minimapBaseY - sMapDisp.minimapPrevY; + } + } else { + sMapDisp.minimapPrevX = sMapDisp.minimapPrevY = 0; + sMapDisp.minimapCurX = sMapDisp.minimapBaseX; + sMapDisp.minimapCurY = sMapDisp.minimapBaseY; + } + sMapDisp.minimapCurTex = NULL; + + switch (MapData_MID_GetType(nextMapDataRoom->mapId)) { + case MAPDATA_MID_GAMEPLAY_DANGEON_KEEP: + sMapDisp.minimapCurTex = MapData_GetMapTexGameplayDangeonKeep(nextMapDataRoom->mapId); + return; + + case MAPDATA_MID_MAP_GRAND_STATIC: + if (sMapDisp.minimapPrevTex == sMapDisp.texBuff0) { + sMapDisp.minimapCurTex = sMapDisp.texBuff1; + } else { + sMapDisp.minimapCurTex = sMapDisp.texBuff0; + } + if (MapData_GetSizeOfMapGrandTex(nextMapDataRoom->mapId) != 0) { + CmpDma_LoadFile(SEGMENT_ROM_START(map_grand_static), + MAPDATA_GET_MAP_GRAND_ID_FROM_MAP_ID(nextMapDataRoom->mapId), + sMapDisp.minimapCurTex, MapData_GetSizeOfMapGrandTex(nextMapDataRoom->mapId)); + } + break; + + default: + break; + } + } + } +} + +void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot) { + MapDataRoom* mapDataRoom; + s32 posX; + s32 posY; + s32 texOffsetX; + s32 texOffsetY; + s32 texWidth; + s32 texHeight; + s32 scale; + f32 scaleFrac; + + mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + return; + } + + MapDisp_GetMapOffset(mapDataRoom, &texOffsetX, &texOffsetY); + MapDisp_GetMapTexDim(mapDataRoom, &texWidth, &texHeight); + scale = sMapDisp.mapDataScene->scale; + + if (sMapDisp.mapDataScene->scale == 0) { + scale = 20; + } else if (sMapDisp.mapDataScene->scale == -1) { + s32 scaleTemp; + + MapDisp_GetMapScale(mapDataRoom, &scaleTemp); + scale = scaleTemp; + } + + scaleFrac = 1.0f / scale; + if (!MapDisp_IsDataRotated(play)) { + posX = (s32)((x - (f32)mapDataRoom->centerX) * scaleFrac) + sMapDisp.minimapBaseX + + (sMapDisp.minimapCurX - sMapDisp.minimapBaseX) + texOffsetX; + posY = (s32)((z - (f32)mapDataRoom->centerZ) * scaleFrac) + sMapDisp.minimapBaseY + + (sMapDisp.minimapCurY - sMapDisp.minimapBaseY) + texOffsetY; + } else { + posX = -(s32)((x - (f32)mapDataRoom->centerX) * scaleFrac) + sMapDisp.minimapBaseX + + (sMapDisp.minimapCurX - sMapDisp.minimapBaseX) + texOffsetX; + posY = -(s32)((z - (f32)mapDataRoom->centerZ) * scaleFrac) + sMapDisp.minimapBaseY + + (sMapDisp.minimapCurY - sMapDisp.minimapBaseY) + texOffsetY; + } + + if ((posX > 0) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL42_Overlay(play->state.gfxCtx); + gSPMatrix(OVERLAY_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPSetRenderMode(OVERLAY_DISP++, G_RM_AA_DEC_LINE, G_RM_NOOP2); + Matrix_Translate(posX - 160.0f, 120.0f - posY, 0.0f, MTXMODE_NEW); + Matrix_RotateXFApply(-1.6f); + if (MapDisp_IsDataRotated(play)) { + rot += 0x7FFF; + } + Matrix_RotateYF(rot / 10.0f, MTXMODE_APPLY); + Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); + gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(OVERLAY_DISP++, 0, 255, 200, 0, 0, play->interfaceCtx.minimapAlpha); + gSPDisplayList(OVERLAY_DISP++, gCompassArrowDL); + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +s32 MapDisp_IsLocationRomaniRanchAltScene(PlayState* play) { + if ((gSaveContext.save.entrance == ENTRANCE(ROMANI_RANCH, 0)) && (Cutscene_GetSceneLayer(play) != 0)) { + return true; + } + return false; +} + +s32 MapDisp_CanDisplayMinimap(PlayState* play) { + if ((!Map_CurRoomHasMapI(play) && Inventory_IsMapVisible(play->sceneId)) || + (Map_CurRoomHasMapI(play) && CHECK_DUNGEON_ITEM(DUNGEON_MAP, gSaveContext.mapIndex))) { + return true; + } + return false; +} + +s32 MapDisp_IsLocationMinimapBlocked(PlayState* play) { + if (((play->csCtx.state != CS_STATE_IDLE) && !MapDisp_IsLocationRomaniRanchAltScene(play)) || + (sMapDisp.unk20 & 2) || Map_IsInBossScene(play)) { + return true; + } + return false; +} + +s32 MapDisp_IsMinimapToggleBlocked(PlayState* play) { + if ((MapDisp_IsLocationMinimapBlocked(play) == true) || !MapDisp_CanDisplayMinimap(play)) { + return true; + } + return false; +} + +s32 MapDisp_AreRoomsSameStorey(s32 curRoom, s32 prevRoom) { + MapDataRoom* mapDataRoom; + s16* roomStoreyList; + + if ((curRoom == -1) || (prevRoom == -1)) { + return false; + } + mapDataRoom = &sMapDisp.mapDataScene->rooms[curRoom]; + roomStoreyList = sMapDisp.roomStoreyList; + if ((roomStoreyList[curRoom] <= roomStoreyList[prevRoom]) && + (roomStoreyList[prevRoom] <= (roomStoreyList[curRoom] + MAP_DATA_ROOM_GET_EXTRA_STOREYS(mapDataRoom)))) { + return true; + } + mapDataRoom = &sMapDisp.mapDataScene->rooms[prevRoom]; + if ((roomStoreyList[prevRoom] <= roomStoreyList[curRoom]) && + (roomStoreyList[curRoom] <= (roomStoreyList[prevRoom] + MAP_DATA_ROOM_GET_EXTRA_STOREYS(mapDataRoom)))) { + return true; + } + return false; +} + +void MapDisp_DrawMinimap(PlayState* play, s32 playerInitX, s32 playerInitZ, s32 playerInitDir) { + PauseContext* pauseCtx = &play->pauseCtx; + + if ((sMapDisp.mapDataScene != NULL) && ((s32)pauseCtx->state <= PAUSE_STATE_OPENING_2) && !R_MINIMAP_DISABLED && + (play->interfaceCtx.minimapAlpha != 0)) { + if (!MapDisp_IsLocationMinimapBlocked(play) && (sSceneNumRooms != 0)) { + if (MapDisp_CanDisplayMinimap(play)) { + MapDisp_DrawMinimapRoom(play, sMapDisp.minimapCurTex, sMapDisp.minimapCurX, sMapDisp.minimapCurY, + sMapDisp.curRoom, 1.0f - (sMapDisp.swapAnimTimer * 0.05f)); + if ((sMapDisp.curRoom != sMapDisp.prevRoom) && + MapDisp_AreRoomsSameStorey(sMapDisp.curRoom, sMapDisp.prevRoom)) { + MapDisp_DrawMinimapRoom(play, sMapDisp.minimapPrevTex, sMapDisp.minimapCurX + sMapDisp.minimapPrevX, + sMapDisp.minimapCurY + sMapDisp.minimapPrevY, sMapDisp.prevRoom, + sMapDisp.swapAnimTimer * 0.05f); + } + MapDisp_Minimap_DrawDoorActors(play); + } + if ((!Map_CurRoomHasMapI(play) || CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, gSaveContext.mapIndex)) && + (Map_CurRoomHasMapI(play) || Inventory_IsMapVisible(play->sceneId))) { + if (play->interfaceCtx.minigameState == MINIGAME_STATE_NONE) { + MapDisp_Minimap_DrawRedCompassIcon(play, playerInitX, playerInitZ, playerInitDir); + } + MapDisp_Minimap_DrawActors(play); + } + } + } +} + +void MapDisp_ResetMapI(void) { + s32 i; + + sPauseDungeonMap.textureCount = 0; + for (i = 0; i < ROOM_MAX; i++) { + sPauseDungeonMap.mapI_mapCompactId[i] = 0; + sPauseDungeonMap.mapI_roomTextures[i] = NULL; + sPauseDungeonMap.roomSprite[i] = NULL; + } + + sPauseDungeonMap.animTimer = 0; + sMapDisp.unk20 &= ~1; +} + +void MapDisp_InitMapI(PlayState* play) { + MapDisp_ResetMapI(); +} + +void MapDisp_DestroyMapI(PlayState* play) { + MapDisp_ResetMapI(); +} + +// alloc pause screen dungeon map +void* MapDisp_AllocDungeonMap(PlayState* play, void* heap) { + void* heapNext; + s32 dungeonMapRoomIter; + s32 sceneRoomIter; + + heapNext = heap; + if ((sMapDisp.mapDataScene == NULL) || (sSceneNumRooms == 0)) { + return heapNext; + } + sPauseDungeonMap.textureCount = 0; + + // loop for number of rooms + for (sceneRoomIter = 0; sceneRoomIter < sSceneNumRooms; sceneRoomIter++) { + s32 mapCompactId; + MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[sceneRoomIter]; + s32 isDuplicateTexture = false; + + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + continue; + } + mapCompactId = MapData_GetMapCompactId(mapDataRoom->mapId); + if (mapCompactId == -1) { + continue; + } + // test if the texture reference already exists + for (dungeonMapRoomIter = 0; dungeonMapRoomIter < sPauseDungeonMap.textureCount; dungeonMapRoomIter++) { + if (mapCompactId == sPauseDungeonMap.mapI_mapCompactId[dungeonMapRoomIter]) { + isDuplicateTexture = true; + break; + } + } + if (isDuplicateTexture == false) { + sPauseDungeonMap.mapI_mapCompactId[sPauseDungeonMap.textureCount] = mapCompactId; + sPauseDungeonMap.textureCount++; + } + } + + // fetch all textures from rom + sPauseDungeonMap.mapI_roomTextures[0] = heap; + for (dungeonMapRoomIter = 0; dungeonMapRoomIter < sPauseDungeonMap.textureCount; dungeonMapRoomIter++) { + s32 mapCompactId = sPauseDungeonMap.mapI_mapCompactId[dungeonMapRoomIter]; + + MapDisp_GetMapITexture(sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter], mapCompactId); + if (dungeonMapRoomIter + 1 < sPauseDungeonMap.textureCount) { + sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter + 1] = + (void*)ALIGN16((uintptr_t)sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter] + + MapData_CPID_GetSizeOfMapTex(mapCompactId)); + } else { + heapNext = (void*)((uintptr_t)sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter] + + MapData_CPID_GetSizeOfMapTex(mapCompactId)); + } + } + + for (sceneRoomIter = 0; sceneRoomIter < sSceneNumRooms; sceneRoomIter++) { + MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[sceneRoomIter]; + s32 foundTexture = false; + s32 mapCompactId; + + if (mapDataRoom->mapId == MAP_DATA_NO_MAP) { + sPauseDungeonMap.roomSprite[sceneRoomIter] = NULL; + } else { + mapCompactId = MapData_GetMapCompactId(mapDataRoom->mapId); + for (dungeonMapRoomIter = 0; dungeonMapRoomIter < sPauseDungeonMap.textureCount; dungeonMapRoomIter++) { + if (mapCompactId == sPauseDungeonMap.mapI_mapCompactId[dungeonMapRoomIter]) { + foundTexture = true; + break; + } + } + if (!foundTexture) { + sPauseDungeonMap.roomSprite[sceneRoomIter] = NULL; + } else { + void* dummy = sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter]; //! FAKE: + + sPauseDungeonMap.roomSprite[sceneRoomIter] = sPauseDungeonMap.mapI_roomTextures[dungeonMapRoomIter]; + } + } + } + return heapNext; +} + +s32 MapDisp_IsOnStorey(s32 storey, f32 checkY) { + if (storey == 0) { + if ((sMapDisp.storeyYList[0] <= checkY) && ((sMapDisp.numStoreys == 1) || (checkY < sMapDisp.storeyYList[1]))) { + return true; + } + } else if (storey >= (sMapDisp.numStoreys - 1)) { + if (sMapDisp.storeyYList[sMapDisp.numStoreys - 1] <= checkY) { + return true; + } + } else if ((sMapDisp.storeyYList[storey] <= checkY) && (checkY < sMapDisp.storeyYList[storey + 1])) { + return true; + } + return false; +} + +s32 MapDisp_ConvertBossSceneToDungeonScene(s32 sceneId) { + switch (sceneId) { + case SCENE_MITURIN_BS: + return SCENE_MITURIN; + + case SCENE_HAKUGIN_BS: + return SCENE_HAKUGIN; + + case SCENE_SEA_BS: + return SCENE_SEA; + + case SCENE_INISIE_BS: + return SCENE_INISIE_N; + + default: + return sceneId; + } +} + +/** + * @brief Draws the dungeon room sprites for the pause menu dungeon map + * + * @param play + * @param viewX top left x position of the dungeon map view window + * @param viewY top left y posiiton of the dungeon map view window + * @param viewWidth width in pixels of the dungeon map view window + * @param viewHeight height in pixels of the dungeon map view window + * @param scaleFrac ratio to convert world space coordinates to map coordinates + * @param dungeonSceneSharedIndex enum DungeonSceneIndex for retrieving map/compass data + */ +void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 viewHeight, f32 scaleFrac, + s32 dungeonSceneSharedIndex) { + static u16 sUnvisitedRoomPal[16] = { + 0x0000, 0x0000, 0xFFC1, 0x07C1, 0x07FF, 0x003F, 0xFB3F, 0xF305, + 0x0453, 0x0577, 0x0095, 0x82E5, 0xFD27, 0x7A49, 0x94A5, 0x0001, + }; // palette 0 + static u16 sVisitedRoomPal[16] = { + 0x0000, 0x027F, 0xFFC1, 0x07C1, 0x07FF, 0x003F, 0xFB3F, 0xF305, + 0x0453, 0x0577, 0x0095, 0x82E5, 0xFD27, 0x7A49, 0x94A5, 0x0001, + }; // palette 1 + static u16 sCurrentRoomPal[16] = { + 0x0000, 0x0623, 0xFFC1, 0x07C1, 0x07FF, 0x003F, 0xFB3F, 0xF305, + 0x0453, 0x0577, 0x0095, 0x82E5, 0xFD27, 0x7A49, 0x94A5, 0x0001, + }; // palette 2 + PauseContext* pauseCtx = &play->pauseCtx; + s32 pad[4]; + s32 i; + s32 green = ((sPauseDungeonMap.animTimer * -120.0f / 40.0f) + 200.0f) * 31.0f / 255.0f; + s32 blue = ((sPauseDungeonMap.animTimer * 115.0f / 40.0f) + 140.0f) * 31.0f / 255.0f; + + sCurrentRoomPal[1] = (green << 6) | (blue << 1) | 1; + + if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, dungeonSceneSharedIndex)) { + s32 requiredScopeTemp; + + sUnvisitedRoomPal[15] = 0xAD5F; + sVisitedRoomPal[15] = 0xAD5F; + sCurrentRoomPal[15] = 0xAD5F; + } else { + sCurrentRoomPal[15] = sVisitedRoomPal[15] = sUnvisitedRoomPal[15] = 0; + } + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL39_Opa(play->state.gfxCtx); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + gDPLoadTLUT_pal16(POLY_OPA_DISP++, 0, sUnvisitedRoomPal); + gDPLoadTLUT_pal16(POLY_OPA_DISP++, 1, sVisitedRoomPal); + gDPLoadTLUT_pal16(POLY_OPA_DISP++, 2, sCurrentRoomPal); + gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_RGBA16); + + for (i = 0; i < sSceneNumRooms; i++) { + s32 texWidth; + s32 texHeight; + s32 offsetX; + s32 offsetY; + MapDataRoom* mapDataRoom; + TexturePtr roomTexture; + s32 s; + s32 t; + s32 dsdx; + s32 dtdy; + s32 texPosX; + s32 texPosY; + s32 spE8; + s32 two = 2; + + mapDataRoom = &sMapDisp.mapDataScene->rooms[i]; + if ((mapDataRoom->mapId == MAP_DATA_NO_MAP) || (mapDataRoom->mapId >= MAPDATA_MAP_GRAND_MAX)) { + continue; + } + + if ((sMapDisp.pauseMapCurStorey < sMapDisp.roomStoreyList[i]) || + ((sMapDisp.roomStoreyList[i] + MAP_DATA_ROOM_GET_EXTRA_STOREYS(mapDataRoom)) < + sMapDisp.pauseMapCurStorey)) { + continue; + } + + roomTexture = sPauseDungeonMap.roomSprite[i]; + if (roomTexture == NULL) { + continue; + } + + spE8 = MapData_GetMapCompactId(mapDataRoom->mapId); + if (spE8 == -1) { + continue; + } + + MapData_CPID_GetTexDim(spE8, &texWidth, &texHeight); + MapData_CPID_GetTexOffset(spE8, &offsetX, &offsetY); + + if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) { + offsetX = ((texWidth / 2) - offsetX) + (texWidth / 2); + s = (texWidth - 1) << 5; + dsdx = 0xFC00; + } else { + s = 0; + dsdx = 0x400; + } + + if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) { + s32 requiredScopeTemp; + + offsetY = ((texHeight / 2) - offsetY) + (texHeight / 2); + t = (texHeight - 1) << 5; + dtdy = 0xFC00; + } else { + t = 0; + dtdy = 0x400; + } + + texPosX = + ((mapDataRoom->centerX - (f32)sMapDisp.sceneMidX) * scaleFrac - offsetX) + ((viewWidth / two) + viewX); + texPosY = + ((mapDataRoom->centerZ - (f32)sMapDisp.sceneMidZ) * scaleFrac - offsetY) + ((viewHeight / two) + viewY); + + if (i == play->roomCtx.curRoom.num) { + if (Map_IsInBossScene(play)) { + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 1, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + } else { + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 2, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + } + } else if (GET_ROOM_VISITED(Play_GetOriginalSceneId(MapDisp_ConvertBossSceneToDungeonScene(play->sceneId)), + i)) { + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 1, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + } else if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, dungeonSceneSharedIndex)) { + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 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); + } else { + continue; + } + gSPTextureRectangle(POLY_OPA_DISP++, (texPosX << 2), (texPosY << 2), (texPosX + texWidth) << 2, + (texPosY + texHeight) << 2, 0, s, t, dsdx, dtdy); + gDPPipeSync(POLY_OPA_DISP++); + } + + gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); + + CLOSE_DISPS(play->state.gfxCtx); +} + +/** + * @brief Draws the chests for the pause menu dungeon map + * + * @param play + * @param viewX top left x position of the dungeon map view window + * @param viewY top left y posiiton of the dungeon map view window + * @param viewWidth width in pixels of the dungeon map view window + * @param viewHeight height in pixels of the dungeon map view window + * @param scaleFrac ratio to convert world space coordinates to map coordinates + * @param dungeonSceneSharedIndex enum DungeonSceneIndex for retrieving map/compass data + */ +void MapDisp_DrawChests(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 viewHeight, f32 scaleFrac) { + s32 pad[23]; + MapDataChest* mapDataChests = sMapDisp.mapDataChests; + s32 room; + MapDataRoom* mapDataRoom; + s32 texPosX; + s32 texPosY; + s32 i; + s32 isChestOpen; + s32 offsetX = 4; + s32 offsetZ = 4; + + if (mapDataChests == NULL) { + return; + } + + OPEN_DISPS(play->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, play->pauseCtx.alpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + gDPPipeSync(POLY_OPA_DISP++); + + gDPLoadTextureBlock_Runtime(POLY_OPA_DISP++, gMapChestIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 8, 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); + + for (i = 0; i < sMapDisp.numChests; i++) { + room = mapDataChests[i].room; + mapDataRoom = &sMapDisp.mapDataScene->rooms[room]; + + switch (play->sceneId) { + case SCENE_MITURIN_BS: + isChestOpen = GET_CYCLE_CHEST_OPENED(SCENE_MITURIN, mapDataChests[i].chestFlagId); + break; + + case SCENE_HAKUGIN_BS: + isChestOpen = GET_CYCLE_CHEST_OPENED(SCENE_HAKUGIN, mapDataChests[i].chestFlagId); + break; + + case SCENE_SEA_BS: + isChestOpen = GET_CYCLE_CHEST_OPENED(SCENE_SEA, mapDataChests[i].chestFlagId); + break; + + case SCENE_INISIE_BS: + isChestOpen = GET_CYCLE_CHEST_OPENED(SCENE_INISIE_N, mapDataChests[i].chestFlagId); + break; + + default: + isChestOpen = Flags_GetTreasure(play, mapDataChests[i].chestFlagId); + break; + } + + if ((sMapDisp.pauseMapCurStorey < sMapDisp.roomStoreyList[room]) || + ((sMapDisp.roomStoreyList[room] + MAP_DATA_ROOM_GET_EXTRA_STOREYS(mapDataRoom)) < + sMapDisp.pauseMapCurStorey) || + (isChestOpen != 0)) { + continue; + } + + if (!MapDisp_IsOnStorey((s32)sMapDisp.pauseMapCurStorey, (f32)mapDataChests[i].y)) { + continue; + } + + texPosX = + (s32)((((mapDataChests[i].x - (f32)sMapDisp.sceneMidX) * scaleFrac) - offsetX) + ((viewWidth / 2) + viewX)); + texPosY = (s32)((((mapDataChests[i].z - (f32)sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + + ((viewHeight / 2) + viewY)); + + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +/** + * @brief Draws the room exit points for the pause menu dungeon map + * + * @param play + * @param viewX top left x position of the dungeon map view window + * @param viewY top left y posiiton of the dungeon map view window + * @param viewWidth width in pixels of the dungeon map view window + * @param viewHeight height in pixels of the dungeon map view window + * @param scaleFrac ratio to convert world space coordinates to map coordinates + * @param dungeonSceneSharedIndex enum DungeonSceneIndex for retrieving map/compass data + */ +void MapDisp_DrawRoomExits(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 viewHeight, f32 scaleFrac, + s32 dungeonSceneSharedIndex) { + PauseContext* pauseCtx = &play->pauseCtx; + TransitionActorList* transitionActors = &sTransitionActorList; + s32 texPosX; + s32 texPosY; + s32 i; + s8 roomA; + s8 roomB; + + if (transitionActors->count != 0) { + OPEN_DISPS(play->state.gfxCtx); + + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPLoadTextureBlock_4b(POLY_OPA_DISP++, &sWhiteSquareTex, G_IM_FMT_I, 16, 16, 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); + for (i = 0; i < transitionActors->count; i++) { + if (MapDisp_IsOnStorey(sMapDisp.pauseMapCurStorey, sTransitionActors[i].pos.y)) { + if ((ABS_ALT(sTransitionActors[i].id) != ACTOR_EN_HOLL) && + !MapDisp_IsBossDoor(sTransitionActors[i].params)) { + roomA = sTransitionActors[i].sides[0].room; + roomB = sTransitionActors[i].sides[1].room; + if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, gSaveContext.mapIndex) || (roomA < 0) || + GET_ROOM_VISITED(Play_GetOriginalSceneId(MapDisp_ConvertBossSceneToDungeonScene(play->sceneId)), + roomA) || + (roomB < 0) || + GET_ROOM_VISITED(Play_GetOriginalSceneId(MapDisp_ConvertBossSceneToDungeonScene(play->sceneId)), + roomB)) { + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + + texPosX = ((f32)sTransitionActors[i].pos.x - sMapDisp.sceneMidX) * scaleFrac + + ((viewWidth / 2) + viewX); + texPosY = ((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac + + ((viewHeight / 2) + viewY); + gSPTextureRectangle(POLY_OPA_DISP++, ((texPosX - 1) << 2), ((texPosY - 1) << 2), + ((texPosX + 1) << 2), ((texPosY + 1) << 2), G_TX_RENDERTILE, 0, 0, 1 << 10, + 1 << 10); + } + } + } + } + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +/** + * @brief Draws the boss room icon for the pause menu dungeon map. + * + * @param play + * @param viewX top left x position of the dungeon map view window + * @param viewY top left y posiiton of the dungeon map view window + * @param viewWidth width in pixels of the dungeon map view window + * @param viewHeight height in pixels of the dungeon map view window + * @param scaleFrac ratio to convert world space coordinates to map coordinates + * @param dungeonSceneSharedIndex enum DungeonSceneIndex for retrieving map/compass data + */ +void MapDisp_DrawBossIcon(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 viewHeight, f32 scaleFrac, + s32 dungeonSceneSharedIndex) { + s32 i; + TransitionActorList* transitionActorList = &sTransitionActorList; + s32 offsetX = 4; + s32 offsetZ = 4; + s32 texPosX; + s32 texPosY; + + OPEN_DISPS(play->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_AA_DEC_LINE, G_RM_NOOP2); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, play->pauseCtx.alpha); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + gDPPipeSync(POLY_OPA_DISP++); + + if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, dungeonSceneSharedIndex)) { + gDPLoadTextureBlock_Runtime(POLY_OPA_DISP++, gMapBossIconTex, G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 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); + + for (i = 0; i < transitionActorList->count; i++) { + if (!MapDisp_IsBossDoor(sTransitionActors[i].params)) { + continue; + } + if (!MapDisp_IsOnStorey(sMapDisp.pauseMapCurStorey, sTransitionActors[i].pos.y)) { + continue; + } + if (ABS_ALT(sTransitionActors[i].id) == ACTOR_EN_HOLL) { + continue; + } + + texPosX = ((((f32)sTransitionActors[i].pos.x - sMapDisp.sceneMidX) * scaleFrac) - offsetX) + + ((viewWidth / 2) + viewX); + texPosY = ((((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + + ((viewHeight / 2) + viewY); + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +TexturePtr MapDisp_GetDungeonMapFloorTexture(s32 floorNumber) { + static TexturePtr sDungeonMapFloorTextures[] = { + gDungeonMap1FButtonTex, gDungeonMap2FButtonTex, gDungeonMap3FButtonTex, gDungeonMap4FButtonTex, + gDungeonMap5FButtonTex, gDungeonMap6FButtonTex, gDungeonMap7FButtonTex, gDungeonMap8FButtonTex, + gDungeonMapB1ButtonTex, gDungeonMapB2ButtonTex, gDungeonMapB3ButtonTex, gDungeonMapB4ButtonTex, + gDungeonMapB5ButtonTex, gDungeonMapB6ButtonTex, gDungeonMapB7ButtonTex, gDungeonMapB8ButtonTex, + }; + if ((floorNumber >= 0) && (floorNumber < 8)) { + return sDungeonMapFloorTextures[floorNumber]; + } + if ((floorNumber >= -8) && (floorNumber < 0)) { + return sDungeonMapFloorTextures[7 + -floorNumber]; + } + return gDungeonMapBlankFloorButtonTex; +} + +/** + * @brief Tests if the dungeon map on the Map screen should be drawn. + * + * @param play + * @return true if the map should be drawn, else false. + */ +s32 MapDisp_SkipDrawDungeonMap(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + + if (pauseCtx->pageIndex != PAUSE_MAP) { + return true; + } + if ((pauseCtx->state == PAUSE_STATE_SAVEPROMPT) || IS_PAUSE_STATE_GAMEOVER(pauseCtx)) { + return true; + } + if ((pauseCtx->state != PAUSE_STATE_MAIN) || (pauseCtx->mainState != PAUSE_MAIN_STATE_IDLE)) { + return true; + } + if (pauseCtx->alpha == 0) { + return true; + } + return false; +} + +void MapDisp_DrawDungeonFloorSelect(PlayState* play) { + PauseContext* pauseCtx = &play->pauseCtx; + s32 texULY; + s32 texLRY; + s16 texULX; + s16 texLRX; + s32 pad; + s32 storey; + s32 dungeonSceneSharedIndex = 0; + + if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0) && !MapDisp_SkipDrawDungeonMap(play)) { + if (Map_IsInBossScene(play)) { + switch (play->sceneId) { + case SCENE_MITURIN_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE; + break; + + case SCENE_HAKUGIN_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE; + break; + + case SCENE_SEA_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE; + break; + + case SCENE_INISIE_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE; + break; + + default: + break; + } + } else { + dungeonSceneSharedIndex = gSaveContext.mapIndex; + } + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL39_Opa(play->state.gfxCtx); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 200, pauseCtx->alpha); + + // Draw unlocked storeys + for (storey = 0; storey < sMapDisp.numStoreys; storey++) { + if (GET_DUNGEON_FLOOR_VISITED( + Play_GetOriginalSceneId(MapDisp_ConvertBossSceneToDungeonScene(play->sceneId)), 4 - storey) || + CHECK_DUNGEON_ITEM_ALT(DUNGEON_MAP, dungeonSceneSharedIndex)) { + gDPLoadTextureBlock(POLY_OPA_DISP++, MapDisp_GetDungeonMapFloorTexture(sMapDisp.bottomStorey + storey), + G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 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); + gSPTextureRectangle(POLY_OPA_DISP++, 81 << 2, (125 - storey * 15) << 2, 105 << 2, + ((125 - storey * 15) + 16) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } + } + gDPPipeSync(POLY_OPA_DISP++); + + // Draw currently selected storey + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 150, 255, pauseCtx->alpha); + gDPLoadTextureBlock( + POLY_OPA_DISP++, + MapDisp_GetDungeonMapFloorTexture((sMapDisp.bottomStorey - pauseCtx->cursorMapDungeonItem) + 8), + G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 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); + + texULX = 80; + texLRX = 106; + texULY = (5 + (pauseCtx->cursorMapDungeonItem * 0xF)); + texLRY = texULY + 16; + if ((pauseCtx->cursorSpecialPos == 0) && (pauseCtx->cursorXIndex[1] == 0)) { + texLRX++; + texULX--; + texLRY += 4; + texULY -= 4; + gSPTextureRectangle(POLY_OPA_DISP++, texULX << 2, texULY << 2, texLRX << 2, (texLRY) << 2, G_TX_RENDERTILE, + 0, 0, 0x036E, 0x02AA); + } else { + gSPTextureRectangle(POLY_OPA_DISP++, (texULX + 1) << 2, texULY << 2, (texLRX - 1) << 2, texLRY << 2, + G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + } + Gfx_SetupDL42_Opa(play->state.gfxCtx); + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +s32 MapDisp_IsValidStorey(s32 storey) { + if ((sMapDisp.mapDataScene == NULL) || (sSceneNumRooms == 0)) { + return false; + } + if ((storey < 0) || (storey > 5)) { + return false; + } + if (sMapDisp.storeyYList[storey] != FLOOR_MIN_Y) { + return true; + } + return false; +} + +s32 MapDisp_GetPlayerStorey(s16 checkY) { + s32 i; + + if ((sMapDisp.mapDataScene == NULL) || (sSceneNumRooms == 0)) { + return -1; + } + if (sMapDisp.numStoreys <= 1) { + return 0; + } + if ((sMapDisp.storeyYList[1] - 5) >= checkY) { + return 0; + } + for (i = 1; i < sMapDisp.numStoreys; i++) { + if (((sMapDisp.storeyYList[i] - 5) < checkY) && ((sMapDisp.storeyYList[i + 1] - 5) >= checkY)) { + return i; + } + } + return sMapDisp.numStoreys - 1; +} + +typedef struct { + /* 0x0 */ s16 sceneId; + /* 0x4 */ s32 offsetX; + /* 0x8 */ s32 offsetY; +} MapCustomPosOffset; // size = 0xC + +/** + * Draws the dungeon map within the pause menu's Map screen. + * + * @param play + */ +void MapDisp_DrawDungeonMap(PlayState* play) { + static MapCustomPosOffset sCustomMapOffset[] = { + { SCENE_MITURIN, 0, -10 }, + { SCENE_MITURIN_BS, 0, -10 }, + }; + MapDataRoom* mapDataRoom; + f32 scaleFrac; + s32 scale; + s32 var_v0; + s32 dungeonSceneSharedIndex = 0; + s32 offsetX = 0; + s32 offsetY = 0; + + if (MapDisp_SkipDrawDungeonMap(play)) { + return; + } + + if (Map_IsInBossScene(play)) { + switch (play->sceneId) { + case SCENE_MITURIN_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE; + break; + + case SCENE_HAKUGIN_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE; + break; + + case SCENE_SEA_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE; + break; + + case SCENE_INISIE_BS: + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE; + break; + + default: + break; + } + } else { + dungeonSceneSharedIndex = gSaveContext.mapIndex; + } + + mapDataRoom = sMapDisp.mapDataScene->rooms; + if ((mapDataRoom->mapId == MAP_DATA_NO_MAP) || (mapDataRoom->mapId >= MAPDATA_MAP_GRAND_MAX)) { + return; + } + + var_v0 = MapData_GetMapCompactId(mapDataRoom->mapId); + if (var_v0 == -1) { + return; + } + + scale = MapData_CPID_GetMapScale(var_v0); + if (scale == 0) { + scale = 80; + } + + for (var_v0 = 0; var_v0 < ARRAY_COUNT(sCustomMapOffset); var_v0++) { + if (play->sceneId == sCustomMapOffset[var_v0].sceneId) { + offsetX = sCustomMapOffset[var_v0].offsetX; + offsetY = sCustomMapOffset[var_v0].offsetY; + } + } + + scaleFrac = 1.0f / scale; + + MapDisp_DrawRooms(play, offsetX + 144, offsetY + 85, 120, 100, scaleFrac, dungeonSceneSharedIndex); + MapDisp_DrawRoomExits(play, offsetX + 144, offsetY + 85, 120, 100, scaleFrac, dungeonSceneSharedIndex); + MapDisp_DrawBossIcon(play, offsetX + 144, offsetY + 85, 120, 100, scaleFrac, dungeonSceneSharedIndex); + + if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, dungeonSceneSharedIndex)) { + MapDisp_DrawChests(play, offsetX + 144, offsetY + 85, 120, 100, scaleFrac); + } +} + +void MapDisp_UpdateDungeonMap(PlayState* play) { + sMapDisp.timer++; + if (!(sMapDisp.unk20 & 1)) { + sPauseDungeonMap.animTimer++; + if (sPauseDungeonMap.animTimer > 40) { + sMapDisp.unk20 |= 1; + } + } else { + sPauseDungeonMap.animTimer--; + if (sPauseDungeonMap.animTimer < 0) { + sMapDisp.unk20 &= ~1; + } + } +} diff --git a/src/code/z_map_exp.c b/src/code/z_map_exp.c index 49e525b9d..fa2c42a9b 100644 --- a/src/code/z_map_exp.c +++ b/src/code/z_map_exp.c @@ -1,19 +1,26 @@ #include "global.h" -s16 sMinimapInitPosX = 0; -s16 sMinimapInitPosZ = 0; -s16 sMinimapInitDir = 0; - -s32 sDungeonAndBossSceneIds[] = { - SCENE_MITURIN, SCENE_HAKUGIN, SCENE_SEA, SCENE_INISIE_N, SCENE_INISIE_R, - SCENE_MITURIN_BS, SCENE_HAKUGIN_BS, SCENE_SEA_BS, SCENE_INISIE_BS, -}; +s16 sPlayerInitPosX = 0; +s16 sPlayerInitPosZ = 0; +s16 sPlayerInitDir = 0; /** - * If the current scene is a dungeon or boss scene, this function returns an index - * indicating which one it is. Otherwise, it returns -1. + * Gets the mapIndex for the current dungeon scene + * @return the current scene's DungeonSceneIndex, or -1 if it isn't a dungeon or boss scene. */ -s32 Map_GetDungeonOrBossAreaIndex(PlayState* play) { +s32 Map_GetDungeonSceneIndex(PlayState* play) { + static s32 sDungeonAndBossSceneIds[] = { + SCENE_MITURIN, // DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE + SCENE_HAKUGIN, // DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE + SCENE_SEA, // DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE + SCENE_INISIE_N, // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE + SCENE_INISIE_R, // Play_GetOriginalSceneId converts play->sceneId to SCENE_INISIE_N, returning + // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE + SCENE_MITURIN_BS, // DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE_BOSS + SCENE_HAKUGIN_BS, // DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE_BOSS + SCENE_SEA_BS, // DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE_BOSS + SCENE_INISIE_BS, // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE_BOSS + }; s32 i; for (i = 0; i < ARRAY_COUNT(sDungeonAndBossSceneIds); i++) { @@ -26,33 +33,38 @@ s32 Map_GetDungeonOrBossAreaIndex(PlayState* play) { } /** - * Returns true if the current scene is a dungeon or boss scene, false otherwise. + * Tests if the current scene is in a dungeon or boss scene. + * @return true if the current scene is a dungeon or boss scene, false otherwise. */ -s32 Map_IsInDungeonOrBossArea(PlayState* play) { - if (Map_GetDungeonOrBossAreaIndex(play) == -1) { +s32 Map_IsInDungeonOrBossScene(PlayState* play) { + if (Map_GetDungeonSceneIndex(play) == -1) { return false; } return true; } -s32 func_8010A0A4(PlayState* play) { - if ((Map_GetDungeonOrBossAreaIndex(play) == -1) || !func_80102EF0(play)) { +s32 Map_CurRoomHasMapI(PlayState* play) { + if ((Map_GetDungeonSceneIndex(play) == -1) || !MapDisp_CurRoomHasMapI(play)) { return false; } return true; } -s32 sDungeonSceneIds[] = { - SCENE_MITURIN, SCENE_HAKUGIN, SCENE_SEA, SCENE_INISIE_N, SCENE_INISIE_R, -}; - /** - * If the current scene is a dungeon scene, this function returns an index - * indicating which one it is. Otherwise, it returns -1. + * Tests if the current scene is a dungeon scene, excluding boss scenes. + * @return -1 if not a dungeon scene, else returns the DungeonSceneIndex of the dungeon scene */ -s32 Map_GetDungeonAreaIndex(PlayState* play) { +s32 Map_GetDungeonSceneIndexForDungeon(PlayState* play) { + static s32 sDungeonSceneIds[] = { + SCENE_MITURIN, // DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE + SCENE_HAKUGIN, // DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE + SCENE_SEA, // DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE + SCENE_INISIE_N, // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE + SCENE_INISIE_R, // Play_GetOriginalSceneId converts play->sceneId to SCENE_INISIE_N, returning + // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE + }; s32 i; for (i = 0; i < ARRAY_COUNT(sDungeonSceneIds); i++) { @@ -65,28 +77,29 @@ s32 Map_GetDungeonAreaIndex(PlayState* play) { } /** - * Returns true if the current scene is a dungeon scene, false otherwise. + * Test if the current scene is a dungeon scene, excluding boss rooms + * @return true if the current scene is a dungeon scene, false otherwise. */ -s32 Map_IsInDungeonArea(PlayState* play) { - if (Map_GetDungeonAreaIndex(play) == -1) { +s32 Map_IsInDungeonScene(PlayState* play) { + if (Map_GetDungeonSceneIndexForDungeon(play) == -1) { return false; } return true; } -s32 sBossSceneIds[] = { - SCENE_MITURIN_BS, // DUNGEON_INDEX_WOODFALL_TEMPLE - SCENE_HAKUGIN_BS, // DUNGEON_INDEX_SNOWHEAD_TEMPLE - SCENE_SEA_BS, // DUNGEON_INDEX_GREAT_BAY_TEMPLE - SCENE_INISIE_BS, // DUNGEON_INDEX_STONE_TOWER_TEMPLE -}; - /** - * If the current scene is a boss scene, this function returns an index - * indicating which one it is. Otherwise, it returns -1. + * Tests if the current scene is a boss scene. + * @return -1 if not a boss scene, else returns the DungeonSceneIndex corresponding to that boss scene's primary dungeon + * scene */ -s32 Map_GetBossAreaIndex(PlayState* play) { +s32 Map_GetDungeonSceneIndexForBoss(PlayState* play) { + static s32 sBossSceneIds[] = { + SCENE_MITURIN_BS, // DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE + SCENE_HAKUGIN_BS, // DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE + SCENE_SEA_BS, // DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE + SCENE_INISIE_BS, // DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE + }; s32 i; for (i = 0; i < ARRAY_COUNT(sBossSceneIds); i++) { @@ -99,27 +112,33 @@ s32 Map_GetBossAreaIndex(PlayState* play) { } /** - * Returns true if the current scene is a boss scene, false otherwise. + * Checks if the current scene is a boss scene. + * @return true if the current scene is a boss scene, false otherwise. */ -s32 Map_IsInBossArea(PlayState* play) { - if (Map_GetBossAreaIndex(play) == -1) { +s32 Map_IsInBossScene(PlayState* play) { + if (Map_GetDungeonSceneIndexForBoss(play) == -1) { return false; } return true; } -s32 D_801BF5A4[] = { - SCENE_22DEKUCITY, - SCENE_KOEPONARACE, - SCENE_F01, -}; - -s32 func_8010A238(PlayState* play) { +/** + * Intended to check if the current scene is an overworld scene with a minimap. + * The implementation is incomplete due to a complete rewrite of z_map_exp.c and other map systems, making the function + * obsolete. + * @return -1 if not in the list, else returns the MapIndex for the overworld scene + */ +s32 Map_GetMapIndexForOverworld(PlayState* play) { + static s32 sSceneIds[] = { + SCENE_22DEKUCITY, + SCENE_KOEPONARACE, + SCENE_F01, + }; s32 i; - for (i = 0; i < ARRAY_COUNT(D_801BF5A4); i++) { - if (Play_GetOriginalSceneId(play->sceneId) == D_801BF5A4[i]) { + for (i = 0; i < ARRAY_COUNT(sSceneIds); i++) { + if (Play_GetOriginalSceneId(play->sceneId) == sSceneIds[i]) { return i; } } @@ -127,8 +146,14 @@ s32 func_8010A238(PlayState* play) { return -1; } -s32 func_8010A2AC(PlayState* play) { - if (func_8010A238(play) == -1) { +/** + * Intended to check if the current scene is an overworld scene with a minimap. + * The implementation is incomplete due to a complete rewrite of z_map_exp.c and other map systems, making the function + * obsolete. + * @return true if the current scene is in the set, false otherwise. + */ +s32 Map_IsInOverworldSceneWithMapIndex(PlayState* play) { + if (Map_GetMapIndexForOverworld(play) == -1) { return false; } @@ -136,29 +161,28 @@ s32 func_8010A2AC(PlayState* play) { } /** - * When a room is loaded, this function is used to save the player's position and rotation - * so that the red arrow on the minimap can be drawn correctly. + * Sets the position and rotation of where the player has entered the area. + * Used to draw the red marker on the minimap. */ -void Minimap_SavePlayerRoomInitInfo(PlayState* play) { +void Map_SetAreaEntrypoint(PlayState* play) { Player* player = GET_PLAYER(play); - sMinimapInitPosX = player->actor.world.pos.x; - sMinimapInitPosZ = player->actor.world.pos.z; - sMinimapInitDir = (0x7FFF - player->actor.shape.rot.y) / 0x400; + sPlayerInitPosX = player->actor.world.pos.x; + sPlayerInitPosZ = player->actor.world.pos.z; + sPlayerInitDir = (0x7FFF - player->actor.shape.rot.y) / 0x400; } void Map_InitRoomData(PlayState* play, s16 room) { s32 mapIndex = gSaveContext.mapIndex; InterfaceContext* interfaceCtx = &play->interfaceCtx; - func_80105C40(room); + MapDisp_SwapRooms(room); if (room >= 0) { - if (Map_IsInDungeonOrBossArea(play)) { - gSaveContext.save.saveInfo.permanentSceneFlags[Play_GetOriginalSceneId(play->sceneId)].rooms |= - gBitFlags[room]; + if (Map_IsInDungeonOrBossScene(play)) { + SET_ROOM_VISITED(Play_GetOriginalSceneId(play->sceneId), room); interfaceCtx->mapRoomNum = room; - interfaceCtx->dungeonOrBossAreaMapIndex = mapIndex; + interfaceCtx->dungeonSceneIndex = mapIndex; } } else { interfaceCtx->mapRoomNum = 0; @@ -170,50 +194,52 @@ void Map_InitRoomData(PlayState* play, s16 room) { } void Map_Destroy(PlayState* play) { - func_80105A40(play); + MapDisp_Destroy(play); } void Map_Init(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; - s32 dungeonIndex; + s32 dungeonSceneSharedIndex; - func_80105C40(play->roomCtx.curRoom.num); + MapDisp_SwapRooms(play->roomCtx.curRoom.num); interfaceCtx->unk_278 = -1; - interfaceCtx->dungeonOrBossAreaMapIndex = -1; + interfaceCtx->dungeonSceneIndex = -1; interfaceCtx->mapSegment = THA_AllocTailAlign16(&play->state.tha, 0x1000); - if (func_8010A2AC(play)) { - gSaveContext.mapIndex = func_8010A238(play); + + //! This block does pretty much nothing, as z_map_exp.c and other map systems were heavily rewritten after OoT to no + //! longer need mapIndex to retrieve minimap data. + if (Map_IsInOverworldSceneWithMapIndex(play)) { + gSaveContext.mapIndex = Map_GetMapIndexForOverworld(play); return; } - if (Map_IsInDungeonOrBossArea(play)) { - dungeonIndex = Map_GetDungeonOrBossAreaIndex(play); - gSaveContext.mapIndex = dungeonIndex; + if (Map_IsInDungeonOrBossScene(play)) { + gSaveContext.mapIndex = dungeonSceneSharedIndex = Map_GetDungeonSceneIndex(play); switch (play->sceneId) { case SCENE_MITURIN_BS: - dungeonIndex = DUNGEON_INDEX_WOODFALL_TEMPLE; + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE; break; case SCENE_HAKUGIN_BS: - dungeonIndex = DUNGEON_INDEX_SNOWHEAD_TEMPLE; + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE; break; case SCENE_SEA_BS: - dungeonIndex = DUNGEON_INDEX_GREAT_BAY_TEMPLE; + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE; break; case SCENE_INISIE_BS: - dungeonIndex = DUNGEON_INDEX_STONE_TOWER_TEMPLE; + dungeonSceneSharedIndex = DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE; break; } - gSaveContext.dungeonIndex = dungeonIndex; + gSaveContext.dungeonSceneSharedIndex = dungeonSceneSharedIndex; Map_InitRoomData(play, play->roomCtx.curRoom.num); } } -void Minimap_Draw(PlayState* play) { - func_80106644(play, sMinimapInitPosX, sMinimapInitPosZ, sMinimapInitDir); +void Map_DrawMinimap(PlayState* play) { + MapDisp_DrawMinimap(play, sPlayerInitPosX, sPlayerInitPosZ, sPlayerInitDir); } s16 sLastRoomNum = 99; @@ -227,7 +253,7 @@ void Map_Update(PlayState* play) { s32 pad2; if ((play->pauseCtx.state <= PAUSE_STATE_OPENING_2) && (CHECK_BTN_ALL(controller->press.button, BTN_L)) && - !Play_InCsMode(play) && !func_80106530(play)) { + !Play_InCsMode(play) && !MapDisp_IsMinimapToggleBlocked(play)) { if (!R_MINIMAP_DISABLED) { Audio_PlaySfx(NA_SE_SY_CAMERA_ZOOM_UP); } else { @@ -237,22 +263,21 @@ void Map_Update(PlayState* play) { R_MINIMAP_DISABLED ^= 1; } - func_80105B34(play); + MapDisp_Update(play); if (!IS_PAUSED(&play->pauseCtx)) { - if (Map_IsInDungeonArea(play)) { - floor = func_80109124(player->actor.world.pos.y); + if (Map_IsInDungeonScene(play)) { + floor = MapDisp_GetPlayerStorey(player->actor.world.pos.y); if (floor != -1) { - gSaveContext.save.saveInfo.permanentSceneFlags[Play_GetOriginalSceneId(play->sceneId)].unk_14 |= - gBitFlags[FLOOR_INDEX_MAX - floor]; - R_REVERSE_FLOOR_INDEX = FLOOR_INDEX_MAX - floor; + SET_DUNGEON_FLOOR_VISITED(Play_GetOriginalSceneId(play->sceneId), FLOOR_INDEX_MAX - floor); + R_PLAYER_FLOOR_REVERSE_INDEX = FLOOR_INDEX_MAX - floor; if (interfaceCtx->mapRoomNum != sLastRoomNum) { sLastRoomNum = interfaceCtx->mapRoomNum; } } - } else if (Map_IsInBossArea(play)) { - func_80105294(); - R_REVERSE_FLOOR_INDEX = FLOOR_INDEX_MAX - func_80105318(); + } else if (Map_IsInBossScene(play)) { + MapDisp_GetBossIconY(); + R_PLAYER_FLOOR_REVERSE_INDEX = FLOOR_INDEX_MAX - MapDisp_GetBossRoomStorey(); } } } diff --git a/src/code/z_message.c b/src/code/z_message.c index 5068553b1..8cb55ef1f 100644 --- a/src/code/z_message.c +++ b/src/code/z_message.c @@ -930,21 +930,22 @@ void Message_DrawItemIcon(PlayState* play, Gfx** gfxP) { } else if (msgCtx->itemId == ITEM_STRAY_FAIRIES) { msgCtx->unk12016 = 0x18; gDPPipeSync(gfx++); - gDPSetPrimColor(gfx++, 0, 0, sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonIndex)].r, - sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonIndex)].g, - sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonIndex)].b, msgCtx->textColorAlpha); - gDPSetEnvColor(gfx++, sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonIndex)].r, - sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonIndex)].g, - sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonIndex)].b, 0); + gDPSetPrimColor(gfx++, 0, 0, sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].r, + sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].g, + sStrayFairyIconPrimColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].b, + msgCtx->textColorAlpha); + gDPSetEnvColor(gfx++, sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].r, + sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].g, + sStrayFairyIconEnvColors[((void)0, gSaveContext.dungeonSceneSharedIndex)].b, 0); gDPLoadTextureBlock_4b(gfx++, gStrayFairyGlowingCircleIconTex, G_IM_FMT_I, 32, 24, 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); gSPTextureRectangle(gfx++, msgCtx->unk12010 << 2, msgCtx->unk12012 << 2, (msgCtx->unk12010 + msgCtx->unk12014) << 2, (msgCtx->unk12012 + msgCtx->unk12016) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); gDPSetPrimColor(gfx++, 0, 0, 255, 255, 255, msgCtx->textColorAlpha); - gDPLoadTextureBlock(gfx++, sStrayFairyIconTextures[((void)0, gSaveContext.dungeonIndex)], G_IM_FMT_RGBA, - G_IM_SIZ_32b, 32, 24, 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); + gDPLoadTextureBlock(gfx++, sStrayFairyIconTextures[((void)0, gSaveContext.dungeonSceneSharedIndex)], + G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 24, 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); } else if ((msgCtx->itemId >= ITEM_SONG_SONATA) && (msgCtx->itemId <= ITEM_SONG_SUN)) { index = msgCtx->itemId - ITEM_SONG_SONATA; gDPSetPrimColor(gfx++, 0, 0, D_801CFE04[index], D_801CFE1C[index], D_801CFE34[index], msgCtx->textColorAlpha); @@ -2134,7 +2135,7 @@ void Message_LoadOwlWarpText(PlayState* play, s32* offset, f32* arg2, s16* decod s16 owlWarpId; s16 i; - if (func_8010A0A4(play) || (play->sceneId == SCENE_SECOM)) { + if (Map_CurRoomHasMapI(play) || (play->sceneId == SCENE_SECOM)) { owlWarpId = OWL_WARP_ENTRANCE; } else { owlWarpId = pauseCtx->cursorPoint[PAUSE_WORLD_MAP]; @@ -2463,7 +2464,8 @@ void Message_Decode(PlayState* play) { Message_LoadTime(play, curChar, &charTexIndex, &spC0, &decodedBufPos); } else if (curChar == 0x21C) { digits[0] = digits[1] = 0; - digits[2] = gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex]; + digits[2] = + gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex]; while (digits[2] >= 100) { digits[0]++; @@ -3121,7 +3123,7 @@ void Message_OpenText(PlayState* play, u16 textId) { if (msgCtx) {} textId = 0xC9; } else if (textId == 0x11) { - if (gSaveContext.save.saveInfo.inventory.strayFairies[((void)0, gSaveContext.dungeonIndex)] == 0xF) { + if (gSaveContext.save.saveInfo.inventory.strayFairies[((void)0, gSaveContext.dungeonSceneSharedIndex)] == 0xF) { textId = 0xF3; } } else if ((textId == 0x92) && (play->sceneId == SCENE_KOEPONARACE)) { @@ -5687,7 +5689,7 @@ void Message_Update(PlayState* play) { if (sLastPlayedSong == OCARINA_SONG_SOARING) { if (interfaceCtx->restrictions.songOfSoaring == 0) { - if (func_8010A0A4(play) || (play->sceneId == SCENE_SECOM)) { + if (Map_CurRoomHasMapI(play) || (play->sceneId == SCENE_SECOM)) { Message_StartTextbox(play, 0x1B93, NULL); play->msgCtx.ocarinaMode = OCARINA_MODE_1B; sLastPlayedSong = 0xFF; diff --git a/src/code/z_message_nes.c b/src/code/z_message_nes.c index 286548216..4a3e49575 100644 --- a/src/code/z_message_nes.c +++ b/src/code/z_message_nes.c @@ -280,7 +280,7 @@ void Message_LoadOwlWarpTextNES(PlayState* play, s32* offset, f32* arg2, s16* de s16 owlWarpId; s16 stringLimit; - if (func_8010A0A4(play) || (play->sceneId == SCENE_SECOM)) { + if (Map_CurRoomHasMapI(play) || (play->sceneId == SCENE_SECOM)) { owlWarpId = OWL_WARP_ENTRANCE; } else { owlWarpId = play->pauseCtx.cursorPoint[PAUSE_WORLD_MAP]; @@ -1310,7 +1310,8 @@ void Message_DecodeNES(PlayState* play) { Message_LoadTimeNES(play, curChar, &charTexIndex, &spA4, &decodedBufPos); } else if (curChar == MESSAGE_STRAY_FAIRIES) { digits[0] = digits[1] = 0; - digits[2] = gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex]; + digits[2] = + gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex]; while (digits[2] >= 100) { digits[0]++; @@ -1332,18 +1333,24 @@ void Message_DecodeNES(PlayState* play) { } } - if ((gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 1) || - (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 21)) { + if ((gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == + 1) || + (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == + 21)) { Message_LoadCharNES(play, 's', &charTexIndex, &spA4, decodedBufPos); decodedBufPos++; Message_LoadCharNES(play, 't', &charTexIndex, &spA4, decodedBufPos); - } else if ((gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 2) || - (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 22)) { + } else if ((gSaveContext.save.saveInfo.inventory + .strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == 2) || + (gSaveContext.save.saveInfo.inventory + .strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == 22)) { Message_LoadCharNES(play, 'n', &charTexIndex, &spA4, decodedBufPos); decodedBufPos++; Message_LoadCharNES(play, 'd', &charTexIndex, &spA4, decodedBufPos); - } else if ((gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 3) || - (gSaveContext.save.saveInfo.inventory.strayFairies[(void)0, gSaveContext.dungeonIndex] == 23)) { + } else if ((gSaveContext.save.saveInfo.inventory + .strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == 3) || + (gSaveContext.save.saveInfo.inventory + .strayFairies[(void)0, gSaveContext.dungeonSceneSharedIndex] == 23)) { Message_LoadCharNES(play, 'r', &charTexIndex, &spA4, decodedBufPos); decodedBufPos++; Message_LoadCharNES(play, 'd', &charTexIndex, &spA4, decodedBufPos); diff --git a/src/code/z_parameter.c b/src/code/z_parameter.c index 3660f923d..f9b6d9cfb 100644 --- a/src/code/z_parameter.c +++ b/src/code/z_parameter.c @@ -6428,7 +6428,7 @@ void Interface_Draw(PlayState* play) { } Magic_DrawMeter(play); - Minimap_Draw(play); + Map_DrawMinimap(play); if ((R_PAUSE_BG_PRERENDER_STATE != 2) && (R_PAUSE_BG_PRERENDER_STATE != 3)) { Target_Draw(&play->actorCtx.targetCtx, play); diff --git a/src/code/z_play.c b/src/code/z_play.c index 085f7f8a0..054bfe8e2 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -1575,7 +1575,7 @@ void Play_InitScene(PlayState* this, s32 spawn) { this->numSetupActors = 0; Object_InitContext(&this->state, &this->objectCtx); LightContext_Init(this, &this->lightCtx); - Door_InitContext(&this->state, &this->doorCtx); + Scene_ResetTransitionActorList(&this->state, &this->transitionActors); Room_Init(this, &this->roomCtx); gSaveContext.worldMapArea = 0; Scene_ExecuteCommands(this, this->sceneSegment); @@ -1975,7 +1975,7 @@ s32 func_8016A02C(GameState* thisx, Actor* actor, s16* yaw) { return false; } - transitionActor = &this->doorCtx.transitionActorList[(u16)actor->params >> 10]; + transitionActor = &this->transitionActors.list[(u16)actor->params >> 10]; frontRoom = transitionActor->sides[0].room; if (frontRoom == transitionActor->sides[1].room) { return false; diff --git a/src/code/z_room.c b/src/code/z_room.c index 1e8700e09..347844630 100644 --- a/src/code/z_room.c +++ b/src/code/z_room.c @@ -502,11 +502,11 @@ size_t Room_AllocateAndLoad(PlayState* play, RoomContext* roomCtx) { } } - if ((u32)play->doorCtx.numTransitionActors != 0) { + if ((u32)play->transitionActors.count != 0) { RomFile* roomList = play->roomList; - TransitionActorEntry* transitionActor = &play->doorCtx.transitionActorList[0]; + TransitionActorEntry* transitionActor = &play->transitionActors.list[0]; - for (j = 0; j < play->doorCtx.numTransitionActors; j++) { + for (j = 0; j < play->transitionActors.count; j++) { frontRoom = transitionActor->sides[0].room; backRoom = transitionActor->sides[1].room; frontRoomSize = (frontRoom < 0) ? 0 : roomList[frontRoom].vromEnd - roomList[frontRoom].vromStart; @@ -620,7 +620,7 @@ void func_8012EBF8(PlayState* play, RoomContext* roomCtx) { Actor_SpawnTransitionActors(play, &play->actorCtx); if (roomCtx->curRoom.num > -1) { Map_InitRoomData(play, roomCtx->curRoom.num); - Minimap_SavePlayerRoomInitInfo(play); + Map_SetAreaEntrypoint(play); } Audio_SetEnvReverb(play->roomCtx.curRoom.echo); } diff --git a/src/code/z_scene.c b/src/code/z_scene.c index bb7aec737..cbcea15cb 100644 --- a/src/code/z_scene.c +++ b/src/code/z_scene.c @@ -334,15 +334,15 @@ void Scene_CommandPathList(PlayState* play, SceneCmd* cmd) { } // SceneTableEntry Header Command 0x0E: Transition Actor List -void Scene_CommandTransiActorList(PlayState* play, SceneCmd* cmd) { - play->doorCtx.numTransitionActors = cmd->transiActorList.num; - play->doorCtx.transitionActorList = Lib_SegmentedToVirtual(cmd->transiActorList.segment); - func_80105818(play, play->doorCtx.numTransitionActors, play->doorCtx.transitionActorList); +void Scene_CommandTransitionActorList(PlayState* play, SceneCmd* cmd) { + play->transitionActors.count = cmd->transitionActorList.num; + play->transitionActors.list = Lib_SegmentedToVirtual(cmd->transitionActorList.segment); + MapDisp_InitTransitionActorData(play, play->transitionActors.count, play->transitionActors.list); } // Init function for the transition system. -void Door_InitContext(GameState* state, DoorContext* doorCtx) { - doorCtx->numTransitionActors = 0; +void Scene_ResetTransitionActorList(GameState* state, TransitionActorList* transitionActors) { + transitionActors->count = 0; } // SceneTableEntry Header Command 0x0F: Environment Light Settings List @@ -495,19 +495,19 @@ void Scene_CommandCutsceneList(PlayState* play, SceneCmd* cmd) { CutsceneManager_Init(play, Lib_SegmentedToVirtual(cmd->cutsceneList.segment), cmd->cutsceneList.num); } -// SceneTableEntry Header Command 0x1C: Mini Maps -void Scene_CommandMiniMap(PlayState* play, SceneCmd* cmd) { - func_80104CF4(play); - func_8010549C(play, cmd->minimapSettings.segment); +// SceneTableEntry Header Command 0x1C: Map Data +void Scene_CommandMapData(PlayState* play, SceneCmd* cmd) { + MapDisp_Init(play); + MapDisp_InitMapData(play, cmd->mapData.segment); } // SceneTableEntry Header Command 0x1D: Undefined void Scene_Command1D(PlayState* play, SceneCmd* cmd) { } -// SceneTableEntry Header Command 0x1E: Minimap Compass Icon Info -void Scene_CommandMiniMapCompassInfo(PlayState* play, SceneCmd* cmd) { - func_8010565C(play, cmd->minimapChests.num, cmd->minimapChests.segment); +// SceneTableEntry Header Command 0x1E: Map Data Chests +void Scene_CommandMapDataChests(PlayState* play, SceneCmd* cmd) { + MapDisp_InitChestData(play, cmd->mapDataChests.num, cmd->mapDataChests.segment); } // SceneTableEntry Header Command 0x19: Sets Region Visited Flag @@ -565,7 +565,7 @@ void (*sSceneCmdHandlers[SCENE_CMD_MAX])(PlayState*, SceneCmd*) = { Scene_CommandObjectList, // SCENE_CMD_ID_OBJECT_LIST Scene_CommandLightList, // SCENE_CMD_ID_LIGHT_LIST Scene_CommandPathList, // SCENE_CMD_ID_PATH_LIST - Scene_CommandTransiActorList, // SCENE_CMD_ID_TRANSI_ACTOR_LIST + Scene_CommandTransitionActorList, // SCENE_CMD_ID_TRANSI_ACTOR_LIST Scene_CommandEnvLightSettings, // SCENE_CMD_ID_ENV_LIGHT_SETTINGS Scene_CommandTimeSettings, // SCENE_CMD_ID_TIME_SETTINGS Scene_CommandSkyboxSettings, // SCENE_CMD_ID_SKYBOX_SETTINGS @@ -579,9 +579,9 @@ void (*sSceneCmdHandlers[SCENE_CMD_MAX])(PlayState*, SceneCmd*) = { Scene_CommandSetRegionVisitedFlag, // SCENE_CMD_ID_SET_REGION_VISITED Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST Scene_CommandCutsceneList, // SCENE_CMD_ID_ACTOR_CUTSCENE_LIST - Scene_CommandMiniMap, // SCENE_CMD_ID_MINIMAP_INFO + Scene_CommandMapData, // SCENE_CMD_ID_MAP_DATA Scene_Command1D, // SCENE_CMD_ID_UNUSED_1D - Scene_CommandMiniMapCompassInfo, // SCENE_CMD_ID_MINIMAP_COMPASS_ICON_INFO + Scene_CommandMapDataChests, // SCENE_CMD_ID_MAP_DATA_CHESTS }; /** -- cgit v1.2.3