summaryrefslogtreecommitdiff
path: root/mm/src/code
diff options
context:
space:
mode:
authorGarrett Cox <garrettjcox@gmail.com>2024-12-06 00:56:48 -0600
committerGarrett Cox <garrettjcox@gmail.com>2024-12-06 00:56:48 -0600
commita108880a8c159bb59530821bb358dfa9cba04ee9 (patch)
tree848a4ae527f1282ddfc7213ead68fc06756624a6 /mm/src/code
parentd1df056e40c0c4cbdb441edc9dd025f7b3883306 (diff)
parent1d2a94561fab7d8608c0ac6be615f70f3fb1b769 (diff)
Merge branch 'develop' of garrettjoecox.github.com:HarbourMasters/2ship2harkinian into develop-rando
Diffstat (limited to 'mm/src/code')
-rw-r--r--mm/src/code/z_actor.c24
-rw-r--r--mm/src/code/z_collision_check.c16
-rw-r--r--mm/src/code/z_eff_blure.c1
-rw-r--r--mm/src/code/z_fbdemo_circle.c10
-rw-r--r--mm/src/code/z_kankyo.c69
-rw-r--r--mm/src/code/z_message.c17
-rw-r--r--mm/src/code/z_player_lib.c4
7 files changed, 119 insertions, 22 deletions
diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c
index 7f193158a..a770f2b01 100644
--- a/mm/src/code/z_actor.c
+++ b/mm/src/code/z_actor.c
@@ -131,6 +131,9 @@ void ActorShadow_Draw(Actor* actor, Lights* lights, PlayState* play, Gfx* dlist,
if ((dlist != gCircleShadowDL) || (actor->scale.x != actor->scale.z)) {
Matrix_RotateYS(actor->shape.rot.y, MTXMODE_APPLY);
+ } else {
+ // Mark non-rotating shadows to ignore the actor mtx prevents interpolation glitches when actor moves
+ FrameInterpolation_IgnoreActorMtx();
}
shadowScale *= actor->shape.shadowScale;
@@ -179,6 +182,9 @@ void ActorShadow_DrawFoot(PlayState* play, Light* light, MtxF* arg2, s32 lightNu
OPEN_DISPS(play->state.gfxCtx);
+ // Ignore the players rotation prevents feet shadow from glitching when turning abruptly
+ FrameInterpolation_IgnoreActorMtx();
+
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, (u8)(CLAMP_MAX(lightNum * 1.3e-05f, 1.0f) * shadowAlpha));
dir0 = light->l.dir[0];
@@ -5101,6 +5107,10 @@ TexturePtr sElectricSparkTextures[] = {
*/
void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[], s16 bodyPartsCount, f32 effectScale,
f32 frozenSteamScale, f32 effectAlpha, u8 type) {
+ if (!GameInteractor_Should(VB_DRAW_DAMAGE_EFFECT, true, actor, &type)) {
+ return;
+ }
+
if (effectAlpha > 0.001f) {
s32 twoTexScrollParam;
s16 bodyPartIndex;
@@ -5113,7 +5123,6 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
Vec3f* bodyPartsPosStart = bodyPartsPos;
u32 gameplayFrames = play->gameplayFrames;
f32 effectAlphaScaled;
- static int effectEpoch = 0;
currentMatrix = Matrix_GetCurrent();
@@ -5153,8 +5162,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
// Apply and draw ice over each body part of frozen actor
for (bodyPartIndex = 0; bodyPartIndex < bodyPartsCount; bodyPartIndex++, bodyPartsPos++) {
- // BENTODO is using bodyPartsPos OK here? should actor be used instead?
- FrameInterpolation_RecordOpenChild(bodyPartsPos, effectEpoch++);
+ FrameInterpolation_RecordOpenChild(bodyPartsPos, type);
alpha = bodyPartIndex & 3;
alpha = effectAlphaScaled - (30.0f * alpha);
if (effectAlphaScaled < (30.0f * (bodyPartIndex & 3))) {
@@ -5201,7 +5209,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
// Apply and draw steam over each body part of frozen actor
for (bodyPartIndex = 0; bodyPartIndex < bodyPartsCount; bodyPartIndex++, bodyPartsPos++) {
- FrameInterpolation_RecordOpenChild(bodyPartsPos, effectEpoch++);
+ FrameInterpolation_RecordOpenChild(bodyPartsPos, type);
twoTexScrollParam = ((bodyPartIndex * 3) + gameplayFrames);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(play->state.gfxCtx, 0, twoTexScrollParam * 3, twoTexScrollParam * -12,
@@ -5237,7 +5245,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
// Apply and draw fire on every body part
for (bodyPartIndex = 0; bodyPartIndex < bodyPartsCount; bodyPartIndex++, bodyPartsPos++) {
- FrameInterpolation_RecordOpenChild(bodyPartsPos, effectEpoch++);
+ FrameInterpolation_RecordOpenChild(bodyPartsPos, type);
alpha = bodyPartIndex & 3;
alpha = effectAlphaScaled - 30.0f * alpha;
if (effectAlphaScaled < 30.0f * (bodyPartIndex & 3)) {
@@ -5299,7 +5307,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
// Apply and draw a light orb over each body part of frozen actor
for (bodyPartIndex = 0; bodyPartIndex < bodyPartsCount; bodyPartIndex++, bodyPartsPos++) {
- FrameInterpolation_RecordOpenChild(bodyPartsPos, effectEpoch++);
+ FrameInterpolation_RecordOpenChild(bodyPartsPos, type);
Matrix_RotateZF(Rand_CenteredFloat(2 * M_PI), MTXMODE_APPLY);
currentMatrix->mf[3][0] = bodyPartsPos->x;
currentMatrix->mf[3][1] = bodyPartsPos->y;
@@ -5339,7 +5347,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
// Every body part draws two electric sparks at random orientations
for (bodyPartIndex = 0; bodyPartIndex < bodyPartsCount; bodyPartIndex++, bodyPartsPos++) {
- FrameInterpolation_RecordOpenChild(bodyPartsPos, effectEpoch++);
+ FrameInterpolation_RecordOpenChild(bodyPartsPos, type);
// first electric spark
Matrix_RotateXFApply(Rand_ZeroFloat(2 * M_PI));
Matrix_RotateZF(Rand_ZeroFloat(2 * M_PI), MTXMODE_APPLY);
@@ -5368,7 +5376,7 @@ void Actor_DrawDamageEffects(PlayState* play, Actor* actor, Vec3f bodyPartsPos[]
break;
}
- effectEpoch = 0;
+
CLOSE_DISPS(play->state.gfxCtx);
}
}
diff --git a/mm/src/code/z_collision_check.c b/mm/src/code/z_collision_check.c
index b3a2723af..107d95cc2 100644
--- a/mm/src/code/z_collision_check.c
+++ b/mm/src/code/z_collision_check.c
@@ -1,5 +1,6 @@
#include "global.h"
#include "z64collision_check.h"
+#include "2s2h/GameInteractor/GameInteractor.h"
typedef s32 (*ColChkResetFunc)(struct PlayState*, Collider*);
typedef void (*ColChkBloodFunc)(struct PlayState*, Collider*, Vec3f*);
@@ -59,8 +60,16 @@ f32 CollisionCheck_GetDamageAndEffectOnBumper(Collider* at, ColliderInfo* atInfo
dmgFlags >>= 1;
}
- damage *= damageMultipliers[ac->actor->colChkInfo.damageTable->attack[i] & 0xF];
- *effect = (ac->actor->colChkInfo.damageTable->attack[i] >> 4) & 0xF;
+ // #region 2S2H - Enhancements - Damage Multiplier and Effect
+ if ((GameInteractor_Should(VB_DAMAGE_MULTIPLIER, true, i, ac->actor->colChkInfo.damageTable, &damage,
+ damageMultipliers))) {
+ damage *= damageMultipliers[ac->actor->colChkInfo.damageTable->attack[i] & 0xF];
+ }
+
+ if ((GameInteractor_Should(VB_DAMAGE_EFFECT, true, i, ac->actor->colChkInfo.damageTable, effect, ac->actor))) {
+ *effect = (ac->actor->colChkInfo.damageTable->attack[i] >> 4) & 0xF;
+ }
+ // #endregion
}
return damage;
}
@@ -1361,7 +1370,8 @@ s32 CollisionCheck_SkipBump(ColliderInfo* info) {
* If the AT element has no dmgFlags in common with the AC element, no collision happens.
*/
s32 CollisionCheck_NoSharedFlags(ColliderInfo* toucher, ColliderInfo* bumper) {
- if (!(toucher->toucher.dmgFlags & bumper->bumper.dmgFlags)) {
+ if (GameInteractor_Should(VB_CHECK_BUMPER_COLLISION, !(toucher->toucher.dmgFlags & bumper->bumper.dmgFlags),
+ toucher, bumper)) {
return 1;
}
return 0;
diff --git a/mm/src/code/z_eff_blure.c b/mm/src/code/z_eff_blure.c
index 77fb627f4..e8b865965 100644
--- a/mm/src/code/z_eff_blure.c
+++ b/mm/src/code/z_eff_blure.c
@@ -649,6 +649,7 @@ void EffectBlure_DrawSmooth(EffectBlure* this2, GraphicsContext* gfxCtx) {
interpolationEpoch++;
OPEN_DISPS(gfxCtx);
+ // Force blure effects to never interpolate
FrameInterpolation_RecordOpenChild(this, interpolationEpoch);
if (this->numElements < 2) {
diff --git a/mm/src/code/z_fbdemo_circle.c b/mm/src/code/z_fbdemo_circle.c
index 22dac2f59..5dfbbc735 100644
--- a/mm/src/code/z_fbdemo_circle.c
+++ b/mm/src/code/z_fbdemo_circle.c
@@ -120,11 +120,8 @@ void TransitionCircle_LoadAndSetTexture(Gfx** gfxp, TexturePtr texture, s32 fmt,
}
// #region 2S2H [Cosmetic] Adjust circle overlay to support widescreen
- // The first wide rectangle instruction renders the tile information on the extra space on the left edge
- // The second instruction renders the original overlay in the center and has it extend to the right edge
- // gSPTextureRectangle(gfx++, 0, 0, xh << 2, yh << 2, G_TX_RENDERTILE, (s32)(s * (1 << 5)), (s32)(t * (1 << 5)),
- // dsdx,
- // dtdy);
+ // The first wide rectangle instruction renders the tile information on the extra space off the left edge
+ // The second instruction renders the original overlay in the center and has it extended to the right edge
s32 x = OTRGetRectDimensionFromLeftEdge(0) << 2;
if (x < 0) {
// Only render if the screen is wider then original
@@ -152,6 +149,9 @@ void TransitionCircle_Draw(void* thisx, Gfx** gfxp) {
gDPSetCombineLERP(gfx++, 0, 0, 0, PRIMITIVE, 1, TEXEL0, PRIM_LOD_FRAC, PRIMITIVE, 0, 0, 0, PRIMITIVE, 1, TEXEL0,
PRIM_LOD_FRAC, PRIMITIVE);
}
+ // 2S2H [Port] We need to set the render mode to XLU_SURF for alpha logic to be used in Fast3D
+ // If Fast3D changes how it decides alpha in the future, we may be able to remove this line
+ gDPSetRenderMode(gfx++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
TransitionCircle_LoadAndSetTexture(&gfx, this->texture, G_IM_FMT_I, 0, this->masks, this->maskt,
this->referenceRadius);
gDPPipeSync(gfx++);
diff --git a/mm/src/code/z_kankyo.c b/mm/src/code/z_kankyo.c
index 86d8abb27..fff939230 100644
--- a/mm/src/code/z_kankyo.c
+++ b/mm/src/code/z_kankyo.c
@@ -3172,6 +3172,64 @@ void Environment_DrawSkyboxStar(Gfx** gfxp, f32 x, f32 y, s32 width, s32 height)
*gfxp = gfx;
}
+// 2S2H [Enhancement] Renders a star as a quad against the projection matrix by rotating it with the billboard matrix
+void Ship_DrawSkyboxStarInterpolated(Gfx** gfxP, PlayState* play, Vec3f pos, u32 width, u32 height, s32 starNum) {
+ static MtxF origBillboardMtxF;
+ static Vtx starVtxData[] = {
+ VTX(-1, -1, 0, 0, 0, 0, 0, 0, 255),
+ VTX(1, -1, 0, 0, 0, 0, 0, 0, 255),
+ VTX(-1, 1, 0, 0, 0, 0, 0, 0, 255),
+ VTX(1, 1, 0, 0, 0, 0, 0, 0, 255),
+ };
+
+ Gfx* gfx = *gfxP;
+
+ // One time logic before drawing the first star
+ if (starNum == 0) {
+ // play->billboardMtxF is overwitten by the skybox stars draw earlier,
+ // so we need to derive the MtxF from the original Mtx
+ Matrix_MtxToMtxF(play->billboardMtx, &origBillboardMtxF);
+
+ gSPLoadGeometryMode(gfx++, G_CULL_BACK);
+ }
+
+ if (width >= 2) {
+ // The following math is used to compute new position values for each star such that they are
+ // each 5500 units from the view eye. This is necessary as some stars are further way than the zFar
+ // of the loaded view projection, which caused those stars to be clipped away.
+ // 5500 was choosen as this is roughly the largest distance that the sun is ever from the view eye.
+ f32 eyeDist = Math3D_Vec3f_DistXYZ(&pos, &play->view.eye);
+ f32 distRatio = 5500.0f / eyeDist;
+
+ f32 x = play->view.eye.x + (pos.x - play->view.eye.x) * distRatio;
+ f32 y = play->view.eye.y + (pos.y - play->view.eye.y) * distRatio;
+ f32 z = play->view.eye.z + (pos.z - play->view.eye.z) * distRatio;
+
+ // This scale mulitplier is set to draw the stars at a matching size as the texture rectangle
+ // and made to cancel out field of view changes so that the stars always have the same
+ // apparent size, preventing stars from appearing larger in first person mode or when looking through the
+ // telescope.
+ f32 scaleMultiplier = 3.0f / (60.0f / play->view.fovy);
+
+ Matrix_Push();
+
+ // Set the matrix so the star renders billboarded and scale to "stretch" it so that it matches
+ // roughly how the texture rectangle would have looked
+ Matrix_Translate(x, y, z, MTXMODE_NEW);
+ Matrix_Scale(width * scaleMultiplier, height * scaleMultiplier, 1.0f, MTXMODE_APPLY);
+ Matrix_ReplaceRotation(&origBillboardMtxF);
+
+ gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+
+ gSPVertex(gfx++, starVtxData, ARRAY_COUNT(starVtxData), 0);
+ gSP2Triangles(gfx++, 0, 1, 2, 0, 1, 3, 2, 0);
+
+ Matrix_Pop();
+ }
+
+ *gfxP = gfx;
+}
+
void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) {
static const Vec3s D_801DD880[] = {
{ 0x0384, 0x2328, 0xD508 }, { 0x09C4, 0x2328, 0xDA1C }, { 0x0E74, 0x22D8, 0xDA1C }, { 0x1450, 0x2468, 0xD8F0 },
@@ -3230,6 +3288,10 @@ void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) {
G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
G_AC_NONE | G_ZS_PRIM | G_RM_AA_XLU_LINE | G_RM_AA_XLU_LINE2);
+ // 2S2H [Port] We need to set the render mode to XLU_SURF for alpha logic to be used in Fast3D
+ // If Fast3D changes how it decides alpha in the future, we may be able to remove this line
+ gDPSetRenderMode(gfx++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
+
randInt = ((u32)gSaveContext.save.saveInfo.playerData.playerName[0] << 0x18) ^
((u32)gSaveContext.save.saveInfo.playerData.playerName[1] << 0x14) ^
((u32)gSaveContext.save.saveInfo.playerData.playerName[2] << 0x10) ^
@@ -3301,6 +3363,13 @@ void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) {
imgYPtr = &imgY;
viewProjectionMtxF = play->viewProjectionMtxF.mf;
+ // 2S2H [Enhancement] The stars are originally drawn as texture rectangles which cannot be interpolated,
+ // so if interpolation is enabled we branch and render the stars through the projection matrix instead.
+ if (Ship_GetInterpolationFPS() != 20) {
+ Ship_DrawSkyboxStarInterpolated(&gfx, play, pos, imgWidth, 4, i);
+ continue;
+ }
+
if (imgWidth >= 2) {
// w component
scale = pos.x * play->viewProjectionMtxF.mf[0][3] + pos.y * play->viewProjectionMtxF.mf[1][3] +
diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c
index cb794d522..6c7756495 100644
--- a/mm/src/code/z_message.c
+++ b/mm/src/code/z_message.c
@@ -4536,7 +4536,10 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) {
if ((msgCtx->ocarinaAction == OCARINA_ACTION_PROMPT_EVAN_PART1_SECOND_HALF) ||
(msgCtx->ocarinaAction == OCARINA_ACTION_PROMPT_EVAN_PART2_SECOND_HALF)) {
AudioOcarina_StartForSongCheck(
- (1 << (OCARINA_ACTION_PROMPT_SONATA + msgCtx->ocarinaAction)) | 0x80000000, 4);
+ (1 << ((msgCtx->ocarinaAction - OCARINA_ACTION_PROMPT_EVAN_PART1_SECOND_HALF) +
+ OCARINA_SONG_EVAN_PART1)) |
+ 0x80000000,
+ 4);
msgCtx->msgMode = MSGMODE_SONG_PROMPT;
} else {
if ((msgCtx->ocarinaAction >= OCARINA_ACTION_PROMPT_WIND_FISH_HUMAN) &&
@@ -6029,12 +6032,14 @@ void Message_Update(PlayState* play) {
} else if (sLastPlayedSong == OCARINA_SONG_DOUBLE_TIME) {
if (interfaceCtx->restrictions.songOfDoubleTime == 0) {
if ((CURRENT_DAY != 3) || (gSaveContext.save.isNight == 0)) {
- if (gSaveContext.save.isNight) {
- Message_StartTextbox(play, D_801D0464[CURRENT_DAY - 1], NULL);
- } else {
- Message_StartTextbox(play, D_801D045C[CURRENT_DAY - 1], NULL);
+ if (GameInteractor_Should(VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT, true)) {
+ if (gSaveContext.save.isNight) {
+ Message_StartTextbox(play, D_801D0464[CURRENT_DAY - 1], NULL);
+ } else {
+ Message_StartTextbox(play, D_801D045C[CURRENT_DAY - 1], NULL);
+ }
+ play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME;
}
- play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME;
} else {
Message_StartTextbox(play, 0x1B94, NULL);
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
diff --git a/mm/src/code/z_player_lib.c b/mm/src/code/z_player_lib.c
index 9f624b93d..12c6e86e9 100644
--- a/mm/src/code/z_player_lib.c
+++ b/mm/src/code/z_player_lib.c
@@ -46,6 +46,7 @@
#include "2s2h/BenPort.h"
#include "2s2h/GameInteractor/GameInteractor.h"
+#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h"
void PlayerCall_Init(Actor* thisx, PlayState* play);
void PlayerCall_Destroy(Actor* thisx, PlayState* play);
@@ -3186,6 +3187,9 @@ void Player_DrawBunnyHood(PlayState* play) {
OPEN_DISPS(play->state.gfxCtx);
+ // Ignoring the players actor mtx allows the bunny hood to render interpolated without issues
+ FrameInterpolation_IgnoreActorMtx();
+
gSPSegment(POLY_OPA_DISP++, 0x0B, mtx);
Matrix_Push();