diff --git a/src/SB/Core/x/xBehaviour.h b/src/SB/Core/x/xBehaviour.h index 2ec31439..e93081bb 100644 --- a/src/SB/Core/x/xBehaviour.h +++ b/src/SB/Core/x/xBehaviour.h @@ -106,6 +106,10 @@ struct xPsyche : RyzMemData xGoal* GetCurGoal() const; S32 GIDOfActive() const; S32 GIDOfPending() const; + S32 GIDOfSafety() const + { + return gid_safegoal; + } S32 Timestep(F32 dt, void* updCtxt); xGoal* FindGoal(S32 gid); S32 GoalSet(S32 gid, S32 r5); diff --git a/src/SB/Core/x/xNPCBasic.h b/src/SB/Core/x/xNPCBasic.h index 760bfab5..2d0e5a57 100644 --- a/src/SB/Core/x/xNPCBasic.h +++ b/src/SB/Core/x/xNPCBasic.h @@ -35,7 +35,7 @@ struct xNPCBasic : xEnt, xFactoryInst { S32 flg_basenpc : 16; S32 inUpdate : 8; - U32 flg_upward : 8; + S32 flg_upward : 8; } flags1; // Offset: 0xE8 diff --git a/src/SB/Game/zMovePoint.h b/src/SB/Game/zMovePoint.h index 59b39f79..fb583299 100644 --- a/src/SB/Game/zMovePoint.h +++ b/src/SB/Game/zMovePoint.h @@ -9,8 +9,18 @@ struct zMovePoint : xMovePoint { - F32 RadiusZone(); - F32 Delay(); + F32 RadiusZone() + { + return asset->zoneRadius; + } + F32 Delay() + { + return asset->delay; + } + xVec3* PosGet() + { + return pos; + } U32 NumNodes(); U8 IsOn(); }; diff --git a/src/SB/Game/zNPCGoalRobo.cpp b/src/SB/Game/zNPCGoalRobo.cpp index 8f064d11..d5c23e2f 100644 --- a/src/SB/Game/zNPCGoalRobo.cpp +++ b/src/SB/Game/zNPCGoalRobo.cpp @@ -453,9 +453,9 @@ xPsyche* xGoal::GetPsyche() const return psyche; } -xVec3* zNPCCommon::XZVecToPlayer(xVec3* unk1, F32* unk2) +void zNPCCommon::XZVecToPlayer(xVec3* unk1, F32* unk2) { - return zNPCCommon::XZVecToPos(unk1, xEntGetPos(&globals.player.ent), unk2); + XZVecToPos(unk1, xEntGetPos(&globals.player.ent), unk2); } RwMatrix* zNPCCommon::BoneMat(S32 unk) const @@ -468,8 +468,7 @@ RwV3d* zNPCCommon::BonePos(S32 unk) const return &this->model->Mat[unk].pos; } -// Return type is probably wrong -S32 zNPCCommon::XYZDstSqToPlayer(xVec3* unk) +F32 zNPCCommon::XYZDstSqToPlayer(xVec3* unk) { return XYZDstSqToPos(xEntGetPos(&globals.player.ent), unk); } diff --git a/src/SB/Game/zNPCGoalStd.cpp b/src/SB/Game/zNPCGoalStd.cpp index 5de65454..57566967 100644 --- a/src/SB/Game/zNPCGoalStd.cpp +++ b/src/SB/Game/zNPCGoalStd.cpp @@ -1,14 +1,15 @@ #include "xMath.h" +#include "xMathInlines.h" +#include "zGlobals.h" #include "zNPCGoalStd.h" #include "zNPCGoals.h" +#include "zNPCSupport.h" #include -// Nonmatching: not finished -#if 0 xFactoryInst* GOALCreate_Standard(S32 who, RyzMemGrow* grow, void*) { - xFactoryInst* std = NULL; + xGoal* std = NULL; switch (who) { @@ -24,11 +25,31 @@ xFactoryInst* GOALCreate_Standard(S32 who, RyzMemGrow* grow, void*) case NPC_GOAL_PATROL: std = new (who, grow) zNPCGoalPatrol(who); break; + case NPC_GOAL_FIDGET: + std = new (who, grow) zNPCGoalFidget(who); + break; + case NPC_GOAL_DEAD: + std = new (who, grow) zNPCGoalDead(who); + break; + case NPC_GOAL_NOMANLAND: + std = new (who, grow) zNPCGoalNoManLand(who); + break; + case NPC_GOAL_LIMBO: + std = new (who, grow) zNPCGoalLimbo(who); + break; + case NPC_GOAL_DEVANIMCYCLE: + std = new (who, grow) zNPCGoalDEVAnimCycle(who); + break; + case NPC_GOAL_DEVANIMSPIN: + std = new (who, grow) zNPCGoalDEVAnimSpin(who); + break; + case NPC_GOAL_DEVANIMHERO: + std = new (who, grow) zNPCGoalDEVHero(who); + break; } return std; } -#endif void GOALDestroy_Goal(xFactoryInst* inst) { @@ -50,6 +71,53 @@ S32 zNPCGoalPushAnim::Exit(F32 dt, void* updCtxt) return xGoal::Exit(dt, updCtxt); } +S32 zNPCGoalPushAnim::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + S32 nextgoal = 0; + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + F32 anim_time = npc->AnimTimeCurrent(); + + if (flg_pushanim & (1 << 0)) + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + else if (anid_played != npc->AnimCurStateID()) + { + if (flg_pushanim & (1 << 1)) + { + flg_pushanim &= ~(1 << 1); + anid_played = npc->AnimCurStateID(); + } + else if (flg_pushanim & (1 << 2)) + { + flg_pushanim &= ~(1 << 2); + anid_played = npc->AnimCurStateID(); + } + else + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + } + else if ((anim_time < lastAnimTime || npc->AnimTimeRemain(NULL) <= 2.1f * dt) && + !(flg_pushanim & ((1 << 2) | (1 << 1)))) + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + + lastAnimTime = anim_time; + + if (*trantype != GOAL_TRAN_NONE) + { + return nextgoal; + } + + return xGoal::Process(trantype, dt, updCtxt, scene); +} + S32 zNPCGoalPushAnim::Resume(F32 dt, void* updCtxt) { flg_pushanim |= (1 << 0); @@ -57,12 +125,115 @@ S32 zNPCGoalPushAnim::Resume(F32 dt, void* updCtxt) return zNPCGoalCommon::Resume(dt, updCtxt); } +S32 zNPCGoalLoopAnim::Enter(F32 dt, void* updCtxt) +{ + if (!(flg_info & (1 << 4))) + { + cnt_loop = 1; + } + + cnt_loop = CLAMP(cnt_loop, 1, 10000); + + origAnimFlags = 0; + animWeMolested = 0; + + if (!(flg_info & (1 << 5))) + { + UseDefaultAnims(); + } + + ValidateStages(); + MolestLoopAnim(); + + flg_npcgauto &= ~((1 << 2) | (1 << 1)); + + if (anid_stage[0] != 0) + { + DoExplicitAnim(anid_stage[0], 1); + } + else + { + DoExplicitAnim(anid_stage[1], 1); + } + + flg_info = 0; + lastAnimTime = -1.0f; + + return zNPCGoalLoopAnim::Enter(dt, updCtxt); +} + S32 zNPCGoalLoopAnim::Exit(F32 dt, void* updCtxt) { UnmolestAnim(); return xGoal::Exit(dt, updCtxt); } +S32 zNPCGoalLoopAnim::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + S32 nextgoal = 0; + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + U32 anim_state = npc->AnimCurStateID(); + F32 anim_time = npc->AnimTimeCurrent(); + if (flg_loopanim & (1 << 2)) + { + if (anim_state != anid_played) + { + flg_loopanim &= ~(1 << 2); + anid_played = anim_state; + } + } + else if (anim_state == anid_stage[1]) + { + if (cnt_loop > 1) + { + if (anim_time < lastAnimTime) + { + cnt_loop--; + } + } + else if (anim_time < lastAnimTime) + { + if (flg_loopanim & (1 << 3)) + { + DoExplicitAnim(anid_stage[2], 0); + } + else + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + } + } + else if (flg_loopanim & (1 << 3)) + { + if (anim_state != anid_stage[2]) + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + else if (anim_time < lastAnimTime) + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + } + else + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + + lastAnimTime = anim_time; + + if (*trantype != GOAL_TRAN_NONE) + { + return nextgoal; + } + + return xGoal::Process(trantype, dt, updCtxt, scene); +} + void zNPCGoalLoopAnim::MolestLoopAnim() { zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; @@ -246,7 +417,7 @@ S32 zNPCGoalIdle::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* flg_user = 0; } - npc->tmr_fidget = (-1.0f > (npc->tmr_fidget - dt)) ? -1.0f : (npc->tmr_fidget - dt); + npc->tmr_fidget = MAX(-1.0f, npc->tmr_fidget - dt); return xGoal::Process(trantype, dt, updCtxt, scene); } @@ -342,7 +513,7 @@ S32 zNPCGoalPatrol::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene if (flg_patrol & (1 << 1)) { npc->VelStop(); - tmr_wait = (-1.0f > (tmr_wait - dt)) ? -1.0f : (tmr_wait - dt); + tmr_wait = MAX(-1.0f, tmr_wait - dt); if (tmr_wait < 0.0f) { if (npc->nav_dest == NULL && npc->MvptCycle() == 0) @@ -356,7 +527,7 @@ S32 zNPCGoalPatrol::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene tmr_wait = npc->nav_curr->Delay(); } - tmr_wait = (2.0f > tmr_wait) ? 2.0f : tmr_wait; + tmr_wait = MAX(2.0f, tmr_wait); } else { @@ -441,17 +612,58 @@ void zNPCGoalPatrol::PickTransition(S32* goal, en_trantype* trantype) } } -// Nonmatching: nowhere near finished -#if 0 -void zNPCGoalPatrol::MoveNormal(F32 dt) +// Equivalent: scheduling +void zNPCGoalPatrol::Chk_AutoSmooth() { zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; - if (npc->DBG_IsNormLog(eNPCDCAT_Eleven, -1)) + if (npc->spl_mvptspline != NULL) + { + return; + } + + if (npc->nav_curr == NULL) + { + return; + } + + if (npc->nav_dest == NULL) + { + return; + } + + if (npc->nav_curr == NULL) + { + return; + } + + if (npc->nav_dest == NULL) + { + return; + } + + if (npc->nav_lead == NULL) { + return; + } + + if (npc->nav_curr == npc->nav_dest) + { + return; + } + + if (npc->nav_curr == npc->nav_lead) + { + return; + } + + static F32 ds2_min = SQ(1.5f); + + if (npc->XZDstSqToPos(npc->nav_dest->PosGet(), NULL, NULL) > ds2_min) + { + flg_patrol |= (1 << 4) | (1 << 3); } } -#endif S32 zNPCGoalFidget::Enter(F32 dt, void* updCtxt) { @@ -475,3 +687,576 @@ S32 zNPCGoalFidget::Exit(F32 dt, void* updCtxt) return zNPCGoalPushAnim::Enter(dt, updCtxt); } + +S32 zNPCGoalWander::Enter(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + npc->tmr_fidget = + npc->cfg_npc->tym_fidget * (0.25f * (xurand() - 0.5f)) + npc->cfg_npc->tym_fidget; + + zMovePoint* nav = npc->nav_curr; + tmr_remain = 0.0f; + rad_wand = 0.0f; + if (nav != NULL) + { + xVec3Copy(&pos_home, nav->PosGet()); + tmr_remain = nav->Delay(); + rad_wand = nav->RadiusZone(); + if (!(tmr_remain > 0.25f) || !(rad_wand > 0.0f)) + { + xSceneID2Name(globals.sceneCur, npc->id); + xSceneID2Name(globals.sceneCur, nav->id); + } + } + else + { + xVec3Copy(&pos_home, xEntGetPos(npc)); + } + + tmr_remain = MAX(1.0f, tmr_remain); + rad_wand = MAX(1.0f, rad_wand); + + xSceneID2Name(globals.sceneCur, npc->id); + + F32 dst = 0.75f * rad_wand; + xVec3Copy(&dir_cur, &pos_home); + + xVec3AddScaled(&dir_cur, NPCC_rightDir(npc), dst * xurand()); + dst *= 0.25f; + xVec3AddScaled(&dir_cur, NPCC_rightDir(npc), dst * (2.0f * (xurand() - 0.5f))); + + if (npc->flg_move & (1 << 1)) + { + dir_cur.y = 0.0f; + xVec3Normalize(&dir_cur, &dir_cur); + } + + tmr_newdir = 0.25f * rad_wand; + tmr_newdir = MIN(tmr_newdir, 3.0f); + tmr_minwalk = 0.25f * tmr_newdir; + tmr_minwalk = MIN(tmr_minwalk, 3.0f); + + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalWander::Resume(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + npc->tmr_fidget = + npc->cfg_npc->tym_fidget * (0.25f * (xurand() - 0.5f)) + npc->cfg_npc->tym_fidget; + + return zNPCGoalCommon::Resume(dt, updCtxt); +} + +// Equivalent: stack offsets, fmuls register order +S32 zNPCGoalWander::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + S32 nextgoal = 0; + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + tmr_remain = MAX(-1.0f, tmr_remain - dt); + tmr_newdir = MAX(-1.0f, tmr_newdir - dt); + tmr_minwalk = MAX(-1.0f, tmr_minwalk - dt); + + xVec3 delta; + xVec3 vec_dest; + + if (tmr_minwalk < 0.0f) + { + xVec3Sub(&delta, &pos_home, xEntGetPos(npc)); + + F32 length2 = xVec3Length2(&delta); + S32 calc = 0; + if (length2 > 0.95f * SQ(rad_wand)) + { + calc = 1; + } + else if (tmr_newdir < 0.0f) + { + calc = 1; + } + + if (calc) + { + CalcNewDir(); + } + } + + if (tmr_remain < 0.0f) + { + zMovePoint* nav_curr = npc->nav_curr; + if (nav_curr == NULL) + { + tmr_remain = 3.0f; + } + else if (npc->nav_dest == NULL) + { + zMovePoint* next; + zMovePointGetNext(nav_curr, NULL, &next, NULL); + if (next == NULL) + { + tmr_remain = nav_curr->Delay(); + } + } + } + + if (tmr_remain < 0.0f) + { + nextgoal = 1; + *trantype = GOAL_TRAN_POP; + } + else if (!(flg_wand & (1 << 0)) && npc->tmr_fidget < 0.0f) + { + *trantype = GOAL_TRAN_PUSH; + nextgoal = NPC_GOAL_FIDGET; + } + + if (*trantype != GOAL_TRAN_NONE) + { + return nextgoal; + } + + npc->ThrottleAccel(dt, 1, 0.75f); + NPCC_ang_toXZDir(npc->frame->rot.angle + npc->TurnToFace(dt, &dir_cur, -1.0f), &vec_dest); + npc->ThrottleApply(dt, &vec_dest, 0); + flg_wand &= ~(1 << 1); + + if (npc->flg_move & (1 << 2)) + { + F32 dVar7 = npc->XYZDstSqToPos(&pos_home, &vec_dest); + F32 spd_dt = npc->spd_throttle * dt; + if (flg_wand & (1 << 1)) + { + VerticalWander(spd_dt, &vec_dest); + } + else if (iabs(vec_dest.y) > 0.1f) + { + npc->frame->dpos.y = vec_dest.y * (spd_dt / dVar7); + npc->frame->mode |= 2; + } + } + + npc->tmr_fidget = MAX(-1.0f, npc->tmr_fidget - dt); + + return xGoal::Process(trantype, dt, updCtxt, NULL); +} + +// Equivalent: regalloc +void zNPCGoalWander::CalcNewDir() +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + xVec3 direction; + xVec3* player_pos; + xVec3* npc_pos; + + F32 dVar4 = NPCC_aimVary(&dir_cur, xEntGetPos(npc), &pos_home, rad_wand, 0, NULL); + if (npc->flg_move & (1 << 1)) + { + dir_cur.y = 0.0f; + } + if (dVar4 < rad_wand) + { + npc_pos = xEntGetPos(npc); + player_pos = xEntGetPos(&globals.player.ent); + xVec3Sub(&direction, player_pos, npc_pos); + + F32 length = xVec3Length(&direction); + if (length < 1.0f) + { + xVec3Copy(&direction, NPCC_rightDir(&globals.player.ent)); + if ((xrand() & 0x800000) != 0) + { + xVec3SMulBy(&direction, -1.0f); + } + } + else if (length < 10.0f) + { + xVec3SMulBy(&direction, -1.0f / length); + } + else + { + xVec3Copy(&direction, &g_O3); + } + } + else + { + xVec3Copy(&direction, &g_O3); + } + + xVec3AddTo(&dir_cur, &direction); + xVec3Normalize(&dir_cur, &dir_cur); + dVar4 = MAX(0.5f, dVar4); + F32 dVar6 = npc->cfg_npc->spd_moveMax; + F32 dVar5 = rad_wand * xurand() + dVar4; + if (dVar6 < 0.5f) + { + tmr_minwalk = 0.25f * dVar4; + tmr_newdir = 0.25f * dVar5; + } + else + { + tmr_minwalk = dVar4 / dVar6; + tmr_newdir = dVar5 / dVar6; + } +} + +S32 zNPCGoalWaiting::Enter(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + if (!(flg_info & (1 << 4))) + { + zMovePoint* current = npc->nav_curr; + if (current != NULL && current->Delay() > 0.75f) + { + tmr_waiting = current->Delay() + (0.25f * (xurand() - 0.5f)) * current->Delay(); + } + else + { + tmr_waiting = 10.0f + (0.25f * (xurand() - 0.5f)) * 10.0f; + } + } + + flg_info = 0; + + tmr_waiting = MAX(0.75f, tmr_waiting); + + npc->flags2.flg_colCheck = 0; + npc->flags2.flg_penCheck = 0; + npc->pflags &= ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + npc->tmr_fidget = + npc->cfg_npc->tym_fidget * (0.25f * (xurand() - 0.5f)) + npc->cfg_npc->tym_fidget; + + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalWaiting::Exit(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + npc->RestoreColFlags(); + + return xGoal::Exit(dt, updCtxt); +} + +S32 zNPCGoalWaiting::Resume(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + if (tmr_waiting < 0.15f) + { + tmr_waiting = 0.5f; + } + + npc->flags2.flg_colCheck = 0; + npc->flags2.flg_penCheck = 0; + npc->pflags &= ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + npc->tmr_fidget = + npc->cfg_npc->tym_fidget * (0.25f * (xurand() - 0.5f)) + npc->cfg_npc->tym_fidget; + + return zNPCGoalCommon::Resume(dt, updCtxt); +} + +S32 zNPCGoalWaiting::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + S32 nextgoal = 0; + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + npc->VelStop(); + + if (tmr_waiting < 0.0f) + { + TriggerExit(); + } + else if (!(flg_waiting & (1 << 0)) && npc->tmr_fidget < 0.0f) + { + *trantype = GOAL_TRAN_PUSH; + nextgoal = NPC_GOAL_FIDGET; + } + else + { + LoopCountSet(2); + } + + if (*trantype != GOAL_TRAN_NONE) + { + return nextgoal; + } + + tmr_waiting = MAX(-1.0f, tmr_waiting - dt); + npc->tmr_fidget = MAX(-1.0f, npc->tmr_fidget - dt); + + return xGoal::Process(trantype, dt, updCtxt, NULL); +} + +S32 zNPCGoalDead::Enter(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + old_moreFlags = npc->moreFlags; + + xEntHide(npc); + npc->moreFlags = 0; + npc->pflags = 0; + npc->flags2.flg_colCheck = 0; + npc->flags2.flg_penCheck = 0; + npc->chkby = 0; + npc->penby = 0; + npc->model->Flags &= (U16) ~(1 << 1); + npc->flags1.flg_upward |= (1 << 0); + + if (!(flg_deadinfo & (1 << 0))) + { + zEntEvent(npc, npc, eEventDeath); + } + flg_deadinfo = 0; + + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalDead::Exit(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + xEntShow(npc); + npc->RestoreColFlags(); + npc->moreFlags = old_moreFlags; + npc->model->Flags |= (1 << 1); + npc->flags1.flg_upward &= ~(1 << 0); + + return xGoal::Exit(dt, updCtxt); +} + +S32 zNPCGoalLimbo::Enter(F32 dt, void* updCtxt) +{ + DieQuietly(); + return zNPCGoalDead::Enter(dt, updCtxt); +} + +S32 zNPCGoalLimbo::NPCMessage(NPCMsg* mail) +{ + S32 handled = 1; + + switch (mail->msgid) + { + case NPC_MID_SYSEVENT: + xPsyche* psyche_ = psyche; // why? + if (mail->sysevent.toEvent != eEventNPCSetActiveOff) + { + if (mail->sysevent.toEvent == eEventNPCSetActiveOn) + { + U32 gid = psyche->GIDOfSafety(); // why??? + psyche_->GoalSet(gid, 0); + } + else if (mail->sysevent.toEvent != eEventNPCRespawn) + { + handled = 0; + } + } + break; + case NPC_MID_RESPAWN: + case NPC_MID_DAMAGE: + break; + default: + handled = 0; + break; + } + + return handled; +} + +S32 zNPCGoalDEVAnimCycle::Enter(F32 dt, void* updCtxt) +{ + xAnimState* next = ASTGetNext(NULL); + DoExplicitAnim(next->ID, 0); + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalDEVAnimCycle::Exit(F32 dt, void* updCtxt) +{ + return xGoal::Exit(dt, updCtxt); +} + +S32 zNPCGoalDEVAnimCycle::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + npc->VelStop(); + npc->TurnToFace(dt, &g_Z3, -1.0f); + + if (npc->AnimTimeRemain(NULL) < dt + 0.001f) + { + xAnimState* next = ASTGetNext(npc->AnimCurState()); + DoExplicitAnim(next->ID, 0); + } + + npc->AnimCurState(); + return xGoal::Process(trantype, dt, updCtxt, NULL); +} + +S32 zNPCGoalDEVAnimCycle::NPCMessage(NPCMsg* mail) +{ + S32 handled = 1; + + switch (mail->msgid) + { + case NPC_MID_DEV_ANIMSPIN: + psyche->GoalSet(NPC_GOAL_DEVANIMCYCLE, 0); + break; + case NPC_MID_DEV_HEROMODE: + psyche->GoalSet(NPC_GOAL_DEVANIMHERO, 0); + break; + case NPC_MID_DEV_DONE: + psyche->GoalSet(psyche->GIDOfSafety(), 0); + break; + case NPC_MID_DEV_ANIMCYCLE: + break; + default: + handled = 1; + break; + } + + return handled; +} + +xAnimState* zNPCGoalDEVAnimCycle::ASTGetNext(xAnimState* ast) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + xAnimState* list = npc->model->Anim->Table->StateList; + + if (ast == NULL) + { + return list; + } + if (ast->Next == NULL) + { + return list; + } + + return ast->Next; +} + +S32 zNPCGoalDEVAnimSpin::Enter(F32 dt, void* updCtxt) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + xAnimState* state = npc->AnimCurState(); + + ASTMolestAnim(state); + DoExplicitAnim(state->ID, 1); + + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalDEVAnimSpin::Exit(F32 dt, void* updCtxt) +{ + ASTUnmolestAnim(); + return xGoal::Exit(dt, updCtxt); +} + +S32 zNPCGoalDEVAnimSpin::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + npc->VelStop(); + npc->frame->drot.angle = (2.0f * PI) * dt; + npc->frame->mode |= 0x20; + + return xGoal::Process(trantype, dt, updCtxt, NULL); +} + +S32 zNPCGoalDEVAnimSpin::NPCMessage(NPCMsg* mail) +{ + S32 handled = 1; + + switch (mail->msgid) + { + case NPC_MID_DEV_ANIMCYCLE: + psyche->GoalSet(NPC_GOAL_DEVANIMSPIN, 0); + break; + case NPC_MID_DEV_HEROMODE: + psyche->GoalSet(NPC_GOAL_DEVANIMHERO, 0); + break; + case NPC_MID_DEV_DONE: + psyche->GoalSet(psyche->GIDOfSafety(), 0); + break; + case NPC_MID_DEV_ANIMSPIN: + break; + default: + handled = 1; + break; + } + + return handled; +} + +void zNPCGoalDEVAnimSpin::ASTMolestAnim(xAnimState* state) +{ + if (animWeMolested != 0) + { + ASTUnmolestAnim(); + } + + origAnimFlags = state->Flags; + animWeMolested = state->ID; + state->Flags &= ~(1 << 5); + state->Flags |= (1 << 4); +} + +void zNPCGoalDEVAnimSpin::ASTUnmolestAnim() +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + + if (animWeMolested == 0) + { + return; + } + + xAnimState* state = npc->AnimFindState(animWeMolested); + state->Flags = origAnimFlags; + + animWeMolested = 0; + origAnimFlags = 0; +} + +S32 zNPCGoalDEVHero::Enter(F32 dt, void* updCtxt) +{ + return zNPCGoalCommon::Enter(dt, updCtxt); +} + +S32 zNPCGoalDEVHero::Exit(F32 dt, void* updCtxt) +{ + return xGoal::Exit(dt, updCtxt); +} + +S32 zNPCGoalDEVHero::Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene) +{ + zNPCCommon* npc = (zNPCCommon*)psyche->clt_owner; + npc->VelStop(); + npc->TurnToFace(dt, &g_Z3, -1.0f); + + return xGoal::Process(trantype, dt, updCtxt, NULL); +} + +S32 zNPCGoalDEVHero::NPCMessage(NPCMsg* mail) +{ + S32 handled = 1; + + switch (mail->msgid) + { + case NPC_MID_DEV_ANIMCYCLE: + psyche->GoalSet(NPC_GOAL_DEVANIMSPIN, 0); + break; + case NPC_MID_DEV_ANIMSPIN: + psyche->GoalSet(NPC_GOAL_DEVANIMCYCLE, 0); + break; + case NPC_MID_DEV_DONE: + psyche->GoalSet(psyche->GIDOfSafety(), 0); + break; + case NPC_MID_DEV_HEROMODE: + break; + default: + handled = 1; + break; + } + + return handled; +} diff --git a/src/SB/Game/zNPCGoalStd.h b/src/SB/Game/zNPCGoalStd.h index 347fe623..6c00fa84 100644 --- a/src/SB/Game/zNPCGoalStd.h +++ b/src/SB/Game/zNPCGoalStd.h @@ -75,11 +75,16 @@ struct zNPCGoalLoopAnim : zNPCGoalCommon U32 origAnimFlags; U32 animWeMolested; - zNPCGoalLoopAnim(S32 myType) : zNPCGoalCommon(myType) + zNPCGoalLoopAnim(S32 goalID) : zNPCGoalCommon(goalID) { SetFlags(1 << 1); } + void TriggerExit() + { + cnt_loop = 0; + } + void MolestLoopAnim(); void UnmolestAnim(); void LoopCountSet(S32 num); @@ -95,7 +100,7 @@ struct zNPCGoalIdle : zNPCGoalCommon { S32 flg_idle; - zNPCGoalIdle(S32 myType) : zNPCGoalCommon(myType) + zNPCGoalIdle(S32 goalID) : zNPCGoalCommon(goalID) { SetFlags((1 << 3) | (1 << 2)); flg_npcgauto &= ~((1 << 2) | (1 << 1)); @@ -114,9 +119,14 @@ struct zNPCGoalWaiting : zNPCGoalLoopAnim S32 flg_waiting; F32 tmr_waiting; - zNPCGoalWaiting(S32 myType) : zNPCGoalLoopAnim(myType) + zNPCGoalWaiting(S32 goalID) : zNPCGoalLoopAnim(goalID) { } + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Exit(F32 dt, void* updCtxt); + virtual S32 Resume(F32 dt, void* updCtxt); + virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); }; struct zNPCGoalWander : zNPCGoalCommon @@ -129,11 +139,18 @@ struct zNPCGoalWander : zNPCGoalCommon F32 tmr_newdir; xVec3 dir_cur; - zNPCGoalWander(S32 myType) : zNPCGoalCommon(myType) + zNPCGoalWander(S32 goalID) : zNPCGoalCommon(goalID) { SetFlags((1 << 2) | (1 << 1)); flg_wand = 0xFFFF0000; } + + void VerticalWander(F32 spd_dt, const xVec3* vec_dest); + void CalcNewDir(); + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Resume(F32 dt, void* updCtxt); + virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); }; struct zNPCGoalPatrol : zNPCGoalCommon @@ -143,7 +160,7 @@ struct zNPCGoalPatrol : zNPCGoalCommon xVec3 pos_midpnt[4]; S32 idx_midpnt; - zNPCGoalPatrol(S32 myType) : zNPCGoalCommon(myType) + zNPCGoalPatrol(S32 goalID) : zNPCGoalCommon(goalID) { SetFlags((1 << 2) | (1 << 1)); } @@ -166,7 +183,7 @@ struct zNPCGoalPushAnim : zNPCGoalCommon S32 flg_pushanim; F32 lastAnimTime; - zNPCGoalPushAnim(S32 myType) : zNPCGoalCommon(myType) + zNPCGoalPushAnim(S32 goalID) : zNPCGoalCommon(goalID) { SetFlags((1 << 2) | (1 << 1)); } @@ -179,8 +196,101 @@ struct zNPCGoalPushAnim : zNPCGoalCommon struct zNPCGoalFidget : zNPCGoalPushAnim { + zNPCGoalFidget(S32 goalID) : zNPCGoalPushAnim(goalID) + { + } + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Exit(F32 dt, void* updCtxt); +}; + +struct zNPCGoalNoManLand : zNPCGoalCommon +{ + zNPCGoalNoManLand(S32 goalID) : zNPCGoalCommon(goalID) + { + } +}; + +struct zNPCGoalDead : zNPCGoalCommon +{ + S32 flg_deadinfo; + U8 old_moreFlags; + + zNPCGoalDead(S32 goalID) : zNPCGoalCommon(goalID) + { + SetFlags((1 << 2) | (1 << 1)); + } + + void DieQuietly() + { + flg_deadinfo |= (1 << 0); + flg_deadinfo &= ~(1 << 1); + } + void DieWithAWhimper(); + void DieWithABang(); + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Exit(F32 dt, void* updCtxt); + +protected: + ~zNPCGoalDead(); +}; + +struct zNPCGoalLimbo : zNPCGoalDead +{ + zNPCGoalLimbo(S32 goalID) : zNPCGoalDead(goalID) + { + } + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 NPCMessage(NPCMsg* mail); +}; + +struct zNPCGoalDEVAnimCycle : zNPCGoalCommon +{ + zNPCGoalDEVAnimCycle(S32 goalID) : zNPCGoalCommon(goalID) + { + flg_npcgauto &= ~((1 << 2) | (1 << 1)); + } + + xAnimState* ASTGetNext(xAnimState* ast); + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Exit(F32 dt, void* updCtxt); + virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); + virtual S32 NPCMessage(NPCMsg* mail); +}; + +struct zNPCGoalDEVAnimSpin : zNPCGoalCommon +{ + U32 origAnimFlags; + U32 animWeMolested; + + zNPCGoalDEVAnimSpin(S32 goalID) : zNPCGoalCommon(goalID) + { + flg_npcgauto &= ~((1 << 2) | (1 << 1)); + } + + void ASTMolestAnim(xAnimState* state); + void ASTUnmolestAnim(); + + virtual S32 Enter(F32 dt, void* updCtxt); + virtual S32 Exit(F32 dt, void* updCtxt); + virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); + virtual S32 NPCMessage(NPCMsg* mail); +}; + +struct zNPCGoalDEVHero : zNPCGoalCommon +{ + zNPCGoalDEVHero(S32 goalID) : zNPCGoalCommon(goalID) + { + flg_npcgauto &= ~((1 << 2) | (1 << 1)); + } + virtual S32 Enter(F32 dt, void* updCtxt); virtual S32 Exit(F32 dt, void* updCtxt); + virtual S32 Process(en_trantype* trantype, F32 dt, void* updCtxt, xScene* scene); + virtual S32 NPCMessage(NPCMsg* mail); }; struct zNPCGoalTaunt : zNPCGoalLoopAnim @@ -349,28 +459,6 @@ struct zNPCGoalDogLaunch : zNPCGoalCommon void ViciousAttack(xVec3* unk1, xVec3* unk2, zMovePoint* unk3, S32 unk4); }; -struct zNPCGoalDead : zNPCGoalCommon -{ - S32 flg_deadinfo; - U8 old_moreFlags; - - zNPCGoalDead(S32 goalID); - - virtual S32 Enter(F32 dt, void* updCtxt); - virtual S32 Exit(F32 dt, void* updCtxt); - - void DieQuietly() - { - flg_deadinfo |= (1 << 0); - flg_deadinfo &= ~(1 << 1); - } - void DieWithAWhimper(); - void DieWithABang(); - -protected: - ~zNPCGoalDead(); -}; - xFactoryInst* GOALCreate_Standard(S32 who, RyzMemGrow* grow, void*); void GOALDestroy_Goal(xFactoryInst* inst); diff --git a/src/SB/Game/zNPCSupport.h b/src/SB/Game/zNPCSupport.h index dfff4536..965296e1 100644 --- a/src/SB/Game/zNPCSupport.h +++ b/src/SB/Game/zNPCSupport.h @@ -45,5 +45,6 @@ void NPCSupport_ScenePostInit(); S32 NPCC_LampStatus(); xVec3* NPCC_rightDir(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); #endif diff --git a/src/SB/Game/zNPCTypeCommon.h b/src/SB/Game/zNPCTypeCommon.h index f8ae72c7..6060af24 100644 --- a/src/SB/Game/zNPCTypeCommon.h +++ b/src/SB/Game/zNPCTypeCommon.h @@ -399,6 +399,7 @@ struct zNPCCommon : xNPCBasic U32 DBG_InstName(); // return type might be wrong xAnimTable* AnimGetTable(); F32 AnimTimeRemain(xAnimState* ast); + F32 AnimTimeCurrent(); F32 AnimDuration(xAnimState* ast); bool IsMountableType(en_ZBASETYPE type); void MvptReset(zMovePoint* nav_goto); @@ -436,10 +437,24 @@ struct zNPCCommon : xNPCBasic xVec3* Pos(); RwMatrix* BoneMat(S32 unk) const; RwV3d* BonePos(S32 unk) const; - xVec3* XZVecToPlayer(xVec3* unk1, F32* unk2); // might have wrong return type - xVec3* XZVecToPos(xVec3* unk1, const xVec3* unk2, F32* unk3); // ? return type - S32 XYZDstSqToPlayer(xVec3* unk); // return type is probably wrong - S32 XYZDstSqToPos(xVec3* unk1, xVec3* unk2); + void XZVecToPlayer(xVec3* unk1, F32* unk2); + F32 XZDstSqToPos(const xVec3* unk1, xVec3* unk2, F32* unk3); + void XZVecToPos(xVec3* unk1, const xVec3* unk2, F32* unk3); + void XYZVecToPos(xVec3* dest, xVec3* unk2) + { + xVec3Sub(dest, unk2, Pos()); + } + F32 XYZDstSqToPlayer(xVec3* unk); + F32 XYZDstSqToPos(xVec3* unk1, xVec3* dest) + { + xVec3 dest_vec; + if (dest == NULL) + { + dest = &dest_vec; + } + XYZVecToPos(dest, unk1); + return xVec3Length2(dest); + } void WonderOfTalking(S32 inprogress, xBase* owner); // return type is probably wrong S32 SomethingWonderful();