Mirror Mode (#535)

* Mirror mode initial version

* Update mm/src/code/z_actor.c

Co-authored-by: Archez <Archez@users.noreply.github.com>

* mirror mode support for minimaps and dungeon pause map

* mirror mode support overworld pause map and song of soaring

* mirror mode support for various remaining things

* mirror mode support pause warp enhancement

* Add searchable menu item

---------

Co-authored-by: Archez <Archez@users.noreply.github.com>
Co-authored-by: Archez <archez39@me.com>
This commit is contained in:
Garrett Cox
2024-10-02 23:44:36 -04:00
committed by GitHub
co-authored by Archez Archez
parent 71c2c94ece
commit c474a82a94
26 changed files with 487 additions and 73 deletions
+8
View File
@@ -626,6 +626,14 @@ void DrawEnhancementsMenu() {
if (UIWidgets::CVarCheckbox("Time Moves When You Move", "gModes.TimeMovesWhenYouMove")) {
RegisterTimeMovesWhenYouMove();
}
if (UIWidgets::CVarCheckbox("Mirrored World", "gModes.MirroredWorld.Mode")) {
if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) {
CVarSetInteger("gModes.MirroredWorld.State", 1);
} else {
CVarClear("gModes.MirroredWorld.State");
}
}
ImGui::EndMenu();
}
+13 -1
View File
@@ -878,7 +878,19 @@ void AddEnhancements() {
"Time only moves when Link is not standing still.",
WIDGET_CVAR_CHECKBOX,
{},
([](widgetInfo& info) { RegisterTimeMovesWhenYouMove(); }) } },
([](widgetInfo& info) { RegisterTimeMovesWhenYouMove(); }) },
{ "Mirrored World",
"gModes.MirroredWorld.Mode",
"Mirrors the world horizontally.",
WIDGET_CVAR_CHECKBOX,
{},
([](widgetInfo& info) {
if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) {
CVarSetInteger("gModes.MirroredWorld.State", 1);
} else {
CVarClear("gModes.MirroredWorld.State");
}
}) } },
{ { .widgetName = "Saving", .widgetType = WIDGET_SEPARATOR_TEXT },
{ "Persistent Owl Saves", "gEnhancements.Saving.PersistentOwlSaves",
"Continuing a save will not remove the owl save. Playing Song of "
+1 -1
View File
@@ -172,7 +172,7 @@ void Camera_DebugCam(Camera* camera) {
if (CVarGetInteger("gEnhancements.Camera.DebugCam.6DOF", 0)) {
camera->roll += (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DLEFT) -
CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DRIGHT)) *
1200.0f * camSpeed;
1200.0f * camSpeed * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X);
} else {
camera->roll = Camera_ScaledStepToCeilS(0, camera->roll, 0.1f, 5);
}
@@ -268,16 +268,24 @@ int GameInteractor_InvertControl(GIInvertType type) {
break;
}
/*
// Invert all X axis inputs if the Mirrored World mode is enabled
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
switch (type) {
case GI_INVERT_CAMERA_RIGHT_STICK_X:
case GI_INVERT_MOVEMENT_X:
case GI_INVERT_FIRST_PERSON_AIM_X:
case GI_INVERT_SHIELD_X:
case GI_INVERT_SHOP_X:
case GI_INVERT_HORSE_X:
case GI_INVERT_ZORA_SWIM_X:
case GI_INVERT_DEBUG_DPAD_X:
case GI_INVERT_TELESCOPE_X:
result *= -1;
break;
default:
break;
}
}
*/
/*
if (CrowdControl::State::InvertedInputs) {
@@ -67,6 +67,14 @@ typedef enum {
typedef enum {
GI_INVERT_CAMERA_RIGHT_STICK_X,
GI_INVERT_CAMERA_RIGHT_STICK_Y,
GI_INVERT_MOVEMENT_X,
GI_INVERT_FIRST_PERSON_AIM_X,
GI_INVERT_SHIELD_X,
GI_INVERT_SHOP_X,
GI_INVERT_HORSE_X,
GI_INVERT_ZORA_SWIM_X,
GI_INVERT_DEBUG_DPAD_X,
GI_INVERT_TELESCOPE_X,
} GIInvertType;
typedef enum {
+4 -2
View File
@@ -31,6 +31,7 @@ typedef struct {
static std::vector<NameTag> nameTags;
static std::vector<Gfx> nameTagDl;
static bool sMirrorWorldActive = false;
void NameTag_RegisterHooks();
@@ -94,8 +95,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
// Set position, billboard effect, scale (with mirror mode), then center nametag
Matrix_Translate(nameTag->actor->world.pos.x, posY, nameTag->actor->world.pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF);
// BENTODO: Apply mirror world flipping to X scale
Matrix_Scale(scale, -scale, 1.0f, MTXMODE_APPLY);
Matrix_Scale(scale * (sMirrorWorldActive ? -1.0f : 1.0f), -scale, 1.0f, MTXMODE_APPLY);
Matrix_Translate(-(float)nameTag->width / 2, -nameTag->height, 0, MTXMODE_APPLY);
Matrix_ToMtx(nameTag->mtx);
@@ -206,6 +206,8 @@ void UpdateNameTags() {
return aDistToCamera > bDistToCamera;
});
sMirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0);
}
extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options) {
+82 -52
View File
@@ -66,71 +66,101 @@ void HandleConfirmingState(PauseContext* pauseCtx, Input* input) {
}
}
// This is a variation of KaleidoScope_UpdateWorldMapCursor that deals with the warp points instead of region points
// and supports mirror mode
void UpdateCursorForOwlWarpPoints(PauseContext* pauseCtx) {
if (pauseCtx->cursorSpecialPos == 0) {
if (pauseCtx->stickAdjX > 30) {
if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) &&
(pauseCtx->pageIndex == PAUSE_MAP)) {
InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx;
s16 oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
bool mirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0);
bool goingLeft = pauseCtx->stickAdjX < -30;
bool goingRight = pauseCtx->stickAdjX > 30;
// Handle moving off page buttons
if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && goingRight) {
pauseCtx->cursorSpecialPos = 0;
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = mirrorWorldActive ? OWL_WARP_STONE_TOWER + 1 : REGION_NONE;
Audio_PlaySfx(NA_SE_SY_CURSOR);
} else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && goingLeft) {
pauseCtx->cursorSpecialPos = 0;
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = mirrorWorldActive ? REGION_NONE : OWL_WARP_STONE_TOWER + 1;
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
// Handle updating cursor color and A button action
if (pauseCtx->cursorSpecialPos == 0) {
pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_BLUE;
if (gSaveContext.buttonStatus[EQUIP_SLOT_A] == BTN_DISABLED) {
gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_ENABLED;
gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE;
Interface_SetHudVisibility(HUD_VISIBILITY_ALL);
}
if (!sIsConfirming && interfaceCtx->aButtonHorseDoAction != DO_ACTION_WARP) {
Interface_SetAButtonDoAction(gPlayState, DO_ACTION_WARP);
}
} else {
pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE;
if (gSaveContext.buttonStatus[EQUIP_SLOT_A] != BTN_DISABLED) {
gSaveContext.buttonStatus[EQUIP_SLOT_A] = BTN_DISABLED;
gSaveContext.hudVisibility = HUD_VISIBILITY_IDLE;
Interface_SetHudVisibility(HUD_VISIBILITY_ALL);
}
if (interfaceCtx->aButtonHorseDoAction != DO_ACTION_INFO) {
Interface_SetAButtonDoAction(gPlayState, DO_ACTION_INFO);
}
}
// Handle mirror mode flip and starting cursor movement
if (pauseCtx->cursorSpecialPos == 0 && (goingLeft || goingRight)) {
pauseCtx->cursorShrinkRate = 4.0f;
sStickAdjTimer = 0;
if (mirrorWorldActive) {
goingLeft = !goingLeft;
goingRight = !goingRight;
}
}
// Actually move the cursor
if (goingRight) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) {
KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT);
return;
KaleidoScope_MoveCursorToSpecialPos(gPlayState, mirrorWorldActive ? PAUSE_CURSOR_PAGE_LEFT
: PAUSE_CURSOR_PAGE_RIGHT);
pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE;
break;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) {
pauseCtx->cursorItem[PAUSE_MAP] =
sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY;
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
} else if (pauseCtx->stickAdjX < -30) {
pauseCtx->cursorShrinkRate = 4.0f;
sStickAdjTimer = 0;
} else if (goingLeft) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < OWL_WARP_GREAT_BAY_COAST) {
KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT);
return;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] <= REGION_NONE) {
KaleidoScope_MoveCursorToSpecialPos(gPlayState, mirrorWorldActive ? PAUSE_CURSOR_PAGE_RIGHT
: PAUSE_CURSOR_PAGE_LEFT);
pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE;
break;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
if (pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) {
pauseCtx->cursorItem[PAUSE_MAP] =
sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY;
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
} else {
sStickAdjTimer++;
}
} else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && pauseCtx->stickAdjX > 30) {
KaleidoScope_MoveCursorFromSpecialPos(gPlayState);
for (int i = OWL_WARP_GREAT_BAY_COAST; i <= OWL_WARP_STONE_TOWER; i++) {
if (pauseCtx->worldMapPoints[i]) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i;
pauseCtx->cursorItem[PAUSE_MAP] =
sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY;
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
KaleidoScope_UpdateWorldMapCursor(gPlayState);
KaleidoScope_UpdateNamePanel(gPlayState);
return;
}
// Updates name panel and cursor slot
if (pauseCtx->cursorSpecialPos == 0) {
// Offset from `ITEM_MAP_POINT_GREAT_BAY` is to get the correct ordering in `map_name_static`
pauseCtx->cursorItem[PAUSE_MAP] =
sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY;
// Used as cursor vtxIndex
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
}
KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_RIGHT);
} else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && pauseCtx->stickAdjX < -30) {
KaleidoScope_MoveCursorFromSpecialPos(gPlayState);
for (int i = OWL_WARP_STONE_TOWER; i >= OWL_WARP_GREAT_BAY_COAST; i--) {
if (pauseCtx->worldMapPoints[i]) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = i;
pauseCtx->cursorItem[PAUSE_MAP] =
sOwlWarpPauseItems[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]] - ITEM_MAP_POINT_GREAT_BAY;
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
KaleidoScope_UpdateWorldMapCursor(gPlayState);
KaleidoScope_UpdateNamePanel(gPlayState);
return;
}
if (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]) {
pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE;
}
if (oldCursorPoint != pauseCtx->cursorPoint[PAUSE_WORLD_MAP]) {
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT);
}
}
@@ -219,4 +249,4 @@ void RegisterPauseOwlWarp() {
HandlePauseOwlWarp(pauseCtx);
}
});
}
}
+1
View File
@@ -1330,6 +1330,7 @@ void PadMgr_ThreadEntry();
void Heaps_Alloc(void);
void KaleidoScope_UpdateOwlWarpNamePanel(PlayState* play);
void KaleidoScope_UpdateNamePanel(PlayState* play);
void SkinMatrix_Clear(MtxF* mf);
// #endregion
// #region 2S2H [Port] New methods added for porting
void AudioSeq_SetPortVolumeScale(u8 seqPlayerIndex, f32 volume);
+1
View File
@@ -41,6 +41,7 @@ typedef struct View {
/* 0x15C */ u16 perspNorm; // used to normalize the projection matrix
/* 0x160 */ u32 flags; // bit 3: Render to an orthographic perspective
/* 0x164 */ s32 unk164;
/* */ Mtx* shipMirrorProjectionPtr;
} View; // size = 0x168
#define VIEW_VIEWING (1 << 0)
+5 -1
View File
@@ -867,7 +867,11 @@ Acmd* AudioSynth_ProcessSamples(s16* aiBuf, s32 numSamplesPerUpdate, Acmd* cmd,
}
size = numSamplesPerUpdate * SAMPLE_SIZE;
aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, size);
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
aInterleave(cmd++, DMEM_TEMP, DMEM_RIGHT_CH, DMEM_LEFT_CH, size);
} else {
aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, size);
}
if (gAudioCustomSynthFunction != NULL) {
cmd = gAudioCustomSynthFunction(cmd, 2 * size, updateIndex);
+4
View File
@@ -1402,6 +1402,10 @@ void func_800B6F20(PlayState* play, Input* input, f32 magnitude, s16 baseYaw) {
s16 relativeYaw = baseYaw - Camera_GetInputDirYaw(GET_ACTIVE_CAM(play));
input->cur.stick_x = -Math_SinS(relativeYaw) * magnitude;
// 2S2H [Enhancement] Allow inverting the X axis with GI, primarily for mirror mode,
// otherwise link moves in the opposite direction and likely get soft locked, and
// kafei turns the wrong direction as he paths.
input->cur.stick_x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X);
input->rel.stick_x = input->cur.stick_x;
input->cur.stick_y = Math_CosS(relativeYaw) * magnitude;
input->rel.stick_y = input->cur.stick_y;
+3
View File
@@ -3326,6 +3326,9 @@ void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) {
if ((scale >= 1.0f) && (imgX > -adjustedXBounds) && (imgX < adjustedXBounds) && (imgY > -1.0f) &&
(imgY < 1.0f)) {
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
imgX *= -1.0f;
}
// #endregion
imgX = (imgX * (SCREEN_WIDTH / 2)) + (SCREEN_WIDTH / 2);
imgY = (imgY * -(SCREEN_HEIGHT / 2)) + (SCREEN_HEIGHT / 2);
+4
View File
@@ -1,5 +1,7 @@
#include "global.h"
#include <libultraship/bridge.h>
#include "BenPort.h"
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
f32 Math_CosS(s16 angle) {
return coss(angle) * SHT_MINV;
@@ -223,12 +225,14 @@ void Lib_GetControlStickData(f32* outMagnitude, s16* outAngle, Input* input) {
f32 y = input->rel.stick_y;
f32 magnitude;
x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X);
magnitude = sqrtf(SQ(x) + SQ(y));
*outMagnitude = (60.0f < magnitude) ? 60.0f : magnitude;
if (magnitude > 0.0f) {
x = input->cur.stick_x;
y = input->cur.stick_y;
x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X);
*outAngle = Math_Atan2S_XY(y, -x);
} else {
*outAngle = 0;
+59 -1
View File
@@ -156,6 +156,31 @@ static const char* sMapGrandTextures[] = {
map_grand_static_Blob_034BB0, map_grand_static_Blob_034F50,
};
static bool sMirrorWorldActive = false;
static u16 sOriginalMapDataRoomFlags[32] = { 0 };
s32 Ship_MapModifyPosMirrorMode(s32 pos, s32 offset) {
if (sMirrorWorldActive) {
pos -= offset;
pos *= -1;
pos += offset;
}
return pos;
}
void Ship_MapDispUpdateMirrorMode() {
sMirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0);
for (s32 i = 0; i < sSceneNumRooms; i++) {
sMapDataRooms[i].flags = sOriginalMapDataRoomFlags[i];
if (sMirrorWorldActive) {
// Toggle the bit in case the scene already has this flag set, this way the map is still "flipped" visually
sMapDataRooms[i].flags ^= MAP_DATA_ROOM_FLIP_X;
}
}
}
// BENTODO, can we just set dest insetead of doing a memcpy?
void MapDisp_GetMapITexture(void* dst, s32 mapCompactId) {
s32 mapSize = MapDisp_GetSizeOfMapITex(mapCompactId);
@@ -414,6 +439,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) {
sMapDisp.minimapCurY - sMapDisp.minimapBaseY + texOffsetY;
}
posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX +
texOffsetX);
// 2S2H [Cosmetic] Widescreen support
if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) {
// #region 2S2H [Cosmetic] Hud Editor override actor values and use them below
@@ -449,6 +477,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) {
if (MapDisp_IsDataRotated(play)) {
compassRot += 0x7FFF;
}
if (sMirrorWorldActive) {
compassRot *= -1;
}
Matrix_RotateYF(compassRot / 10.0f, MTXMODE_APPLY);
Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY);
// #region 2S2H [Cosmetic] Hud Editor yellow compass matrix scale on x and z
@@ -586,6 +617,9 @@ void MapDisp_Minimap_DrawDoorActor(PlayState* play, Actor* actor) {
texOffsetY;
}
posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX +
texOffsetX);
// 2S2H [Cosmetic] Widescreen support
if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) {
OPEN_DISPS(play->state.gfxCtx);
@@ -893,6 +927,8 @@ void MapDisp_InitMapData(PlayState* play, void* segmentAddress) {
for (i = 0; i < sSceneNumRooms; i++) {
sMapDataRooms[i] = *mapDataRooms++;
// 2S2H [Enhancement] Track original flags to that we can make modifications mid-scene
sOriginalMapDataRoomFlags[i] = sMapDataRooms[i].flags;
}
sMapDataScene.rooms = sMapDataRooms;
@@ -996,6 +1032,7 @@ void MapDisp_Update(PlayState* play) {
s16 targetY;
if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0)) {
Ship_MapDispUpdateMirrorMode();
// #region 2S2H [Cosmetic] Hud Editor minimap base position
// This value is used to determine the relative positioning for all the other elements
MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom];
@@ -1161,6 +1198,8 @@ void MapDisp_SwapRooms(s16 nextRoom) {
(f32)prevOffsetY);
}
sMapDisp.minimapPrevX = Ship_MapModifyPosMirrorMode(sMapDisp.minimapPrevX, offsetX - prevOffsetX);
sMapDisp.minimapCurX = minimapBaseX - sMapDisp.minimapPrevX;
sMapDisp.minimapCurY = minimapBaseY - sMapDisp.minimapPrevY;
}
@@ -1243,6 +1282,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot)
(sMapDisp.minimapCurY - sMapDisp.minimapBaseY) + texOffsetY;
}
posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX +
texOffsetX);
// 2S2H [Cosmetic] Widescreen support
if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) {
// 2S2H [Cosmetic] Hud Editor red compass position
@@ -1264,6 +1306,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot)
if (MapDisp_IsDataRotated(play)) {
rot += 0x7FFF;
}
if (sMirrorWorldActive) {
rot *= -1;
}
Matrix_RotateYF(rot / 10.0f, MTXMODE_APPLY);
Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY);
// #region 2S2H [Cosmetic] Hud Editor red compass scale the matrix in x and z
@@ -1642,7 +1687,10 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32
if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) {
offsetX = ((texWidth / 2) - offsetX) + (texWidth / 2);
s = (texWidth - 1) << 5;
// 2S2H [Port] The width originally was subtracted by 1, but this caused the flipped texture to overflow on
// the edge. There are no vanilla scenes that leverage this, so its possibly an authentic bug.
// Removing it will allow the texture to display correctly for things like Mirror Mode.
s = (texWidth - 0) << 5;
dsdx = 0xFC00;
} else {
s = 0;
@@ -1665,6 +1713,8 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32
texPosY =
((mapDataRoom->centerZ - (f32)sMapDisp.sceneMidZ) * scaleFrac - offsetY) + ((viewHeight / two) + viewY);
texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / two) + viewX));
if (i == play->roomCtx.curRoom.num) {
if (Map_IsInBossScene(play)) {
gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 1,
@@ -1781,6 +1831,8 @@ void MapDisp_DrawChests(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s3
texPosY = (s32)((((mapDataChests[i].z - (f32)sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) +
((viewHeight / 2) + viewY));
texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX));
gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
@@ -1833,6 +1885,9 @@ void MapDisp_DrawRoomExits(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth,
((viewWidth / 2) + viewX);
texPosY = ((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac +
((viewHeight / 2) + viewY);
texPosX = Ship_MapModifyPosMirrorMode(texPosX, ((viewWidth / 2) + viewX));
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);
@@ -1894,6 +1949,9 @@ void MapDisp_DrawBossIcon(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth,
((viewWidth / 2) + viewX);
texPosY = ((((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) +
((viewHeight / 2) + viewY);
texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX));
gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
+8
View File
@@ -8610,7 +8610,15 @@ void Interface_Draw(PlayState* play) {
Map_DrawMinimap(play);
if ((R_PAUSE_BG_PRERENDER_STATE != 2) && (R_PAUSE_BG_PRERENDER_STATE != 3)) {
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.shipMirrorProjectionPtr,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
}
Target_Draw(&play->actorCtx.targetCtx, play);
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.projectionPtr,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
}
}
Gfx_SetupDL39_Overlay(play->state.gfxCtx);
+17
View File
@@ -1248,6 +1248,18 @@ void Play_DrawMain(PlayState* this) {
View_Apply(&this->view, 0xF);
// Setup mirror mode matrix handling when we are not drawing kaleido
if (R_PAUSE_BG_PRERENDER_STATE <= PAUSE_BG_PRERENDER_SETUP && CVarGetInteger("gModes.MirroredWorld.State", 0)) {
gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
gSPMatrix(POLY_OPA_DISP++, this->view.shipMirrorProjectionPtr,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, this->view.shipMirrorProjectionPtr,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(POLY_OPA_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
}
// The billboard matrix temporarily stores the viewing matrix
Matrix_MtxToMtxF(&this->view.viewing, &this->billboardMtxF);
Matrix_MtxToMtxF(&this->view.projection, &this->viewProjectionMtxF);
@@ -1523,6 +1535,11 @@ void Play_DrawMain(PlayState* this) {
Play_PostWorldDraw(this);
}
}
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING);
}
}
SkipPostWorldDraw:
+41
View File
@@ -325,6 +325,7 @@ s32 View_ApplyPerspective(View* view) {
s32 height;
Vp* vp;
Mtx* projection;
Mtx* projectionFlipped;
Mtx* viewing;
GraphicsContext* gfxCtx = view->gfxCtx;
@@ -342,13 +343,26 @@ s32 View_ApplyPerspective(View* view) {
// Perspective projection
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
view->projectionPtr = projection;
view->shipMirrorProjectionPtr = projectionFlipped;
width = view->viewport.rightX - view->viewport.leftX;
height = view->viewport.bottomY - view->viewport.topY;
aspect = (f32)width / (f32)height;
guPerspective(projection, &view->perspNorm, view->fovy, aspect, view->zNear, view->zFar, view->scale);
if (CVarGetInteger("gModes.MirroredWorld.State", 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;
View_StepDistortion(view, projection);
@@ -450,6 +464,7 @@ s32 View_ApplyPerspective(View* view) {
s32 View_ApplyOrtho(View* view) {
Vp* vp;
Mtx* projection;
Mtx* projectionFlipped;
GraphicsContext* gfxCtx = view->gfxCtx;
OPEN_DISPS(gfxCtx);
@@ -465,11 +480,23 @@ s32 View_ApplyOrtho(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
view->projectionPtr = projection;
view->shipMirrorProjectionPtr = projectionFlipped;
guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f,
view->zNear, view->zFar, view->scale);
// if (CVarGetInteger("gModes.MirroredWorld.State", 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(POLY_OPA_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
@@ -486,6 +513,7 @@ s32 View_ApplyOrtho(View* view) {
s32 View_ApplyOrthoToOverlay(View* view) {
Vp* vp;
Mtx* projection;
Mtx* projectionFlipped;
GraphicsContext* gfxCtx;
gfxCtx = view->gfxCtx;
@@ -509,10 +537,23 @@ s32 View_ApplyOrthoToOverlay(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
view->projectionPtr = projection;
view->shipMirrorProjectionPtr = projectionFlipped;
guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f,
view->zNear, view->zFar, view->scale);
if (CVarGetInteger("gModes.MirroredWorld.State", 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);
@@ -6,6 +6,7 @@
#include "z_en_fsn.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10)
@@ -452,6 +453,10 @@ void EnFsn_UpdateCursorPos(EnFsn* this, PlayState* play) {
this->cursorPos.x = x + xOffset;
this->cursorPos.y = y + yOffset;
this->cursorPos.z = 1.2f;
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x;
}
}
s32 EnFsn_FacingShopkeeperDialogResult(EnFsn* this, PlayState* play) {
@@ -509,6 +514,8 @@ void EnFsn_UpdateJoystickInputState(EnFsn* this, PlayState* play) {
s8 stickX = CONTROLLER1(&play->state)->rel.stick_x;
s8 stickY = CONTROLLER1(&play->state)->rel.stick_y;
stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X);
if (this->stickAccumX == 0) {
if ((stickX > 30) || (stickX < -30)) {
this->stickAccumX = stickX;
@@ -1602,6 +1609,11 @@ void EnFsn_DrawStickDirectionPrompts(EnFsn* this, PlayState* play) {
s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled;
s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled;
if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) {
drawStickLeftPrompt = !drawStickLeftPrompt;
drawStickRightPrompt = !drawStickRightPrompt;
}
OPEN_DISPS(play->state.gfxCtx);
if (drawStickRightPrompt || drawStickLeftPrompt) {
@@ -267,6 +267,11 @@ void EnGakufu_Draw(Actor* thisx, PlayState* play) {
gDPPipeSync(POLY_XLU_DISP++);
gSPSegment(POLY_XLU_DISP++, 0x02, play->interfaceCtx.parameterSegment);
// Invert the whole music staff, so the notes appear correctly in mirrored world
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
Matrix_Scale(-1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
}
for (i = 0; (i < ARRAY_COUNT(this->buttonIndex)) && (this->buttonIndex[i] != OCARINA_BTN_INVALID); i++) {
Matrix_Push();
Matrix_Translate(30 * i - 105, sOcarinaBtnWallYOffsets[this->buttonIndex[i]] * 7.5f, 1.0f, MTXMODE_APPLY);
@@ -12,6 +12,7 @@
#include "overlays/actors/ovl_Obj_Um/z_obj_um.h"
#include "overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.h"
#include "objects/object_horse_link_child/object_horse_link_child.h"
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
#define FLAGS (ACTOR_FLAG_10)
@@ -3691,6 +3692,8 @@ void EnHorse_UpdateStick(EnHorse* this, PlayState* play) {
this->lastStick = this->curStick;
this->curStick.x = input->rel.stick_x;
this->curStick.z = input->rel.stick_y;
this->curStick.x *= GameInteractor_InvertControl(GI_INVERT_HORSE_X);
}
void EnHorse_ResolveCollision(EnHorse* this, PlayState* play, CollisionPoly* colPoly) {

Some files were not shown because too many files have changed in this diff Show More