Mirrored world enhancement (#1569)

* Mirrored world PoC

* invert culling for health meter and A button action

* A few more fixes

* Fix for item equip animations

* Fix for pause triforce

* Mirror scenes with static backgrounds

* mirror minimap for mirror world

* mirror dungeon maps and icons on the pause menu

* mirror overworld map and icons on the pause menu

* mirror debug world movement

* mirror shops cursor and movement

* use flip flag

* Reverse crouch stab x axis for mirror mode

* use invert culling command and clean up culling logic

* Move mirror mode handler to mods and support random modes

* Small cvar tweaks

* mirror billboard score numbers and fix gyro horse mirrored inputs

---------

Co-authored-by: Adam Bird <archez39@me.com>
This commit is contained in:
Garrett Cox 2023-06-13 07:46:15 -05:00 committed by GitHub
parent 90d45d4397
commit 7a41bd3878
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 363 additions and 84 deletions

View File

@ -203,6 +203,7 @@ typedef struct {
/* 0x0060 */ Mtx projection;
/* 0x00A0 */ Mtx viewing;
/* 0x00E0 */ Mtx* projectionPtr;
/* 0x00E0 */ Mtx* projectionFlippedPtr;
/* 0x00E4 */ Mtx* viewingPtr;
/* 0x00E8 */ Vec3f distortionOrientation;
/* 0x00F4 */ Vec3f distortionScale;

View File

@ -11,6 +11,13 @@ typedef enum {
BUNNY_HOOD_FAST
} BunnyHoodMode;
typedef enum {
MIRRORED_WORLD_OFF,
MIRRORED_WORLD_ALWAYS,
MIRRORED_WORLD_RANDOM,
MIRRORED_WORLD_RANDOM_SEEDED,
} MirroredWorldMode;
typedef enum {
FASTFILE_1,
FASTFILE_2,

View File

@ -4,6 +4,7 @@
#include "tts/tts.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/randomizer/3drando/random.hpp"
extern "C" {
#include <z64.h>
@ -550,6 +551,29 @@ void RegisterMenuPathFix() {
});
}
void UpdateMirrorModeState(int32_t sceneNum) {
if (CVarGetInteger("gMirroredWorldMode", MIRRORED_WORLD_OFF) == MIRRORED_WORLD_RANDOM_SEEDED) {
uint32_t seed = sceneNum + (gSaveContext.n64ddFlag ? (gSaveContext.seedIcons[0] + gSaveContext.seedIcons[1] + gSaveContext.seedIcons[2] + gSaveContext.seedIcons[3] + gSaveContext.seedIcons[4]) : gSaveContext.sohStats.fileCreatedAt);
Random_Init(seed);
}
uint8_t randomNumber = Random(0, 2);
if (
CVarGetInteger("gMirroredWorldMode", MIRRORED_WORLD_OFF) == MIRRORED_WORLD_ALWAYS ||
CVarGetInteger("gMirroredWorldMode", MIRRORED_WORLD_OFF) > MIRRORED_WORLD_ALWAYS && randomNumber == 1
) {
CVarSetInteger("gMirroredWorld", 1);
} else {
CVarClear("gMirroredWorld");
}
}
void RegisterMirrorModeHandler() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int32_t sceneNum) {
UpdateMirrorModeState(sceneNum);
});
}
void InitMods() {
RegisterTTS();
RegisterInfiniteMoney();
@ -571,4 +595,5 @@ void InitMods() {
RegisterHyperEnemies();
RegisterBonkDamage();
RegisterMenuPathFix();
RegisterMirrorModeHandler();
}

View File

@ -8,6 +8,7 @@ extern "C" {
#endif
void UpdateDirtPathFixState(int32_t sceneNum);
void UpdateMirrorModeState(int32_t sceneNum);
void InitMods();
#ifdef __cplusplus

View File

@ -62,6 +62,7 @@ std::string GetWindowButtonText(const char* text, bool menuOpen) {
static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" };
static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" };
static const char* mirroredWorldModes[4] = { "Disabled", "Always", "Random", "Random (Seeded)" };
static const char* allPowers[9] = {
"Vanilla (1x)",
"Double (2x)",
@ -1015,6 +1016,19 @@ void DrawEnhancementsMenu() {
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Extra Modes")) {
UIWidgets::PaddedText("Mirrored World Mode", true, false);
if (UIWidgets::EnhancementCombobox("gMirroredWorldMode", mirroredWorldModes, MIRRORED_WORLD_OFF) && gPlayState != NULL) {
UpdateMirrorModeState(gPlayState->sceneNum);
}
UIWidgets::Tooltip(
"Mirrors the world horizontally\n\n"
"- Always: Always mirror the world\n"
"- Random: Randomly decide to mirror the world on each scene change\n"
"- Random (Seeded): Scenes are mirrored based on the current randomizer seed/file\n"
);
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Ivan the Fairy (Coop Mode)", "gIvanCoopModeEnabled", true, false);
UIWidgets::Tooltip("Enables Ivan the Fairy upon the next map change. Player 2 can control Ivan and "
"press the C-Buttons to use items and mess with Player 1!");

View File

@ -653,7 +653,11 @@ Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updat
}
updateIndex = aiBufLen * 2;
aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, updateIndex);
if (CVarGetInteger("gMirroredWorld", 0)) {
aInterleave(cmd++, DMEM_TEMP, DMEM_RIGHT_CH, DMEM_LEFT_CH, updateIndex);
} else {
aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, updateIndex);
}
aSaveBuffer(cmd++, DMEM_TEMP, aiBuf, updateIndex * 2);
return cmd;

View File

@ -1487,8 +1487,9 @@ s32 Camera_Free(Camera* camera) {
f32 newCamX = -D_8015BD7C->state.input[0].cur.right_stick_x * 10.0f * (CVarGetFloat("gThirdPersonCameraSensitivityX", 1.0f));
f32 newCamY = D_8015BD7C->state.input[0].cur.right_stick_y * 10.0f * (CVarGetFloat("gThirdPersonCameraSensitivityY", 1.0f));
bool invertXAxis = (CVarGetInteger("gInvertXAxis", 0) && !CVarGetInteger("gMirroredWorld", 0)) || (!CVarGetInteger("gInvertXAxis", 0) && CVarGetInteger("gMirroredWorld", 0));
camera->play->camX += newCamX * (CVarGetInteger("gInvertXAxis", 0) ? -1 : 1);
camera->play->camX += newCamX * (invertXAxis ? -1 : 1);
camera->play->camY += newCamY * (CVarGetInteger("gInvertYAxis", 1) ? 1 : -1);
if (camera->play->camY > 0x32A4) {

View File

@ -201,6 +201,10 @@ void func_80077D10(f32* arg0, s16* arg1, Input* input) {
f32 relX = input->rel.stick_x;
f32 relY = input->rel.stick_y;
if (CVarGetInteger("gMirroredWorld", 0)) {
relX = -input->rel.stick_x;
}
*arg0 = sqrtf(SQ(relX) + SQ(relY));
*arg0 = (60.0f < *arg0) ? 60.0f : *arg0;

View File

@ -635,32 +635,49 @@ void Minimap_DrawCompassIcons(PlayState* play) {
gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
s16 mapWidth = 0;
s16 mapStartPosX = 0;
if (play->sceneNum >= SCENE_SPOT00 && play->sceneNum <= SCENE_GANON_TOU) { // Overworld
mapStartPosX = R_OW_MINIMAP_X;
mapWidth = gMapData->owMinimapWidth[R_MAP_INDEX];
} else if (play->sceneNum >= SCENE_YDAN && play->sceneNum <= SCENE_ICE_DOUKUTO) { // Dungeons
mapStartPosX = R_DGN_MINIMAP_X;
mapWidth = 96;
}
// The compass offset value is a factor of 10 compared to N64 screen pixels and originates in the center of the screen
// Compute the additional mirror offset value by normalizing the original offset position
// and taking it's distance to the center of the map, duplicating that result and casting back to a factor of 10
s16 mirrorOffset = ((mapWidth / 2) - ((R_COMPASS_OFFSET_X / 10) - (mapStartPosX - SCREEN_WIDTH / 2))) * 2 * 10;
tempX = player->actor.world.pos.x;
tempZ = player->actor.world.pos.z;
tempX /= R_COMPASS_SCALE_X;
tempX /= R_COMPASS_SCALE_X * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1);
tempZ /= R_COMPASS_SCALE_Y;
s16 tempXOffset = R_COMPASS_OFFSET_X + (CVarGetInteger("gMirroredWorld", 0) ? mirrorOffset : 0);
if (CVarGetInteger("gMinimapPosType", 0) != 0) {
if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;};
Matrix_Translate(
OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
Matrix_Translate(
OTRGetDimensionFromLeftEdge((tempXOffset + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
} else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;};
Matrix_Translate(
OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
OTRGetDimensionFromRightEdge((tempXOffset + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y +((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
} else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None
Matrix_Translate(
(R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f),
(tempXOffset + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f),
(R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
}
} else {
Matrix_Translate(OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X+(X_Margins_Minimap*10) + tempX) / 10.0f), (R_COMPASS_OFFSET_Y+((Y_Margins_Minimap*10)*-1) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW);
Matrix_Translate(OTRGetDimensionFromRightEdge((tempXOffset+(X_Margins_Minimap*10) + tempX) / 10.0f), (R_COMPASS_OFFSET_Y+((Y_Margins_Minimap*10)*-1) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW);
}
Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY);
Matrix_RotateX(-1.6f, MTXMODE_APPLY);
tempX = (0x7FFF - player->actor.shape.rot.y) / 0x400;
tempX = ((0x7FFF - player->actor.shape.rot.y) / 0x400) * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1);
Matrix_RotateY(tempX / 10.0f, MTXMODE_APPLY);
gSPMatrix(OVERLAY_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -669,32 +686,32 @@ void Minimap_DrawCompassIcons(PlayState* play) {
gSPDisplayList(OVERLAY_DISP++, gCompassArrowDL);
//Player map entry (red arrow)
tempX = sPlayerInitialPosX+X_Margins_Minimap;
tempZ = sPlayerInitialPosZ+Y_Margins_Minimap;
tempX /= R_COMPASS_SCALE_X;
tempX = sPlayerInitialPosX;
tempZ = sPlayerInitialPosZ;
tempX /= R_COMPASS_SCALE_X * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1);
tempZ /= R_COMPASS_SCALE_Y;
if (CVarGetInteger("gMinimapPosType", 0) != 0) {
if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;};
Matrix_Translate(
OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
Matrix_Translate(
OTRGetDimensionFromLeftEdge((tempXOffset + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
} else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;};
Matrix_Translate(
OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
OTRGetDimensionFromRightEdge((tempXOffset + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f),
(R_COMPASS_OFFSET_Y +((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
} else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None
Matrix_Translate(
(R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f),
(tempXOffset + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f),
(R_COMPASS_OFFSET_Y - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW);
}
} else {
Matrix_Translate(OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X+(X_Margins_Minimap*10) + tempX) / 10.0f), (R_COMPASS_OFFSET_Y+((Y_Margins_Minimap*10)*-1) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW);
Matrix_Translate(OTRGetDimensionFromRightEdge((tempXOffset+(X_Margins_Minimap*10) + tempX) / 10.0f), (R_COMPASS_OFFSET_Y+((Y_Margins_Minimap*10)*-1) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW);
}
Matrix_Scale(VREG(9) / 100.0f, VREG(9) / 100.0f, VREG(9) / 100.0f, MTXMODE_APPLY);
Matrix_RotateX(VREG(52) / 10.0f, MTXMODE_APPLY);
Matrix_RotateY(sPlayerInitialDirection / 10.0f, MTXMODE_APPLY);
Matrix_RotateY((sPlayerInitialDirection * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1)) / 10.0f, MTXMODE_APPLY);
gSPMatrix(OVERLAY_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -752,8 +769,9 @@ void Minimap_Draw(PlayState* play) {
if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha);
u8 mirrorMode = CVarGetInteger("gMirroredWorld", 0) ? G_TX_MIRROR : G_TX_NOMIRROR;
gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_I, 96, 85, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
s16 dgnMiniMapX = OTRGetRectDimensionFromRightEdge(R_DGN_MINIMAP_X + X_Margins_Minimap);
@ -770,9 +788,16 @@ void Minimap_Draw(PlayState* play) {
dgnMiniMapX = CVarGetInteger("gMinimapPosX", 0);
}
}
s32 sValue = 0;
if (CVarGetInteger("gMirroredWorld", 0)) {
// Flip the minimap on the x-axis (s-axis) by setting s to the textures mirror boundary
sValue = 96 << 5;
}
gSPWideTextureRectangle(OVERLAY_DISP++, dgnMiniMapX << 2, dgnMiniMapY << 2,
(dgnMiniMapX + 96) << 2, (dgnMiniMapY + 85) << 2, G_TX_RENDERTILE,
0, 0, 1 << 10, 1 << 10);
sValue, 0, 1 << 10, 1 << 10);
}
if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, mapIndex)) {
@ -820,9 +845,10 @@ void Minimap_Draw(PlayState* play) {
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha);
u8 mirrorMode = CVarGetInteger("gMirroredWorld", 0) ? G_TX_MIRROR : G_TX_NOMIRROR;
gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_IA,
gMapData->owMinimapWidth[mapIndex], gMapData->owMinimapHeight[mapIndex], 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
s16 oWMiniMapX = OTRGetRectDimensionFromRightEdge(R_OW_MINIMAP_X + X_Margins_Minimap);
@ -839,9 +865,16 @@ void Minimap_Draw(PlayState* play) {
oWMiniMapX = CVarGetInteger("gMinimapPosX", 0);
}
}
s32 sValue = 0;
if (CVarGetInteger("gMirroredWorld", 0)) {
// Flip the minimap on the x-axis (s-axis) by setting s to the textures mirror boundary
sValue = gMapData->owMinimapWidth[mapIndex] << 5;
}
gSPWideTextureRectangle(OVERLAY_DISP++, oWMiniMapX << 2, oWMiniMapY << 2,
(oWMiniMapX + gMapData->owMinimapWidth[mapIndex]) << 2,
(oWMiniMapY + gMapData->owMinimapHeight[mapIndex]) << 2, G_TX_RENDERTILE, 0,
(oWMiniMapY + gMapData->owMinimapHeight[mapIndex]) << 2, G_TX_RENDERTILE, sValue,
0, 1 << 10, 1 << 10);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha);
@ -851,26 +884,33 @@ void Minimap_Draw(PlayState* play) {
if (((play->sceneNum != SCENE_SPOT01) && (play->sceneNum != SCENE_SPOT04) &&
(play->sceneNum != SCENE_SPOT08)) ||
(LINK_AGE_IN_YEARS != YEARS_ADULT)) {
s16 origX = gMapData->owEntranceIconPosX[sEntranceIconMapIndex];
// Compute the distance of the center of the original texture location to the center of the map
// Then duplicate that and right-align the texture (extra 2 pixels are due to the texture being a 6px left-aligned in a 8px tex)
s16 distFromCenter = (R_OW_MINIMAP_X + (gMapData->owMinimapWidth[mapIndex] / 2)) - (origX + (iconSize / 2));
s16 mirrorOffset = distFromCenter * 2 + (iconSize / 2) - 2;
s16 newX = origX + (CVarGetInteger("gMirroredWorld", 0) ? mirrorOffset : 0);
// The game authentically uses larger negative values for the entrance icon Y pos value. Normally only the first 12 bits
// would be read when the final value is passed into `gSPTextureRectangle`, but our cosmetic hud placements requires using
// `gSPWideTextureRectangle` which reads the first 24 bits instead. This caused the icon to be placed off screen.
// To address this, we take only the first 10 bits (which are later left-shifted by 2 to get our final 12 bits)
// to fix the entrance icon position when used with `gSPWideTextureRectangle`
s16 newY = gMapData->owEntranceIconPosY[sEntranceIconMapIndex] & 0x3FF;
s16 PosX = gMapData->owEntranceIconPosX[sEntranceIconMapIndex] + X_Margins_Minimap;
s16 entranceX = OTRGetRectDimensionFromRightEdge(PosX);
s16 entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap);
s16 entranceY = newY + Y_Margins_Minimap;
if (CVarGetInteger("gMinimapPosType", 0) != 0) {
entranceY = newY + CVarGetInteger("gMinimapPosY", 0) + Y_Margins_Minimap;
if (CVarGetInteger("gMinimapPosType", 0) == 1) { // Anchor Left
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;};
entranceX = OTRGetRectDimensionFromLeftEdge(PosX + CVarGetInteger("gMinimapPosX", 0));
entranceX = OTRGetRectDimensionFromLeftEdge(newX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
} else if (CVarGetInteger("gMinimapPosType", 0) == 2) { // Anchor Right
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;};
entranceX = OTRGetRectDimensionFromRightEdge(PosX + CVarGetInteger("gMinimapPosX", 0));
entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
} else if (CVarGetInteger("gMinimapPosType", 0) == 3) { // Anchor None
entranceX = PosX + CVarGetInteger("gMinimapPosX", 0);
entranceX = newX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0);
}
}
@ -894,18 +934,19 @@ void Minimap_Draw(PlayState* play) {
}
}
s16 entranceX = OTRGetRectDimensionFromRightEdge(270 + X_Margins_Minimap);
s16 origX = CVarGetInteger("gMirroredWorld", 0) ? 256 : 270;
s16 entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap);
s16 entranceY = 154 + Y_Margins_Minimap;
if (CVarGetInteger("gMinimapPosType", 0) != 0) {
entranceY = 154 + Y_Margins_Minimap + CVarGetInteger("gMinimapPosY", 0);
if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;};
entranceX = OTRGetRectDimensionFromLeftEdge(270 + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
entranceX = OTRGetRectDimensionFromLeftEdge(origX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
} else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;};
entranceX = OTRGetRectDimensionFromRightEdge(270 + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0));
} else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None
entranceX = 270 + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0);
entranceX = origX + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0);
}
}

View File

@ -132,8 +132,19 @@ void MapMark_DrawForDungeon(PlayState* play) {
//Place each chest / boss room icon
for (i = 0; i < mapMarkIconData->count; i++) {
if ((mapMarkIconData->markType != MAP_MARK_CHEST) || !Flags_GetTreasure(play, markPoint->chestFlag)) {
markInfo = &sMapMarkInfoTable[mapMarkIconData->markType];
int height = markInfo->textureHeight * 1.0f; //Adjust Height with scale
int width = markInfo->textureWidth * 1.0f; //Adjust Width with scale
int height_factor = (1 << 10) * markInfo->textureHeight / height;
int width_factor = (1 << 10) * markInfo->textureWidth / width;
// The original mark point X originates from the left edge of the map
// For mirror mode, we compute the new mark point X by subtracting it from the right side of the
// dungeon map and the textures width
s16 markPointX = CVarGetInteger("gMirroredWorld", 0) ? 96 - markPoint->x - width : markPoint->x;
//Minimap chest / boss icon
const s32 PosX_Minimap_ori = GREG(94) + OTRGetRectDimensionFromRightEdge(markPoint->x+X_Margins_Minimap_ic) + 204;
const s32 PosX_Minimap_ori = GREG(94) + OTRGetRectDimensionFromRightEdge(markPointX+X_Margins_Minimap_ic) + 204;
const s32 PosY_Minimap_ori = GREG(95) + markPoint->y + Y_Margins_Minimap_ic + 140;
if (CVarGetInteger("gMinimapPosType", 0) != 0) {
rectTop = (markPoint->y + Y_Margins_Minimap_ic + 140 + CVarGetInteger("gMinimapPosY", 0));
@ -143,15 +154,15 @@ void MapMark_DrawForDungeon(PlayState* play) {
play->sceneNum == SCENE_BMORI1 || play->sceneNum == SCENE_HIDAN || play->sceneNum == SCENE_MIZUSIN ||
play->sceneNum == SCENE_JYASINZOU || play->sceneNum == SCENE_HAKADAN || play->sceneNum == SCENE_HAKADANCH ||
play->sceneNum == SCENE_ICE_DOUKUTO) {
rectLeft = OTRGetRectDimensionFromLeftEdge(markPoint->x+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
rectLeft = OTRGetRectDimensionFromLeftEdge(markPointX+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
} else {
rectLeft = OTRGetRectDimensionFromLeftEdge(markPoint->x+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
rectLeft = OTRGetRectDimensionFromLeftEdge(markPointX+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
}
} else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right
if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap_ic = Right_MC_Margin;};
rectLeft = OTRGetRectDimensionFromRightEdge(markPoint->x+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
rectLeft = OTRGetRectDimensionFromRightEdge(markPointX+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic);
} else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None
rectLeft = markPoint->x+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic;
rectLeft = markPointX+CVarGetInteger("gMinimapPosX", 0)+204+X_Margins_Minimap_ic;
} else if (CVarGetInteger("gMinimapPosType", 0) == 4) {//Hidden
rectLeft = -9999;
}
@ -160,13 +171,6 @@ void MapMark_DrawForDungeon(PlayState* play) {
rectTop = PosY_Minimap_ori;
}
int height = 8 * 1.0f; //Adjust Height with scale
int width = 8 * 1.0f; //Adjust Width with scale
int height_factor = (1 << 10) * 8 / height;
int width_factor = (1 << 10) * 8 / width;
markInfo = &sMapMarkInfoTable[mapMarkIconData->markType];
gDPPipeSync(OVERLAY_DISP++);
gDPLoadTextureBlock(OVERLAY_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK,

View File

@ -5090,7 +5090,13 @@ void Interface_Draw(PlayState* play) {
Minimap_Draw(play);
if ((R_PAUSE_MENU_MODE != 2) && (R_PAUSE_MENU_MODE != 3)) {
if (CVarGetInteger("gMirroredWorld", 0)) {
gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.projectionFlippedPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
}
func_8002C124(&play->actorCtx.targetCtx, play); // Draw Z-Target
if (CVarGetInteger("gMirroredWorld", 0)) {
gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.projectionPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
}
}
Gfx_SetupDL_39Overlay(play->state.gfxCtx);

View File

@ -1473,6 +1473,17 @@ void Play_Draw(PlayState* play) {
func_800AA460(&play->view, play->view.fovy, play->view.zNear, play->lightCtx.fogFar);
func_800AAA50(&play->view, 15);
// Flip the projections and invert culling for the OPA and XLU display buffers
// These manage the world and effects
if (CVarGetInteger("gMirroredWorld", 0)) {
gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
gSPMatrix(POLY_OPA_DISP++, play->view.projectionFlippedPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, play->view.projectionFlippedPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_OPA_DISP++, play->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, play->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
}
// The billboard matrix temporarily stores the viewing matrix
Matrix_MtxToMtxF(&play->view.viewing, &play->billboardMtxF);
Matrix_MtxToMtxF(&play->view.projection, &play->viewProjectionMtxF);
@ -1694,6 +1705,12 @@ void Play_Draw(PlayState* play) {
}
}
}
// Reset the inverted culling
if (CVarGetInteger("gMirroredWorld", 0)) {
gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
}
}
if (play->view.unk_124 != 0) {

View File

@ -1776,7 +1776,7 @@ void func_80091A24(PlayState* play, void* seg04, void* seg06, SkelAnime* skelAni
Matrix_SetTranslateRotateYXZ(pos->x - ((CVarGetInteger("gPauseLiveLink", 0) && LINK_AGE_IN_YEARS == YEARS_ADULT) ? 25 : 0),
pos->y - (CVarGetInteger("gPauseTriforce", 0) ? 16 : 0), pos->z, rot);
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
Matrix_Scale(scale * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1), scale, scale, MTXMODE_APPLY);
gSPSegment(POLY_OPA_DISP++, 0x04, seg04);
gSPSegment(POLY_OPA_DISP++, 0x06, seg06);
@ -1798,7 +1798,7 @@ void func_80091A24(PlayState* play, void* seg04, void* seg06, SkelAnime* skelAni
Matrix_SetTranslateRotateYXZ(pos->x - (LINK_AGE_IN_YEARS == YEARS_ADULT ? 25 : 0),
pos->y + 280 + (LINK_AGE_IN_YEARS == YEARS_ADULT ? 48 : 0), pos->z, rot);
Matrix_Scale(scale * 1, scale * 1, scale * 1, MTXMODE_APPLY);
Matrix_Scale(scale * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1), scale * 1, scale * 1, MTXMODE_APPLY);
Gfx* ohNo = POLY_XLU_DISP;
POLY_XLU_DISP = POLY_OPA_DISP;

View File

@ -270,7 +270,7 @@ void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 h
bg->b.imageFmt = fmt;
bg->b.imageSiz = siz;
bg->b.imagePal = 0;
bg->b.imageFlip = 0;
bg->b.imageFlip = CVarGetInteger("gMirroredWorld", 0) ? G_BG_FLAG_FLIPS : 0;
if (ResourceMgr_ResourceIsBackground((char*) source)) {
char* blob = (char*) ResourceGetDataByName((char *) source);

View File

@ -296,6 +296,7 @@ s32 func_800AAA9C(View* view) {
s32 height;
Vp* vp;
Mtx* projection;
Mtx* projectionFlipped;
Mtx* viewing;
GraphicsContext* gfxCtx = view->gfxCtx;
@ -313,8 +314,11 @@ s32 func_800AAA9C(View* view) {
gSPViewport(POLY_KAL_DISP++, vp);
projection = Graph_Alloc(gfxCtx, sizeof(Mtx));
projectionFlipped = Graph_Alloc(gfxCtx, sizeof(Mtx));
LOG_CHECK_NULL_POINTER("projection", projection);
LOG_CHECK_NULL_POINTER("projectionFlipped", projectionFlipped);
view->projectionPtr = projection;
view->projectionFlippedPtr = projectionFlipped;
width = view->viewport.rightX - view->viewport.leftX;
height = view->viewport.bottomY - view->viewport.topY;
@ -427,6 +431,15 @@ s32 func_800AAA9C(View* view) {
}
osSyncPrintf("\n");
}
if (CVarGetInteger("gMirroredWorld", 0)) {
MtxF flipF;
SkinMatrix_Clear(&flipF);
flipF.xx = -1.0;
MtxF projectionF;
Matrix_MtxToMtxF(projection, &projectionF);
SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF);
Matrix_MtxFToMtx(&projectionF, projectionFlipped);
}
view->projection = *projection;
@ -511,6 +524,7 @@ s32 func_800AB0A8(View* view) {
s32 func_800AB2C4(View* view) {
Vp* vp;
Mtx* projection;
Mtx* projectionFlipped;
GraphicsContext* gfxCtx;
gfxCtx = view->gfxCtx;
@ -528,12 +542,26 @@ s32 func_800AB2C4(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = Graph_Alloc(gfxCtx, sizeof(Mtx));
projectionFlipped = Graph_Alloc(gfxCtx, sizeof(Mtx));
LOG_CHECK_NULL_POINTER("projection", projection);
LOG_CHECK_NULL_POINTER("projectionFlipped", projectionFlipped);
view->projectionPtr = projection;
view->projectionFlippedPtr = projectionFlipped;
guOrtho(projection, -(f32)gScreenWidth * 0.5f, (f32)gScreenWidth * 0.5f, -(f32)gScreenHeight * 0.5f,
(f32)gScreenHeight * 0.5f, -30, view->zFar, view->scale);
// This is for z-targeting
if (CVarGetInteger("gMirroredWorld", 0)) {
MtxF flipF;
SkinMatrix_Clear(&flipF);
flipF.xx = -1.0;
MtxF projectionF;
Matrix_MtxToMtxF(projection, &projectionF);
SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF);
Matrix_MtxFToMtx(&projectionF, projectionFlipped);
}
view->projection = *projection;
gSPMatrix(OVERLAY_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);

View File

@ -3042,7 +3042,7 @@ void EnHorse_StickDirection(Vec2f* curStick, f32* stickMag, s16* angle) {
void EnHorse_UpdateStick(EnHorse* this, PlayState* play) {
this->lastStick = this->curStick;
this->curStick.x = play->state.input[0].rel.stick_x;
this->curStick.x = play->state.input[0].rel.stick_x * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1);
this->curStick.y = play->state.input[0].rel.stick_y;
}

View File

@ -661,6 +661,10 @@ void EnOssan_UpdateCursorPos(PlayState* play, EnOssan* this) {
Actor_GetScreenPos(play, &this->shelfSlots[this->cursorIndex]->actor, &x, &y);
this->cursorX = x;
this->cursorY = y;
if (CVarGetInteger("gMirroredWorld", 0)) {
this->cursorX = SCREEN_WIDTH - x;
}
}
void EnOssan_EndInteraction(PlayState* play, EnOssan* this) {
@ -769,6 +773,10 @@ void EnOssan_UpdateJoystickInputState(PlayState* play, EnOssan* this) {
s8 stickX = input->rel.stick_x;
s8 stickY = input->rel.stick_y;
if (CVarGetInteger("gMirroredWorld", 0)) {
stickX = -input->rel.stick_x;
}
this->moveHorizontal = this->moveVertical = false;
if (this->stickAccumX == 0) {
@ -979,8 +987,16 @@ void EnOssan_State_FacingShopkeeper(EnOssan* this, PlayState* play, Player* play
func_80078884(NA_SE_SY_DECIDE);
return;
}
u16 dLeft = BTN_DLEFT;
u16 dRight = BTN_DRIGHT;
if (CVarGetInteger("gMirroredWorld", 0)) {
dLeft = BTN_DRIGHT;
dRight = BTN_DLEFT;
}
// Stick Left
if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, dLeft))) {
nextIndex = EnOssan_SetCursorIndexFromNeutral(this, 4);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
@ -989,7 +1005,7 @@ void EnOssan_State_FacingShopkeeper(EnOssan* this, PlayState* play, Player* play
this->stickLeftPrompt.isEnabled = false;
func_80078884(NA_SE_SY_CURSOR);
}
} else if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
} else if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, dRight))) {
nextIndex = EnOssan_SetCursorIndexFromNeutral(this, 0);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
@ -1219,8 +1235,16 @@ void EnOssan_State_BrowseLeftShelf(EnOssan* this, PlayState* play, Player* playe
EnOssan_UpdateCursorPos(play, this);
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) &&
!EnOssan_HasPlayerSelectedItem(play, this, &play->state.input[0])) {
u16 dLeft = BTN_DLEFT;
u16 dRight = BTN_DRIGHT;
if (CVarGetInteger("gMirroredWorld", 0)) {
dLeft = BTN_DRIGHT;
dRight = BTN_DLEFT;
}
if (this->moveHorizontal) {
if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, dRight))) {
a = EnOssan_CursorRight(this, this->cursorIndex, 4);
if (a != CURSOR_INVALID) {
this->cursorIndex = a;
@ -1228,14 +1252,14 @@ void EnOssan_State_BrowseLeftShelf(EnOssan* this, PlayState* play, Player* playe
EnOssan_SetLookToShopkeeperFromShelf(play, this);
return;
}
} else if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
} else if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, dLeft))) {
b = EnOssan_CursorLeft(this, this->cursorIndex, 8);
if (b != CURSOR_INVALID) {
this->cursorIndex = b;
}
}
} else {
if ((this->stickAccumX > 0 && this->stickAccumX > 500) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
if ((this->stickAccumX > 0 && this->stickAccumX > 500) || (dpad && CHECK_BTN_ALL(input->press.button, dRight))) {
c = EnOssan_CursorRight(this, this->cursorIndex, 4);
if (c != CURSOR_INVALID) {
this->cursorIndex = c;
@ -1243,7 +1267,7 @@ void EnOssan_State_BrowseLeftShelf(EnOssan* this, PlayState* play, Player* playe
EnOssan_SetLookToShopkeeperFromShelf(play, this);
return;
}
} else if ((this->stickAccumX < 0 && this->stickAccumX < -500) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
} else if ((this->stickAccumX < 0 && this->stickAccumX < -500) || (dpad && CHECK_BTN_ALL(input->press.button, dLeft))) {
d = EnOssan_CursorLeft(this, this->cursorIndex, 8);
if (d != CURSOR_INVALID) {
this->cursorIndex = d;
@ -1280,8 +1304,16 @@ void EnOssan_State_BrowseRightShelf(EnOssan* this, PlayState* play, Player* play
EnOssan_UpdateCursorPos(play, this);
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) &&
!EnOssan_HasPlayerSelectedItem(play, this, &play->state.input[0])) {
u16 dLeft = BTN_DLEFT;
u16 dRight = BTN_DRIGHT;
if (CVarGetInteger("gMirroredWorld", 0)) {
dLeft = BTN_DRIGHT;
dRight = BTN_DLEFT;
}
if (this->moveHorizontal) {
if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
if ((this->stickAccumX < 0) || (dpad && CHECK_BTN_ALL(input->press.button, dLeft))) {
nextIndex = EnOssan_CursorRight(this, this->cursorIndex, 0);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
@ -1289,14 +1321,14 @@ void EnOssan_State_BrowseRightShelf(EnOssan* this, PlayState* play, Player* play
EnOssan_SetLookToShopkeeperFromShelf(play, this);
return;
}
} else if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
} else if ((this->stickAccumX > 0) || (dpad && CHECK_BTN_ALL(input->press.button, dRight))) {
nextIndex = EnOssan_CursorLeft(this, this->cursorIndex, 4);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
}
}
} else {
if ((this->stickAccumX < 0 && this->stickAccumX < -500) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
if ((this->stickAccumX < 0 && this->stickAccumX < -500) || (dpad && CHECK_BTN_ALL(input->press.button, dLeft))) {
nextIndex = EnOssan_CursorRight(this, this->cursorIndex, 0);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
@ -1304,7 +1336,7 @@ void EnOssan_State_BrowseRightShelf(EnOssan* this, PlayState* play, Player* play
EnOssan_SetLookToShopkeeperFromShelf(play, this);
return;
}
} else if ((this->stickAccumX > 0 && this->stickAccumX > 500) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
} else if ((this->stickAccumX > 0 && this->stickAccumX > 500) || (dpad && CHECK_BTN_ALL(input->press.button, dRight))) {
nextIndex = EnOssan_CursorLeft(this, this->cursorIndex, 4);
if (nextIndex != CURSOR_INVALID) {
this->cursorIndex = nextIndex;
@ -2375,6 +2407,12 @@ void EnOssan_DrawStickDirectionPrompts(PlayState* play, EnOssan* this) {
s32 drawStickLeftPrompt = this->stickLeftPrompt.isEnabled;
s32 drawStickRightPrompt = this->stickRightPrompt.isEnabled;
// Invert which stick prompt is active when only one is active
if (CVarGetInteger("gMirroredWorld", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) {
drawStickLeftPrompt = !drawStickLeftPrompt;
drawStickRightPrompt = !drawStickRightPrompt;
}
OPEN_DISPS(play->state.gfxCtx);
if (drawStickLeftPrompt || drawStickRightPrompt) {
Gfx_SetupDL_39Overlay(play->state.gfxCtx);

View File

@ -8170,7 +8170,7 @@ void func_80843188(Player* this, PlayState* play) {
if (this->unk_850 != 0) {
sp54 = sControlInput->rel.stick_y * 100;
sp50 = sControlInput->rel.stick_x * -120;
sp50 = sControlInput->rel.stick_x * (CVarGetInteger("gMirroredWorld", 0) ? 120 : -120);
sp4E = this->actor.shape.rot.y - Camera_GetInputDirYaw(GET_ACTIVE_CAM(play));
sp40 = Math_CosS(sp4E);
@ -11347,12 +11347,13 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
s32 temp1;
s16 temp2;
s16 temp3;
bool gInvertAimingXAxis = (CVarGetInteger("gInvertAimingXAxis", 0) && !CVarGetInteger("gMirroredWorld", 0)) || (!CVarGetInteger("gInvertAimingXAxis", 0) && CVarGetInteger("gMirroredWorld", 0));
if (!func_8002DD78(this) && !func_808334B4(this) && (arg2 == 0) && !CVarGetInteger("gDisableAutoCenterViewFirstPerson", 0)) {
temp2 = sControlInput->rel.stick_y * 240.0f * (CVarGetInteger("gInvertAimingYAxis", 1) ? 1 : -1); // Sensitivity not applied here because higher than default sensitivies will allow the camera to escape the autocentering, and glitch out massively
Math_SmoothStepToS(&this->actor.focus.rot.x, temp2, 14, 4000, 30);
temp2 = sControlInput->rel.stick_x * -16.0f * (CVarGetInteger("gInvertAimingXAxis", 0) ? -1 : 1) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
temp2 = sControlInput->rel.stick_x * -16.0f * (gInvertAimingXAxis ? -1 : 1) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
temp2 = CLAMP(temp2, -3000, 3000);
this->actor.focus.rot.y += temp2;
} else {
@ -11377,18 +11378,18 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
temp2 = this->actor.focus.rot.y - this->actor.shape.rot.y;
temp3 = ((sControlInput->rel.stick_x >= 0) ? 1 : -1) *
(s32)((1.0f - Math_CosS(sControlInput->rel.stick_x * 200)) * -1500.0f *
(CVarGetInteger("gInvertAimingXAxis", 0) ? -1 : 1)) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
(gInvertAimingXAxis ? -1 : 1)) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
temp2 += temp3;
this->actor.focus.rot.y = CLAMP(temp2, -temp1, temp1) + this->actor.shape.rot.y;
if (fabsf(sControlInput->cur.gyro_y) > 0.01f) {
this->actor.focus.rot.y += (sControlInput->cur.gyro_y) * 750.0f;
this->actor.focus.rot.y += (sControlInput->cur.gyro_y) * 750.0f * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1);
}
if (fabsf(sControlInput->cur.right_stick_x) > 15.0f && CVarGetInteger("gRightStickAiming", 0) != 0) {
this->actor.focus.rot.y +=
(sControlInput->cur.right_stick_x) * 10.0f * (CVarGetInteger("gInvertAimingXAxis", 0) ? 1 : -1) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
(sControlInput->cur.right_stick_x) * 10.0f * (gInvertAimingXAxis ? 1 : -1) * (CVarGetFloat("gFirstPersonCameraSensitivityX", 1.0f));
}
}
@ -11939,7 +11940,7 @@ void func_8084BF1C(Player* this, PlayState* play) {
if ((this->unk_84F != 0) && (sp80 != 0)) {
anim2 = this->ageProperties->unk_BC[this->unk_850];
if (sp80 > 0) {
if (CVarGetInteger("gMirroredWorld", 0) ? (sp80 < 0) : (sp80 > 0)) {
this->skelAnime.prevTransl = this->ageProperties->unk_7A[this->unk_850];
func_80832264(play, this, anim2);
} else {
@ -13619,9 +13620,9 @@ s32 func_8084FCAC(Player* this, PlayState* play) {
if (CHECK_BTN_ALL(sControlInput->cur.button, BTN_DDOWN)) {
angle = temp + 0x8000;
} else if (CHECK_BTN_ALL(sControlInput->cur.button, BTN_DLEFT)) {
angle = temp + 0x4000;
angle = temp + (0x4000 * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1));
} else if (CHECK_BTN_ALL(sControlInput->cur.button, BTN_DRIGHT)) {
angle = temp - 0x4000;
angle = temp - (0x4000 * (CVarGetInteger("gMirroredWorld", 0) ? -1 : 1));
}
this->actor.world.pos.x += speed * Math_SinS(angle);

View File

@ -62,6 +62,7 @@ void EffectSsExtra_Draw(PlayState* play, u32 index, EffectSs* this) {
s32 pad;
f32 scale = this->rScale / 100.0f;
void* object = play->objectCtx.status[this->rObjBankIdx].segment;
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
OPEN_DISPS(play->state.gfxCtx);
@ -71,11 +72,23 @@ void EffectSsExtra_Draw(PlayState* play, u32 index, EffectSs* this) {
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
Matrix_ReplaceRotation(&play->billboardMtxF);
// Flip the score texture matrix and un-invert the culling to display it normally
if (mirroredWorld) {
gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
Matrix_Scale(-1, 1, 1, MTXMODE_APPLY);
}
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sTextures[this->rScoreIdx]));
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_yabusame_point_DL_000DC0));
// Set back inverted culling
if (mirroredWorld) {
gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
}
CLOSE_DISPS(play->state.gfxCtx);
}

View File

@ -338,22 +338,40 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalette);
gDPSetTextureLUT(POLY_KAL_DISP++, G_TT_RGBA16);
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
u8 mirrorMode = mirroredWorld ? G_TX_MIRROR : G_TX_NOMIRROR;
// Offset the U value of each vertex to be in the mirror boundary for the map textures
if (mirroredWorld) {
for (size_t i = 0; i < 8; i++) {
pauseCtx->mapPageVtx[60 + i].v.tc[0] += 48 << 5;
}
}
gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[60], 8, 0);
// The dungeon map textures are recreated each frame, so always invalidate them
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]);
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | G_TX_NOMIRROR,
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | mirrorMode,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
// Swap vertices to render left half on the right and vice-versa
if (mirroredWorld) {
gSP1Quadrangle(POLY_KAL_DISP++, 4, 6, 7, 5, 0);
} else {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
}
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 0,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gSP1Quadrangle(POLY_KAL_DISP++, 4, 6, 7, 5, 0);
if (mirroredWorld) {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
} else {
gSP1Quadrangle(POLY_KAL_DISP++, 4, 6, 7, 5, 0);
}
gDPPipeSync(POLY_KAL_DISP++);
gDPSetTextureFilter(POLY_KAL_DISP++, G_TF_BILERP);
@ -420,6 +438,8 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
s16 stepG;
s16 stepB;
bool dpad = CVarGetInteger("gDpadPause", 0);
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
u8 mirrorMode = mirroredWorld ? G_TX_MIRROR : G_TX_NOMIRROR;
OPEN_DISPS(gfxCtx);
@ -428,25 +448,27 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
if (pauseCtx->cursorSpecialPos == 0) {
if ((pauseCtx->stickRelX > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
if ((!mirroredWorld && ((pauseCtx->stickRelX > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT)))) ||
(mirroredWorld && ((pauseCtx->stickRelX < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))))) {
D_8082A6D4 = 0;
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > 11) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 11;
KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_RIGHT);
KaleidoScope_MoveCursorToSpecialPos(play, !mirroredWorld ? PAUSE_CURSOR_PAGE_RIGHT : PAUSE_CURSOR_PAGE_LEFT);
break;
}
} while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0);
} else if ((pauseCtx->stickRelX < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
} else if ((!mirroredWorld && ((pauseCtx->stickRelX < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT)))) ||
(mirroredWorld && ((pauseCtx->stickRelX > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))))) {
D_8082A6D4 = 0;
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 0;
KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_LEFT);
KaleidoScope_MoveCursorToSpecialPos(play, !mirroredWorld ? PAUSE_CURSOR_PAGE_LEFT : PAUSE_CURSOR_PAGE_RIGHT);
break;
}
} while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0);
@ -461,11 +483,18 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
pauseCtx->cursorItem[PAUSE_MAP] = gSaveContext.worldMapArea + 0x18;
if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) {
if ((pauseCtx->stickRelX > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 0;
pauseCtx->cursorSpecialPos = 0;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
if (!mirroredWorld) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 0;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
}
} else {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 11;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
}
}
pauseCtx->cursorItem[PAUSE_MAP] = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
@ -476,11 +505,18 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
}
} else {
if ((pauseCtx->stickRelX < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 11;
pauseCtx->cursorSpecialPos = 0;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
if (!mirroredWorld) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 11;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
}
} else {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = 0;
while (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] == 0) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
}
}
pauseCtx->cursorItem[PAUSE_MAP] = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
@ -501,6 +537,16 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
}
}
// Use matrix scaling to flip the entire overworld map for mirror world
if (mirroredWorld) {
// Invert culling to counter act the matrix flip
gSPSetExtraGeometryMode(POLY_KAL_DISP++, G_EX_INVERT_CULLING);
Matrix_Push();
Matrix_Scale(-1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
Matrix_Pop();
}
gDPPipeSync(POLY_KAL_DISP++);
if (HREG(15) == 0) {
@ -708,6 +754,17 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
KaleidoScope_DrawCursor(play, PAUSE_MAP);
}
if (mirroredWorld) {
// Offset U value for current position area name texture into mirror boundary
for (i = 0; i < 4; i++) {
pauseCtx->mapPageVtx[176 + 4 + i].v.tc[0] += 80 << 5;
}
// Offset U value for "current position" texture into mirror boundary
for (i = 0; i < 4; i++) {
pauseCtx->mapPageVtx[176 + 8 + i].v.tc[0] += 64 << 5;
}
}
gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[176], 16, 0);
if (pauseCtx->tradeQuestLocation != 0xFF) {
@ -739,12 +796,17 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) {
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 0, 0, 0, pauseCtx->alpha);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, currentPosTitleTexs[gSaveContext.language], G_IM_FMT_I, 64, 8, 0,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gSP1Quadrangle(POLY_KAL_DISP++, 8, 10, 11, 9, 0);
gDPPipeSync(POLY_KAL_DISP++);
if (mirroredWorld) {
// Revert the inversion
gSPClearExtraGeometryMode(POLY_KAL_DISP++, G_EX_INVERT_CULLING);
}
CLOSE_DISPS(gfxCtx);
}

View File

@ -814,7 +814,8 @@ Gfx* KaleidoScope_QuadTextureIA4(Gfx* gfx, void* texture, s16 width, s16 height,
}
Gfx* KaleidoScope_QuadTextureIA8(Gfx* gfx, void* texture, s16 width, s16 height, u16 point) {
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP,
u8 mirrorMode = CVarGetInteger("gMirroredWorld", 0) ? G_TX_MIRROR : G_TX_NOMIRROR;
gDPLoadTextureBlock(gfx++, texture, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, mirrorMode | G_TX_WRAP,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gSP1Quadrangle(gfx++, point, point + 2, point + 3, point + 1, 0);
@ -3042,6 +3043,14 @@ void KaleidoScope_Draw(PlayState* play) {
func_800AAA50(&play->view, 15);
// Flip the OPA and XLU projections again as the set view call above reset the original flips from z_play
if (CVarGetInteger("gMirroredWorld", 0)) {
gSPMatrix(POLY_OPA_DISP++, play->view.projectionFlippedPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, play->view.projectionFlippedPtr, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_OPA_DISP++, play->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, play->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
}
CLOSE_DISPS(play->state.gfxCtx);
}

View File

@ -131,8 +131,11 @@ void PauseMapMark_DrawForDungeon(PlayState* play) {
markInfo->textureWidth, markInfo->textureHeight, 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);
// Compute the offset to mirror icons over the map center (48) as an axis line
s16 mirrorOffset = CVarGetInteger("gMirroredWorld", 0) ? mirrorOffset = (48 - markPoint->x) * 2 + 1 : 0;
Matrix_Push();
Matrix_Translate(GREG(92) + markPoint->x, GREG(93) + markPoint->y, 0.0f, MTXMODE_APPLY);
Matrix_Translate(GREG(92) + markPoint->x + mirrorOffset, GREG(93) + markPoint->y, 0.0f, MTXMODE_APPLY);
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);