diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index 491dd8938..0120809b0 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -905,6 +905,7 @@ namespace SohImGui { Tooltip("The default response to Kaepora Gaebora is always that you understood what he said"); EnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime"); Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); + EnhancementCheckbox("Enable visible guard vision", "gGuardVision"); EnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect"); ImGui::EndMenu(); } diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 83755ee5d..5b51fc1b3 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -39,6 +39,7 @@ void BootCommands_Init() CVar_RegisterS32("gHudColors", 1); //0 = N64 / 1 = NGC / 2 = Custom CVar_RegisterS32("gUseNaviCol", 0); CVar_RegisterS32("gUseTunicsCol", 0); + CVar_RegisterS32("gGuardVision", 0); CVar_RegisterS32("gTimeFlowFileSelect", 0); } diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp index 2b6d27189..19ea22f86 100644 --- a/soh/soh/Enhancements/savestates.cpp +++ b/soh/soh/Enhancements/savestates.cpp @@ -264,6 +264,9 @@ typedef struct SaveStateInfo { uint8_t sKankyoIsSpawned_copy; int16_t sTrailingFairies_copy; + // z_en_heishi1 + uint32_t sHeishi1PlayerIsCaughtCopy; + //Misc static data // z_map_exp @@ -616,6 +619,8 @@ void SaveState::SaveOverlayStaticData(void) { info->D_80B5A4BC_copy = D_80B5A4BC; info->sKankyoIsSpawned_copy = sKankyoIsSpawned; info->sTrailingFairies_copy = sTrailingFairies; + + info->sHeishi1PlayerIsCaughtCopy = sHeishi1PlayerIsCaught; } @@ -686,6 +691,8 @@ void SaveState::LoadOverlayStaticData(void) { D_80B5A4BC = info->D_80B5A4BC_copy; sKankyoIsSpawned = info->sKankyoIsSpawned_copy; sTrailingFairies = info->sTrailingFairies_copy; + + sHeishi1PlayerIsCaught = info->sHeishi1PlayerIsCaughtCopy; } void SaveState::SaveMiscCodeData(void) { diff --git a/soh/soh/Enhancements/savestates_extern.inc b/soh/soh/Enhancements/savestates_extern.inc index c3b129a32..b950333e5 100644 --- a/soh/soh/Enhancements/savestates_extern.inc +++ b/soh/soh/Enhancements/savestates_extern.inc @@ -200,6 +200,9 @@ extern "C" s16 sPlayerInitialPosX; extern "C" s16 sPlayerInitialPosZ; extern "C" s16 sPlayerInitialDirection; +// z_en_heishi1 +extern "C" s32 sHeishi1PlayerIsCaught; + // code_800EC960 // Related to ocarina extern "C" u8 sOcarinaInpEnabled; diff --git a/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c b/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c index e0bad7df3..b8ddacffb 100644 --- a/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c +++ b/soh/src/overlays/actors/ovl_En_Heishi1/z_en_heishi1.c @@ -29,7 +29,7 @@ void EnHeishi1_TurnTowardLink(EnHeishi1* this, GlobalContext* globalCtx); void EnHeishi1_Kick(EnHeishi1* this, GlobalContext* globalCtx); void EnHeishi1_WaitNight(EnHeishi1* this, GlobalContext* globalCtx); -static s32 sPlayerIsCaught = false; +s32 sHeishi1PlayerIsCaught = false; const ActorInit En_Heishi1_InitVars = { 0, @@ -154,7 +154,7 @@ void EnHeishi1_Walk(EnHeishi1* this, GlobalContext* globalCtx) { Audio_PlayActorSound2(&this->actor, NA_SE_EV_KNIGHT_WALK); } - if (!sPlayerIsCaught) { + if (!sHeishi1PlayerIsCaught) { path = &globalCtx->setupPathList[this->path]; pointPos = SEGMENTED_TO_VIRTUAL(path->points); pointPos += this->waypoint; @@ -259,7 +259,7 @@ void EnHeishi1_Wait(EnHeishi1* this, GlobalContext* globalCtx) { s32 i; SkelAnime_Update(&this->skelAnime); - if (!sPlayerIsCaught) { + if (!sHeishi1PlayerIsCaught) { switch (this->headBehaviorDecided) { case false: this->headDirection++; @@ -352,7 +352,7 @@ void EnHeishi1_Kick(EnHeishi1* this, GlobalContext* globalCtx) { globalCtx->nextEntranceIndex = 0x4FA; globalCtx->sceneLoadFlag = 0x14; this->loadStarted = true; - sPlayerIsCaught = false; + sHeishi1PlayerIsCaught = false; globalCtx->fadeTransition = 0x2E; gSaveContext.nextTransition = 0x2E; } @@ -413,7 +413,7 @@ void EnHeishi1_Update(Actor* thisx, GlobalContext* globalCtx) { if (this->type != 5) { path = this->path * 2; if ((sCamDataIdxs[path] == activeCam->camDataIdx) || (sCamDataIdxs[path + 1] == activeCam->camDataIdx)) { - if (!sPlayerIsCaught) { + if (!sHeishi1PlayerIsCaught) { if ((this->actionFunc == EnHeishi1_Walk) || (this->actionFunc == EnHeishi1_Wait)) { Vec3f searchBallVel; Vec3f searchBallAccel = { 0.0f, 0.0f, 0.0f }; @@ -459,7 +459,7 @@ void EnHeishi1_Update(Actor* thisx, GlobalContext* globalCtx) { // "Discovered!" osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 発見! ☆☆☆☆☆ \n" VT_RST); func_8002DF54(globalCtx, &this->actor, 1); - sPlayerIsCaught = true; + sHeishi1PlayerIsCaught = true; this->actionFunc = EnHeishi1_SetupMoveToLink; } } diff --git a/soh/src/overlays/effects/ovl_Effect_Ss_Solder_Srch_Ball/z_eff_ss_solder_srch_ball.c b/soh/src/overlays/effects/ovl_Effect_Ss_Solder_Srch_Ball/z_eff_ss_solder_srch_ball.c index babae2517..a8952883b 100644 --- a/soh/src/overlays/effects/ovl_Effect_Ss_Solder_Srch_Ball/z_eff_ss_solder_srch_ball.c +++ b/soh/src/overlays/effects/ovl_Effect_Ss_Solder_Srch_Ball/z_eff_ss_solder_srch_ball.c @@ -5,11 +5,14 @@ */ #include "z_eff_ss_solder_srch_ball.h" +#include "objects/gameplay_keep/gameplay_keep.h" +#include #define rUnused regs[1] u32 EffectSsSolderSrchBall_Init(GlobalContext* globalCtx, u32 index, EffectSs* this, void* initParamsx); void EffectSsSolderSrchBall_Update(GlobalContext* globalCtx, u32 index, EffectSs* this); +void EffectSsSolderSrchBall_Draw(GlobalContext* globalCtx, u32 index, EffectSs* this); EffectSsInit Effect_Ss_Solder_Srch_Ball_InitVars = { EFFECT_SS_SOLDER_SRCH_BALL, @@ -23,6 +26,7 @@ u32 EffectSsSolderSrchBall_Init(GlobalContext* globalCtx, u32 index, EffectSs* t this->velocity = initParams->velocity; this->accel = initParams->accel; this->update = EffectSsSolderSrchBall_Update; + this->draw = EffectSsSolderSrchBall_Draw; this->life = 100; this->rUnused = initParams->unused; this->actor = initParams->linkDetected; // actor field was incorrectly used as a pointer to something else @@ -53,3 +57,198 @@ void EffectSsSolderSrchBall_Update(GlobalContext* globalCtx, u32 index, EffectSs } } } + +static void vtxn_f2l(Vtx* r, Vec3f* v) { + r->n.ob[0] = floorf(0.5f + v->x * 128.f); + r->n.ob[1] = floorf(0.5f + v->y * 128.f); + r->n.ob[2] = floorf(0.5f + v->z * 128.f); + r->n.flag = 0; + r->n.tc[0] = 0; + r->n.tc[1] = 0; + r->n.n[0] = v->x * 127.f; + r->n.n[1] = v->y * 127.f; + r->n.n[2] = v->z * 127.f; + r->n.a = 0xFF; +} + +static void ico_sph_subdivide_edge(Vec3f* r, Vec3f* a, Vec3f* b) { + Math_Vec3f_Sum(a, b, r); + Math_Vec3f_Scale(r, (1.0f / Math3D_Vec3fMagnitude(r))); +} + +static void draw_ico_sphere(Gfx** p_gfx_p, f32 x, f32 y, f32 z, f32 radius, GraphicsContext* gfxCtx) { + static Gfx* p_sph_gfx = NULL; + static Vtx sph_vtx[42]; + static Gfx sph_gfx[45]; + Gfx* sph_gfx_p; + s32 i; + + if (!p_sph_gfx) { + Vec3f vtx[42]; + s32 r0_n = 1, r0_m = r0_n / 5, r0_i = 0 + 0; + s32 r1_n = 5, r1_m = r1_n / 5, r1_i = r0_i + r0_n; + s32 r2_n = 10, r2_m = r2_n / 5, r2_i = r1_i + r1_n; + s32 r3_n = 10, r3_m = r3_n / 5, r3_i = r2_i + r2_n; + s32 r4_n = 10, r4_m = r4_n / 5, r4_i = r3_i + r3_n; + s32 r5_n = 5, r5_m = r5_n / 5, r5_i = r4_i + r4_n; + s32 r6_n = 1, r6_m = r6_n / 5, r6_i = r5_i + r5_n; + + vtx[r0_i + (0 * r0_m + 0) % r0_n].x = 0.0f; + vtx[r0_i + (0 * r0_m + 0) % r0_n].y = 1.0f; + vtx[r0_i + (0 * r0_m + 0) % r0_n].z = 0.0f; + + vtx[r6_i + (0 * r6_m + 0) % r6_n].x = 0.0f; + vtx[r6_i + (0 * r6_m + 0) % r6_n].y = -1.0f; + vtx[r6_i + (0 * r6_m + 0) % r6_n].z = 0.0f; + + for (i = 0; i < 5; ++i) { + f32 a_xz = 2.f * M_PI / 10.f; + f32 a_y = atanf(1.0f / 2.0f); + + vtx[r2_i + (i * r2_m + 0) % r2_n].x = cosf(a_xz * (i * r2_m + 0)) * cosf(a_y * 1.f); + vtx[r2_i + (i * r2_m + 0) % r2_n].y = sinf(a_y * 1.f); + vtx[r2_i + (i * r2_m + 0) % r2_n].z = -sinf(a_xz * (i * r2_m + 0)) * cosf(a_y * 1.f); + + vtx[r4_i + (i * r4_m + 0) % r4_n].x = cosf(a_xz * (i * r4_m + 1)) * cosf(a_y * -1.f); + vtx[r4_i + (i * r4_m + 0) % r4_n].y = sinf(a_y * -1.f); + vtx[r4_i + (i * r4_m + 0) % r4_n].z = -sinf(a_xz * (i * r4_m + 1)) * cosf(a_y * -1.f); + } + for (i = 0; i < 5; ++i) { + ico_sph_subdivide_edge(&vtx[r1_i + (i * r1_m + 0) % r1_n], &vtx[r0_i + (i * r0_m + 0) % r0_n], + &vtx[r2_i + (i * r2_m + 0) % r2_n]); + ico_sph_subdivide_edge(&vtx[r2_i + (i * r2_m + 1) % r2_n], &vtx[r2_i + (i * r2_m + 0) % r2_n], + &vtx[r2_i + (i * r2_m + 2) % r2_n]); + ico_sph_subdivide_edge(&vtx[r3_i + (i * r3_m + 0) % r3_n], &vtx[r2_i + (i * r2_m + 0) % r2_n], + &vtx[r4_i + (i * r4_m + 0) % r4_n]); + ico_sph_subdivide_edge(&vtx[r3_i + (i * r3_m + 1) % r3_n], &vtx[r4_i + (i * r4_m + 0) % r4_n], + &vtx[r2_i + (i * r2_m + 2) % r2_n]); + ico_sph_subdivide_edge(&vtx[r4_i + (i * r4_m + 1) % r4_n], &vtx[r4_i + (i * r4_m + 0) % r4_n], + &vtx[r4_i + (i * r4_m + 2) % r4_n]); + ico_sph_subdivide_edge(&vtx[r5_i + (i * r5_m + 0) % r5_n], &vtx[r4_i + (i * r4_m + 0) % r4_n], + &vtx[r6_i + (i * r6_m + 0) % r6_n]); + } + + for (i = 0; i < 42; ++i) + vtxn_f2l(&sph_vtx[i], &vtx[i]); + + p_sph_gfx = sph_gfx; + sph_gfx_p = p_sph_gfx; + + gSPSetGeometryMode(sph_gfx_p++, G_CULL_BACK | G_SHADING_SMOOTH); + + gSPVertex(sph_gfx_p++, &sph_vtx[r0_i], r0_n + r1_n + r2_n + r3_n, r0_i - r0_i); + r3_i -= r0_i; + r2_i -= r0_i; + r1_i -= r0_i; + r0_i -= r0_i; + for (i = 0; i < 5; ++i) { + s32 v[24]; + v[0] = r0_i + (i * r0_m + 0) % r0_n; + v[1] = r1_i + (i * r1_m + 0) % r1_n; + v[2] = r1_i + (i * r1_m + 1) % r1_n; + v[3] = r1_i + (i * r1_m + 0) % r1_n; + v[4] = r2_i + (i * r2_m + 0) % r2_n; + v[5] = r2_i + (i * r2_m + 1) % r2_n; + v[6] = r1_i + (i * r1_m + 0) % r1_n; + v[7] = r2_i + (i * r2_m + 1) % r2_n; + v[8] = r1_i + (i * r1_m + 1) % r1_n; + v[9] = r1_i + (i * r1_m + 1) % r1_n; + v[10] = r2_i + (i * r2_m + 1) % r2_n; + v[11] = r2_i + (i * r2_m + 2) % r2_n; + v[12] = r2_i + (i * r2_m + 0) % r2_n; + v[13] = r3_i + (i * r3_m + 0) % r3_n; + v[14] = r2_i + (i * r2_m + 1) % r2_n; + v[15] = r2_i + (i * r2_m + 1) % r2_n; + v[16] = r3_i + (i * r3_m + 0) % r3_n; + v[17] = r3_i + (i * r3_m + 1) % r3_n; + v[18] = r2_i + (i * r2_m + 1) % r2_n; + v[19] = r3_i + (i * r3_m + 1) % r3_n; + v[20] = r2_i + (i * r2_m + 2) % r2_n; + v[21] = r2_i + (i * r2_m + 2) % r2_n; + v[22] = r3_i + (i * r3_m + 1) % r3_n; + v[23] = r3_i + (i * r3_m + 2) % r3_n; + gSP2Triangles(sph_gfx_p++, v[0], v[1], v[2], 0, v[3], v[4], v[5], 0); + gSP2Triangles(sph_gfx_p++, v[6], v[7], v[8], 0, v[9], v[10], v[11], 0); + gSP2Triangles(sph_gfx_p++, v[12], v[13], v[14], 0, v[15], v[16], v[17], 0); + gSP2Triangles(sph_gfx_p++, v[18], v[19], v[20], 0, v[21], v[22], v[23], 0); + } + + gSPVertex(sph_gfx_p++, &sph_vtx[r4_i], r4_n + r5_n + r6_n, r4_i - r4_i); + r6_i -= r4_i; + r5_i -= r4_i; + r4_i -= r4_i; + for (i = 0; i < 5; ++i) { + s32 v[24]; + v[0] = r3_i + (i * r3_m + 1) % r3_n; + v[1] = r4_i + (i * r4_m + 0) % r4_n; + v[2] = r4_i + (i * r4_m + 1) % r4_n; + v[3] = r3_i + (i * r3_m + 1) % r3_n; + v[4] = r4_i + (i * r4_m + 1) % r4_n; + v[5] = r3_i + (i * r3_m + 2) % r3_n; + v[6] = r3_i + (i * r3_m + 2) % r3_n; + v[7] = r4_i + (i * r4_m + 1) % r4_n; + v[8] = r4_i + (i * r4_m + 2) % r4_n; + v[9] = r3_i + (i * r3_m + 2) % r3_n; + v[10] = r4_i + (i * r4_m + 2) % r4_n; + v[11] = r3_i + (i * r3_m + 3) % r3_n; + v[12] = r4_i + (i * r4_m + 0) % r4_n; + v[13] = r5_i + (i * r5_m + 0) % r5_n; + v[14] = r4_i + (i * r4_m + 1) % r4_n; + v[15] = r4_i + (i * r4_m + 1) % r4_n; + v[16] = r5_i + (i * r5_m + 0) % r5_n; + v[17] = r5_i + (i * r5_m + 1) % r5_n; + v[18] = r4_i + (i * r4_m + 1) % r4_n; + v[19] = r5_i + (i * r5_m + 1) % r5_n; + v[20] = r4_i + (i * r4_m + 2) % r4_n; + v[21] = r5_i + (i * r5_m + 0) % r5_n; + v[22] = r6_i + (i * r6_m + 0) % r6_n; + v[23] = r5_i + (i * r5_m + 1) % r5_n; + gSP2Triangles(sph_gfx_p++, v[0], v[1], v[2], 0, v[3], v[4], v[5], 0); + gSP2Triangles(sph_gfx_p++, v[6], v[7], v[8], 0, v[9], v[10], v[11], 0); + gSP2Triangles(sph_gfx_p++, v[12], v[13], v[14], 0, v[15], v[16], v[17], 0); + gSP2Triangles(sph_gfx_p++, v[18], v[19], v[20], 0, v[21], v[22], v[23], 0); + } + + gSPClearGeometryMode(sph_gfx_p++, G_CULL_BACK | G_SHADING_SMOOTH); + gSPEndDisplayList(sph_gfx_p++); + } + Matrix_Push(); + Matrix_Translate(x, y, z, MTXMODE_NEW); + Matrix_Scale(radius / 128.0f, radius / 128.0f, radius / 128.0f, MTXMODE_APPLY); + gSPMatrix((*p_gfx_p)++, Matrix_NewMtx(gfxCtx, __FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH); + gSPDisplayList((*p_gfx_p)++, p_sph_gfx); + gSPPopMatrix((*p_gfx_p)++, G_MTX_MODELVIEW); + Matrix_Pop(); +} + +void EffectSsSolderSrchBall_Draw(GlobalContext* globalCtx, u32 index, EffectSs* this) { + if (CVar_GetS32("gGuardVision", 0) == 0) { + return; + } + + GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; + u32 rm; + u32 blc1; + u32 blc2; + s16* seenLink = this->actor; + + OPEN_DISPS(globalCtx->state.gfxCtx, __FILE__, __LINE__); + rm = Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU; + blc1 = GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA); + blc2 = GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA); + + gSPLoadGeometryMode(POLY_XLU_DISP++, G_ZBUFFER | G_SHADE | G_LIGHTING); + gSPTexture(POLY_XLU_DISP++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); + gDPPipeSync(POLY_XLU_DISP++); + gDPSetCycleType(POLY_XLU_DISP++, G_CYC_1CYCLE); + gDPSetRenderMode(POLY_XLU_DISP++, rm | blc1, rm | blc2); + gDPSetCombineLERP(POLY_XLU_DISP++, PRIMITIVE, 0, SHADE, 0, 0, 0, 0, ENVIRONMENT, PRIMITIVE, 0, SHADE, 0, 0, 0, + 0, ENVIRONMENT); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255); + if (*seenLink) { + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 0, 0, 255); + } + draw_ico_sphere(&POLY_XLU_DISP, this->pos.x, this->pos.y, this->pos.z, 30.0f, gfxCtx); + + CLOSE_DISPS(globalCtx->state.gfxCtx, __FILE__, __LINE__); +} \ No newline at end of file