mm/src/code/z_map_disp.c

1827 lines
69 KiB
C

#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"
void MapDisp_DestroyMapI(PlayState* play);
void MapDisp_InitMapI(PlayState* play);
#include "gDPLoadTextureBlock_Runtime.inc.c"
static UNK_TYPE4 D_801BEB30[2] = { 0, 0 };
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,
};
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 },
};
TransitionActorEntry sTransitionActors[ROOM_TRANSITION_MAX];
PauseDungeonMap sPauseDungeonMap;
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));
}
}
void MapDisp_InitRoomStoreyRecord(PlayState* play, s16* roomStorey) {
*roomStorey = -1;
}
void MapDisp_DestroyRoomStoreyRecord(PlayState* play, s16* roomStory) {
}
void func_80102EB4(u32 flag) {
sMapDisp.unk20 |= flag;
}
void func_80102ED0(u32 flag) {
sMapDisp.unk20 &= ~flag;
}
s32 MapDisp_CurRoomHasMapI(PlayState* play) {
MapDataRoom* mapDataRoom;
s8 curRoom;
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;
}
/**
* 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;
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;
}
void MapDisp_GetMapTexDim(MapDataRoom* mapDataRoom, s32* width, s32* height) {
MapData_GetMapTexDim(mapDataRoom->mapId, width, height);
}
void MapDisp_GetMapScale(MapDataRoom* mapDataRoom, s32* scale) {
MapData_GetMapScale(mapDataRoom->mapId, scale);
if (*scale == 0) {
*scale = 20;
}
}
void MapDisp_GetMapOffset(MapDataRoom* mapDataRoom, s32* offsetX, s32* offsetY) {
s32 width;
s32 height;
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);
*offsetX = ((width / 2) - *offsetX) + (width / 2);
}
if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) {
s32 temp = (height / 2);
*offsetY = (temp - *offsetY) + temp;
}
}
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;
if ((mapDataRoom->mapId == MAP_DATA_NO_MAP) || (texture == NULL)) {
return;
}
MapDisp_GetMapTexDim(mapDataRoom, &texWidth, &texHeight);
OPEN_DISPS(play->state.gfxCtx);
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);
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;
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;
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;
}
s = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) ? (texWidth - 1) << 5 : 0;
t = (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_Y) ? 0 : (texHeight - 1) << 5;
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);
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;
gSPTextureRectangle(OVERLAY_DISP++, x << 2, y << 2, (texWidth + x) << 2, (y + texHeight) << 2, G_TX_RENDERTILE, s,
t, dsdx, dtdy);
CLOSE_DISPS(play->state.gfxCtx);
}
// 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;
}
s32 MapDisp_CanDrawDoors(PlayState* play) {
if ((gSaveContext.save.entrance == ENTRANCE(ROMANI_RANCH, 0)) && (Cutscene_GetSceneLayer(play) != 0)) {
return false;
}
return true;
}
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;
// inferred from `MapDisp_Minimap_DrawDoorActor`
unused1 = fabsf(player->actor.world.pos.y - actor->world.pos.y);
unused2 = 1.0f - (1 / 350.0f) * unused1;
if (unused2 < 0.0f) {
unused2 = 0.0f;
}
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)((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;
}
if ((posX > 0) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) {
OPEN_DISPS(play->state.gfxCtx);
if ((actor->category == ACTORCAT_PLAYER) && (actor->flags & ACTOR_FLAG_MINIMAP_ICON_ENABLED)) {
s16 compassRot;
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);
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);
MATRIX_FINALIZE_AND_LOAD(OVERLAY_DISP++, play->state.gfxCtx);
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++);
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);
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_MINIMAP_ICON_ENABLED) {
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);
}
}
void MapDisp_Minimap_DrawActors(PlayState* play) {
ActorContext* actorCtx;
s32 i;
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);
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_MINIMAP_ICON_ENABLED)) &&
((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->roomList.count;
}
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++) {
TransitionActorEntry* entry = &sTransitionActors[i];
if (MapDisp_IsBossDoor(entry->params)) {
if (ABS_ALT(entry->id) != ACTOR_EN_HOLL) {
for (storey = 0; storey < sMapDisp.numStoreys; storey++) {
if (((storey == sMapDisp.numStoreys - 1) && (entry->pos.y >= (sMapDisp.storeyYList[storey] - 5))) ||
((storey != sMapDisp.numStoreys - 1) && (entry->pos.y >= (sMapDisp.storeyYList[storey] - 5)) &&
(entry->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->roomList.count;
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);
MATRIX_FINALIZE_AND_LOAD(OVERLAY_DISP++, play->state.gfxCtx);
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 {
s32 requiredScopeTemp;
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;
}
}
}