diff --git a/configure.py b/configure.py index 8f1608937..a45e7cbcf 100644 --- a/configure.py +++ b/configure.py @@ -556,7 +556,7 @@ def MatchingFor(*versions): Object(Matching, "SB/Game/zNPCTypes.cpp"), Object(NonMatching, "SB/Game/zNPCTypeCommon.cpp", extra_cflags=["-sym on"]), Object(NonMatching, "SB/Game/zNPCTypeRobot.cpp"), - Object(NonMatching, "SB/Game/zNPCTypeVillager.cpp"), + Object(NonMatching, "SB/Game/zNPCTypeVillager.cpp", extra_cflags=["-sym on"]), Object(NonMatching, "SB/Game/zNPCTypeAmbient.cpp"), Object(NonMatching, "SB/Game/zNPCTypeTiki.cpp", extra_cflags=["-sym on"]), Object(NonMatching, "SB/Core/x/xBehaveMgr.cpp", extra_cflags=["-sym on"]), @@ -583,7 +583,7 @@ def MatchingFor(*versions): Object(NonMatching, "SB/Game/zGoo.cpp"), Object(NonMatching, "SB/Game/zGrid.cpp"), Object(Matching, "SB/Game/zNPCGoalScript.cpp", extra_cflags=["-sym on"]), - Object(NonMatching, "SB/Game/zNPCSndTable.cpp"), + Object(NonMatching, "SB/Game/zNPCSndTable.cpp", extra_cflags=["-sym on"]), Object(Matching, "SB/Game/zNPCSndLists.cpp"), Object(NonMatching, "SB/Game/zNPCTypeDuplotron.cpp"), Object(Equivalent, "SB/Core/x/xModelBucket.cpp"), diff --git a/src/SB/Core/x/xFX.h b/src/SB/Core/x/xFX.h index 408c848ff..009740fb8 100644 --- a/src/SB/Core/x/xFX.h +++ b/src/SB/Core/x/xFX.h @@ -167,6 +167,8 @@ extern xFXStreak sStreakList[10]; extern xFXShine sShineList[2]; extern xFXRing ringlist[RING_COUNT]; +extern RpAtomic* (*gAtomicRenderCallBack)(RpAtomic*); + void xFXInit(); U32 xFXShineStart(const xVec3*, F32, F32, F32, F32, U32, const iColor_tag*, const iColor_tag*, F32, S32); diff --git a/src/SB/Core/x/xutil.h b/src/SB/Core/x/xutil.h index 313356b01..20b01e152 100644 --- a/src/SB/Core/x/xutil.h +++ b/src/SB/Core/x/xutil.h @@ -1,6 +1,7 @@ #ifndef XUTIL_H #define XUTIL_H +#include "xMath.h" #include S32 xUtilStartup(); @@ -11,6 +12,89 @@ U32 xUtil_crc_update(U32 crc_accum, char* data, S32 datasize); S32 xUtil_yesno(F32 wt_yes); void xUtil_wtadjust(F32* wts, S32 cnt, F32 arbref); -template static T* xUtil_select(T** arg0, S32 arg1, const F32* arg3); +template T* xUtil_select(T** data, S32 size, const F32* arg2) +{ + T* selected = NULL; + S32 selectIdx = 0; + F32 tempValue; + + if (data == NULL) + { + return NULL; + } + else if (size < 1) + { + return NULL; + } + + F32 randOffset = xurand(); + if (arg2 == NULL) + { + selectIdx = (S32)(randOffset * (F32)size); + } + else + { + F32* roundingData = (F32*)arg2; + F32 threshold = 0.0f; + S32 counter = 0; + + for (S32 i = size; i > 0; i--) + { + tempValue = threshold; + threshold += *roundingData; + if (randOffset >= tempValue && randOffset <= threshold) + { + selectIdx = counter; + break; + } + roundingData++; + counter++; + } + } + + if (selectIdx >= size) + { + selectIdx = size - 1; + } + + if (selectIdx < 0) + { + selectIdx = 0; + } + + return data[selectIdx]; +} + +template T xUtil_choose(T const* list, S32 size, F32 const* float_list) +{ + if (list == NULL) + return NULL; + if (size < 1) + return NULL; + S32 idx = 0; + F32 rand = xurand(); + if (float_list == NULL) + idx = rand * size; + else + { + const F32* float_it = float_list; + F32 total = 0.0f; + for (S32 i = 0; i < size; float_it++, i++) + { + F32 prev_total = total; + total += *float_it; + if (rand >= prev_total && rand <= total) + { + idx = i; + break; + } + } + } + if (idx >= size) + idx = size - 1; + if (idx < 0) + idx = 0; + return list[idx]; +} #endif diff --git a/src/SB/Game/zEntCruiseBubble.cpp b/src/SB/Game/zEntCruiseBubble.cpp index 27bd996dc..d3d2feeb0 100644 --- a/src/SB/Game/zEntCruiseBubble.cpp +++ b/src/SB/Game/zEntCruiseBubble.cpp @@ -40,8 +40,6 @@ basic_rect default_adjust = { 0.0f, 0.0f, 1.0f, 1.0f }; extern iColor_tag zEntCruiseBubble_color_80_00_00_FF; // 128, 0, 0, 255 extern iColor_tag zEntCruiseBubble_color_FF_14_14_FF; // 255, 20, 20, 255 -extern RpAtomic* (*gAtomicRenderCallBack)(RpAtomic*); - namespace cruise_bubble { namespace diff --git a/src/SB/Game/zGameExtras.cpp b/src/SB/Game/zGameExtras.cpp index 4bdd0e791..0a17e5a77 100644 --- a/src/SB/Game/zGameExtras.cpp +++ b/src/SB/Game/zGameExtras.cpp @@ -7,7 +7,7 @@ #include "xSnd.h" #include "xEnt.h" #include "xCounter.h" -#include "xMath.h" +#include "xUtil.h" #include "zGameExtras.h" #include "zEntPlayer.h" @@ -740,49 +740,3 @@ U32 zGame_HackIsGallery() } return 0; } - -template <> U32 xUtil_choose(U32 const* list, S32 size, F32 const* float_list) -{ - if (list == NULL) - { - return NULL; - } - - if (size < 1) - { - return NULL; - } - - S32 idx = 0; - F32 rand = xurand(); - - if (float_list == NULL) - { - idx = rand * size; - } - else - { - const F32* float_it = float_list; - F32 total = 0.0f; - for (S32 i = 0; i < size; float_it++, i++) - { - float prev_total = total; - total += *float_it; - if (rand >= prev_total && rand <= total) - { - idx = i; - break; - } - } - } - - if (idx >= size) - { - idx = size - 1; - } - if (idx < 0) - { - idx = 0; - } - return list[idx]; -} diff --git a/src/SB/Game/zGameExtras.h b/src/SB/Game/zGameExtras.h index a97ac4811..74a060ec9 100644 --- a/src/SB/Game/zGameExtras.h +++ b/src/SB/Game/zGameExtras.h @@ -84,6 +84,4 @@ void GEC_cb_PanHandle(); void zGame_HackGalleryInit(); U32 zGame_HackIsGallery(); -template T xUtil_choose(T const* list, S32 size, F32 const* c); - #endif diff --git a/src/SB/Game/zNPCGoalCommon.h b/src/SB/Game/zNPCGoalCommon.h index b11b38f6e..2e760b47a 100644 --- a/src/SB/Game/zNPCGoalCommon.h +++ b/src/SB/Game/zNPCGoalCommon.h @@ -44,7 +44,7 @@ struct zNPCGoalCommon : xGoal return 0; } - virtual U8 CollReview(void*) + virtual S32 CollReview(void*) { return 0; } diff --git a/src/SB/Game/zNPCGoalRobo.cpp b/src/SB/Game/zNPCGoalRobo.cpp index 674c48992..64fa3c23b 100644 --- a/src/SB/Game/zNPCGoalRobo.cpp +++ b/src/SB/Game/zNPCGoalRobo.cpp @@ -5037,12 +5037,12 @@ void zNPCGoalDogLaunch::SilentSwimout(xVec3* unk1, xVec3* unk2, zMovePoint* unk3 this->ViciousAttack(unk1, unk2, unk3, 1); } -U8 zNPCGoalPatThrow::CollReview(void*) +S32 zNPCGoalPatThrow::CollReview(void*) { return 0; } -U8 zNPCGoalDogLaunch::CollReview(void*) +S32 zNPCGoalDogLaunch::CollReview(void*) { return 0; } diff --git a/src/SB/Game/zNPCGoalStd.h b/src/SB/Game/zNPCGoalStd.h index dee0ae678..f40c30fc6 100644 --- a/src/SB/Game/zNPCGoalStd.h +++ b/src/SB/Game/zNPCGoalStd.h @@ -323,7 +323,7 @@ class zNPCGoalLassoThrow : public zNPCGoalCommon S32 Enter(F32 dt, void* updCtxt); S32 Exit(F32 dt, void* updCtxt); S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* xscn); - U8 CollReview(void*); + S32 CollReview(void*); void ApplyYank(S32 left); S32 flg_throw; // offset 0x4C, size 0x4 S32 floorBounce; // offset 0x50, size 0x4 @@ -635,7 +635,7 @@ struct zNPCGoalPatThrow : zNPCGoalCommon } S32 Enter(F32 dt, void* updCtxt); - U8 CollReview(void*); + S32 CollReview(void*); }; enum en_alertchuk @@ -771,7 +771,7 @@ class zNPCGoalAlertGlove : public zNPCGoalCommon void FXWhirlwind(); void CalcAttackVector(); void CheckHandBones(); - U8 CollReview(void*); + S32 CollReview(void*); F32 tmr_attack; // offset 0x4C, size 0x4 F32 tmr_minAttack; // offset 0x50, size 0x4 xVec3 pos_began; // offset 0x54, size 0xC @@ -1050,11 +1050,12 @@ struct zNPCGoalDogLaunch : zNPCGoalCommon void ViciousAttack(xVec3* unk1, xVec3* unk2, zMovePoint* unk3, S32 unk4); void PreCollide(); S32 BallisticUpdate(F32 dt); - void BubTrailCone(const xVec3* pos, S32 num, const xVec3* pos_rand, const xVec3* vel_rand, const xMat3x3* mat); + void BubTrailCone(const xVec3* pos, S32 num, const xVec3* pos_rand, const xVec3* vel_rand, + const xMat3x3* mat); void FurryFlurry(); void SilentSwimout(xVec3* unk1, xVec3* unk2, zMovePoint* unk3); - U8 CollReview(void*); + S32 CollReview(void*); }; class zNPCGoalDogBark : public zNPCGoalLoopAnim @@ -1349,7 +1350,7 @@ class zNPCGoalKnock : public zNPCGoalCommon S32 Exit(F32 dt, void* updCtxt); S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* xscn); S32 InputInfo(NPCDamageInfo* info); - U8 CollReview(void*); + S32 CollReview(void*); void StreakPrep(); void StreakDone(); void StreakUpdate(); @@ -1371,7 +1372,7 @@ class zNPCGoalWound : public zNPCGoalPushAnim S32 Enter(F32, void*); S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* xscn); - U8 CollReview(void*); + S32 CollReview(void*); S32 NPCMessage(NPCMsg*); xVec3 dir_fling; // offset 0x54, size 0xC S32 flg_knock; // offset 0x60, size 0x4 diff --git a/src/SB/Game/zNPCGoalVillager.h b/src/SB/Game/zNPCGoalVillager.h index bbb0da4c8..8f401be29 100644 --- a/src/SB/Game/zNPCGoalVillager.h +++ b/src/SB/Game/zNPCGoalVillager.h @@ -141,7 +141,7 @@ struct zNPCGoalBoyFall : zNPCGoalCommon } virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); - virtual U8 CollReview(void*); + virtual S32 CollReview(void*); }; struct zNPCGoalBoyWeep : zNPCGoalCommon diff --git a/src/SB/Game/zNPCHazard.cpp b/src/SB/Game/zNPCHazard.cpp index 59811c473..c6674836f 100644 --- a/src/SB/Game/zNPCHazard.cpp +++ b/src/SB/Game/zNPCHazard.cpp @@ -10,7 +10,7 @@ #include "zNPCSupport.h" #include "xMath.h" #include "xMathInlines.h" -#include "zGameExtras.h" +#include "xUtil.h" extern U32 g_hash_hazanim[3]; extern char* g_strz_hazanim[3]; @@ -40,7 +40,7 @@ static en_hazmodel g_funfrag_choices[8] = { NPC_HAZMDL_FUNFRAG_CELLPHONE, NPC_HAZMDL_FUNFRAG_SHOE, }; -static zShrapnelAsset * g_data_hazshrap[5] = { NULL, NULL, NULL, NULL, NULL }; +static zShrapnelAsset* g_data_hazshrap[5] = { NULL, NULL, NULL, NULL, NULL }; static char* g_strz_hazModel[30]; static NPCHazard g_hazards[64]; @@ -374,7 +374,8 @@ void NPCHazard::Upd_PuppyNuke(F32 dt) } } - if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && this->pam_interp > 0.7f) + if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && + this->pam_interp > 0.7f) { zNPCMsg_AreaNPCExplodeNoRobo(npc_owner, ball->rad_max, &this->pos_hazard); this->flg_casthurt = 1; @@ -399,7 +400,8 @@ void NPCHazard::Upd_FodBomb(F32 dt) } } - if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && this->pam_interp > 0.7f) + if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && + this->pam_interp > 0.7f) { zNPCMsg_AreaNPCExplodeNoRobo(npc_owner, ball->rad_max, &this->pos_hazard); this->flg_casthurt = 1; @@ -415,7 +417,7 @@ void NPCHazard::FodBombBubbles(F32 dt) static const xVec3 pos_spread = { 0.1f, 2.0f, 0.1f }; static const xVec3 pos_offsetFirst = { 0.0f, -0.5f, 0.0f }; static const xVec3 pos_offsetLater = { 0.0f, -1.0f, 0.0f }; - + if (this->flg_hazard & 0x8) { xVec3 pos_emit = this->pos_hazard; @@ -429,7 +431,7 @@ void NPCHazard::FodBombBubbles(F32 dt) xVec3 pos_emit = this->pos_hazard; pos_emit += pos_offsetLater; - zFX_SpawnBubbleSlam(&pos_emit, 0x18, PI, 4.0f * tym, tym); + zFX_SpawnBubbleSlam(&pos_emit, 0x18, PI, 4.0f * tym, tym); } } @@ -438,7 +440,8 @@ void NPCHazard::Upd_CattleProd(F32 dt) HAZCatProd* catprod = &this->custdata.catprod; catprod->rad_cur = LERP(isin(PI * this->pam_interp), catprod->rad_min, catprod->rad_max); - if (this->flg_hazard & 0x2000 && !(globals.player.DamageTimer > 0.0f) && this->tym_lifespan - this->tmr_remain > 0.25f) + if (this->flg_hazard & 0x2000 && !(globals.player.DamageTimer > 0.0f) && + this->tym_lifespan - this->tmr_remain > 0.25f) { if (ColPlyrSphere(catprod->rad_cur)) { @@ -455,7 +458,7 @@ void NPCHazard::Upd_CattleProd(F32 dt) pos_lytend.x = catprod->rad_cur; pos_lytend.y = catprod->rad_cur; pos_lytend.z = catprod->rad_cur; - + info.time = this->tmr_remain; info.start = &this->pos_hazard; @@ -470,7 +473,7 @@ void NPCHazard::Upd_CattleProd(F32 dt) xVec3AddTo(&pos_lytend, &this->pos_hazard); info.end = &pos_lytend; catprod->zap_lyta = zLightningAdd(&info); - + xVec3SubFrom(&pos_lytend, &this->pos_hazard); pos_lytend.y *= -1.0f; xVec3AddTo(&pos_lytend, &this->pos_hazard); @@ -490,20 +493,21 @@ void NPCHazard::Upd_CattleProd(F32 dt) if (tym > 0.8f && tym < 1.0f) { xVec3SMul(&pos_lytend, NPCC_faceDir(this->npc_owner), catprod->rad_cur); - xVec3AddScaled(&pos_lytend, NPCC_rightDir(this->npc_owner), (xrand() & 0x800000 ? 0.2f : 0.2f) * xurand()); + xVec3AddScaled(&pos_lytend, NPCC_rightDir(this->npc_owner), + (xrand() & 0x800000 ? 0.2f : 0.2f) * xurand()); } else { pos_lytend.x *= xurand(); pos_lytend.y *= xurand(); - pos_lytend.z *= xurand(); + pos_lytend.z *= xurand(); } } else { pos_lytend.x *= xurand(); pos_lytend.y *= xurand(); - pos_lytend.z *= xurand(); + pos_lytend.z *= xurand(); } xVec3AddTo(&pos_lytend, &this->pos_hazard); @@ -543,7 +547,7 @@ void NPCHazard::Upd_TubeletBlast(F32 dt) } static S32 moreorless = 0; - + if (--moreorless < 0) { moreorless = 3; @@ -578,7 +582,8 @@ void NPCHazard::Upd_DuploBoom(F32 dt) } } - if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && this->pam_interp > 0.7f) + if (this->flg_casthurt == 0 && this->npc_owner != NULL && this->flg_hazard & 0x2000 && + this->pam_interp > 0.7f) { zNPCMsg_AreaNPCExplodeNoRobo(npc_owner, ball->rad_max, &this->pos_hazard); this->flg_casthurt = 1; @@ -687,7 +692,7 @@ void NPCHazard::Upd_TTFlight(F32 dt) ReconTarTar(); return; } - + MarkForRecycle(); return; } @@ -728,7 +733,9 @@ void NPCHazard::Upd_TTFlight(F32 dt) PreCollide(); } - F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? this->tym_lifespan : this->tym_lifespan - this->tmr_remain; + F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? + this->tym_lifespan : + this->tym_lifespan - this->tmr_remain; xParabolaEvalPos(parab, &this->pos_hazard, tym); xParabolaEvalVel(parab, &tartar->vel, tym); @@ -748,36 +755,36 @@ void NPCHazard::Upd_TTFlight(F32 dt) if (ColPlyrSphere(tartar->rad_cur)) { HurtThePlayer(); - g_data_hazshrap[2]->initCB(g_data_hazshrap[2], globals.player.ent.model, &tartar->vel, NULL); - + g_data_hazshrap[2]->initCB(g_data_hazshrap[2], globals.player.ent.model, + &tartar->vel, NULL); + xVec3 whence; xParabolaEvalVel(parab, &whence, parab->maxTime); xVec3Inv(&whence, &whence); - + TarTarSplash(&whence); MarkForRecycle(); return; } - } - StaggeredCollide(); + StaggeredCollide(); - if (this->flg_hazard & 0x8) - { - TarTarFalumpf(); - } - else - { - TarTarGunkTrail(); - } + if (this->flg_hazard & 0x8) + { + TarTarFalumpf(); + } + else + { + TarTarGunkTrail(); + } - static S32 moreorless = 0; + static S32 moreorless = 0; - if (--moreorless < 0) - { - moreorless = 4; - zFX_SpawnBubbleTrail(&this->pos_hazard, 0x6); - } + if (--moreorless < 0) + { + moreorless = 4; + zFX_SpawnBubbleTrail(&this->pos_hazard, 0x6); + } } } @@ -1551,7 +1558,8 @@ void NPCHazard::ReconSlickOil() { xVec3Copy((xVec3*)&this->mdl_hazard->Mat->up, &dir_norm); NPCC_MakePerp((xVec3*)&this->mdl_hazard->Mat->at, &dir_norm); - xVec3Cross((xVec3*)&this->mdl_hazard->Mat->right, (xVec3*)&this->mdl_hazard->Mat->up, (xVec3*)&this->mdl_hazard->Mat->at); + xVec3Cross((xVec3*)&this->mdl_hazard->Mat->right, (xVec3*)&this->mdl_hazard->Mat->up, + (xVec3*)&this->mdl_hazard->Mat->at); } xMat3x3 mat; @@ -1574,7 +1582,7 @@ void NPCHazard::OilSplash(const xVec3* dir_norm) xVec3 up; xVec3 at; xVec3 rt; - + if (dir_norm) { up = *dir_norm; @@ -1626,7 +1634,7 @@ void NPCHazard::Upd_OilOoze(F32 dt) { static F32 seg_pam[2] = { 0.15f, 0.75f }; HAZBall* ball = &this->custdata.ball; - + if (this->pam_interp <= seg_pam[0]) { ball->rad_cur = (ball->rad_max - ball->rad_min) * EASE(this->pam_interp / seg_pam[0]); @@ -1634,7 +1642,8 @@ void NPCHazard::Upd_OilOoze(F32 dt) } else if (this->pam_interp >= seg_pam[1]) { - ball->rad_cur = (ball->rad_max - ball->rad_min) * EASE(1.0f - ((this->pam_interp - seg_pam[1]) / (1.0f - seg_pam[1]))); + ball->rad_cur = (ball->rad_max - ball->rad_min) * + EASE(1.0f - ((this->pam_interp - seg_pam[1]) / (1.0f - seg_pam[1]))); ball->rad_cur += ball->rad_min; } else @@ -1667,7 +1676,8 @@ void NPCHazard::Upd_OilOoze(F32 dt) this->tmr_nextglob = -1.0f > this->tmr_nextglob - dt ? -1.0f : this->tmr_nextglob - dt; - if (this->flg_hazard & 0x2000 && !(globals.player.DamageTimer > 0.0f) && ColPlyrSphere(ball->rad_cur)) + if (this->flg_hazard & 0x2000 && !(globals.player.DamageTimer > 0.0f) && + ColPlyrSphere(ball->rad_cur)) { NPCC_Slick_MakePlayerSlip(this->npc_owner); } @@ -1689,7 +1699,7 @@ void NPCHazard::Upd_OilOoze(F32 dt) S32 NPCHazard::KickOilBurst() { NPCHazard* haz = HAZ_Acquire(); - + S32 ok; if (haz == NULL) { @@ -1719,7 +1729,7 @@ S32 NPCHazard::KickOilGlobby() { HAZBall* ball = &this->custdata.ball; NPCHazard* haz = HAZ_Acquire(); - + S32 ok; if (haz == NULL) { @@ -1783,7 +1793,7 @@ void NPCHazard::Upd_OilGlob(F32 dt) shroom->vel_rise += shroom->acc_rise * dt; if (this->flg_hazard & 0x2000 && !(globals.player.DamageTimer > 0.0f) && - ColPlyrSphere(shroom->rad_cur)) + ColPlyrSphere(shroom->rad_cur)) { NPCC_Slick_MakePlayerSlip(this->npc_owner); } @@ -1821,7 +1831,9 @@ void NPCHazard::Upd_FunFrag(F32 dt) PreCollide(); } - F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? this->tym_lifespan : this->tym_lifespan - this->tmr_remain; + F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? + this->tym_lifespan : + this->tym_lifespan - this->tmr_remain; xParabolaEvalPos(parab, &this->pos_hazard, tym); xParabolaEvalVel(parab, &tartar->vel, tym); @@ -1837,7 +1849,7 @@ void NPCHazard::StreakUpdate(U32 streakID, F32 rad) { xVec3 pos_left; pos_left = *(xVec3*)At() * 0.5f * rad; - + xVec3 pos_right; pos_right = *(xVec3*)Up() * rad; pos_right += pos_left; @@ -1881,7 +1893,9 @@ void NPCHazard::Upd_RoboBits(F32 dt) this->tym_lifespan = keepFlightTime; } - F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? this->tym_lifespan : this->tym_lifespan - this->tmr_remain; + F32 tym = this->tym_lifespan < this->tym_lifespan - this->tmr_remain ? + this->tym_lifespan : + this->tym_lifespan - this->tmr_remain; xParabolaEvalPos(parab, &this->pos_hazard, tym); xParabolaEvalVel(parab, &tartar->vel, tym); @@ -1895,7 +1909,8 @@ void NPCHazard::Upd_RoboBits(F32 dt) void NPCHazard::Upd_VisSplash(F32 dt) { - this->custdata.collide.rad_cur = LERP(this->pam_interp, this->custdata.collide.rad_min, this->custdata.collide.rad_max); + this->custdata.collide.rad_cur = + LERP(this->pam_interp, this->custdata.collide.rad_min, this->custdata.collide.rad_max); if (this->flg_hazard & 0x8) { @@ -1917,7 +1932,7 @@ void NPCHazard::VisSplashSparklies() pos_emit *= rad; pos_emit += *(xVec3*)Up() * 0.2f; pos_emit += this->pos_hazard; - + xVec3 vel_emit; vel_emit = *(xVec3*)Up(); vel_emit *= 3.5f; diff --git a/src/SB/Game/zNPCSndTable.cpp b/src/SB/Game/zNPCSndTable.cpp index 1ad4f080f..e191e15b3 100644 --- a/src/SB/Game/zNPCSndTable.cpp +++ b/src/SB/Game/zNPCSndTable.cpp @@ -118,7 +118,6 @@ NPCSndProp* NPCS_SndFindProps(en_NPC_SOUND sndtype) en_NPC_SOUND NPCS_SndTypeFromHash(U32 aid_snd, NPCSndTrax* cust, NPCSndTrax* share) { - // non-matching en_NPC_SOUND da_type = NPC_STYP_BOGUS; NPCSndTrax* trax; @@ -149,7 +148,7 @@ en_NPC_SOUND NPCS_SndTypeFromHash(U32 aid_snd, NPCSndTrax* cust, NPCSndTrax* sha { da_type = trax->typ_sound; - return da_type; + break; } } } @@ -158,82 +157,82 @@ en_NPC_SOUND NPCS_SndTypeFromHash(U32 aid_snd, NPCSndTrax* cust, NPCSndTrax* sha return da_type; } -// WIP U32 NPCS_SndPickSimilar(en_NPC_SOUND sndtype, NPCSndTrax* cust, NPCSndTrax* share) { - S32 cnt = 0; + U32 aid_choice; + NPCSndTrax* trax; + S32 i; + S32 ingroup; S32 list[32] = {}; F32 wts[32] = { 1.0f }; + S32 cnt; + F32 use_wt; - for (S32 si = 0; si < 4; si++) - { - NPCSndTrax* trax; - F32 weight; + aid_choice = 0; + cnt = 0; - if (si == 0) + for (i = 0; i < 3; i++) + { + if (i == 0) { + use_wt = 2.0f; trax = cust; - weight = 2.0f; } - else if (si == 1) + else if (i == 1) { + use_wt = 1.5f; trax = share; - weight = 1.5f; } - else + else if (i == 2) { - if (cnt >= 5) - { - trax = NULL; - weight = 0.0f; - } - else if (si == 2) - { + use_wt = 1.0f; + trax = NULL; + if (cnt < 5) trax = g_sndTrax_General; - weight = 1.0f; - } - else - { + } + else + { + use_wt = 1.0f; + trax = NULL; + if (cnt < 5) trax = g_sndTrax_Universal; - weight = 1.0f; - } } if (trax == NULL) - { continue; - } - bool in_group = false; - for (; trax->typ_sound != NPC_STYP_LISTEND; trax++) + ingroup = 0; + + while (trax->typ_sound != NPC_STYP_LISTEND) { if (trax->typ_sound == sndtype) { - in_group = true; - if (trax->aid_sound != 0 && cnt < 32) + ingroup = 1; + + if (trax->aid_sound != 0) { - wts[cnt] = weight; + wts[cnt] = use_wt; list[cnt] = trax->aid_sound; cnt++; } } - else if (in_group) + else if (ingroup) { break; } if (cnt >= 32) - { break; - } + + trax++; } } if (cnt > 0) { xUtil_wtadjust(wts, cnt, 1.0f); - return xUtil_choose(list, cnt, wts); + aid_choice = xUtil_choose(list, cnt, wts); } - return 0; + return aid_choice; } diff --git a/src/SB/Game/zNPCSpawner.cpp b/src/SB/Game/zNPCSpawner.cpp index 7ac848e40..22c013204 100644 --- a/src/SB/Game/zNPCSpawner.cpp +++ b/src/SB/Game/zNPCSpawner.cpp @@ -8,6 +8,7 @@ #include "zGlobals.h" #include "xMathInlines.h" #include "zNPCTypeRobot.h" +#include "xUtil.h" static SMDepot g_smdepot = {}; static S32 g_drawSpawnBounds; @@ -843,62 +844,3 @@ S32 zMovePoint::IsOn() // even though a single byte is moved into the return register return (S32)this->on; } - -template T* xUtil_select(T** data, S32 size, const F32* arg2) -{ - T* selected = NULL; - S32 selectIdx = 0; - - F32 randOffset; - - if (data == NULL) - { - return NULL; - } - else if (size < 1) - { - return NULL; - } - - randOffset = xurand(); - if (arg2 == NULL) - { - selectIdx = (S32)(randOffset * (F32)size); - } - else - { - F32* roundingData = (F32*)arg2; - F32 threshold = 0.0f; - S32 counter = 0; - - // TODO: Fix float arithmetic and symbols - for (S32 i = size; i > 0; i--) - { - F32 tempValue = threshold; - threshold += *roundingData; - - if (randOffset >= threshold) - { - if (randOffset <= tempValue) - { - selectIdx = counter; - break; - } - } - roundingData++; - counter++; - } - } - - if (selectIdx >= size) - { - selectIdx = size - 1; - } - - if (selectIdx < 0) - { - selectIdx = 0; - } - - return data[selectIdx]; -} diff --git a/src/SB/Game/zNPCSupplement.h b/src/SB/Game/zNPCSupplement.h index 97bdd1a51..dfeafc782 100644 --- a/src/SB/Game/zNPCSupplement.h +++ b/src/SB/Game/zNPCSupplement.h @@ -340,7 +340,11 @@ void NPAR_Upd_DogBreath(NPARMgmt* mgmt, F32 dt); void NPAR_Upd_Fireworks(NPARMgmt* mgmt, F32 dt); NPARMgmt* NPAR_PartySetup(en_nparptyp parType, void** userData, NPARXtraData* xtraData); void NPAR_SceneReset(); +void NPCC_RenderProjTexture(RwRaster* rast, F32 factor, xMat4x3* mat, F32 radius, F32 height, + xShadowCache* cache, S32 fillCache, xEnt* ent); static void NPCC_ShadowCacheReset(); +xShadowCache* NPCC_ShadowCacheReserve(); +void NPCC_ShadowCacheRelease(xShadowCache* shadcache); void NPAR_Timestep(F32 dt); void NPAR_EmitDroplets(en_nparmode, const xVec3*, const xVec3*); void NPCC_MakeStreakInfo(en_npcstreak styp, StreakInfo* info); diff --git a/src/SB/Game/zNPCSupport.h b/src/SB/Game/zNPCSupport.h index 0a860971e..179328e7b 100644 --- a/src/SB/Game/zNPCSupport.h +++ b/src/SB/Game/zNPCSupport.h @@ -72,7 +72,10 @@ struct NPCTarget S32 IsDead(); S32 FindNearest(S32 flg_consider, xBase* skipme, xVec3* from, F32 dst_max); S32 InCylinder(xVec3* from, F32 rad, F32 hyt, F32 off); - U32 HaveTarget(); + S32 HaveTarget() + { + return (*(S32*)this != 0); + } }; struct NPCBlinker diff --git a/src/SB/Game/zNPCTypeVillager.cpp b/src/SB/Game/zNPCTypeVillager.cpp index d4e9e9ae3..a58e9c32e 100644 --- a/src/SB/Game/zNPCTypeVillager.cpp +++ b/src/SB/Game/zNPCTypeVillager.cpp @@ -1,13 +1,16 @@ #include "zNPCTypeVillager.h" -#include "xMath3.h" -#include "xVec3.h" +#include "xBehaveMgr.h" +#include "xJaw.h" +#include "xMathInlines.h" +#include "zGameExtras.h" #include "zGlobals.h" -#include "zNPCTypeCommon.h" -#include "zNPCTypes.h" +#include "zNPCGoalVillager.h" +#include "zNPCSupplement.h" #include "zNPCGoals.h" -#include "zTaskBox.h" +#include "zRenderState.h" #include "xDebug.h" +#include "xUtil.h" #define Unknown 0 #define Idle01 1 @@ -36,110 +39,22 @@ #define Talk03 24 #define Talk04 25 -extern U32 g_hash_folkanim[26]; -extern char* g_strz_platanim[2]; -extern U32 g_hash_platanim[2]; -extern zParEmitter* g_pemit_aqualeak; -extern xParEmitterCustomSettings g_parf_aqualeak; -extern const xVec3 g_O3; +U32 g_hash_folkanim[26] = {}; -static char* g_strz_folkanim[26] = { +zParEmitter* g_pemit_aqualeak; +static xParEmitterCustomSettings g_parf_aqualeak; + +char* g_strz_folkanim[26] = { "Unknown", "Idle01", "Move01", "Hurt01", "Yawn01", "Talk01", "Flee01", "Fear01", "Pray01", "Clap01", "Special01", "Ride01", "Bump01", "Fall01", "Land01", "Weep01", "Swim01", "Idle02", "Idle03", "Idle04", "Yawn02", "Yawn03", "Yawn04", "Talk02", "Talk03", "Talk04", }; -// Taken from zNPCTypeVillager.s -// Defining these here makes the stringBase0 offsets match in the later functions. -static char* str27 = "fish_d_balloon_move"; -static char* str28 = "fish_d_balloon_hit"; -static char* str29 = "zNPCVillager"; -static char* str30 = "zNPCBallonBoy"; -static char* str31 = "zNPCSuperFriend"; -static char* str32 = "NonRandomTalkAnims"; -static char* str33 = "FAB1001"; -static char* str34 = "FAB1002"; -static char* str35 = "FAB1003"; -static char* str36 = "FAB1004"; -static char* str37 = "FAB1011"; -static char* str38 = "FAB1017"; -static char* str39 = "FAB1018"; -static char* str40 = "FAB1019"; -static char* str41 = "FAB1020"; -static char* str42 = "FAB1021"; -static char* str43 = "FAB1022"; -static char* str44 = "FAB1023"; -static char* str45 = "FAB1025"; -static char* str46 = "FAB1029"; -static char* str47 = "FAB1030"; -static char* str48 = "FAB1032"; -static char* str49 = "FAB1033"; -static char* str50 = "FAB1034"; -static char* str51 = "FAB1035"; -static char* str52 = "FAB1038"; -static char* str53 = "FAB1046"; -static char* str54 = "FAB1047"; -static char* str55 = "FAB1049"; -static char* str56 = "FAB1073"; -static char* str57 = "FAB1074"; -static char* str58 = "FAB1076"; -static char* str59 = "FAB1077"; -static char* str60 = "FAB1078"; -static char* str61 = "FAB1079"; -static char* str62 = "FAB1080"; -static char* str63 = "FAB1006"; -static char* str64 = "FAB1012"; -static char* str65 = "FAB1016"; -static char* str66 = "FAB1024"; -static char* str67 = "FAB1026"; -static char* str68 = "FAB1065"; -static char* str69 = "FAB1039_a"; -static char* str70 = "FAB1039_b"; -static char* str71 = "FAB1039_c"; -static char* str72 = "FAB1055"; -static char* str73 = "FAB1040"; -static char* str74 = "FAB1053"; -static char* str75 = "FAB1081_a"; -static char* str76 = "FAB1081_b"; -static char* str77 = "FAB1042"; -static char* str78 = "FAB1045"; -static char* str79 = "FAB1056"; -static char* str80 = "FAB1064"; -static char* str81 = "FAB1050"; -static char* str82 = "FAB1007"; -static char* str83 = "FAB1007_b"; -static char* str84 = "FAB1031"; -static char* str85 = "FAB1082_a"; -static char* str86 = "FAB1082_b"; -static char* str87 = "FAB1010"; -static char* str88 = "FAB1027"; -static char* str89 = "FAB1037"; -static char* str90 = "FAB1052"; -static char* str91 = "FAB1067"; -static char* str92 = "FAB1014"; -static char* str93 = "FAB1008"; -static char* str94 = "FAB1036"; -static char* str95 = "FAB1041_a"; -static char* str96 = "FAB1041_b"; -static char* str97 = "FAB1054"; -static char* str98 = "FAB1013"; -static char* str99 = "FAB1009"; -static char* str100 = "FAB1028"; -static char* str101 = "FAB1051"; -static char* str102 = "FAB1072"; -static char* str103 = "FAB1083"; -static char* str104 = "NPC|zNPCNewsFish|screen|on screen|x"; -static char* str105 = "NPC|zNPCNewsFish|screen|on screen|y"; -static char* str106 = "NPC|zNPCNewsFish|screen|off screen|x"; -static char* str107 = "NPC|zNPCNewsFish|screen|off screen|y"; -static char* str108 = "NPC|zNPCNewsFish|screen|size"; -static char* str109 = "NPC|zNPCNewsFish|screen|rotation"; -static char* str110 = "NPC|zNPCNewsFish|screen|appearSpeed"; -static char* str111 = "NPC|zNPCNewsFish|screen|disappearSpeed"; -static char* str112 = "shadow_balloons"; -static char* str113 = "gloss_edge"; -static char* str114 = "rainbowfilm_smooth32"; -static char* str115 = "PAREMIT_FOLK_SANDYB_LEAK"; +static U32 g_hash_platanim[2] = {}; +static char* g_strz_platanim[2] = { "fish_d_balloon_move", "fish_d_balloon_hit" }; + +F32 g_vilg_ds2_playernear = 25.0f; +static F32 g_rad_cowercheck = 15.0f; void ZNPC_Villager_Startup() { @@ -178,12 +93,7 @@ void zNPCVillager_ScenePostInit() FOLK_InitEffects(); } -void zNPCVillager_SceneTimestep(xScene *xscn, F32 dt) -{ - zNPCBubbleBuddy_AlphaUpdate(dt); -} - -void zNPCVillager_SceneTimestep(F32 dt) +void zNPCVillager_SceneTimestep(xScene* xscn, F32 dt) { zNPCBubbleBuddy_AlphaUpdate(dt); } @@ -283,7 +193,11 @@ xAnimTable* ZNPC_AnimTable_Villager(xAnimTable* callerTable) xAnimTable* table = callerTable; char** names = g_strz_folkanim; - if (table == NULL) + if (callerTable != NULL) + { + table = callerTable; + } + else { table = xAnimTableNew("zNPCVillager", NULL, 0x0); } @@ -309,7 +223,7 @@ xAnimTable* ZNPC_AnimTable_Villager(xAnimTable* callerTable) xAnimTableNewState(table, names[Special01], 0x10, 0x1, 1.0f, NULL, NULL, 0.0f, NULL, NULL, xAnimDefaultBeforeEnter, NULL, NULL); - NPCC_BuildStandardAnimTran(table, names, ourAnims, 1, 0.2f); + NPCC_BuildStandardAnimTran(table, g_strz_folkanim, ourAnims, 1, 0.2f); xAnimTableNewTransition(table, names[Pray01], names[Fear01], NULL, NULL, 0x10, 0x0, 0.0f, 0.0f, 0, 0, 0.35f, NULL); @@ -328,7 +242,11 @@ xAnimTable* ZNPC_AnimTable_BalloonBoy(xAnimTable* callerTable) xAnimTable* table = callerTable; char** names = g_strz_folkanim; - if (table == NULL) + if (callerTable != NULL) + { + table = callerTable; + } + else { table = xAnimTableNew("zNPCBallonBoy", NULL, 0x0); } @@ -348,9 +266,9 @@ xAnimTable* ZNPC_AnimTable_BalloonBoy(xAnimTable* callerTable) xAnimTableNewState(table, names[Swim01], 0x10, 0x1, 1.0f, NULL, NULL, 0.0f, NULL, NULL, xAnimDefaultBeforeEnter, NULL, NULL); - NPCC_BuildStandardAnimTran(table, names, ourAnims, 1, 0.2f); + NPCC_BuildStandardAnimTran(table, g_strz_folkanim, ourAnims, 1, 0.2f); - xAnimTableNewTransition(table, names[Fall01], names[Bump01], NULL, NULL, 0x10, 0x0, 0.0f, 0.0f, + xAnimTableNewTransition(table, names[Bump01], names[Ride01], NULL, NULL, 0x10, 0x0, 0.0f, 0.0f, 0, 0, 0.35f, NULL); xAnimTableNewTransition(table, names[Land01], names[Weep01], NULL, NULL, 0x10, 0x0, 0.0f, 0.0f, 0, 0, 0.35f, NULL); @@ -367,10 +285,14 @@ xAnimTable* ZNPC_AnimTable_SuperFriend(xAnimTable* callerTable) { S32 ourAnims[10] = { Idle02, Idle03, Idle04, Yawn02, Yawn03, Yawn04, Talk02, Talk03, Talk04, Unknown }; - xAnimTable* table = callerTable; + xAnimTable* table; char** names = g_strz_folkanim; - if (table == NULL) + if (callerTable != NULL) + { + table = callerTable; + } + else { table = xAnimTableNew("zNPCSuperFriend", NULL, 0x0); } @@ -396,7 +318,7 @@ xAnimTable* ZNPC_AnimTable_SuperFriend(xAnimTable* callerTable) xAnimTableNewState(table, names[Talk04], 0x10, 0x1, 1.0f, NULL, NULL, 0.0f, NULL, NULL, xAnimDefaultBeforeEnter, NULL, NULL); - NPCC_BuildStandardAnimTran(table, names, ourAnims, 1, 0.35f); + NPCC_BuildStandardAnimTran(table, g_strz_folkanim, ourAnims, 1, 0.35f); xAnimTableNewTransition(table, names[Yawn02], names[Idle02], NULL, NULL, 0x10, 0x0, 0.0f, 0.0f, 0, 0, 0.35f, NULL); @@ -408,6 +330,48 @@ xAnimTable* ZNPC_AnimTable_SuperFriend(xAnimTable* callerTable) return table; } +U8 zNPCVillager::ColChkFlags() const +{ + S32 flags = 0x3E; + flags &= ~0x8; + + if (globals.sceneCur->sceneID == 'B101') // Poseidome + { + flags = 0; + } + else if (this->npcset.reduceCollide != 0) + { + flags &= ~0x6; + } + else if ((this->flg_move & 4) != 0) + { + flags &= ~0x6; + } + + return flags; +} + +U8 zNPCVillager::ColPenFlags() const +{ + S32 flags = 0x3E; + flags &= ~0x8; + + if (globals.sceneCur->sceneID == 'B101') // Poseidome + { + flags = 0; + } + else if (this->npcset.reduceCollide != 0) + { + flags &= ~0x6; + } + else if ((this->flg_move & 4) != 0) + { + flags &= ~0x6; + } + + return flags; +} + U8 zNPCVillager::PhysicsFlags() const { S32 flags = 0; @@ -432,18 +396,28 @@ void zNPCVillager::Init(xEntAsset* asset) zNPCCommon::flg_vuln = 0; } -// void zNPCVillager::Reset() //Not sure what the correct values are for the IFs -// { -// NPCConfig* cfg; -// this->zNPCCommon::Reset(); - -// if (psy_instinct != 0) -// { -// this->psy_instinct->GoalSet(NPC_GOAL_IDLE, 1); -// } -// } void zNPCVillager::Reset() { + NPCConfig* cfg; + + zNPCCommon::Reset(); + + if (this->psy_instinct != NULL) + { + this->psy_instinct->GoalSet(NPC_GOAL_IDLE, 1); + } + + cfg = this->cfg_npc; + if (cfg->dst_castShadow < 0.0f) + { + cfg->dst_castShadow = 0.25f; + } + + cfg = this->cfg_npc; + if (cfg != NULL && cfg->rad_shadowCache < 0.0f) + { + cfg->rad_shadowCache = this->GenShadCacheRad(); + } } void zNPCVillager::ParseINI() @@ -456,21 +430,38 @@ void zNPCVillager::ParseINI() void zNPCVillager::ParseNonRandTalk() { - // NPCConfig* cfg; //0x1d8 - // F32 non_choices[4]; - // S32 found; - // S32 i; - // U8 skip; - // S32 j; + NPCConfig* cfg = this->cfg_npc; + cfg->talk_filter_size = 0; + F32 non_choices[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + S32 found = zParamGetFloatList(this->parmdata, this->pdatsize, "NonRandomTalkAnims", 4, + non_choices, non_choices); + + for (S32 i = 0; i < 4; i++) + { + U8 skip = 0; + for (S32 j = 0; j < found; j++) + { + S32 choice_val = (S32)non_choices[j] - 1; + if (choice_val == i) + { + skip = 1; + break; + } + } - // cfg = cfg_npc; - // cfg = 0; - // non_choices[0] = 0.0; - // non_choices[1] = 0.0; - // non_choices[2] = 0.0; - // non_choices[3] = 0.0; + if (!skip) + { + cfg->talk_filter[cfg->talk_filter_size] = i; + cfg->talk_filter_size++; + } + } - // + if (cfg->talk_filter_size == 0) + { + cfg->talk_filter[0] = 0; + cfg->talk_filter_size = 1; + } } void zNPCVillager::Process(xScene* xscn, F32 dt) @@ -483,380 +474,1833 @@ void zNPCVillager::Process(xScene* xscn, F32 dt) zNPCCommon::Process(xscn, dt); } -void zNPCVillager::SpeakBegin() +void zNPCVillager::ChkCheatSize() { - psy_instinct->GoalSet(NPC_GOAL_SPEAK, 1); -} + S32 cheats; -void zNPCVillager::SpeakEnd() -{ - xPsyche* psy = psy_instinct; - if ((psy->GIDInStack(NPC_GOAL_LIMBO) == 0)) + cheats = zGameExtras_CheatFlags(); + + if ((cheats & 0xd0000) == 0) { - S32 safetyGid = psy->GIDOfSafety(); - if (safetyGid != 0) + return; + } + + S32 npcType = this->SelfType(); + + switch (npcType) + { + case NPC_TYPE_PLANKNPC: + if ((cheats & 0x10000) != 0) { - psy->GoalSet(safetyGid, 1); + this->cfg_npc->scl_model.assign(2.5f); + this->flg_misc |= 4; } - } -} + break; -void zNPCVillager::TossMyConverse() -{ - converse = 0; -} + case NPC_TYPE_FISH: + case NPC_TYPE_FISH_MALE: + case NPC_TYPE_FISH_FEMALE: + case NPC_TYPE_FISH_ELDER: + case NPC_TYPE_FISH_ELDESS: + case NPC_TYPE_VILLAGER: + if ((cheats & 0x40000) != 0) + { + this->cfg_npc->scl_model.assign(0.7f); + this->flg_misc |= 4; + } + break; -void zNPCFish::Reset() -{ -} + case NPC_TYPE_SQUIDWARD: + case NPC_TYPE_SQUIDWARD_MUSIC: + case NPC_TYPE_SQUIDWARD_BANDAID: + case NPC_TYPE_SANDYNPC: + case NPC_TYPE_PATNPC: + case NPC_TYPE_BOBNPC: + case NPC_TYPE_MRKRABS: + case NPC_TYPE_MSPUFFS: + case NPC_TYPE_LARRY: + case NPC_TYPE_BUBBUDDY: + case NPC_TYPE_MERMAN: + case NPC_TYPE_BARNACLEBOY: + if ((cheats & 0x80000) != 0) + { + this->cfg_npc->scl_model.assign(0.6f); + this->flg_misc |= 4; + } + break; -void zNPCFish::ParseINI() -{ - zNPCVillager::ParseINI(); - zNPCFish::FishSoundTables(); + case NPC_TYPE_GARY: + case NPC_TYPE_SANDYBIKINI: + case NPC_TYPE_MERMANCHAIR: + break; + } } - -// void zNPCFish::FishSoundTables() -// { -// S32 tempR; -// tempR = xNPCBasic::SelfType(); -// switch (tempR) -// { -// case NPC_TYPE_FISH: -// { -// } -// case NPC_TYPE_FISH_MALE: -// { -// } -// } -// } - -/* -void FOLK_InitEffects() +void zNPCVillager::CollideReview() { - g_pemit_aqualeak = zParEmitterFind("PAREMIT_FOLK_SANDYB_LEAK"); - g_parf_aqualeak.custom_flags = 0x300; // 0x138 - xVec3Copy((xVec3*)&g_parf_aqualeak.pos, (xVec3*)&g_O3); // 0x140 - xVec3Copy((xVec3*)&g_parf_aqualeak.vel, (xVec3*)&g_O3); // 0x14c -} -*/ + zNPCGoalCommon* goal; + S32 goaldidit; -void zNPCFish::CheckDoChat() -{ + goaldidit = 0; + goal = (zNPCGoalCommon*)this->psy_instinct->GetCurGoal(); + if ((goal != NULL) && ((goal->flg_npcgable & 1) != 0)) + { + goal->Name(); + goaldidit = goal->CollReview(0); + } + if (goaldidit == 0) + { + zNPCCommon::CollideReview(); + } + return; } -void zNPCMerManChair::Init(xEntAsset*) //Seems to load an extra value? +void zNPCVillager::SelfSetup() { - zNPCVillager::Init(asset); - flg_move = 1; - flg_vuln = -1; - flg_vuln = flg_vuln & 0x9effffff; + xBehaveMgr* bmgr = xBehaveMgr_GetSelf(); + this->psy_instinct = bmgr->Subscribe(this, 0); + xPsyche* psy = this->psy_instinct; + + psy->BrainBegin(); + this->AddBaseline(psy, FOLK_grul_goAlert, FOLK_grul_goAlert, FOLK_grul_goAlert, + FOLK_grul_goAlert, NULL); + this->AddScripting(psy, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + this->AddTalking(psy, NULL, NULL, NULL, NULL); + psy->AddGoal(NPC_GOAL_HURT, NULL); + psy->BrainEnd(); + psy->SetSafety(NPC_GOAL_IDLE); } -void zNPCNewsFish::Reset() +U32 zNPCVillager::AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* goal) { - if (!this->was_reset) + S32 idx; + U32 da_anim = 0; + + switch (gid) { - this->was_reset = 1; - this->soundHandle = 0; - this->currSoundID = 0; - this->nextSoundID = 0; - this->jawData = 0; - this->jawTime = 0.0f; - this->screenLerp = 0.0f; + case NPC_GOAL_IDLE: + case NPC_GOAL_WAITING: + case NPC_GOAL_NOMANLAND: + case NPC_GOAL_LIMBO: + { + S32 superfolk = !strcmp("zNPCSuperFriend", this->model->Anim->Table->Name); + static S32 choices[4] = { 1, 0x11, 0x12, 0x13 }; - zNPCVillager::Reset(); - zNPCNewsFish::reset_said(); - - xDebugAddTweak("NPC|zNPCNewsFish|screen|on screen|x", &this->onScreenCoords.x, -5.0f, 5.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|on screen|y", &this->onScreenCoords.y, -5.0f, 5.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|off screen|x", &this->offScreenCoords.x, -5.0f, 5.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|off screen|y", &this->offScreenCoords.y, -5.0f, 5.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|size", &this->screenSize, 0.0001f, 1000000000.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|rotation", &this->screenRot, -1000000000.0f, 1000000000.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|appearSpeed", &this->appearSpeed, 0.0f, 1000000000.0f, 0, 0, 0); - xDebugAddTweak("NPC|zNPCNewsFish|screen|disappearSpeed", &this->disappearSpeed, 0.0f, 1000000000.0f, 0, 0, 0); + if (!superfolk) + { + idx = 1; + } + else + { + idx = xUtil_choose(choices, 4, 0); + } + break; } -} -void zNPCNewsFish::SpeakStop() -{ - S32 tempvar = zNPCNewsFish::IsTalking(); - if (tempvar != 0) + case NPC_GOAL_WANDER: + case NPC_GOAL_PATROL: + if (gspot == 0x26) + idx = 4; + else + idx = 2; + break; + + case NPC_GOAL_FIDGET: { - xSndStop(soundHandle); - } - currSoundID = 0; - nextSoundID = 0; - soundHandle = 0; - jawData = 0; -} + S32 superfolk = !strcmp("zNPCSuperFriend", this->model->Anim->Table->Name); + S32 choices[4] = { 4, 0x14, 0x15, 0x16 }; -S32 zNPCNewsFish::IsTalking() -{ - return (soundHandle) ? xSndIsPlayingByHandle(soundHandle) : false; -} + if (!superfolk) + { + idx = 4; + } + else + { + idx = xUtil_choose(choices, 4, 0); + } + break; + } -void zNPCNewsFish::TalkOnScreen(S32 talkOnScreen) -{ - if (talkOnScreen != 0) + case NPC_GOAL_PLAYERNEAR: { - newsfishFlags = newsfishFlags | 1; - return; + if (gspot == 0x23) + { + S32 superfolk = !strcmp("zNPCSuperFriend", this->model->Anim->Table->Name); + S32 choices[4] = { 4, 0x14, 0x15, 0x16 }; + + if (!superfolk) + { + idx = 4; + } + else + { + idx = xUtil_choose(choices, 4, 0); + } + } + else + { + idx = 1; + } + break; } - newsfishFlags = newsfishFlags & 0xfffffffe; - return; -} -void zNPCNewsFish::reset_said() -{ -} + case NPC_GOAL_TALK: + case NPC_GOAL_CHATTER: + case NPC_GOAL_SPEAK: + { + S32 superfolk = !strcmp("zNPCSuperFriend", this->model->Anim->Table->Name); -void zNPCSandyBikini::Reset() //100% code match -{ - zNPCVillager::Reset(); - tmr_leakCycle = 0.0; -} + if (!superfolk) + { + idx = 5; + } + else + { + idx = this->current_talk_anim; + static S32 choices[4] = { 0x05, 0x17, 0x18, 0x19 }; + + if (idx < 0 || idx > 3) + { + U32 which = xrand(); + idx = choices[this->cfg_npc + ->talk_filter[(which >> 13) % this->cfg_npc->talk_filter_size]]; + } + else + { + idx = choices[idx]; + } + } + break; + } + case NPC_GOAL_CHEER: + idx = 9; + break; + case NPC_GOAL_HURT: + idx = 3; + break; + default: + idx = 1; + break; + } -void zNPCSandyBikini::Process(xScene* xscn, F32 dt) //100% code match -{ - zNPCVillager::Process(xscn, dt); - zNPCSandyBikini::VFXLeakyFaucet(dt); -} + if (idx >= 0) + { + da_anim = g_hash_folkanim[idx]; + } -void zNPCSandyBikini::VFXLeakyFaucet(F32 dt) -{ + return da_anim; } -void zNPCBalloonBoy::Init(xEntAsset* asset) +S32 zNPCVillager::NPCMessage(NPCMsg* mail) { - zNPCFish::Init(asset); - rast_shadBalloon = 0; - cfg_npc->dst_castShadow = -1; - return; + S32 handled; + xPsyche* psy = this->psy_instinct; + zNPCGoalCommon* curgoal; + zNPCGoalCommon* recgoal; - //cfg_npc 0x1d8 - //bound.type 0x84 -} + if (psy) + { + curgoal = (zNPCGoalCommon*)psy->GetCurGoal(); + if (curgoal) + { + handled = curgoal->NPCMessage(mail); + if (handled) + return handled; + } -void zNPCBalloonBoy::Reset() -{ - zNPCFish::Reset(); - - if(!this->rast_shadBalloon) + recgoal = (zNPCGoalCommon*)psy->GetPrevRecovery(0); + if (recgoal && recgoal != curgoal) + { + handled = recgoal->NPCMessage(mail); + if (handled) + return handled; + } + } + + handled = this->FolkHandleMail(mail); + if (!handled) { - this->rast_shadBalloon = NPCC_FindRWRaster("shadow_balloons"); + handled = zNPCCommon::NPCMessage(mail); } -} -void zNPCBalloonBoy::SelfSetup() //100% code match -{ - xPsyche* psy; - zNPCFish::SelfSetup(); - psy = psy_instinct; - psy->BrainExtend(); - zNPCBalloonBoy::AddBallooning(psy); - psy->BrainEnd(); + return handled; } -void zNPCBalloonBoy::Render() +// non-matching: register shenanigans +S32 zNPCVillager::FolkHandleMail(NPCMsg* mail) { - xNPCBasic::Render(); - zNPCBalloonBoy::PlatShadRend(); -} + S32 handled = 1; -void zNPCBalloonBoy::AddBallooning(xPsyche* psy) -{ - psy->AddGoal(NPC_GOAL_BALLOON, NULL); - psy->AddGoal(NPC_GOAL_BOYRIDE, NULL); - psy->AddGoal(NPC_GOAL_BOYFALL, NULL); - psy->AddGoal(NPC_GOAL_BOYWEEP, NULL); - psy->AddGoal(NPC_GOAL_BOYSWIM, NULL); + xPsyche* psy = this->psy_instinct; // not in dwarf + + switch (mail->msgid) + { + case 3: + { + if (psy && !psy->GIDInStack(NPC_GOAL_CHEER)) + { + if (!psy->GIDInStack(NPC_GOAL_HURT)) + { + psy->GoalPush(NPC_GOAL_HURT, 0); + } + } + break; + } + + case 1: + if (mail->sysevent.toEvent == 0x20e) + { + psy->GoalSet(NPC_GOAL_TALK, 0); + } + else if (mail->sysevent.toEvent == 0x1d9) + { + handled = zNPCCommon::NPCMessage(mail); + } + else if (mail->sysevent.toEvent == 0x1d8) + { + handled = zNPCCommon::NPCMessage(mail); + } + else + { + handled = zNPCCommon::NPCMessage(mail); + } + break; + + default: + handled = 0; + break; + } + + return handled; +} + +void zNPCVillager::SpeakBegin() +{ + psy_instinct->GoalSet(NPC_GOAL_SPEAK, 1); +} + +void zNPCVillager::SpeakEnd() +{ + xPsyche* psy = psy_instinct; + if ((psy->GIDInStack(NPC_GOAL_LIMBO) == 0)) + { + S32 safetyGid = psy->GIDOfSafety(); + if (safetyGid != 0) + { + psy->GoalSet(safetyGid, 1); + } + } +} + +void zNPCVillager::SpeakStart(U32 sndid, U32 sndhandle, S32 anim) +{ + this->current_talk_anim = anim; + xGoal* goal = this->psy_instinct->GetCurGoal(); + switch (goal->GetID()) + { + case NPC_GOAL_TALK: + { + zNPCGoalTalk* talkgoal = (zNPCGoalTalk*)goal; + talkgoal->jawdata = xJaw_FindData(sndid); + talkgoal->jawtime = 0.0f; + talkgoal->tmr_cycleAnim = -1.0f; + talkgoal->tmr_minTalk = -1.0f; + break; + } + case NPC_GOAL_SPEAK: + { + zNPCGoalSpeak* talkgoal = (zNPCGoalSpeak*)goal; + talkgoal->jawdata = xJaw_FindData(sndid); + talkgoal->jawtime = 0.0f; + talkgoal->tmr_cycleAnim = -1.0f; + break; + } + } +} + +void zNPCVillager::SpeakStop() +{ + xGoal* goal = this->psy_instinct->GetCurGoal(); + + switch (goal->GetID()) + { + case NPC_GOAL_TALK: + { + zNPCGoalTalk* talkgoal = (zNPCGoalTalk*)goal; + talkgoal->jawdata = NULL; + talkgoal->jawtime = 0.0f; + break; + } + case NPC_GOAL_SPEAK: + { + zNPCGoalSpeak* talkgoal = (zNPCGoalSpeak*)goal; + talkgoal->jawdata = NULL; + talkgoal->jawtime = 0.0f; + break; + } + } +} + +S32 zNPCVillager::PlayerIsStaring() +{ + xVec3 vec; + + if (globals.player.ControlOff != 0) + { + return 0; + } + + if ((U8)this->npcset.allowDetect == 0) + { + return 0; + } + + F32 dy = 0.0f; + F32 dSq = this->XZDstSqToPlayer(&vec, &dy); + + if (dy > 5.0f) + { + return 0; + } + + if (dy < -2.0f) + { + return 0; + } + + xEntNPCAsset* npcass = this->npcass; + if (npcass->taskWidgetPrime != 0 || npcass->taskWidgetSecond != 0) + { + if (dSq > g_vilg_ds2_playernear * 4.0f) + { + return 0; + } + } + else + { + if (dSq > g_vilg_ds2_playernear) + { + return 0; + } + } + + return 1; +} + +void zNPCVillager::AddTalking(xPsyche* psy, + S32 (*eval_plyrnear)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_talking)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_chatter)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_speak)(xGoal*, void*, en_trantype*, F32, void*)) +{ + xGoal* goal; + goal = psy->AddGoal(NPC_GOAL_PLAYERNEAR, NULL); + if (eval_plyrnear) + { + goal->SetCallbacks(eval_plyrnear, NULL, NULL, NULL); + } + goal = psy->AddGoal(NPC_GOAL_TALK, NULL); + if (eval_talking) + { + goal->SetCallbacks(eval_talking, NULL, NULL, NULL); + } + goal = psy->AddGoal(NPC_GOAL_CHATTER, NULL); + if (eval_chatter) + { + goal->SetCallbacks(eval_chatter, NULL, NULL, NULL); + } + goal = psy->AddGoal(NPC_GOAL_SPEAK, NULL); + if (eval_speak) + { + goal->SetCallbacks(eval_speak, NULL, NULL, NULL); + } +} + +void zNPCVillager::FindMyConverse() +{ + xEntNPCAsset* nass = this->npcass; + if ((gCurrentPlayer == eCurrentPlayerSpongeBob) && (nass->taskWidgetPrime != 0)) + { + this->converse = (ztaskbox*)zSceneFindObject(nass->taskWidgetPrime); + if (this->converse == NULL) + { + this->converse = (ztaskbox*)zSceneFindObject((((U8*)&nass->taskWidgetPrime)[3] << 24) | + (((U8*)&nass->taskWidgetPrime)[2] << 16) | + (((U8*)&nass->taskWidgetPrime)[1] << 8) | + ((U8*)&nass->taskWidgetPrime)[0]); + } + } + else if ((gCurrentPlayer != eCurrentPlayerSpongeBob) && (nass->taskWidgetSecond != 0)) + { + this->converse = (ztaskbox*)zSceneFindObject(nass->taskWidgetSecond); + if (this->converse == NULL) + { + this->converse = (ztaskbox*)zSceneFindObject((((U8*)&nass->taskWidgetSecond)[3] << 24) | + (((U8*)&nass->taskWidgetSecond)[2] << 16) | + (((U8*)&nass->taskWidgetSecond)[1] << 8) | + ((U8*)&nass->taskWidgetSecond)[0]); + } + } + else + { + this->converse = NULL; + } +} + +void zNPCVillager::TossMyConverse() +{ + this->converse = NULL; +} + +void zNPCFish::Init(xEntAsset* asset) + +{ + zNPCVillager::Init(asset); + if (globals.sceneCur->sceneID == 'B101') // Poseidome + { + this->flg_move &= ~0x2; + this->flg_move = 0xc; + } + else + { + this->flg_move = 10; + } + this->flg_vuln = -1; + this->flg_vuln &= ~0x61000000; + return; +} + +void zNPCFish::Reset() +{ + zNPCVillager::Reset(); + this->tgt_robonear.TargetClear(); + this->tmr_robonear = -1.0f; + this->tmr_checkagain = xurand() * 60.25f; + en_NPCTYPES npc_type = (en_NPCTYPES)this->SelfType(); + if (npc_type == NPC_TYPE_MERMAN) + { + this->ModelAtomicShow(0, NULL); + this->ModelAtomicHide(1, NULL); + } + else if (npc_type == NPC_TYPE_MERMANCHAIR) + { + this->ModelAtomicShow(0, NULL); + this->ModelAtomicShow(1, NULL); + } + else if (npc_type == NPC_TYPE_SQUIDWARD) + { + this->ModelAtomicShow(1, NULL); + this->ModelAtomicHide(0, NULL); + this->ModelAtomicHide(2, NULL); + } + else if (npc_type == NPC_TYPE_SQUIDWARD_BANDAID) + { + this->ModelAtomicShow(1, NULL); + this->ModelAtomicHide(0, NULL); + this->ModelAtomicShow(2, NULL); + } + else if (npc_type == NPC_TYPE_SQUIDWARD_MUSIC) + { + this->ModelAtomicShow(1, NULL); + this->ModelAtomicShow(0, NULL); + this->ModelAtomicHide(2, NULL); + } + return; +} + +void zNPCFish::ParseINI() +{ + zNPCVillager::ParseINI(); + zNPCFish::FishSoundTables(); +} + +void zNPCFish::FishSoundTables() +{ + en_NPCTYPES npc_type = (en_NPCTYPES)this->SelfType(); + + switch (npc_type) + { + case NPC_TYPE_GARY: + case NPC_TYPE_DUTCHMAN_NSB: + case NPC_TYPE_SANDYBIKINI: + case NPC_TYPE_PLANKNPC: + case NPC_TYPE_MRKRABS: + case NPC_TYPE_MSPUFFS: + case NPC_TYPE_LARRY: + case NPC_TYPE_BUBBUDDY: + case NPC_TYPE_MERMANCHAIR: + case NPC_TYPE_MERMAN: + case NPC_TYPE_BARNACLEBOY: + this->cfg_npc->snd_trax = g_sndTrax_VillagerCoStar; + break; + case NPC_TYPE_SQUIDWARD: + case NPC_TYPE_SQUIDWARD_MUSIC: + case NPC_TYPE_SQUIDWARD_BANDAID: + this->cfg_npc->snd_trax = g_sndTrax_Squidward; + break; + case NPC_TYPE_FISH: + case NPC_TYPE_FISH_MALE: + this->cfg_npc->snd_trax = g_sndTrax_VillagerMale; + break; + case NPC_TYPE_FISH_FEMALE: + this->cfg_npc->snd_trax = g_sndTrax_VillagerFemale; + break; + case NPC_TYPE_FISH_ELDER: + this->cfg_npc->snd_trax = g_sndTrax_VillagerElder; + break; + case NPC_TYPE_FISH_ELDESS: + this->cfg_npc->snd_trax = g_sndTrax_VillagerEldess; + break; + case NPC_TYPE_FISH_BOY: + case NPC_TYPE_BALLOONBOY: + this->cfg_npc->snd_trax = g_sndTrax_VillagerBoy; + break; + case NPC_TYPE_FISH_GIRL: + this->cfg_npc->snd_trax = g_sndTrax_VillagerGirl; + break; + case NPC_TYPE_WORM: + default: + this->cfg_npc->snd_trax = NULL; + } + + NPCS_SndTablePrepare(g_sndTrax_VillagerCoStar); + NPCS_SndTablePrepare(g_sndTrax_Squidward); + NPCS_SndTablePrepare(g_sndTrax_VillagerMale); + NPCS_SndTablePrepare(g_sndTrax_VillagerFemale); + NPCS_SndTablePrepare(g_sndTrax_VillagerElder); + NPCS_SndTablePrepare(g_sndTrax_VillagerEldess); + NPCS_SndTablePrepare(g_sndTrax_VillagerBoy); + NPCS_SndTablePrepare(g_sndTrax_VillagerGirl); + return; +} + +void zNPCFish::SelfSetup() +{ + zNPCVillager* npc; // from dwarf, unused? + xBehaveMgr* bmgr = xBehaveMgr_GetSelf(); + xPsyche* psy = bmgr->Subscribe(this, 0); + this->psy_instinct = psy; + psy = this->psy_instinct; + psy->BrainBegin(); + this->AddBaseline(psy, FOLK_grul_goAlert, FOLK_grul_goAlert, FOLK_grul_goAlert, + FOLK_grul_goAlert, NULL); + this->AddScripting(psy, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + this->AddTalking(psy, NULL, NULL, NULL, NULL); + psy->AddGoal(NPC_GOAL_CHEER, NULL); + psy->AddGoal(NPC_GOAL_HURT, NULL); + psy->BrainEnd(); + psy->SetSafety(NPC_GOAL_IDLE); +} + +U32 zNPCFish::AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal) +{ + S32 idx = -1; + U32 da_anim = 0; + + switch (gid) + { + case NPC_GOAL_IDLE: + case NPC_GOAL_WAITING: + if (!(this->tmr_robonear < 0.0f)) + { + idx = 7; + } + else + { + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + } + break; + + case NPC_GOAL_WANDER: + case NPC_GOAL_PATROL: + if (!(this->tmr_robonear < 0.0f)) + { + if (gspot == 0x26) + { + idx = 7; + } + else + { + idx = 6; + } + } + else + { + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + } + break; + + case NPC_GOAL_FIDGET: + if (!(this->tmr_robonear < 0.0f)) + { + idx = 8; + } + else + { + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + } + break; + + default: + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + break; + } + + if (idx >= 0) + { + da_anim = g_hash_folkanim[idx]; + } + + return da_anim; +} + +void zNPCFish::Process(xScene* xscn, F32 dt) +{ + this->CheckDoChat(); + if (this->IsAlive() && this->tmr_checkagain < 0.0f) + { + this->MonitorCowering(xscn, dt); + } + this->tmr_robonear = MAX(-1.0f, this->tmr_robonear - dt); + this->tmr_checkagain = MAX(-1.0f, this->tmr_checkagain - dt); + zNPCVillager::Process(xscn, dt); +} + +static S32 goalsWhichCheer[6] = { NPC_GOAL_IDLE, NPC_GOAL_WANDER, NPC_GOAL_PATROL, + NPC_GOAL_WAITING, NPC_GOAL_PLAYERNEAR, '\0' }; // null-terminated + +S32 zNPCFish::FolkHandleMail(NPCMsg* msg) +{ + S32 handled = 0; + xPsyche* psy = this->psy_instinct; + S32 cancheer; + S32 gid; + zNPCGoalCheer* cheer; + + switch (msg->msgid) + { + case NPC_MID_CELEBRATE: + case 0x14: + case 0x15: + gid = psy->GIDOfPending(); + if (gid == NPC_GOAL_CHEER || psy->GIDInStack(NPC_GOAL_CHEER) != 0) + break; + + gid = psy->GIDOfPending(); + if (gid == NPC_GOAL_HURT || psy->GIDInStack(NPC_GOAL_HURT) != 0) + break; + + if (msg->infotype == NPC_MDAT_AREANOTIFY) + { + if (msg->areadata.npc_origin == 0) + break; + if ((msg->areadata.npc_origin->SelfType() & 0xffffff00) != 'NTR\0') + break; + } + + cancheer = false; + gid = psy->GIDOfActive(); + + for (S32 i = 0; goalsWhichCheer[i] != 0; i++) + { + if (gid == goalsWhichCheer[i]) + { + cancheer = true; + break; + } + } + + if (cancheer && (cheer = (zNPCGoalCheer*)psy->FindGoal(NPC_GOAL_CHEER)) != 0) + { + cheer->LoopCountSet(3); + psy->GoalPush(NPC_GOAL_CHEER, 0); + } + + handled = 1; + this->tmr_robonear = -1.0f; + this->tmr_checkagain = -1.0f; + break; + + default: + handled = zNPCVillager::FolkHandleMail(msg); + break; + } + + return handled; +} + +void zNPCFish::MonitorCowering(xScene* xscn, F32 dt) +{ + xVec3 vec; // from dwarf, unused? + NPCTarget* tgt = &this->tgt_robonear; + NPCConfig* cfg = this->cfg_npc; + + tgt->HaveTarget(); + if (!tgt->HaveTarget()) + { + tgt->TargetClear(); + } + else if (tgt->IsDead()) + { + tgt->TargetClear(); + } + else if (!tgt->InCylinder(xEntGetPos(this), g_rad_cowercheck, cfg->hyt_detect, cfg->off_detect)) + { + tgt->TargetClear(); + } + + if (!tgt->HaveTarget()) + { + tgt->FindNearest(NPC_TGT_ENT, this, xEntGetPos(this), g_rad_cowercheck); + } + + if (tgt->HaveTarget()) + { + this->tmr_robonear = cfg->tym_alert * (0.25f * (xurand() - 0.5f)) + cfg->tym_alert; + this->tmr_checkagain = cfg->tym_alert * (0.25f * (xurand() - 0.5f)) + cfg->tym_alert; + zNPCMsg_SendMsg(NPC_MID_BECOMESCARED, *(U32*)this); + } + else + { + this->tmr_robonear = -1.0f; + this->tmr_checkagain = + cfg->tym_alert * PI * (0.25f * (xurand() - 0.5f)) + cfg->tym_alert * PI; + zNPCMsg_SendMsg(NPC_MID_NOLONGERSCARED, *(U32*)this); + } +} + +void zNPCFish::CheckDoChat() +{ +} + +void zNPCMerManChair::Init(xEntAsset* asset) +{ + zNPCVillager::Init(asset); + flg_move = 1; + flg_vuln = -1; + flg_vuln = flg_vuln & 0x9effffff; +} + +void zNPCMerManChair::Reset() +{ + zNPCVillager::Reset(); + this->npcset.allowPatrol = 0; + this->npcset.allowWander = 0; + this->flg_mermanchair = 0; + + if (globals.sceneCur->sceneID == 'BC02') // Mermalair (Main Chamber) + { + ztaskbox* pat_converse = (ztaskbox*)zSceneFindObject(this->npcass->taskWidgetSecond); + if (pat_converse != NULL && (S32)pat_converse->StatusGet() == 5) + { + this->flg_mermanchair |= 1; + } + } +} + +void zNPCMerManChair::SelfSetup() +{ + xBehaveMgr* bmgr = xBehaveMgr_GetSelf(); + xPsyche* psy = bmgr->Subscribe(this, 0); + this->psy_instinct = psy; + psy = this->psy_instinct; + psy->BrainBegin(); + xGoal* goal = psy->AddGoal(NPC_GOAL_IDLE, NULL); + goal->SetCallbacks(MERC_grul_goAlert, NULL, NULL, NULL); + psy->AddGoal(NPC_GOAL_FIDGET, NULL); + psy->AddGoal(NPC_GOAL_HURT, NULL); + this->AddTalking(psy, NULL, NULL, NULL, NULL); + psy->BrainEnd(); + psy->SetSafety(NPC_GOAL_IDLE); +} + +U32 zNPCMerManChair::AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal) +{ + S32 idx; + U32 da_anim; + S32 superfolk; + U32 which; + static S32 choices[4] = { 0x05, 0x17, 0x18, 0x19 }; + + da_anim = 0; + idx = -1; + + switch (gid) + { + case NPC_GOAL_FIDGET: + case NPC_GOAL_IDLE: + case NPC_GOAL_HURT: + case NPC_GOAL_PLAYERNEAR: + if (flg_mermanchair & 1) + { + idx = 10; + } + else + { + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + } + break; + + case NPC_GOAL_TALK: + case NPC_GOAL_CHATTER: + case NPC_GOAL_SPEAK: + superfolk = (strcmp("zNPCSuperFriend", model->Anim->Table->Name) == 0); + + if (flg_mermanchair & 1) + { + if ((current_talk_anim < 0) || (current_talk_anim > 3)) + { + idx = 10; + } + else if (!superfolk) + { + idx = 5; + } + else + { + idx = choices[current_talk_anim]; + } + } + else + { + if (!superfolk) + { + idx = 5; + } + else if ((current_talk_anim < 0) || (current_talk_anim > 3)) + { + which = xrand(); + idx = choices[cfg_npc->talk_filter[(which >> 13) % cfg_npc->talk_filter_size]]; + } + else + { + idx = choices[current_talk_anim]; + } + } + break; + + default: + da_anim = zNPCVillager::AnimPick(gid, gspot, rawgoal); + break; + } + + if (idx >= 0) + { + da_anim = g_hash_folkanim[idx]; + } + + return da_anim; +} + +void zNPCMerManChair::Process(xScene* scn, F32 dt) +{ + xModelInstance* minst; + + this->psy_instinct->Timestep(dt, NULL); + if ((this->flg_misc & 4U) != 0) + { + for (minst = this->model; minst != NULL; minst = minst->Next) + { + xVec3Copy(&minst->Scale, &this->cfg_npc->scl_model); + } + } +} + +static char* news_fish_audio[71] = { + "FAB1001", "FAB1002", "FAB1003", "FAB1004", "FAB1011", "FAB1017", "FAB1018", + "FAB1019", "FAB1020", "FAB1021", "FAB1022", "FAB1023", "FAB1025", "FAB1029", + "FAB1030", "FAB1032", "FAB1033", "FAB1034", "FAB1035", "FAB1038", "FAB1046", + "FAB1047", "FAB1049", "FAB1073", "FAB1074", "FAB1076", "FAB1077", "FAB1078", + "FAB1079", "FAB1080", "FAB1006", "FAB1012", "FAB1016", "FAB1024", "FAB1026", + "FAB1065", "FAB1039_a", "FAB1039_b", "FAB1039_c", "FAB1055", "FAB1040", "FAB1053", + "FAB1081_a", "FAB1081_b", "FAB1042", "FAB1045", "FAB1056", "FAB1064", "FAB1050", + "FAB1007", "FAB1007_b", "FAB1031", "FAB1082_a", "FAB1082_b", "FAB1010", "FAB1027", + "FAB1037", "FAB1052", "FAB1067", "FAB1014", "FAB1008", "FAB1036", "FAB1041_a", + "FAB1041_b", "FAB1054", "FAB1013", "FAB1009", "FAB1028", "FAB1051", "FAB1072", + "FAB1083" +}; + +static unsigned int news_fish_audio_hash[71]; + +// scheduling issue +void zNPCNewsFish::Init(xEntAsset* asset) +{ + zNPCVillager::Init(asset); + + this->was_reset = '\0'; + this->newsfishFlags = 0; + this->onScreenCoords.x = 0.585f; + this->onScreenCoords.y = 0.075f; + this->offScreenCoords.x = 1.0f; + this->offScreenCoords.y = 0.35f; + this->screenCoords.x = this->offScreenCoords.x; + this->screenCoords.y = this->offScreenCoords.y; + this->screenSize = 0.35f; + this->screenRot = 1.0f; + this->appearSpeed = 5.0f; + this->disappearSpeed = 1.0f; + this->screenLerp = 0.0f; + + for (S32 i = 0; i < 71; i++) + { + news_fish_audio_hash[i] = xStrHash(news_fish_audio[i]); + } +} + +void zNPCNewsFish::PostSetup() +{ + xUpdateCull_SetCB(globals.updateMgr, this, xUpdateCull_AlwaysTrueCB, NULL); +} + +void zNPCNewsFish::Process(xScene*, F32 dt) +{ + xModelInstance* minst; + + F32 lerp; + F32 invLerp; + + this->was_reset = 0; + if ((this->flg_misc & 4) != 0) + { + for (minst = this->model; minst != NULL; minst = minst->Next) + { + xVec3Copy(&minst->Scale, &this->cfg_npc->scl_model); + } + } + + xVec3 delta = {}; + + NPCC_ds2_toCam(xEntGetPos(this), &delta); + delta.y = 0.0f; + this->frame->mode |= 0x30000; + xVec3Normalize(&delta, &delta); + + xVec3Copy((xVec3*)&this->model->Mat->up, &g_Y3); + xVec3Copy((xVec3*)&this->model->Mat->at, &delta); + xVec3Cross((xVec3*)&this->model->Mat->right, &delta, &g_Y3); + + if (this->jawData != NULL) + { + this->jawTime += dt; + F32 jawVal = xJaw_EvalData(this->jawData, this->jawTime); + this->model->Anim->Single->BilinearLerp[0] = jawVal; + if (globals.cmgr != NULL) + { + this->SpeakStop(); + } + else + { + if (jawVal < 0.001f && !xSndIsPlayingByHandle(this->soundHandle)) + { + this->soundHandle = 0; + this->jawData = NULL; + this->currSoundID = 0; + if (this->nextSoundID != 0) + { + this->SpeakStart(this->nextSoundID, 0, -1); + this->nextSoundID = 0; + } + } + } + } + else + { + this->model->Anim->Single->BilinearLerp[0] = 0.0f; + } + + if ((this->newsfishFlags & 1) != 0) + { + if (this->jawData != NULL) + { + minst = this->model; + minst->Flags |= 2; + this->screenLerp += this->appearSpeed * dt; + if (this->screenLerp > 1.0f) + { + this->screenLerp = 1.0f; + } + } + else + { + this->screenLerp -= this->disappearSpeed * dt; + if (this->screenLerp < 0.0f) + { + this->screenLerp = 0.0f; + } + else + { + minst = this->model; + minst->Flags |= 2; + } + } + + invLerp = 1.0f - this->screenLerp; + + this->screenCoords.x = + (this->onScreenCoords.x * this->screenLerp) + (this->offScreenCoords.x * invLerp); + + this->screenCoords.y = + (this->onScreenCoords.y * this->screenLerp) + (this->offScreenCoords.y * invLerp); + } +} +void zNPCNewsFish::Reset() +{ + if (!this->was_reset) + { + this->was_reset = 1; + this->soundHandle = 0; + this->currSoundID = 0; + this->nextSoundID = 0; + this->jawData = 0; + this->jawTime = 0.0f; + this->screenLerp = 0.0f; + + zNPCVillager::Reset(); + zNPCNewsFish::reset_said(); + + // clang-format off + xDebugAddTweak("NPC|zNPCNewsFish|screen|on screen|x", &this->onScreenCoords.x, -5.0f, 5.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|on screen|y", &this->onScreenCoords.y, -5.0f, 5.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|off screen|x", &this->offScreenCoords.x, -5.0f, 5.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|off screen|y", &this->offScreenCoords.y, -5.0f, 5.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|size", &this->screenSize, 0.0001f, 1000000000.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|rotation", &this->screenRot, -1000000000.0f, 1000000000.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|appearSpeed", &this->appearSpeed, 0.0f, 1000000000.0f, 0, 0, 0); + xDebugAddTweak("NPC|zNPCNewsFish|screen|disappearSpeed", &this->disappearSpeed, 0.0f, 1000000000.0f, 0, 0, 0); + // clang-format on + } +} + +void zNPCNewsFish::SpeakStart(U32 sndid, U32 sndhandle, S32 anim) +{ + if (sndhandle) + { + this->SpeakStop(); + this->soundHandle = sndhandle; + this->jawTime = 0.0f; + this->jawData = xJaw_FindData(sndid); + } + else + { + if (this->IsTalking()) + { + if (this->nextSoundID != this->currSoundID) + { + this->nextSoundID = sndid; + } + } + else + { + this->soundHandle = xSndPlay(sndid, 1.0f, 0.0f, 0x80, 0, 0, SND_CAT_DIALOG, 0.0f); + this->jawTime = 0.0f; + this->jawData = xJaw_FindData(sndid); + this->currSoundID = sndid; + } + } +} + +void zNPCNewsFish::SpeakStop() +{ + S32 tempvar = zNPCNewsFish::IsTalking(); + if (tempvar != 0) + { + xSndStop(soundHandle); + } + currSoundID = 0; + nextSoundID = 0; + soundHandle = 0; + jawData = 0; +} + +S32 zNPCNewsFish::IsTalking() +{ + return (soundHandle) ? xSndIsPlayingByHandle(soundHandle) : false; +} + +void zNPCNewsFish::TalkOnScreen(S32 talkOnScreen) +{ + if (talkOnScreen != 0) + { + newsfishFlags = newsfishFlags | 1; + return; + } + newsfishFlags = newsfishFlags & 0xfffffffe; + return; } -void zNPCBalloonBoy::PlatAnimSet(en_BBOY_PLATANIM platanim) +void zNPCNewsFish::Render() { - F32 fvals[4]; + xLightKit* lastLightKit; + _SDRenderState oldstate; + xMat4x3 oldMat; + xNPCBasic::Render(); + if (globals.cmgr == NULL || globals.cmgr->csn == NULL) + { + U32 flags = this->newsfishFlags | 1; + this->newsfishFlags = flags; + if (flags != 0) + { + lastLightKit = gLastLightKit; + xLightKit_Enable(NULL, globals.currWorld); + oldstate = zRenderStateCurrent(); + zRenderState(SDRS_Newsfish); + xMat4x3Copy(&oldMat, (const xMat4x3*)this->model->Mat); + basic_rect r = { this->screenCoords.x, this->screenCoords.y, 1.0f, 1.0f }; + xVec3 from = { 0.0f, 0.0f, 1.0f }; + xVec3 to = { 0.0f, 0.0f, 0.0f }; + xVec3Init((xVec3*)&this->model->Mat->pos, 0.0f, 0.0f, 0.0f); + xMat3x3RotZ((xMat3x3*)this->model->Mat, this->screenRot); + xVec3SMulBy((xVec3*)&this->model->Mat->right, this->screenSize); + xVec3SMulBy((xVec3*)&this->model->Mat->up, this->screenSize); + xVec3SMulBy((xVec3*)&this->model->Mat->at, this->screenSize); + xModelRender2D(*this->model->Next, r, from, to); + xModelRender2D(*this->model, r, from, to); + xMat4x3Copy((xMat4x3*)this->model->Mat, &oldMat); + zRenderState(oldstate); + xLightKit_Enable(lastLightKit, globals.currWorld); + } + } } -void zNPCBalloonBoy::PlatAnimSync() +U8 zNPCNewsFish::say(say_enum s, S32 flags) { - zNPCCommon::AnimCurState(); -} + U32 id = news_fish_audio_hash[s]; -void zNPCBubbleBuddy::Init(xEntAsset* a) -{ - zNPCFish::Init(a); + if (this->IsTalking()) + { + if (id == this->currSoundID) + { + return 0; + } - this->aid_fresnelTxtr = 0; - this->txtr_fresnel = 0; - this->rast_fresnel = 0; - this->aid_enviroTxtr = 0; - this->txtr_enviro = 0; - this->rast_enviro = 0; + if (flags & 1) + { + this->SpeakStop(); + } + else if (flags & 2) + { + if (this->nextSoundID != 0) + { + if (this->nextSoundID != this->currSoundID) + { + return 0; + } + } + this->nextSoundID = id; + return 1; + } + else + { + return 0; + } + } + + this->soundHandle = xSndPlay(id, 1.0f, 0.0f, 0x80, 0, 0, SND_CAT_DIALOG, 0.0f); + this->jawTime = 0.0f; + this->jawData = xJaw_FindData(id); + this->currSoundID = id; + + return 1; } -void zNPCBubbleBuddy::Setup() +S32 zNPCNewsFish::say(const say_enum* s, unsigned long size, S32 flags, S32 max_say) { - zNPCCommon::Setup(); - if (!this->rast_fresnel && !this->rast_enviro) + if (size == 0) { - this->aid_fresnelTxtr = xStrHash("gloss_edge"); - this->txtr_fresnel = NPCC_FindRWTexture(this->aid_fresnelTxtr); - this->rast_fresnel = NPCC_FindRWRaster(this->txtr_fresnel); - this->aid_enviroTxtr = xStrHash("gloss_edge"); - this->txtr_enviro = NPCC_FindRWTexture(this->aid_enviroTxtr); - this->rast_enviro = NPCC_FindRWRaster(this->txtr_enviro); + return -1; } + if (size == 1) + { + say_data* data = this->get_said(*s); + data->prev_total = data->total; + if (this->say(*s, flags)) + { + data->total++; + return 0; + } + return -1; + } + else + { + S32 min_say = 0x7fffffff; + const say_enum* it; + const say_enum* end = s + size; - this->model->PipeFlags = (this->model->PipeFlags & 0xffffffdf) | 0x10; -} + for (it = s; it != end; ++it) + { + say_data* data = this->get_said(*it); + if (data->total < min_say && data->total == data->prev_total) + { + min_say = data->total; + } + } -void zNPCBubbleBuddy::Reset() // possible scheduling meme? -{ - zNPCFish::Reset(); - // flags = flags | 0x40; - flags |= 0x40; + if (max_say >= 0 && min_say >= max_say) + { + return -1; + } + + S32 total = 0; + { + const say_enum* it; + const say_enum* end = s + size; + for (it = s; it != end; ++it) + { + say_data* data = this->get_said(*it); + if (data->total <= min_say && data->total == data->prev_total) + { + total++; + } + } + } + + S32 played = -1; + S32 which; + + U32 r = xrand(); + which = (S32)((r >> 13) % total); + + { + const say_enum* it; + const say_enum* end = s + size; + for (it = s; it != end; ++it) + { + say_data* data = this->get_said(*it); + S32 new_total = data->total; + + U32 changed = + ((U32)(data->prev_total - new_total) | (U32)(new_total - data->prev_total)) >> + 31; + U8 last_changed = (U8)changed; + + data->prev_total = new_total; + + if (data->total <= min_say && !last_changed) + { + which--; + if (which == -1) + { + if (this->say(*it, flags)) + { + data->total++; + played = (S32)(it - s); + } + } + } + } + } + + return played; + } } -void zNPCBubbleBuddy::RenderExtra() +void zNPCNewsFish::reset_said() { - if (xEntIsVisible(this) && !(this->model->Flags & 0x400)) + say_data* s = this->said; + say_data* end = s + (S32)MAX_SAY; + + for (; s != end; s++) { - RwRenderStateGet(rwRENDERSTATECULLMODE, 0); - RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)0x3); - xModelRender(this->model); - RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)0x2); - xModelRender(this->model); - RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)0); + s->prev_total = 0; + s->total = 0; } } -S32 NPC_BubBud_RenderCB(RpAtomic*) +void zNPCSandyBikini::Reset() { - return 0; + zNPCVillager::Reset(); + tmr_leakCycle = 0.0f; } -S32 FOLK_grul_goAlert(xGoal* rawgoal, void* x, en_trantype* trantype, F32 f1, void* y) +void zNPCSandyBikini::Process(xScene* xscn, F32 dt) { - return 0; + zNPCVillager::Process(xscn, dt); + zNPCSandyBikini::VFXLeakyFaucet(dt); } -void FOLK_InitEffects() +void zNPCSandyBikini::VFXLeakyFaucet(F32 dt) { - g_pemit_aqualeak = zParEmitterFind("PAREMIT_FOLK_SANDYB_LEAK"); - g_parf_aqualeak.custom_flags = 0x300; - xVec3Copy(&g_parf_aqualeak.pos, &g_O3); - xVec3Copy(&g_parf_aqualeak.vel, &g_O3); + F32 rat_tym; + xVec3 pos_emit; + xVec3 dir_emit; + F32 dist; + static const xVec3 vec_boneOffset = { 0.05f, 0.0f, 0.0f }; + rat_tym = NPCC_TmrCycle(&this->tmr_leakCycle, dt, 0.3f); + const xVec3* bone_pos = (const xVec3*)this->BonePos(17); + pos_emit.x = bone_pos->x; + pos_emit.y = bone_pos->y; + pos_emit.z = bone_pos->z; + pos_emit += vec_boneOffset; + xMat3x3RMulVec(&pos_emit, (const xMat3x3*)this->BoneMat(0), &pos_emit); + pos_emit *= this->cfg_npc->scl_model.x; + pos_emit += *(xVec3*)this->BonePos(0); + this->XZVecToPos(&dir_emit, &pos_emit, NULL); + if (xVec3Length2(&dir_emit) > 0.0f) + { + dir_emit.invert(); + dist = xVec3Normalize(&dir_emit, &dir_emit); + dir_emit.y += 0.25f; + xVec3Normalize(&dir_emit, &dir_emit); + F32 temp_sin = isin((PI / 4.0f) * rat_tym); + xVec3SMul(&g_parf_aqualeak.vel, &dir_emit, temp_sin * dist); + xVec3Copy(&g_parf_aqualeak.pos, &pos_emit); + xParEmitterEmitCustom(g_pemit_aqualeak, dt, &g_parf_aqualeak); + } } -void FOLK_KillEffects() +RwRaster* zNPCBalloonBoy::rast_shadBalloon = NULL; + +void zNPCBalloonBoy::Init(xEntAsset* asset) { + zNPCFish::Init(asset); + rast_shadBalloon = 0; + cfg_npc->dst_castShadow = -1; + return; } -ztaskbox::callback::callback() +void zNPCBalloonBoy::Reset() { + zNPCFish::Reset(); + + if (!this->rast_shadBalloon) + { + this->rast_shadBalloon = NPCC_FindRWRaster("shadow_balloons"); + } } -F32 zNPCVillager::GenShadCacheRad() +void zNPCBalloonBoy::SelfSetup() { - return 1.5f; + xPsyche* psy; + zNPCFish::SelfSetup(); + psy = psy_instinct; + psy->BrainExtend(); + zNPCBalloonBoy::AddBallooning(psy); + psy->BrainEnd(); } -void zNPCBubbleBuddy::Render() +void zNPCBalloonBoy::Render() { - this->flg_xtrarend |= 1; + xNPCBasic::Render(); + zNPCBalloonBoy::PlatShadRend(); } -xEntDrive* zNPCFish::PRIV_GetDriverData() +void zNPCBalloonBoy::PlatShadRend() { - return &raw_drvdata; + F32 ds2_cam; + S32 fillit; + S32 needit; + xMat4x3 mat_fake; + + if (this->rast_shadBalloon) + { + if (!plat_balloons && !shadCache) + { + return; + } + + if (!plat_balloons) + { + NPCC_ShadowCacheRelease(shadCache); + shadCache = NULL; + return; + } + + xVec3* pos = zNPCCommon::Pos(); + ds2_cam = NPCC_ds2_toCam(pos, NULL); + + static S32 takeThePain = 0; + needit = 0; + takeThePain--; + if (takeThePain < 0) + { + takeThePain = 8; + + S32 is_close = (ds2_cam < SQ(30.0f)) ? 1 : 0; + if (is_close && !shadCache) + { + shadCache = NPCC_ShadowCacheReserve(); + } + else if (!is_close && shadCache) + { + NPCC_ShadowCacheRelease(shadCache); + shadCache = NULL; + } + needit = 1; + } + + if (shadCache) + { + F32 ratio = CLAMP(ds2_cam / SQ(30.0f), 0.0f, 1.0f); + F32 alpha = CLAMP(1.0f - ratio + 0.3f, 0.0f, 1.0f); + fillit = alpha; + + mat_fake.at = g_NY3; + mat_fake.up = ((xMat4x3*)plat_balloons->model->Mat)->at; + mat_fake.right = ((xMat4x3*)plat_balloons->model->Mat)->right; + mat_fake.pos = *xEntGetCenter(plat_balloons); + + RwMatrixUpdate((RwMatrix*)&mat_fake); + NPCC_RenderProjTexture(rast_shadBalloon, alpha, &mat_fake, 0.97f, 10.0f, shadCache, + needit, plat_balloons); + } + } } -U8 zNPCVillager::ColChkByFlags() const +void zNPCBalloonBoy::AddBallooning(xPsyche* psy) { - return 24; + psy->AddGoal(NPC_GOAL_BALLOON, NULL); + psy->AddGoal(NPC_GOAL_BOYRIDE, NULL); + psy->AddGoal(NPC_GOAL_BOYFALL, NULL); + psy->AddGoal(NPC_GOAL_BOYWEEP, NULL); + psy->AddGoal(NPC_GOAL_BOYSWIM, NULL); } -U8 zNPCVillager::ColPenByFlags() const +U32 zNPCBalloonBoy::AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal) { - return 24; + S32 idx = -1; + U32 da_anim = 0; + + switch (gid) + { + case NPC_GOAL_BALLOON: + if (gspot == 0x20) + idx = 0xb; + else if (gspot == 0x21) + idx = 0xb; + else + idx = 0xb; + break; + case NPC_GOAL_BOYRIDE: + if (gspot == 0x20) + idx = 0xb; + else if (gspot == 0x21) + idx = 0xb; + else if (gspot == 0x24) + idx = 0xc; + else + idx = 0xb; + break; + case NPC_GOAL_BOYFALL: + if (gspot == 0x20) + idx = 0xd; + else if (gspot == 0x21) + idx = 0xd; + else if (gspot == 0x24) + idx = 0xe; + else + idx = 0xd; + break; + case NPC_GOAL_BOYWEEP: + idx = 0xf; + break; + case NPC_GOAL_BOYSWIM: + idx = 0x10; + break; + default: + da_anim = zNPCFish::AnimPick(gid, gspot, rawgoal); + break; + } + + if (idx >= 0) + { + da_anim = g_hash_folkanim[idx]; + } + return da_anim; } -void zNPCNewsFish::SelfSetup() +S32 zNPCBalloonBoy::FolkHandleMail(NPCMsg* mail) { + S32 handled; + + switch (mail->msgid) + { + case NPC_MID_SYSEVENT: + handled = this->ParseSysEvent(&mail->sysevent); + break; + default: + if (this->IAmBallooning()) + { + handled = 1; + } + else + { + handled = 0; + } + break; + } + + if (handled == 0) + { + handled = zNPCFish::FolkHandleMail(mail); + } + + return handled; } -U8 zNPCMerManChair::ColChkFlags() const +S32 zNPCBalloonBoy::ParseSysEvent(NPCSysEvent* sed) { - return 0; + zPlatform* plat; + S32 handled = 1; + + switch (sed->toEvent) + { + case eEventNPCSpecial_PlatformSnap: + this->plat_balloons = NULL; + plat = (zPlatform*)sed->toParamWidget; + if (plat != NULL && plat->baseType == eBaseTypePlatform) + { + this->plat_balloons = plat; + } + if (this->plat_balloons == NULL) + { + plat = (zPlatform*)sed->from; + if (plat != NULL && plat->baseType == eBaseTypePlatform) + { + this->plat_balloons = plat; + } + } + if (this->plat_balloons != NULL) + { + this->psy_instinct->GoalSet(NPC_GOAL_BALLOON, 1); + } + else + { + this->psy_instinct->GoalSet(NPC_GOAL_IDLE, 1); + } + break; + + case eEventNPCSetActiveOn: + case eEventNPCSetActiveOff: + handled = 0; + break; + + case eEventNPCSpecial_PlatformFall: + break; + default: + if (this->IAmBallooning()) + { + handled = 1; + } + else + { + handled = 0; + } + break; + } + + return handled; } -U8 zNPCMerManChair::ColPenFlags() const +void zNPCBalloonBoy::PlatAnimSet(en_BBOY_PLATANIM platanim) { - return 0; + F32 fvals[4] = { (F32)(platanim + 1), 0.0f, 0.0f, 0.0f }; + if (this->plat_balloons != NULL) + { + zEntAnimEvent(this->plat_balloons, 0xC3, fvals); + } } -U8 zNPCMerManChair::PhysicsFlags() const +void zNPCBalloonBoy::PlatAnimSync() { - return 0; + zNPCCommon::AnimCurState(); } -void HiThere::on_talk_stop() +S32 zNPCBalloonBoy::IAmBallooning() { - if (this->npc) + S32 goals[] = { NPC_GOAL_BALLOON, NPC_GOAL_BOYRIDE, NPC_GOAL_BOYFALL, + NPC_GOAL_BOYWEEP, NPC_GOAL_BOYSWIM, 0 }; + S32 result = 0; + S32 goal_id = this->psy_instinct->GIDOfActive(); + + for (S32* i = goals; *i != 0; i++) { - zNPCMsg_SendMsg(NPC_MID_TALKOFF, this->npc); + if (goal_id == *i) + { + result = 1; + break; + } } + + return result; +} + +U32 zNPCBubbleBuddy::aid_fresnelTxtr = 0; +U32 zNPCBubbleBuddy::aid_enviroTxtr = 0; +RwTexture* zNPCBubbleBuddy::txtr_fresnel = NULL; +RwTexture* zNPCBubbleBuddy::txtr_enviro = NULL; +RwRaster* zNPCBubbleBuddy::rast_fresnel = NULL; +RwRaster* zNPCBubbleBuddy::rast_enviro = NULL; +F32 zNPCBubbleBuddy::alf_currBubBud = 1.0f; +xEnt* CruiseBubbleDoesBubbleBuddyToo; + +void zNPCBubbleBuddy::Init(xEntAsset* a) +{ + zNPCFish::Init(a); + + CruiseBubbleDoesBubbleBuddyToo = this; + this->aid_fresnelTxtr = 0; + this->txtr_fresnel = 0; + this->rast_fresnel = 0; + this->aid_enviroTxtr = 0; + this->txtr_enviro = 0; + this->rast_enviro = 0; + this->alf_currBubBud = 1.0f; } -void HiThere::on_talk_start() +RpAtomic* NPC_BubBud_RenderCB(RpAtomic* atomic); + +void zNPCBubbleBuddy::Setup() { - if (this->npc) + zNPCCommon::Setup(); + if (!this->rast_fresnel && !this->rast_enviro) + { + char* nam_fresTxtr = "gloss_edge"; + this->aid_fresnelTxtr = xStrHash(nam_fresTxtr); + this->txtr_fresnel = NPCC_FindRWTexture(this->aid_fresnelTxtr); + this->rast_fresnel = NPCC_FindRWRaster(this->txtr_fresnel); + this->aid_enviroTxtr = xStrHash(nam_fresTxtr); + this->txtr_enviro = NPCC_FindRWTexture(this->aid_enviroTxtr); + this->rast_enviro = NPCC_FindRWRaster(this->txtr_enviro); + } + this->model->PipeFlags = (this->model->PipeFlags & 0xffffffcf) | 0x10; + this->model->Data->renderCallBack = NPC_BubBud_RenderCB; + if (this->model->Data->renderCallBack == NULL) { - zNPCMsg_SendMsg(NPC_MID_TALKON, this->npc); + this->model->Data->renderCallBack = AtomicDefaultRenderCallBack; } } -U8 zNPCNewsFishTV::ColChkFlags() const +void zNPCBubbleBuddy::Reset() { - return 0; + zNPCFish::Reset(); + flags |= 0x40; } -U8 zNPCNewsFishTV::ColPenFlags() const +void zNPCBubbleBuddy::RenderExtra() { - return 0; + if (xEntIsVisible(this) && !(this->model->Flags & 0x400)) + { + RwCullMode old_cull_mode; + RwRenderStateGet(rwRENDERSTATECULLMODE, &old_cull_mode); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)0x3); + xModelRender(this->model); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)0x2); + xModelRender(this->model); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)old_cull_mode); + } } -U8 zNPCNewsFishTV::ColChkByFlags() const +void zNPCBubbleBuddy_AlphaUpdate(F32 dt) { - return 0; + static F32 tmr_pulseAlpha = 0.0f; // non-matching: stfs too late + F32 angle = NPCC_TmrCycle(&tmr_pulseAlpha, dt, 1.5f) * PI; + zNPCBubbleBuddy::alf_currBubBud = LERP(MAX(0.0f, MIN(xabs(isin(angle)), 1.0f)), 0.5f, 0.5f); } -U8 zNPCNewsFishTV::ColPenByFlags() const +static U32 bb_env_texture = 0; +static U32 bb_fresnel_texture = 0; + +RpAtomic* NPC_BubBud_RenderCB(RpAtomic* atomic) { - return 0; + bb_env_texture = xStrHash("rainbowfilm_smooth32"); + bb_fresnel_texture = xStrHash("gloss_edge"); + + F32 fade = zNPCBubbleBuddy::alf_currBubBud; + + if (zNPCBubbleBuddy::rast_fresnel != 0) + { + iModelSetMaterialAlpha(atomic, fade * 127.5f + 0.5f); + gFXSurfaceFlags = 0x10; + xFXAtomicEnvMapSetup(atomic, bb_fresnel_texture, fade); + gFXSurfaceFlags = 0; + (*gAtomicRenderCallBack)(atomic); + } + + if (zNPCBubbleBuddy::rast_enviro != 0) + { + iModelSetMaterialAlpha(atomic, fade * 127.5f + 0.5f); + AtomicDisableMatFX(atomic); + gFXSurfaceFlags = 0x10; + xFXAtomicEnvMapSetup(atomic, bb_env_texture, fade); + gFXSurfaceFlags = 0; + (*gAtomicRenderCallBack)(atomic); + } + + return atomic; } -U8 zNPCNewsFishTV::PhysicsFlags() const +S32 FOLK_grul_goAlert(xGoal* rawgoal, void*, en_trantype* trantype, F32, void*) { - return 0; + S32 nextgoal = 0; + zNPCVillager* npc = (zNPCVillager*)rawgoal->psyche->clt_owner; + xVec3 vec; // from dwarf, unused? + + if (npc->SomethingWonderful()) + { + return nextgoal; + } + + if (npc->PlayerIsStaring()) + { + *trantype = GOAL_TRAN_SET; + nextgoal = NPC_GOAL_PLAYERNEAR; + } + + return nextgoal; } -U32 NPCTarget::HaveTarget() +S32 MERC_grul_goAlert(xGoal* rawgoal, void*, en_trantype* trantype, F32, void*) { - return (*(U32*)this != 0); + zNPCVillager* npc = (zNPCVillager*)rawgoal->psyche->clt_owner; + xVec3 dir_plyr; + + if (npc->SomethingWonderful()) + { + return 0; + } + + if (!npc->PlayerIsStaring()) + { + return 0; + } + + if (xVec3Dot(NPCC_faceDir(npc), NPCC_faceDir(&globals.player.ent)) > -0.5f) + { + return 0; + } + + F32 dst = npc->XZDstSqToPlayer(&dir_plyr, NULL); + if (dst < 0.5f) + { + return 0; + } + + F32 sqrt_dst = xsqrt(dst); + xVec3SMulBy(&dir_plyr, 1.0f / sqrt_dst); + + if (xVec3Dot(NPCC_faceDir(npc), &dir_plyr) < 0.5f) + { + return 0; + } + + *trantype = GOAL_TRAN_SET; + return NPC_GOAL_PLAYERNEAR; } -U32 ztaskbox::StatusGet() const +void FOLK_InitEffects() { - return this->state; + g_pemit_aqualeak = zParEmitterFind("PAREMIT_FOLK_SANDYB_LEAK"); + g_parf_aqualeak.custom_flags = 0x300; + xVec3Copy(&g_parf_aqualeak.pos, &g_O3); + xVec3Copy(&g_parf_aqualeak.vel, &g_O3); } -void ztaskbox::callback::on_talk_start() +void FOLK_KillEffects() { } -void ztaskbox::callback::on_talk_stop() +void __deadstripped_zNPCTypeVillager(ztaskbox::callback cb) { + // no xrefs to these exist, called to match weak .text section + cb.on_talk_stop(); + cb.on_talk_start(); } diff --git a/src/SB/Game/zNPCTypeVillager.h b/src/SB/Game/zNPCTypeVillager.h index e9c864cfd..4e13633bf 100644 --- a/src/SB/Game/zNPCTypeVillager.h +++ b/src/SB/Game/zNPCTypeVillager.h @@ -1,6 +1,7 @@ #ifndef ZNPCTYPEVILLAGER_H #define ZNPCTYPEVILLAGER_H +#include "xBehaviour.h" #include "zNPCSndLists.h" #include "zNPCSupport.h" #include "zNPCTypeCommon.h" @@ -16,8 +17,20 @@ struct HiThere : ztaskbox::callback zNPCCommon* npc; - virtual void on_talk_start(); - virtual void on_talk_stop(); + virtual void on_talk_stop() + { + if (this->npc) + { + zNPCMsg_SendMsg(NPC_MID_TALKOFF, this->npc); + } + } + virtual void on_talk_start() + { + if (this->npc) + { + zNPCMsg_SendMsg(NPC_MID_TALKON, this->npc); + } + } }; struct zNPCVillager : zNPCCommon @@ -31,8 +44,15 @@ struct zNPCVillager : zNPCCommon } void FindMyConverse(); - U8 ColPenByFlags() const; - U8 ColChkByFlags() const; + U8 ColChkByFlags() const + { + return 24; + } + U8 ColPenByFlags() const + { + return 24; + } + U8 ColChkFlags() const; U8 ColPenFlags() const; U8 PhysicsFlags() const; void Init(xEntAsset*); @@ -40,13 +60,26 @@ struct zNPCVillager : zNPCCommon void ParseINI(); void ParseNonRandTalk(); void Process(xScene* xscn, F32 dt); + void CollideReview(); void SelfSetup(); + U32 AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* goal); + S32 NPCMessage(NPCMsg* mail); void SpeakBegin(); void SpeakEnd(); + void SpeakStart(U32 sndid, U32 sndhandle, S32 anim); + void SpeakStop(); + void AddTalking(xPsyche* psy, S32 (*eval_plyrnear)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_talking)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_chatter)(xGoal*, void*, en_trantype*, F32, void*), + S32 (*eval_speak)(xGoal*, void*, en_trantype*, F32, void*)); void TossMyConverse(); S32 PlayerIsStaring(); void ChkCheatSize(); - F32 GenShadCacheRad(); + F32 GenShadCacheRad() + { + return 1.5f; + } + virtual S32 FolkHandleMail(NPCMsg* mail); }; struct zNPCFish : zNPCVillager @@ -61,12 +94,19 @@ struct zNPCFish : zNPCVillager } void Init(xEntAsset*); + void Reset(); void ParseINI(); void FishSoundTables(); - void CheckDoChat(); - void Reset(); + U32 AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal); void SelfSetup(); - xEntDrive* PRIV_GetDriverData(); + void Process(xScene* xscn, F32 dt); + S32 FolkHandleMail(NPCMsg* mail); + void MonitorCowering(xScene* xscn, F32 dt); + void CheckDoChat(); + xEntDrive* PRIV_GetDriverData() + { + return &raw_drvdata; + } }; struct zNPCBubbleBuddy : zNPCFish @@ -79,7 +119,10 @@ struct zNPCBubbleBuddy : zNPCFish void Setup(); void Reset(); void RenderExtra(); - void Render(); + void Render() + { + this->flg_xtrarend |= 1; + } static RwRaster* rast_fresnel; static RwRaster* rast_enviro; @@ -87,6 +130,7 @@ struct zNPCBubbleBuddy : zNPCFish static RwTexture* txtr_fresnel; static U32 aid_enviroTxtr; static RwTexture* txtr_enviro; + static F32 alf_currBubBud; }; enum en_BBOY_PLATANIM @@ -114,8 +158,12 @@ struct zNPCBalloonBoy : zNPCFish void Render(); void PlatShadRend(); void AddBallooning(xPsyche* psy); + U32 AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal); + S32 FolkHandleMail(NPCMsg* mail); + S32 ParseSysEvent(NPCSysEvent*); void PlatAnimSet(en_BBOY_PLATANIM anim); void PlatAnimSync(); + S32 IAmBallooning(); }; struct zNPCSandyBikini : zNPCVillager @@ -140,9 +188,22 @@ struct zNPCMerManChair : zNPCVillager } void Init(xEntAsset*); - U8 PhysicsFlags() const; - U8 ColPenFlags() const; - U8 ColChkFlags() const; + void Reset(); + void SelfSetup(); + U32 AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal); + void Process(xScene* scn, F32 dt); + U8 ColChkFlags() const + { + return 0; + } + U8 ColPenFlags() const + { + return 0; + } + U8 PhysicsFlags() const + { + return 0; + } }; struct zNPCNewsFish : zNPCVillager @@ -257,58 +318,44 @@ struct zNPCNewsFish : zNPCVillager // 0x00000000; // 0x0 // 0x00000000; // 0x4 void Init(xEntAsset*); // 0x8 zNPCNewsFish - void PostInit(); // 0xC xNPCBasic - void Setup(); // 0x10 zNPCCommon + //void PostInit(); // 0xC xNPCBasic + //void Setup(); // 0x10 zNPCCommon void PostSetup(); // 0x14 zNPCNewsFish void Reset(); // 0x18 zNPCNewsFish void Process(xScene*, F32); // 0x1C zNPCNewsFish - void BUpdate(xVec3*); // 0x20 zNPCCommon - void NewTime(xScene*, F32); // 0x24 zNPCCommon - void Move(xScene*, F32, xEntFrame*); // 0x28 zNPCCommon - S32 SysEvent(xBase*, xBase*, U32, const F32*, xBase*, S32*); // 0x2C zNPCCommon + //void BUpdate(xVec3*); // 0x20 zNPCCommon + //void NewTime(xScene*, F32); // 0x24 zNPCCommon + //void Move(xScene*, F32, xEntFrame*); // 0x28 zNPCCommon + //S32 SysEvent(xBase*, xBase*, U32, const F32*, xBase*, S32*); // 0x2C zNPCCommon void Render(); // 0x30 zNPCNewsFish - void Save(xSerial*) const; // 0x34 xNPCBasic - void Load(xSerial*); // 0x38 xNPCBasic - void CollideReview(); // 0x3C zNPCVillager - U8 ColChkFlags() const; // 0x40 zNPCVillager - U8 ColPenFlags() const; // 0x44 zNPCVillager - U8 ColChkByFlags() const; // 0x48 zNPCVillager - U8 ColPenByFlags() const; // 0x4C zNPCVillager - U8 PhysicsFlags() const; // 0x50 zNPCVillager - void Destroy(); // 0x54 zNPCCommon - S32 NPCMessage(NPCMsg*); // 0x58 zNPCVillager - void RenderExtra(); // 0x5C zNPCCommon - void RenderExtraPostParticles(); // 0x60 zNPCCommon - void ParseINI(); // 0x64 zNPCVillager - void ParseLinks(); // 0x68 zNPCCommon - void ParseProps(); // 0x6C zNPCCommon - void SelfSetup(); // 0x70 zNPCNewsFish - void SelfDestroy(); // 0x74 zNPCCommon - S32 IsHealthy(); // 0x78 zNPCCommon - S32 IsAlive(); // 0x7C zNPCCommon - void Damage(en_NPC_DAMAGE_TYPE, xBase*, const xVec3*); // 0x80 zNPCCommon - S32 Respawn(const xVec3*, zMovePoint*, zMovePoint*); // 0x84 zNPCCommon - void DuploOwner(zNPCCommon*); // 0x88 zNPCCommon - void DuploNotice(en_SM_NOTICES, void*); // 0x8C zNPCCommon - S32 CanRope(); // 0x90 zNPCCommon - void LassoNotify(en_LASSO_EVENT); // 0x94 zNPCCommon - S32 SetCarryState(en_NPC_CARRY_STATE); // 0x98 zNPCCommon - void Stun(F32); // 0x9C zNPCCommon - void SpeakBegin(); // 0xA0 zNPCVillager - void SpeakEnd(); // 0xA4 zNPCVillager + //void Save(xSerial*) const; // 0x34 xNPCBasic + //void Load(xSerial*); // 0x38 xNPCBasic + //void CollideReview(); // 0x3C zNPCVillager + //U8 ColChkFlags() const; // 0x40 zNPCVillager + //U8 ColPenFlags() const; // 0x44 zNPCVillager + //U8 ColChkByFlags() const; // 0x48 zNPCVillager + //U8 ColPenByFlags() const; // 0x4C zNPCVillager + //U8 PhysicsFlags() const; // 0x50 zNPCVillager + //void Destroy(); // 0x54 zNPCCommon + //S32 NPCMessage(NPCMsg*); // 0x58 zNPCVillager + //void RenderExtra(); // 0x5C zNPCCommon + //void RenderExtraPostParticles(); // 0x60 zNPCCommon + //void ParseINI(); // 0x64 zNPCVillager + //void ParseLinks(); // 0x68 zNPCCommon + //void ParseProps(); // 0x6C zNPCCommon + void SelfSetup() + { + } void SpeakStart(U32 sndid, U32 sndhandle, S32 anim); // 0xA8 zNPCNewsFish void SpeakStop(); // 0xAC zNPCNewsFish - U32 AnimPick(S32, en_NPC_GOAL_SPOT, xGoal*); // 0xB0 zNPCVillager - void GetParm(en_npcparm, void*); // 0xB4 zNPCCommon - S32 GetParmDefault(en_npcparm, void*); // 0xB8 zNPCCommon - F32 GenShadCacheRad(); // 0xBC zNPCVillager - xEntDrive* PRIV_GetDriverData(); // 0xC0 zNPCCommon - zNPCLassoInfo* PRIV_GetLassoData(); // 0xC4 zNPCCommon - S32 LassoSetup(); // 0xC8 zNPCCommon - void FolkHandleMail(NPCMsg*); // 0xCC zNPCVillager void TalkOnScreen(S32 talkOnScreen); - zNPCNewsFish* get_said(zNPCNewsFish::say_enum); + S32 say(say_enum const*, unsigned long, S32, S32); + U8 say(say_enum s, S32 flags); + say_data* get_said(zNPCNewsFish::say_enum say) + { + return this->said + (S32)say; + }; }; struct zNPCNewsFishTV : zNPCVillager @@ -317,11 +364,30 @@ struct zNPCNewsFishTV : zNPCVillager { } - U8 PhysicsFlags() const; - U8 ColPenByFlags() const; - U8 ColChkByFlags() const; - U8 ColPenFlags() const; - U8 ColChkFlags() const; + U8 ColChkFlags() const + { + return 0; + } + + U8 ColPenFlags() const + { + return 0; + } + + U8 ColChkByFlags() const + { + return 0; + } + + U8 ColPenByFlags() const + { + return 0; + } + + U8 PhysicsFlags() const + { + return 0; + } }; xAnimTable* ZNPC_AnimTable_Villager(); @@ -331,7 +397,8 @@ xAnimTable* ZNPC_AnimTable_BalloonBoy(); xAnimTable* ZNPC_AnimTable_BalloonBoy(xAnimTable* callerTable); xAnimTable* ZNPC_AnimTable_SuperFriend(); xAnimTable* ZNPC_AnimTable_SuperFriend(xAnimTable* callerTable); -S32 FOLK_grul_goAlert(xGoal*, void*, en_trantype*, F32, void*); +S32 FOLK_grul_goAlert(xGoal* rawgoal, void*, en_trantype* trantype, F32, void*); +S32 MERC_grul_goAlert(xGoal* rawgoal, void*, en_trantype* trantype, F32, void*); void FOLK_KillEffects(); void FOLK_InitEffects(); void zNPCVillager_ScenePostInit(); diff --git a/src/SB/Game/zTaskBox.h b/src/SB/Game/zTaskBox.h index e4cb3ca15..cfb5e6032 100644 --- a/src/SB/Game/zTaskBox.h +++ b/src/SB/Game/zTaskBox.h @@ -31,9 +31,12 @@ struct ztaskbox : xBase struct callback { - callback(); - virtual void on_talk_start(); - virtual void on_talk_stop(); + virtual void on_talk_start() + { + } + virtual void on_talk_stop() + { + } }; struct talk_callback : ztalkbox::callback @@ -107,7 +110,10 @@ struct ztaskbox : xBase static void init(); bool exists(state_enum stage); static U32 get_text(U32); - U32 StatusGet() const; + U32 StatusGet() const + { + return this->state; + } }; #endif