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 22:44:36 -05:00 committed by GitHub
parent 71c2c94ece
commit c474a82a94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 487 additions and 73 deletions

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();
}

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 "

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);
}

View File

@ -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) {

View File

@ -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 {

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) {

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->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) {
if (pauseCtx->stickAdjX > 30) {
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]]) {
}
// 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];
}
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);
}
} 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;
}
}
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;
}
}
KaleidoScope_MoveCursorToSpecialPos(gPlayState, PAUSE_CURSOR_PAGE_LEFT);
}
}

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);

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)

View File

@ -867,7 +867,11 @@ Acmd* AudioSynth_ProcessSamples(s16* aiBuf, s32 numSamplesPerUpdate, Acmd* cmd,
}
size = numSamplesPerUpdate * SAMPLE_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);

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;

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);

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;

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);
}

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);

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:

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);

View File

@ -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) {

View File

@ -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);

View File

@ -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) {

View File

@ -6,6 +6,7 @@
#include "z_en_ossan.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)
@ -298,6 +299,10 @@ void EnOssan_UpdateCursorPos(PlayState* play, EnOssan* this) {
Actor_GetScreenPos(play, &this->items[this->cursorIndex]->actor, &x, &y);
this->cursorPos.x = x;
this->cursorPos.y = y;
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
this->cursorPos.x = SCREEN_WIDTH - this->cursorPos.x;
}
}
void EnOssan_EndInteraction(PlayState* play, EnOssan* this) {
@ -465,6 +470,8 @@ void EnOssan_UpdateJoystickInputState(PlayState* play, EnOssan* this) {
s8 stickX = CONTROLLER1(&play->state)->rel.stick_x;
s8 stickY = CONTROLLER1(&play->state)->rel.stick_y;
stickX *= GameInteractor_InvertControl(GI_INVERT_SHOP_X);
this->moveHorizontal = this->moveVertical = false;
if (this->stickAccumX == 0) {
@ -1680,6 +1687,11 @@ void EnOssan_DrawStickDirectionPrompts(PlayState* play, EnOssan* this) {
s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled;
s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled;
if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) {
drawStickLeftPrompt = !drawStickLeftPrompt;
drawStickRightPrompt = !drawStickRightPrompt;
}
(void)"../z_en_oB1.c";
OPEN_DISPS(play->state.gfxCtx);

View File

@ -8,6 +8,7 @@
#include "objects/object_mastergolon/object_mastergolon.h"
#include "objects/object_masterzoora/object_masterzoora.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)
@ -456,6 +457,10 @@ void EnSob1_UpdateCursorPos(PlayState* play, EnSob1* this) {
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;
}
}
void EnSob1_EndInteraction(PlayState* play, EnSob1* this) {
@ -584,6 +589,8 @@ void EnSob1_UpdateJoystickInputState(PlayState* play, EnSob1* this) {
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;
@ -1579,6 +1586,11 @@ void EnSob1_DrawStickDirectionPrompt(PlayState* play, EnSob1* this) {
s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled;
s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled;
if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) {
drawStickLeftPrompt = !drawStickLeftPrompt;
drawStickRightPrompt = !drawStickRightPrompt;
}
(void)"../z_en_soB1.c";
OPEN_DISPS(play->state.gfxCtx);

View File

@ -7,6 +7,7 @@
#include "z_en_trt.h"
#include "objects/object_trt/object_trt.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY)
@ -166,6 +167,10 @@ void EnTrt_UpdateCursorPos(PlayState* play, EnTrt* this) {
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;
}
}
void EnTrt_SetupGetMushroomCutscene(EnTrt* this) {
@ -273,6 +278,8 @@ void EnTrt_UpdateJoystickInputState(PlayState* play, EnTrt* this) {
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;
@ -1657,6 +1664,11 @@ void EnTrt_DrawStickDirectionPrompt(PlayState* play, EnTrt* this) {
s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled;
s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled;
if (CVarGetInteger("gModes.MirroredWorld.State", 0) && (drawStickLeftPrompt != drawStickRightPrompt)) {
drawStickLeftPrompt = !drawStickLeftPrompt;
drawStickRightPrompt = !drawStickRightPrompt;
}
(void)"../z_en_trt.c";
OPEN_DISPS(play->state.gfxCtx);

View File

@ -8330,6 +8330,7 @@ void func_8083A98C(Actor* thisx, PlayState* play2) {
// Yaw: shape.rot.y is used as a fixed starting position
inputX = sPlayerControlInput->rel.stick_x * -4;
inputX *= GameInteractor_InvertControl(GI_INVERT_TELESCOPE_X);
// Start from current position: no input -> no change
newYaw = thisx->focus.rot.y - thisx->shape.rot.y;
// Add input, clamped to prevent turning too fast
@ -12562,9 +12563,9 @@ s32 Player_UpdateNoclip(Player* this, PlayState* play) {
if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DDOWN)) {
angle = temp + 0x8000;
} else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DLEFT)) {
angle = temp + 0x4000;
angle = temp + 0x4000 * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X);
} else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_DRIGHT)) {
angle = temp - 0x4000;
angle = temp - 0x4000 * GameInteractor_InvertControl(GI_INVERT_DEBUG_DPAD_X);
}
this->actor.world.pos.x += speed * Math_SinS(angle);
@ -13006,12 +13007,15 @@ void Player_Destroy(Actor* thisx, PlayState* play) {
s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
s32 pad;
s16 var_s0;
s32 stickX = sPlayerControlInput->rel.stick_x;
stickX *= GameInteractor_InvertControl(GI_INVERT_FIRST_PERSON_AIM_X);
if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) {
var_s0 = sPlayerControlInput->rel.stick_y * 0xF0;
Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E);
var_s0 = sPlayerControlInput->rel.stick_x * -0x10;
var_s0 = stickX * -0x10;
var_s0 = CLAMP(var_s0, -0xBB8, 0xBB8);
this->actor.focus.rot.y += var_s0;
} else {
@ -13028,8 +13032,7 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
}
var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y;
temp3 = ((sPlayerControlInput->rel.stick_x >= 0) ? 1 : -1) *
(s32)((1.0f - Math_CosS(sPlayerControlInput->rel.stick_x * 0xC8)) * -1500.0f);
temp3 = ((stickX >= 0) ? 1 : -1) * (s32)((1.0f - Math_CosS(stickX * 0xC8)) * -1500.0f);
var_s0 += temp3;
this->actor.focus.rot.y = CLAMP(var_s0, -0x4AAA, 0x4AAA) + this->actor.shape.rot.y;
@ -14630,6 +14633,7 @@ void Player_Action_18(Player* this, PlayState* play) {
s16 var_a2;
s16 var_a3;
xStick *= GameInteractor_InvertControl(GI_INVERT_SHIELD_X);
var_a1 = (yStick * Math_CosS(temp_a0)) + (Math_SinS(temp_a0) * xStick);
temp_ft5 = (xStick * Math_CosS(temp_a0)) - (Math_SinS(temp_a0) * yStick);
@ -16006,6 +16010,8 @@ void Player_Action_50(Player* this, PlayState* play) {
PlayerAnimationHeader* anim1;
PlayerAnimationHeader* anim2;
xStick *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X);
this->fallStartHeight = this->actor.world.pos.y;
this->stateFlags2 |= PLAYER_STATE2_40;
@ -16564,11 +16570,14 @@ void func_80850BA8(Player* this) {
void func_80850BF8(Player* this, f32 arg1) {
f32 temp_fv0;
s16 temp_ft0;
s8 stickX = sPlayerControlInput->rel.stick_x;
stickX *= GameInteractor_InvertControl(GI_INVERT_ZORA_SWIM_X);
Math_AsymStepToF(&this->unk_B48, arg1, 1.0f, (fabsf(this->unk_B48) * 0.01f) + 0.4f);
temp_fv0 = Math_CosS(sPlayerControlInput->rel.stick_x * 0x10E);
temp_fv0 = Math_CosS(stickX * 0x10E);
temp_ft0 = (((sPlayerControlInput->rel.stick_x >= 0) ? 1 : -1) * (1.0f - temp_fv0) * -1100.0f);
temp_ft0 = (((stickX >= 0) ? 1 : -1) * (1.0f - temp_fv0) * -1100.0f);
temp_ft0 = CLAMP(temp_ft0, -0x1F40, 0x1F40);
this->currentYaw += temp_ft0;
@ -16585,6 +16594,9 @@ void Player_Action_56(Player* this, PlayState* play) {
s16 sp3E;
s16 sp3C;
s16 sp3A;
s8 stickX = sPlayerControlInput->rel.stick_x;
stickX *= GameInteractor_InvertControl(GI_INVERT_ZORA_SWIM_X);
this->stateFlags2 |= PLAYER_STATE2_20;
@ -16634,7 +16646,7 @@ void Player_Action_56(Player* this, PlayState* play) {
}
}
Math_SmoothStepToS(&this->unk_B86[1], sPlayerControlInput->rel.stick_x * 0xC8, 0xA, 0x3E8, 0x64);
Math_SmoothStepToS(&this->unk_B86[1], stickX * 0xC8, 0xA, 0x3E8, 0x64);
Math_SmoothStepToS(&this->unk_B8E, this->unk_B86[1], IREG(40) + 1, IREG(41), IREG(42));
} else if (this->unk_B86[0] == 0) {
PlayerAnimation_Update(play, &this->skelAnime);
@ -16662,7 +16674,7 @@ void Player_Action_56(Player* this, PlayState* play) {
Math_SmoothStepToS(&this->unk_AAA, sp3E, 4, 0xFA0, 0x190);
// X
sp42 = sPlayerControlInput->rel.stick_x * 0x64;
sp42 = stickX * 0x64;
if (Math_ScaledStepToS(&this->unk_B8A, sp42, 0x384) && (sp42 == 0)) {
Math_SmoothStepToS(&this->unk_B86[1], 0, 4, 0x5DC, 0x64);
Math_SmoothStepToS(&this->unk_B8E, this->unk_B86[1], IREG(44) + 1, IREG(45), IREG(46));

View File

@ -550,6 +550,18 @@ void KaleidoScope_DrawWorldMap(PlayState* play) {
OPEN_DISPS(play->state.gfxCtx);
// Use matrix scaling to flip the entire overworld map for mirror world
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
// Invert culling to counter act the matrix flip
gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
Matrix_Push();
// We need to shift the matrix a little to the left before flipping it so that it aligns in the same spot
Matrix_Translate(-2.0f, 0.0f, 0.0f, MTXMODE_APPLY);
Matrix_Scale(-1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
Matrix_Pop();
}
KaleidoScope_SetCursorVtxPos(pauseCtx, pauseCtx->cursorSlot[PAUSE_MAP] * 4, pauseCtx->mapPageVtx);
// Draw the world map image
@ -852,14 +864,24 @@ void KaleidoScope_DrawWorldMap(PlayState* play) {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
POLY_OPA_DISP =
Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16, sWorldMapCursorsRectLeft[n],
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
POLY_OPA_DISP = Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16,
(SCREEN_WIDTH - sWorldMapCursorsRectLeft[n] - 16 - 1),
sWorldMapCursorsRectTop[n], 16, 16, 1 << 10, 1 << 10);
} else {
POLY_OPA_DISP = Gfx_DrawTexRectRGBA16(POLY_OPA_DISP, gQuestIconLinkHumanFaceTex, 16, 16,
sWorldMapCursorsRectLeft[n], sWorldMapCursorsRectTop[n], 16, 16,
1 << 10, 1 << 10);
}
}
}
gDPPipeSync(POLY_OPA_DISP++);
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);
}
CLOSE_DISPS(play->state.gfxCtx);
}
@ -876,11 +898,122 @@ u16 sOwlWarpPauseItems[] = {
ITEM_MAP_POINT_STONE_TOWER, // OWL_WARP_STONE_TOWER
};
// 2S2H [Enhancement] Same as KaleidoScope_UpdateWorldMapCursor but with behavior and controls inverted to account for
// mirrored world being used
void Ship_UpdateWorldMapCursorMirrorWorld(PlayState* play) {
PauseContext* pauseCtx = &play->pauseCtx;
s16 oldCursorPoint;
bool goingLeft = pauseCtx->stickAdjX < -30;
bool goingRight = pauseCtx->stickAdjX > 30;
if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) &&
(pauseCtx->pageIndex == PAUSE_MAP) && !PauseOwlWarp_IsOwlWarpEnabled()) {
pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE;
oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
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 (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT && goingRight) {
pauseCtx->cursorSpecialPos = 0;
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = REGION_MAX;
Audio_PlaySfx(NA_SE_SY_CURSOR);
} else if (pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT && goingLeft) {
pauseCtx->cursorSpecialPos = 0;
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = REGION_NONE;
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
if (pauseCtx->cursorSpecialPos == 0 && (goingLeft || goingRight)) {
pauseCtx->cursorShrinkRate = 4.0f;
goingLeft = !goingLeft;
goingRight = !goingRight;
}
if (goingRight) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] >= REGION_MAX) {
KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_LEFT);
pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE;
break;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
} else if (goingLeft) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] <= REGION_NONE) {
KaleidoScope_MoveCursorToSpecialPos(play, PAUSE_CURSOR_PAGE_RIGHT);
pauseCtx->cursorItem[PAUSE_MAP] = PAUSE_ITEM_NONE;
break;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
}
if (pauseCtx->cursorSpecialPos == 0) {
pauseCtx->cursorItem[PAUSE_MAP] = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
// Used as cursor vtxIndex
pauseCtx->cursorSlot[PAUSE_MAP] = 31 + pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
}
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);
}
} else if (pauseCtx->state == PAUSE_STATE_OWLWARP_SELECT) {
pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_BLUE;
oldCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
if (goingLeft || goingRight) {
pauseCtx->cursorShrinkRate = 4.0f;
goingLeft = !goingLeft;
goingRight = !goingRight;
}
if (goingRight) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]++;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] > OWL_WARP_STONE_TOWER) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = OWL_WARP_GREAT_BAY_COAST;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
} else if (goingLeft) {
do {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP]--;
if (pauseCtx->cursorPoint[PAUSE_WORLD_MAP] < OWL_WARP_GREAT_BAY_COAST) {
pauseCtx->cursorPoint[PAUSE_WORLD_MAP] = OWL_WARP_STONE_TOWER;
}
} while (!pauseCtx->worldMapPoints[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]]);
}
// 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];
if (oldCursorPoint != pauseCtx->cursorPoint[PAUSE_WORLD_MAP]) {
Audio_PlaySfx(NA_SE_SY_CURSOR);
}
}
}
void KaleidoScope_UpdateWorldMapCursor(PlayState* play) {
static u16 sStickAdjTimer = 0; // unused timer that counts up every frame. Resets on reading a stickAdj.
PauseContext* pauseCtx = &play->pauseCtx;
s16 oldCursorPoint;
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
Ship_UpdateWorldMapCursorMirrorWorld(play);
return;
}
if ((pauseCtx->state == PAUSE_STATE_MAIN) && (pauseCtx->mainState == PAUSE_MAIN_STATE_IDLE) &&
(pauseCtx->pageIndex == PAUSE_MAP) && !PauseOwlWarp_IsOwlWarpEnabled()) {
pauseCtx->cursorColorSet = PAUSE_CURSOR_COLOR_SET_WHITE;

View File

@ -2918,13 +2918,17 @@ void KaleidoScope_UpdateCursorSize(PlayState* play) {
pauseCtx->cursorX = sWorldMapCursorsX[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]];
pauseCtx->cursorY = sWorldMapCursorsY[pauseCtx->cursorPoint[PAUSE_WORLD_MAP]];
}
if (!IS_PAUSE_STATE_OWLWARP) {
if (!IS_PAUSE_STATE_OWLWARP && !PauseOwlWarp_IsOwlWarpEnabled()) {
pauseCtx->cursorHeight = 10.0f;
pauseCtx->cursorWidth = 10.0f;
} else {
pauseCtx->cursorHeight = 15.0f;
pauseCtx->cursorWidth = 15.0f;
}
// Flip the position of the cursor with an additional offset to align with flipped map points
if (CVarGetInteger("gModes.MirroredWorld.State", 0)) {
pauseCtx->cursorX = (pauseCtx->cursorX * -1.0) + 5.0f;
}
} else {
pauseCtx->cursorX = sDungeonMapCursorsX[pauseCtx->cursorPoint[PAUSE_MAP]];
pauseCtx->cursorY = sDungeonMapCursorsY[pauseCtx->cursorPoint[PAUSE_MAP]];