diff --git a/src/SB/Core/x/xMath3.h b/src/SB/Core/x/xMath3.h index 1e2b2ed57..dbfda11a5 100644 --- a/src/SB/Core/x/xMath3.h +++ b/src/SB/Core/x/xMath3.h @@ -82,6 +82,7 @@ extern const xQuat g_IQ; extern const xVec3 g_O3; extern xVec3 g_X3; extern xVec3 g_Y3; +extern xVec3 g_NY3; extern xVec3 g_Z3; extern xMat4x3 g_I3; extern xVec3 g_Onez; @@ -92,7 +93,9 @@ void xMat4x3Mul(xMat4x3* o, const xMat4x3* a, const xMat4x3* b); void xMat3x3Euler(xMat3x3* m, F32 yaw, F32 pitch, F32 roll); void xMat4x3Toworld(xVec3* o, const xMat4x3* m, const xVec3* v); void xMat3x3RotC(xMat3x3* m, F32 _x, F32 _y, F32 _z, F32 t); +void xMat3x3RotX(xMat3x3* m, F32 t); void xMat3x3RotY(xMat3x3* m, F32 t); +void xMat3x3RotZ(xMat3x3* m, F32 t); void xMat3x3MulRotC(xMat3x3* o, xMat3x3* m, F32 _x, F32 _y, F32 _z, F32 t); void xMat4x3Identity(xMat4x3* m); void xMat3x3Normalize(xMat3x3* o, const xMat3x3* m); diff --git a/src/SB/Core/x/xMathInlines.h b/src/SB/Core/x/xMathInlines.h index 4aec695d7..bf7db9547 100644 --- a/src/SB/Core/x/xMathInlines.h +++ b/src/SB/Core/x/xMathInlines.h @@ -13,6 +13,9 @@ F32 xpow(F32 x, F32 y); F32 SQ(F32 x); +F32 LERP(F32 x, F32 y, F32 z); +U8 LERP(float x, U8 y, U8 z); + void xsqrtfast(F32& out, F32 x); #endif diff --git a/src/SB/Game/zNPCSupport.cpp b/src/SB/Game/zNPCSupport.cpp index da6ee848d..0c04cd95e 100644 --- a/src/SB/Game/zNPCSupport.cpp +++ b/src/SB/Game/zNPCSupport.cpp @@ -1,16 +1,24 @@ #include "zNPCSupport.h" #include +#include +#include +#include "zGlobals.h" #include "zNPCHazard.h" #include "zNPCGlyph.h" #include "zNPCSupplement.h" #include "xMathInlines.h" +#include "xMath3.h" +#include "xUtil.h" +#include "xBound.h" NPCWidget g_npc_widgets[1] = {}; -static U32 g_hash_uiwidgets[1]; -static char* g_strz_uiwidgets[1] = {}; +static U32 g_hash_uiwidgets[1] = { 0 }; +static char* g_strz_uiwidgets[1] = { "MNU4 NPCTALK" }; +S32 g_pc_playerInvisible; +static Firework g_fireworks[32]; void NPCSupport_Startup() { @@ -18,7 +26,6 @@ void NPCSupport_Startup() zNPCGlyph_Startup(); NPCWidget_Startup(); NPCSupplement_Startup(); - return; } void NPCSupport_Shutdown() @@ -29,14 +36,14 @@ void NPCSupport_Shutdown() NPCSupplement_Shutdown(); } -bool NPCSupport_ScenePrepare() +void NPCSupport_ScenePrepare() { zNPCHazard_ScenePrepare(); zNPCGlyph_ScenePrepare(); NPCWidget_ScenePrepare(); NPCSupplement_ScenePrepare(); Firework_ScenePrepare(); - return NPCC_ForceTalkOk(); + NPCC_ForceTalkOk(); } void NPCSupport_SceneFinish() @@ -46,7 +53,6 @@ void NPCSupport_SceneFinish() NPCWidget_SceneFinish(); NPCSupplement_SceneFinish(); Firework_SceneFinish(); - return; } void NPCSupport_ScenePostInit() @@ -56,7 +62,6 @@ void NPCSupport_ScenePostInit() NPCWidget_ScenePostInit(); NPCSupplement_ScenePostInit(); zNPC_SNDInit(); - return; } void NPCSupport_SceneReset() @@ -66,7 +71,6 @@ void NPCSupport_SceneReset() NPCWidget_SceneReset(); NPCSupplement_SceneReset(); Firework_SceneReset(0); - return; } void NPCSupport_Timestep(F32 dt) @@ -104,17 +108,107 @@ void NPCWidget::Reset() { } +U32 NPCWidget::On(const zNPCCommon* npc, int theman) +{ + if ((!theman && !NPCIsTheLocker(npc)) && (((S32)IsLocked()) || (!Lock(npc)))) + { + return 0; + } + if (IsVisible()) + { + return 1; + } + else + { + zEntEvent(base_widge, 0x5e); + zEntEvent(base_widge, 0x03); + return 1; + } + + return 1; +} + +S32 NPCWidget::Unlock(const zNPCCommon* npc) +{ + if (npc_ownerlock == NULL) + { + return 1; + } + if (npc != npc_ownerlock) + { + return 0; + } + npc_ownerlock = NULL; + return 1; +} + +S32 NPCWidget::NPCIsTheLocker(const zNPCCommon* npc) +{ + if ((S32)IsLocked() == 0) + { + return 0; + } + else + { + return npc == npc_ownerlock ? 1 : 0; + } +} + +S32 NPCWidget::IsVisible() +{ + if (base_widge == NULL) + { + return 0; + } + else if (base_widge->baseType != 0x21) + { + return 0; + } + else + { + return xEntIsVisible((xEnt*)base_widge); + } +} + +S32 NPCWidget::Lock(const zNPCCommon* npc) +{ + if ((npc_ownerlock != NULL) && (npc != npc_ownerlock)) + { + return 0; + } + npc_ownerlock = (zNPCCommon*)npc; + return 1; +} + void NPCWidget_ScenePostInit() { + g_npc_widgets->Init(NPC_WIDGE_TALK); } -void NPCWidget_Find(en_NPC_UI_WIDGETS) +NPCWidget* NPCWidget_Find(en_NPC_UI_WIDGETS which) { - zSceneFindObject(g_hash_uiwidgets[1]); + return &g_npc_widgets[(int)which]; } -void NPCWidget::Init(en_NPC_UI_WIDGETS) +void NPCWidget::Init(en_NPC_UI_WIDGETS which) { + base_widge = zSceneFindObject(g_hash_uiwidgets[idxID = which]); +} + +void NPCTarget::TargetSet(xEnt* ent, int b) +{ + ent_target = ent; + if ((ent != NULL) && (b != 0)) + { + typ_target = NPC_TGT_PLYR; + return; + } + if (ent != NULL) + { + typ_target = NPC_TGT_ENT; + return; + } + typ_target = NPC_TGT_NONE; } void NPCTarget::TargetClear() @@ -125,6 +219,34 @@ void NPCTarget::TargetClear() void NPCBlinker::Reset() { + tmr_uvcell = -1.0f; + idx_uvcell = 0; +} + +void NPCBlinker::Update(F32 dt, F32 ratio, F32 tym_slow, F32 tym_fast) +{ + if (tmr_uvcell < 0.0f) + { + idx_uvcell++; + if (3 < idx_uvcell) + { + idx_uvcell = 0; + } + tmr_uvcell = LERP(SQ(ratio), tym_slow, tym_fast); + } + tmr_uvcell = MAX(-1.0f, tmr_uvcell - dt); +} + +void NPCBlinker::IndexToUVCoord(S32 param_1, F32* param_2, F32* param_3) +{ + S32 shift = ((U32)param_1 >> 31); + S32 uVar1 = ((param_1 & 1) ^ shift) - shift; + + param_2[0] = uVar1 * 0.5f; + param_2[1] = ((param_1 - uVar1) / 2) * 0.5f; + + param_3[0] = param_2[0] + 0.5f; + param_3[1] = param_2[1] + 0.5f; } void Firework_Release(Firework* firework) @@ -148,17 +270,75 @@ void Firework::Cleanup() { } -void Firework_SceneReset(int) +void NPAR_EmitFWExhaust(xVec3* pos, xVec3* vel); + +void Firework::Detonate() +{ + xUtil_yesno(0.25f); +} + +void NPCC_ang_toXZDir(F32 angle, xVec3* dir) +{ + dir->x = isin(angle); + dir->y = 0.0f; + dir->z = icos(angle); +} + +void NPCC_dir_toXZAng(const xVec3* vec) { + xatan2(vec->x, vec->z); +} + +void NPCC_aimMiss(xVec3* dir_aim, xVec3* pos_src, xVec3* pos_tgt, F32 dst_miss, xVec3* pos_miss) +{ + NPCC_aimVary(dir_aim, pos_src, pos_tgt, dst_miss, 8, pos_miss); +} + +void Firework_SceneReset(int param_1) +{ + Firework* fw; + for (int i = 0; i < (int)(sizeof(g_fireworks) / sizeof(Firework)); i++) + { + fw = &g_fireworks[i]; + if ((param_1 != 0) && (fw->fwstate != 0)) + { + Firework_Release(fw); + } + fw->fwstate = 0; + fw++; + } } void Firework_Timestep(F32 dt) { + for (int i = 0; i < 32; i++) + { + if (g_fireworks[i].fwstate != FW_STAT_UNUSED) + { + if ((g_fireworks[i].fwstate != FW_STAT_READY) && (g_fireworks[i].flg_firework & 4)) + { + if (g_fireworks[i].fwstate == FW_STAT_DONE) + { + Firework_Release(&g_fireworks[i]); + } + else + { + g_fireworks[i].Update(dt); + g_fireworks[i].flg_firework &= ~2; + } + } + } + } +} + +S32 NPCC_LampStatus() +{ + return g_pc_playerInvisible == 0 ? true : false; } bool NPCC_ForceTalkOk() { - return false; + return globals.player.g.DisableForceConversation == 0 ? 1 : 0; } RwRaster* NPCC_FindRWRaster(const char* txtrname) @@ -171,9 +351,14 @@ RwRaster* NPCC_FindRWRaster(const char* txtrname) return NULL; } -RwTexture* NPCC_FindRWTexture(const char*) +RwTexture* NPCC_FindRWTexture(U32 hashid) { - return NULL; + return (RwTexture*)xSTFindAsset(hashid, NULL); +} + +RwTexture* NPCC_FindRWTexture(const char* txtrname) +{ + return (RwTexture*)xSTFindAsset(xStrHash(txtrname), NULL); } RwRaster* NPCC_FindRWRaster(RwTexture* txtr) @@ -189,6 +374,205 @@ void zNPC_SNDInit() { } +U32 NPCC_LineHitsBound(xVec3* param_1, xVec3* param_2, xBound* param_3, xCollis* param_4) +{ + xRay3 ray; + xVec3 vec; + xCollis local_colrec; + xCollis* colrec = &local_colrec; + F32 len; + + if (param_4 != NULL) + { + colrec = (xCollis *)param_4; + } + xVec3Sub(&vec, param_2, param_1); + len = xVec3Length(&vec); + if (len < 0.001f) + { + len = 0.001f; + } + xVec3Copy(&ray.origin, param_1); + xVec3SMul(&ray.dir, &vec, (1.0f / len)); + + ray.max_t = len; + ray.min_t = 0.1f; + ray.flags = 3072; + + xRayHitsBound(&ray, param_3, colrec); + return colrec->flags & 1; +} + +S32 NPCC_bnd_ofBase(xBase* tgt, xBound* bnd) +{ + S32 retval = 1; + + switch(tgt->baseType) + { + case eBaseTypeCamera: + case eBaseTypeDoor: + case eBaseTypeVolume: + case eBaseTypeEGenerator: + retval = 0; + break; + case eBaseTypePlayer: + case eBaseTypePickup: + case eBaseTypePlatform: + case eBaseTypeStatic: + case eBaseTypeDynamic: + case eBaseTypeBubble: + case eBaseTypePendulum: + case eBaseTypeHangable: + case eBaseTypeButton: + case eBaseTypeProjectile: + case eBaseTypeDestructObj: + case eBaseTypeNPC: + case eBaseTypeBoulder: + *bnd = *(xBound*)((int)tgt + 0x64); + break; + default: + retval = 0; + break; + case eBaseTypeCruiseBubble: + break; + } + return retval; +} + +S32 NPCC_pos_ofBase(xBase* tgt, xVec3* pos) +{ + xVec3 *pxVar1; + S32 retval = 1; + + switch(tgt->baseType) + { + case eBaseTypeCamera: + xVec3Copy(pos, &globals.camera.mat.pos); + break; + case eBaseTypeCruiseBubble: + retval = 0; + break; + case eBaseTypePlayer: + case eBaseTypePickup: + case eBaseTypePlatform: + case eBaseTypeStatic: + case eBaseTypeDynamic: + case eBaseTypeBubble: + case eBaseTypePendulum: + case eBaseTypeHangable: + case eBaseTypeButton: + case eBaseTypeProjectile: + case eBaseTypeDestructObj: + case eBaseTypeNPC: + case eBaseTypeBoulder: + xVec3Copy(pos, xEntGetPos((xEnt *)tgt)); + break; + case eBaseTypeDoor: + case eBaseTypeVolume: + case eBaseTypeEGenerator: + retval = 0; + break; + default: + retval = 0; + break; + } + return retval; +} + +void NPCTarget::PosGet(xVec3* pos) +{ + switch (typ_target) + { + case NPC_TGT_NONE: + break; + case NPC_TGT_PLYR: + case NPC_TGT_ENT: + case NPC_TGT_BASE: + NPCC_pos_ofBase(bas_target, pos); + break; + case NPC_TGT_POS: + xVec3Copy(pos, &pos_target); + break; + case NPC_TGT_MVPT: + xVec3Copy(pos, zMovePointGetPos(nav_target)); + break; + } +} + +void NPCC_xBoundAway(xBound* bnd) +{ + if (bnd->type == XBOUND_TYPE_SPHERE) + { + bnd->box.center.y -= 1000000.0f; + } + else if (bnd->type == XBOUND_TYPE_BOX) + { + bnd->box.center.y -= 1000000.0f; + } +} + +void NPCC_xBoundBack(xBound* bnd) +{ + if (bnd->type == XBOUND_TYPE_SPHERE) + { + bnd->box.center.y += 1000000.0f; + } + else if (bnd->type == XBOUND_TYPE_BOX) + { + bnd->box.center.y += 1000000.0f; + } +} + +void NPCC_DstSq(const xVec3*, const xVec3*, xVec3*); + +void NPCC_DstSqPlyrToPos(const xVec3* pos) +{ + NPCC_DstSq(pos, xEntGetPos(&globals.player.ent), NULL); +} + +F32 NPCC_ds2_toCam(const xVec3* pos_from, xVec3* delta) +{ + xVec3 delt = {}; + xVec3Sub(&delt, &globals.camera.mat.pos, pos_from); + F32 retval = xVec3Length2(&delt); + if (delta != (xVec3 *)0) + { + xVec3Copy(delta, &delt); + } + return retval; +} + +void NPCC_Bounce(xVec3* vec_input, xVec3* vec_anti, F32 elastic) +{ + if (vec_input->x * vec_anti->x < 0.0f) + { + vec_input->x *= -1.0f; + } + + if (vec_input->y * vec_anti->y < 0.0f) + { + vec_input->y *= -1.0f; + } + + if (vec_input->z * vec_anti->z < 0.0f) + { + vec_input->z *= -1.0f; + } + + xVec3SMulBy(vec_input, elastic); +} + +void NPCC_rotHPB(xMat3x3* mat, F32 heading, F32 pitch, F32 bank) +{ + xMat3x3 mat_rot = {}; + + xMat3x3RotZ(mat, bank); + xMat3x3RotX(&mat_rot, -pitch); + xMat3x3Mul(mat, mat, &mat_rot); + xMat3x3RotY(&mat_rot, heading); + xMat3x3Mul(mat, mat, &mat_rot); +} + F32 NPCC_TmrCycle(float* tmr, float dt, float interval) { F32 parameterized; @@ -208,3 +592,18 @@ F32 NPCC_TmrCycle(float* tmr, float dt, float interval) return parameterized; } + +void NPCC_MakePerp(xVec3* dir_perp, const xVec3* dir_axis) +{ + dir_perp->x = dir_axis->y - dir_axis->z; + dir_perp->y = dir_axis->z - dir_axis->x; + dir_perp->z = dir_axis->x - dir_axis->y; + + xVec3Normalize(dir_perp, dir_perp); +} + +void NPCC_MakeArbPlane(const xVec3* dir_norm, xVec3* at, xVec3* rt) +{ + NPCC_MakePerp(at, dir_norm); + xVec3Cross(rt, at, dir_norm); +} \ No newline at end of file diff --git a/src/SB/Game/zNPCSupport.h b/src/SB/Game/zNPCSupport.h index 8dfaa1909..96b6761b9 100644 --- a/src/SB/Game/zNPCSupport.h +++ b/src/SB/Game/zNPCSupport.h @@ -27,7 +27,9 @@ enum _tageNPCSnd enum en_NPC_UI_WIDGETS { - NPC_UI_WIDGETS_unk // Come back after more data is put in + NPC_WIDGE_TALK = 0, + NPC_WIDGE_NOMORE = 1, + NPC_WIDGE_FORCE = 2, }; enum en_fwstate @@ -65,6 +67,9 @@ struct NPCTarget zNPCCommon* npc_owner; void TargetClear(); + void PosGet(xVec3* pos); + void TargetSet(xEnt* ent, int b); + S32 IsDead(); }; struct NPCBlinker @@ -73,6 +78,8 @@ struct NPCBlinker S32 idx_uvcell; void Reset(); + void IndexToUVCoord(int param_1, float* param_2, float* param_3); + void Update(F32 dt, F32 ratio, F32 tym_slow, F32 tym_fast); }; struct NPCWidget @@ -81,16 +88,22 @@ struct NPCWidget xBase* base_widge; zNPCCommon* npc_ownerlock; - U32 NPCIsTheLocker(zNPCCommon* npc_lock); - U32 IsVisible(); + S32 NPCIsTheLocker(const zNPCCommon* npc_lock); + U32 IsLocked(); + S32 IsVisible(); U32 Off(zNPCCommon* npc, U32 theman); - U32 On(zNPCCommon* npc, U32 theman); + U32 On(const zNPCCommon* npc, S32 theman); void Reset(); void Init(en_NPC_UI_WIDGETS); + S32 Lock(const zNPCCommon*); + S32 Unlock(const zNPCCommon*); }; struct Firework { + static F32 acc_thrust; + static F32 acc_gravity; + struct { en_fwstate fwstate : 8; @@ -105,6 +118,7 @@ struct Firework void FlyFlyFly(F32 dt); void Update(F32 dt); void Cleanup(); + void Detonate(); }; bool NPCC_ForceTalkOk(); @@ -115,7 +129,7 @@ void NPCWidget_SceneFinish(); void NPCWidget_SceneReset(); void NPCWidget_ScenePostInit(); void NPCSupport_Startup(); -bool NPCSupport_ScenePrepare(); +void NPCSupport_ScenePrepare(); void NPCSupport_SceneFinish(); void NPCSupport_Timestep(F32 dt); void NPCSupport_SceneReset(); @@ -138,6 +152,7 @@ xVec3* NPCC_faceDir(xEnt* ent); void NPCC_ang_toXZDir(F32 angle, xVec3* dir); F32 NPCC_aimVary(xVec3* dir_aim, xVec3* pos_src, xVec3* pos_tgt, F32 dst_vary, S32 flg_vary, xVec3* pos_aimPoint); +void NPCC_aimMiss(xVec3*, xVec3*, xVec3*, float, xVec3*); F32 NPCC_ds2_toCam(const xVec3* pos_from, xVec3* delta); void zNPC_SNDStop(_tageNPCSnd snd); void zNPC_SNDPlay3D(_tageNPCSnd snd, xEnt*);