NPC Tracking (#1184)

* npc tracking

* fix func declaration

* more cleanup

* rm named var

* more cleanup
This commit is contained in:
engineer124 2023-03-07 21:33:16 -05:00 committed by GitHub
parent e50ab59cf7
commit e8f906100b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 338 additions and 206 deletions

View File

@ -752,8 +752,8 @@ void Actor_SetColorFilter(Actor* actor, u16 colorFlag, u16 colorIntensityMax, u1
Hilite* func_800BCBF4(Vec3f* arg0, PlayState* play);
Hilite* func_800BCC68(Vec3f* arg0, PlayState* play);
void Actor_GetClosestPosOnPath(Vec3s* points, s32 numPoints, Vec3f* srcPos, Vec3f* dstPos, s32 isPathLoop);
s32 func_800BD2B4(PlayState* play, Actor* actor, s16* arg2, f32 arg3, u16 (*textIdCallback)(PlayState*, Actor*), s16 (*arg5)(PlayState*, Actor*));
void func_800BD888(Actor* actor, struct_800BD888_arg1* arg1, s16 arg2, s16 arg3);
s32 Npc_UpdateTalking(PlayState* play, Actor* actor, s16* talkState, f32 interactRange, NpcGetTextIdFunc getTextId, NpcUpdateTalkStateFunc updateTalkState);
void Npc_TrackPoint(Actor* actor, NpcInteractInfo* interactInfo, s16 presetIndex, s16 trackingMode);
void func_800BD9E0(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s16 alpha);
void func_800BDAA0(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s16 alpha);
void Actor_ChangeAnimationByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 animIndex);

View File

@ -417,7 +417,6 @@ extern Color_RGBA8 actorDefaultHitColor;
// extern UNK_TYPE4 D_801AEDD4;
// extern UNK_TYPE4 D_801AEE28;
// extern UNK_TYPE4 D_801AEE30;
// extern UNK_TYPE4 D_801AEE38;
// extern UNK_TYPE2 D_801AEE4C;
extern Gfx D_801AEF88[];
extern Gfx D_801AEFA0[];

View File

@ -839,19 +839,6 @@ typedef struct {
/* 0x10 */ Color_RGBA8_u32 envColor;
} Struct_80140E80; // size = 0x14
// From OoT's struct_80034A14_arg1
typedef struct {
/* 0x00 */ s16 unk_00;
/* 0x02 */ s16 unk_02;
/* 0x04 */ s16 unk_04;
/* 0x06 */ s16 unk_06;
/* 0x08 */ Vec3s unk_08;
/* 0x0E */ Vec3s unk_0E;
/* 0x14 */ f32 unk_14;
/* 0x18 */ Vec3f unk_18; // Usually setted to Player's position or Player's focus
/* 0x24 */ s16 unk_24;
} struct_800BD888_arg1; // size = 0x28
typedef struct {
/* 0x0 */ u32 type;
/* 0x4 */ u32 setScissor;

View File

@ -22,6 +22,8 @@ struct EnBox;
struct EnTorch2;
typedef void(*ActorFunc)(struct Actor* this, struct PlayState* play);
typedef u16 (*NpcGetTextIdFunc)(struct PlayState*, struct Actor*);
typedef s16 (*NpcUpdateTalkStateFunc)(struct PlayState*, struct Actor*);
typedef struct {
/* 0x00 */ Vec3f pos;
@ -639,4 +641,31 @@ typedef enum {
/* 0xFF */ TATL_HINT_ID_NONE = 0xFF
} TatlHintId;
typedef enum NpcTalkState {
/* 0 */ NPC_TALK_STATE_IDLE, // NPC not currently talking to player
/* 1 */ NPC_TALK_STATE_TALKING, // NPC is currently talking to player
/* 2 */ NPC_TALK_STATE_ACTION, // An NPC-defined action triggered in the conversation
/* 3 */ NPC_TALK_STATE_ITEM_GIVEN // NPC finished giving an item and text box is done
} NpcTalkState;
typedef enum NpcTrackingMode {
/* 0 */ NPC_TRACKING_PLAYER_AUTO_TURN, // Determine tracking mode based on player position, see Npc_UpdateAutoTurn
/* 1 */ NPC_TRACKING_NONE, // Don't track the target (usually the player)
/* 2 */ NPC_TRACKING_HEAD_AND_TORSO, // Track target by turning the head and the torso
/* 3 */ NPC_TRACKING_HEAD, // Track target by turning the head
/* 4 */ NPC_TRACKING_FULL_BODY // Track target by turning the body, torso and head
} NpcTrackingMode;
typedef struct NpcInteractInfo {
/* 0x00 */ s16 talkState;
/* 0x02 */ s16 trackingMode;
/* 0x04 */ s16 autoTurnTimer;
/* 0x06 */ s16 autoTurnState;
/* 0x08 */ Vec3s headRot;
/* 0x0E */ Vec3s torsoRot;
/* 0x14 */ f32 yOffset; // Y position offset to add to actor position when calculating angle to target
/* 0x18 */ Vec3f trackPos;
/* 0x24 */ UNK_TYPE1 unk_24[0x4];
} NpcInteractInfo; // size = 0x28
#endif

View File

@ -4015,170 +4015,285 @@ void Actor_GetClosestPosOnPath(Vec3s* points, s32 numPoints, Vec3f* srcPos, Vec3
}
}
// unused
s32 func_800BD2B4(PlayState* play, Actor* actor, s16* arg2, f32 arg3, u16 (*textIdCallback)(PlayState*, Actor*),
s16 (*arg5)(PlayState*, Actor*)) {
/**
* Updates NPC talking state. Checks for a talk request and updates
* the talkState parameter when a dialog is ongoing. Otherwise checks if
* the actor is onscreen, advertises the interaction in a range and sets
* the current text id if necessary.
*
* The talk state values are defined in the NpcTalkState enum.
*
* @see NpcTalkState
*
* @param[in,out] talkState Talk state
* @param interactRange The interact (talking) range for the actor
* @param getTextId Callback for getting the next text id
* @param updateTalkState Callback for getting the next talkState value
* @return True if a new dialog was started (player talked to the actor). False otherwise.
*/
s32 Npc_UpdateTalking(PlayState* play, Actor* actor, s16* talkState, f32 interactRange, NpcGetTextIdFunc getTextId,
NpcUpdateTalkStateFunc updateTalkState) {
if (Actor_ProcessTalkRequest(actor, &play->state)) {
*arg2 = true;
*talkState = NPC_TALK_STATE_TALKING;
return true;
} else if (*arg2) {
*arg2 = arg5(play, actor);
return false;
} else if (!Actor_OnScreen(play, actor)) {
return false;
} else if (!func_800B8614(actor, play, arg3)) {
return false;
} else {
actor->textId = textIdCallback(play, actor);
}
if (*talkState != NPC_TALK_STATE_IDLE) {
*talkState = updateTalkState(play, actor);
return false;
}
if (!Actor_OnScreen(play, actor)) {
return false;
}
if (!func_800B8614(actor, play, interactRange)) {
return false;
}
actor->textId = getTextId(play, actor);
return false;
}
typedef struct {
/* 0x00 */ s16 unk_00;
/* 0x02 */ s16 unk_02;
/* 0x04 */ s16 unk_04;
/* 0x06 */ s16 unk_06;
/* 0x08 */ s16 unk_08;
/* 0x0A */ s16 unk_0A;
/* 0x0C */ u8 unk_0C;
} struct_801AEE38_0; // size = 0x10
/* 0x0 */ s16 maxHeadYaw;
/* 0x2 */ s16 minHeadPitch;
/* 0x4 */ s16 maxHeadPitch;
/* 0x6 */ s16 maxTorsoYaw;
/* 0x8 */ s16 minTorsoPitch;
/* 0xA */ s16 maxTorsoPitch;
/* 0xC */ u8 rotateYaw;
} NpcTrackingRotLimits; // size = 0x10
typedef struct {
/* 0x00 */ struct_801AEE38_0 sub_00;
/* 0x10 */ f32 unk_10;
/* 0x14 */ s16 unk_14;
} struct_801AEE38; // size = 0x18
/* 0x00 */ NpcTrackingRotLimits rotLimits;
// Fields specific to NPC_TRACKING_PLAYER_AUTO_TURN mode
/* 0x10 */ f32 autoTurnDistanceRange; // Max distance to player to enable tracking and auto-turn
/* 0x14 */ s16 maxYawForPlayerTracking; // Player is tracked if within this yaw
} NpcTrackingParams; // size = 0x18
struct_801AEE38 D_801AEE38[] = {
{ { 0x1C20, 0xE390, 0x1C70, 0x1554, 0x0000, 0x0000, 0x0000 }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xEAAC, 0x1554, 0x1554, 0xF8E4, 0x0E38, 0x0001 }, 170.0f, 0x3FFC },
{ { 0x31C4, 0xE390, 0x0E38, 0x0E38, 0xF1C8, 0x071C, 0x0001 }, 170.0f, 0x3FFC },
{ { 0x1554, 0xF1C8, 0x0000, 0x071C, 0xF8E4, 0x0000, 0x0001 }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xF8E4, 0x071C, 0x0E38, 0xD558, 0x2AA8, 0x0001 }, 170.0f, 0x3FFC },
{ { 0x0000, 0xE390, 0x2AA8, 0x3FFC, 0xF1C8, 0x0E38, 0x0001 }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xF1C8, 0x0E38, 0x0E38, 0x0000, 0x0000, 0x0001 }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xF1C8, 0x0000, 0x0E38, 0x0000, 0x1C70, 0x0001 }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xF1C8, 0xF1C8, 0x0000, 0x0000, 0x0000, 0x0001 }, 0.0f, 0x0000 },
{ { 0x071C, 0xF1C8, 0x0E38, 0x1C70, 0x0000, 0x0000, 0x0001 }, 0.0f, 0x0000 },
{ { 0x0E38, 0xF1C8, 0x0000, 0x1C70, 0x0000, 0x0E38, 0x0001 }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xE390, 0x1C70, 0x0E38, 0xF1C8, 0x0E38, 0x0001 }, 0.0f, 0x0000 },
{ { 0x18E2, 0xF1C8, 0x0E38, 0x0E38, 0x0000, 0x0000, 0x0001 }, 0.0f, 0x0000 },
{ { 0x2A6C, 0xE390, 0x1C70, 0x1554, 0x0000, 0x0000, 0x0000 }, 170.0f, 0x3FFC },
/**
* Npc tracking angle limit presets to use with Npc_TrackPoint.
*
* @see Npc_TrackPoint
*/
NpcTrackingParams sNpcTrackingPresets[] = {
{ { 0x1C20, 0xE390, 0x1C70, 0x1554, 0x0000, 0x0000, false }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xEAAC, 0x1554, 0x1554, 0xF8E4, 0x0E38, true }, 170.0f, 0x3FFC },
{ { 0x31C4, 0xE390, 0x0E38, 0x0E38, 0xF1C8, 0x071C, true }, 170.0f, 0x3FFC },
{ { 0x1554, 0xF1C8, 0x0000, 0x071C, 0xF8E4, 0x0000, true }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xF8E4, 0x071C, 0x0E38, 0xD558, 0x2AA8, true }, 170.0f, 0x3FFC },
{ { 0x0000, 0xE390, 0x2AA8, 0x3FFC, 0xF1C8, 0x0E38, true }, 170.0f, 0x3FFC },
{ { 0x2AA8, 0xF1C8, 0x0E38, 0x0E38, 0x0000, 0x0000, true }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xF1C8, 0x0000, 0x0E38, 0x0000, 0x1C70, true }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xF1C8, 0xF1C8, 0x0000, 0x0000, 0x0000, true }, 0.0f, 0x0000 },
{ { 0x071C, 0xF1C8, 0x0E38, 0x1C70, 0x0000, 0x0000, true }, 0.0f, 0x0000 },
{ { 0x0E38, 0xF1C8, 0x0000, 0x1C70, 0x0000, 0x0E38, true }, 0.0f, 0x0000 },
{ { 0x2AA8, 0xE390, 0x1C70, 0x0E38, 0xF1C8, 0x0E38, true }, 0.0f, 0x0000 },
{ { 0x18E2, 0xF1C8, 0x0E38, 0x0E38, 0x0000, 0x0000, true }, 0.0f, 0x0000 },
{ { 0x2A6C, 0xE390, 0x1C70, 0x1554, 0x0000, 0x0000, false }, 170.0f, 0x3FFC },
};
void func_800BD384(Actor* actor, struct_800BD888_arg1* arg1, s16 arg2, s16 arg3, s16 arg4, s16 arg5, s16 arg6, s16 arg7,
u8 arg8) {
s16 sp46;
s16 sp44;
s16 temp2;
s16 sp40;
s16 temp1;
Vec3f sp30;
/**
* Smoothly turns the actor's whole body and updates torso and head rotations in
* NpcInteractInfo so that the actor tracks the point specified in NpcInteractInfo.trackPos.
* Rotations are limited to specified angles.
*
* Head and torso rotation angles are determined by calculating the pitch and yaw
* from the actor position to the given target position.
*
* The y position of the actor is offset by NpcInteractInfo.yOffset
* before calculating the angles. It can be used to configure the height difference
* between the actor and the target.
*
* @param maxHeadYaw maximum head yaw difference from neutral position
* @param maxHeadPitch maximum head pitch angle
* @param minHeadPitch minimum head pitch angle
* @param maxTorsoYaw maximum torso yaw difference from neutral position
* @param maxTorsoPitch maximum torso pitch angle
* @param minTorsoPitch minimum torso pitch angle
* @param rotateYaw if true, the actor's yaw (shape.rot.y) is updated to turn the actor's whole body
*/
void Npc_TrackPointWithLimits(Actor* actor, NpcInteractInfo* interactInfo, s16 maxHeadYaw, s16 maxHeadPitch,
s16 minHeadPitch, s16 maxTorsoYaw, s16 maxTorsoPitch, s16 minTorsoPitch, u8 rotateYaw) {
s16 pitchTowardsTarget;
s16 yawTowardsTarget;
s16 torsoPitch;
s16 bodyYawDiff;
s16 temp;
Vec3f offsetActorPos;
sp30.x = actor->world.pos.x;
sp30.y = actor->world.pos.y + arg1->unk_14;
sp30.z = actor->world.pos.z;
offsetActorPos.x = actor->world.pos.x;
offsetActorPos.y = actor->world.pos.y + interactInfo->yOffset;
offsetActorPos.z = actor->world.pos.z;
sp46 = Math_Vec3f_Pitch(&sp30, &arg1->unk_18);
sp44 = Math_Vec3f_Yaw(&sp30, &arg1->unk_18);
sp40 = Math_Vec3f_Yaw(&actor->world.pos, &arg1->unk_18) - actor->shape.rot.y;
pitchTowardsTarget = Math_Vec3f_Pitch(&offsetActorPos, &interactInfo->trackPos);
yawTowardsTarget = Math_Vec3f_Yaw(&offsetActorPos, &interactInfo->trackPos);
bodyYawDiff = Math_Vec3f_Yaw(&actor->world.pos, &interactInfo->trackPos) - actor->shape.rot.y;
temp1 = CLAMP(sp40, -arg2, arg2);
Math_SmoothStepToS(&arg1->unk_08.y, temp1, 6, 2000, 1);
temp = CLAMP(bodyYawDiff, -maxHeadYaw, maxHeadYaw);
Math_SmoothStepToS(&interactInfo->headRot.y, temp, 6, 0x7D0, 1);
temp1 = (ABS_ALT(sp40) >= 0x8000) ? 0 : ABS_ALT(sp40);
arg1->unk_08.y = CLAMP(arg1->unk_08.y, -temp1, temp1);
temp = (ABS_ALT(bodyYawDiff) >= 0x8000) ? 0 : ABS_ALT(bodyYawDiff);
interactInfo->headRot.y = CLAMP(interactInfo->headRot.y, -temp, temp);
sp40 -= arg1->unk_08.y;
bodyYawDiff -= interactInfo->headRot.y;
temp1 = CLAMP(sp40, -arg5, arg5);
Math_SmoothStepToS(&arg1->unk_0E.y, temp1, 6, 2000, 1);
temp = CLAMP(bodyYawDiff, -maxTorsoYaw, maxTorsoYaw);
Math_SmoothStepToS(&interactInfo->torsoRot.y, temp, 6, 0x7D0, 1);
temp1 = (ABS_ALT(sp40) >= 0x8000) ? 0 : ABS_ALT(sp40);
arg1->unk_0E.y = CLAMP(arg1->unk_0E.y, -temp1, temp1);
temp = (ABS_ALT(bodyYawDiff) >= 0x8000) ? 0 : ABS_ALT(bodyYawDiff);
interactInfo->torsoRot.y = CLAMP(interactInfo->torsoRot.y, -temp, temp);
if (arg8) {
Math_SmoothStepToS(&actor->shape.rot.y, sp44, 6, 2000, 1);
if (rotateYaw) {
Math_SmoothStepToS(&actor->shape.rot.y, yawTowardsTarget, 6, 0x7D0, 1);
}
temp1 = CLAMP(sp46, arg4, (s16)(u16)arg3);
Math_SmoothStepToS(&arg1->unk_08.x, temp1, 6, 2000, 1);
temp = CLAMP(pitchTowardsTarget, minHeadPitch, (s16)(u16)maxHeadPitch);
Math_SmoothStepToS(&interactInfo->headRot.x, temp, 6, 0x7D0, 1);
temp2 = sp46 - arg1->unk_08.x;
torsoPitch = pitchTowardsTarget - interactInfo->headRot.x;
temp1 = CLAMP(temp2, arg7, arg6);
Math_SmoothStepToS(&arg1->unk_0E.x, temp1, 6, 2000, 1);
temp = CLAMP(torsoPitch, minTorsoPitch, maxTorsoPitch);
Math_SmoothStepToS(&interactInfo->torsoRot.x, temp, 6, 0x7D0, 1);
}
// unused
s16 func_800BD6B8(s16 arg0) {
return D_801AEE38[arg0].unk_14;
s16 Npc_GetTrackingPresetMaxPlayerYaw(s16 presetIndex) {
return sNpcTrackingPresets[presetIndex].maxYawForPlayerTracking;
}
s16 func_800BD6E4(Actor* actor, struct_800BD888_arg1* arg1, f32 arg2, s16 arg3, s16 flag) {
/**
* Handles NPC tracking modes and auto-turning towards the player when
* NPC_TRACKING_PLAYER_AUTO_TURN tracking mode is used.
*
* Returns a tracking mode that will determine which actor limbs
* will be rotated towards the target.
*
* When the player is behind the actor (i.e. not in the yaw range in front of the actor
* defined by maxYawForPlayerTracking), the actor will start an auto-turn sequence:
* - look forward for 30-60 frames
* - turn head to look at the player for 10-20 frames
* - look forward for 30-60 frames
* - turn the entire body to face the player
*
* @param distanceRange Max distance to player that tracking and auto-turning will be active for
* @param maxYawForPlayerTracking Maximum angle for tracking the player.
* @param trackingMode The tracking mode selected by the actor. If this is not
* NPC_TRACKING_PLAYER_AUTO_TURN this function does nothing
*
* @return The tracking mode (NpcTrackingMode) to use for the current frame.
*/
s16 Npc_UpdateAutoTurn(Actor* actor, NpcInteractInfo* interactInfo, f32 distanceRange, s16 maxYawForPlayerTracking,
s16 trackingMode) {
s32 pad;
s16 yaw;
s16 yawDiff;
if (flag) {
return flag;
} else if (arg1->unk_00 != 0) {
return 4;
} else if (arg2 < Math_Vec3f_DistXYZ(&actor->world.pos, &arg1->unk_18)) {
arg1->unk_04 = 0;
arg1->unk_06 = 0;
return 1;
} else {
s16 yaw = Math_Vec3f_Yaw(&actor->world.pos, &arg1->unk_18);
s16 phi_a0 = ABS_ALT(BINANG_SUB(yaw, actor->shape.rot.y));
if (trackingMode != NPC_TRACKING_PLAYER_AUTO_TURN) {
return trackingMode;
}
if (arg3 >= phi_a0) {
arg1->unk_04 = 0;
arg1->unk_06 = 0;
return 2;
} else if (DECR(arg1->unk_04) != 0) {
return arg1->unk_02;
} else {
switch (arg1->unk_06) {
case 0:
case 2:
arg1->unk_04 = Rand_S16Offset(30, 30);
arg1->unk_06++;
return 1;
if (interactInfo->talkState != NPC_TALK_STATE_IDLE) {
// When talking, always fully turn to face the player
return NPC_TRACKING_FULL_BODY;
}
case 1:
arg1->unk_04 = Rand_S16Offset(10, 10);
arg1->unk_06++;
return 3;
if (distanceRange < Math_Vec3f_DistXYZ(&actor->world.pos, &interactInfo->trackPos)) {
// Player is too far away, do not track
interactInfo->autoTurnTimer = 0;
interactInfo->autoTurnState = 0;
return NPC_TRACKING_NONE;
}
default:
return 4;
}
}
yaw = Math_Vec3f_Yaw(&actor->world.pos, &interactInfo->trackPos);
yawDiff = ABS_ALT(BINANG_SUB(yaw, actor->shape.rot.y));
if (maxYawForPlayerTracking >= yawDiff) {
// Player is in front of the actor, track with the head and the torso
interactInfo->autoTurnTimer = 0;
interactInfo->autoTurnState = 0;
return NPC_TRACKING_HEAD_AND_TORSO;
}
// Player is behind the actor, run the auto-turn sequence.
if (DECR(interactInfo->autoTurnTimer) != 0) {
// While the timer is still running, return the previous tracking mode
return interactInfo->trackingMode;
}
switch (interactInfo->autoTurnState) {
case 0:
case 2:
// Just stand still, not tracking the player
interactInfo->autoTurnTimer = Rand_S16Offset(30, 30);
interactInfo->autoTurnState++;
return NPC_TRACKING_NONE;
case 1:
// Glance at the player by only turning the head
interactInfo->autoTurnTimer = Rand_S16Offset(10, 10);
interactInfo->autoTurnState++;
return NPC_TRACKING_HEAD;
default:
// Auto-turn sequence complete, turn towards the player
return NPC_TRACKING_FULL_BODY;
}
}
// This function is very similar to OoT's func_80034A14
void func_800BD888(Actor* actor, struct_800BD888_arg1* arg1, s16 arg2, s16 arg3) {
struct_801AEE38_0 sp38;
/**
* Rotates the actor's whole body, torso and head tracking the point specified in NpcInteractInfo.trackPos.
* Uses angle limits from a preset selected from from sNpcTrackingPresets.
*
* The trackingMode parameter controls whether the head and torso are turned towards the target.
* If not, they are smoothly turned towards zero. Setting the parameter to NPC_TRACKING_FULL_BODY
* causes the actor's whole body to be rotated to face the target.
*
* If NPC_TRACKING_PLAYER_AUTO_TURN is used, the actor will track the player with its head and torso as long
* as the player is in front of the actor (within a yaw angle specified in the option preset).
* If the player is outside of this angle, the actor will turn to face the player after a while.
*
* @see Npc_UpdateAutoTurn
* @see sNpcTrackingPresets
* @see NpcTrackingMode
*
* @param presetIndex The index to a preset in sNpcTrackingPresets
* @param trackingMode A value from NpcTrackingMode enum
*/
void Npc_TrackPoint(Actor* actor, NpcInteractInfo* interactInfo, s16 presetIndex, s16 trackingMode) {
NpcTrackingRotLimits rotLimits;
arg1->unk_02 = func_800BD6E4(actor, arg1, D_801AEE38[arg2].unk_10, D_801AEE38[arg2].unk_14, arg3);
sp38 = D_801AEE38[arg2].sub_00;
interactInfo->trackingMode =
Npc_UpdateAutoTurn(actor, interactInfo, sNpcTrackingPresets[presetIndex].autoTurnDistanceRange,
sNpcTrackingPresets[presetIndex].maxYawForPlayerTracking, trackingMode);
switch (arg1->unk_02) {
case 1:
sp38.unk_00 = 0;
sp38.unk_04 = 0;
sp38.unk_02 = 0;
case 3:
sp38.unk_06 = 0;
sp38.unk_0A = 0;
sp38.unk_08 = 0;
case 2:
sp38.unk_0C = 0;
rotLimits = sNpcTrackingPresets[presetIndex].rotLimits;
switch (interactInfo->trackingMode) {
case NPC_TRACKING_NONE:
rotLimits.maxHeadYaw = 0;
rotLimits.maxHeadPitch = 0;
rotLimits.minHeadPitch = 0;
// fallthrough
case NPC_TRACKING_HEAD:
rotLimits.maxTorsoYaw = 0;
rotLimits.maxTorsoPitch = 0;
rotLimits.minTorsoPitch = 0;
// fallthrough
case NPC_TRACKING_HEAD_AND_TORSO:
rotLimits.rotateYaw = false;
break;
default:
break;
}
func_800BD384(actor, arg1, sp38.unk_00, sp38.unk_04, sp38.unk_02, sp38.unk_06, sp38.unk_0A, sp38.unk_08,
sp38.unk_0C);
Npc_TrackPointWithLimits(actor, interactInfo, rotLimits.maxHeadYaw, rotLimits.maxHeadPitch, rotLimits.minHeadPitch,
rotLimits.maxTorsoYaw, rotLimits.maxTorsoPitch, rotLimits.minTorsoPitch,
rotLimits.rotateYaw);
}
Gfx D_801AEF88[] = {

View File

@ -142,19 +142,21 @@ void EnMa4_ChangeAnim(EnMa4* this, s32 animIndex) {
void func_80ABDD9C(EnMa4* this, PlayState* play) {
Player* player = GET_PLAYER(play);
s16 flag;
s16 trackingMode;
if (this->unk_1D8.unk_00 == 0 &&
if ((this->interactInfo.talkState == NPC_TALK_STATE_IDLE) &&
((this->skelAnime.animation == &gRomaniRunAnim) || (this->skelAnime.animation == &gRomaniLookAroundAnim) ||
(this->skelAnime.animation == &gRomaniShootBowAnim))) {
flag = 1;
trackingMode = NPC_TRACKING_NONE;
} else {
flag = (this->type == MA4_TYPE_ALIENS_WON && this->actionFunc != EnMa4_DialogueHandler) ? 1 : 0;
trackingMode = ((this->type == MA4_TYPE_ALIENS_WON) && (this->actionFunc != EnMa4_DialogueHandler))
? NPC_TRACKING_NONE
: NPC_TRACKING_PLAYER_AUTO_TURN;
}
this->unk_1D8.unk_18 = player->actor.world.pos;
this->unk_1D8.unk_18.y -= -10.0f;
func_800BD888(&this->actor, &this->unk_1D8, 0, flag);
this->interactInfo.trackPos = player->actor.world.pos;
this->interactInfo.trackPos.y -= -10.0f;
Npc_TrackPoint(&this->actor, &this->interactInfo, 0, trackingMode);
}
void EnMa4_InitPath(EnMa4* this, PlayState* play) {
@ -192,7 +194,7 @@ void EnMa4_Init(Actor* thisx, PlayState* play) {
Actor_SetScale(&this->actor, 0.01f);
this->actor.targetMode = 0;
this->unk_1D8.unk_00 = 0;
this->interactInfo.talkState = NPC_TALK_STATE_IDLE;
this->unk_334 = 0;
this->hasBow = true;
this->mouthTexIndex = 0;
@ -1027,17 +1029,17 @@ void EnMa4_Update(Actor* thisx, PlayState* play) {
s32 EnMa4_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
EnMa4* this = THIS;
Vec3s sp4;
Vec3s limbRot;
if (limbIndex == ROMANI_LIMB_HEAD) {
sp4 = this->unk_1D8.unk_08;
rot->x = rot->x + sp4.y;
rot->z = rot->z + sp4.x;
limbRot = this->interactInfo.headRot;
rot->x += limbRot.y;
rot->z += limbRot.x;
}
if (limbIndex == ROMANI_LIMB_TORSO) {
sp4 = this->unk_1D8.unk_0E;
rot->x = rot->x - sp4.y;
rot->z = rot->z - sp4.x;
limbRot = this->interactInfo.torsoRot;
rot->x -= limbRot.y;
rot->z -= limbRot.x;
}
return false;

View File

@ -13,7 +13,7 @@ typedef struct EnMa4 {
/* 0x144 */ SkelAnime skelAnime;
/* 0x188 */ EnMa4ActionFunc actionFunc;
/* 0x18C */ ColliderCylinder collider;
/* 0x1D8 */ struct_800BD888_arg1 unk_1D8;
/* 0x1D8 */ NpcInteractInfo interactInfo;
/* 0x200 */ Vec3s* pathPoints;
/* 0x204 */ Vec3s jointTable[ROMANI_LIMB_MAX];
/* 0x28E */ UNK_TYPE1 unk28E[0x6];

View File

@ -1268,29 +1268,29 @@ void EnMaYto_ChangeAnim(EnMaYto* this, s32 animIndex) {
void func_80B90C78(EnMaYto* this, PlayState* play) {
Player* player = GET_PLAYER(play);
s16 flag;
s16 trackingMode;
SkelAnime_Update(&this->skelAnime);
flag = this->unk31E == 2 ? true : false;
trackingMode = (this->unk31E == 2) ? NPC_TRACKING_NONE : NPC_TRACKING_PLAYER_AUTO_TURN;
if (this->unk31E == 0) {
this->unk_1D8.unk_18 = player->actor.world.pos;
this->unk_1D8.unk_14 = 0.0f;
this->interactInfo.trackPos = player->actor.world.pos;
this->interactInfo.yOffset = 0.0f;
} else if (this->unk31E == 1) {
Math_Vec3f_StepTo(&this->unk_1D8.unk_18, &this->actor.child->world.pos, 8.0f);
this->unk_1D8.unk_14 = 0.0f;
Math_Vec3f_StepTo(&this->interactInfo.trackPos, &this->actor.child->world.pos, 8.0f);
this->interactInfo.yOffset = 0.0f;
}
if (this->unk320 == 0) {
if (this->actionFunc == EnMaYto_WarmFuzzyFeelingCs) {
this->unk_1D8.unk_08.y = 0;
this->unk_1D8.unk_08.x = 0;
this->interactInfo.headRot.y = 0;
this->interactInfo.headRot.x = 0;
} else {
func_800BD888(&this->actor, &this->unk_1D8, 0xD, flag);
Npc_TrackPoint(&this->actor, &this->interactInfo, 13, trackingMode);
}
} else {
Math_SmoothStepToS(&this->unk_1D8.unk_08.y, 0, 3, 0x71C, 0xB6);
Math_SmoothStepToS(&this->unk_1D8.unk_08.x, 0x18E3, 5, 0x71C, 0xB6);
Math_SmoothStepToS(&this->interactInfo.headRot.y, 0, 3, 0x71C, 0xB6);
Math_SmoothStepToS(&this->interactInfo.headRot.x, 0x18E3, 5, 0x71C, 0xB6);
}
EnMaYto_UpdateEyes(this);
@ -1423,26 +1423,26 @@ void EnMaYto_Update(Actor* thisx, PlayState* play) {
s32 EnMaYto_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
EnMaYto* this = THIS;
Vec3s sp4;
Vec3s limbRot;
if (limbIndex == CREMIA_LIMB_HEAD) {
sp4 = this->unk_1D8.unk_08;
limbRot = this->interactInfo.headRot;
rot->x += sp4.y;
rot->z += sp4.x;
rot->x += limbRot.y;
rot->z += limbRot.x;
} else if (limbIndex == CREMIA_LIMB_TORSO) {
if (this->skelAnime.animation != &gCremiaSittingPetCowAnim &&
this->skelAnime.animation != &gCremiaSittingLookDownAnim) {
sp4 = this->unk_1D8.unk_0E;
if ((this->skelAnime.animation != &gCremiaSittingPetCowAnim) &&
(this->skelAnime.animation != &gCremiaSittingLookDownAnim)) {
limbRot = this->interactInfo.torsoRot;
rot->x += sp4.y;
if (this->skelAnime.animation == &gCremiaIdleAnim || this->skelAnime.animation == &gCremiaSittingAnim ||
this->skelAnime.animation == &gCremiaSittingLookDownAnim) {
rot->z += sp4.x;
rot->x += limbRot.y;
if ((this->skelAnime.animation == &gCremiaIdleAnim) || (this->skelAnime.animation == &gCremiaSittingAnim) ||
(this->skelAnime.animation == &gCremiaSittingLookDownAnim)) {
rot->z += limbRot.x;
}
}
}
return 0;
return false;
}
void EnMaYto_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {

View File

@ -13,7 +13,7 @@ typedef struct EnMaYto {
/* 0x144 */ SkelAnime skelAnime;
/* 0x188 */ EnMaYtoActionFunc actionFunc;
/* 0x18C */ ColliderCylinder collider;
/* 0x1D8 */ struct_800BD888_arg1 unk_1D8;
/* 0x1D8 */ NpcInteractInfo interactInfo;
/* 0x200 */ s32 unk200; // unused
/* 0x204 */ s32 type;
/* 0x208 */ Vec3s jointTable[CREMIA_LIMB_MAX];

View File

@ -121,17 +121,17 @@ void EnMaYts_ChangeAnim(EnMaYts* this, s32 animIndex) {
void func_80B8D12C(EnMaYts* this, PlayState* play) {
Player* player = GET_PLAYER(play);
s16 flag = this->unk_32C == 2 ? true : false;
s16 trackingMode = (this->unk_32C == 2) ? NPC_TRACKING_NONE : NPC_TRACKING_PLAYER_AUTO_TURN;
if (this->unk_32C == 0 || this->actor.parent == NULL) {
this->unk_1D8.unk_18 = player->actor.world.pos;
this->unk_1D8.unk_18.y -= -10.0f;
this->interactInfo.trackPos = player->actor.world.pos;
this->interactInfo.trackPos.y -= -10.0f;
} else {
Math_Vec3f_StepTo(&this->unk_1D8.unk_18, &this->actor.parent->world.pos, 8.0f);
this->unk_1D8.unk_18.y -= -10.0f;
Math_Vec3f_StepTo(&this->interactInfo.trackPos, &this->actor.parent->world.pos, 8.0f);
this->interactInfo.trackPos.y -= -10.0f;
}
func_800BD888(&this->actor, &this->unk_1D8, 0, flag);
Npc_TrackPoint(&this->actor, &this->interactInfo, 0, trackingMode);
}
void EnMaYts_InitAnimation(EnMaYts* this, PlayState* play) {
@ -238,7 +238,7 @@ void EnMaYts_Init(Actor* thisx, PlayState* play) {
Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, 0.0f, 0.0f, 0x4);
Actor_SetScale(&this->actor, 0.01f);
this->unk_1D8.unk_00 = 0;
this->interactInfo.talkState = NPC_TALK_STATE_IDLE;
this->unk_200 = 0;
this->blinkTimer = 0;
@ -248,7 +248,7 @@ void EnMaYts_Init(Actor* thisx, PlayState* play) {
this->hasBow = false;
}
if (CURRENT_DAY == 1 || CHECK_WEEKEVENTREG(WEEKEVENTREG_22_01)) {
if ((CURRENT_DAY == 1) || CHECK_WEEKEVENTREG(WEEKEVENTREG_22_01)) {
this->overrideEyeTexIndex = 0;
this->eyeTexIndex = 0;
this->mouthTexIndex = 0;
@ -501,18 +501,18 @@ void EnMaYts_Update(Actor* thisx, PlayState* play) {
s32 EnMaYts_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
EnMaYts* this = THIS;
Vec3s sp4;
Vec3s limbRot;
if (limbIndex == ROMANI_LIMB_HEAD) {
sp4 = this->unk_1D8.unk_08;
rot->x += sp4.y;
limbRot = this->interactInfo.headRot;
rot->x += limbRot.y;
if ((this->skelAnime.animation == &gRomaniIdleAnim) || (this->skelAnime.animation == &gRomaniSittingAnim)) {
rot->z += sp4.x;
rot->z += limbRot.x;
}
} else if (limbIndex == ROMANI_LIMB_TORSO) {
sp4 = this->unk_1D8.unk_0E;
rot->x += sp4.y;
rot->z += sp4.x;
limbRot = this->interactInfo.torsoRot;
rot->x += limbRot.y;
rot->z += limbRot.x;
}
return false;

View File

@ -13,7 +13,7 @@ typedef struct EnMaYts {
/* 0x144 */ SkelAnime skelAnime;
/* 0x188 */ EnMaYtsActionFunc actionFunc;
/* 0x18C */ ColliderCylinder collider;
/* 0x1D8 */ struct_800BD888_arg1 unk_1D8;
/* 0x1D8 */ NpcInteractInfo interactInfo;
/* 0x200 */ s32 unk_200; // Set, but not used
/* 0x204 */ Vec3s jointTable[ROMANI_LIMB_MAX];
/* 0x28E */ UNK_TYPE1 unk_28E[0x6];

View File

@ -868,11 +868,11 @@
0x800BCBF4:("func_800BCBF4",),
0x800BCC68:("func_800BCC68",),
0x800BCCDC:("Actor_GetClosestPosOnPath",),
0x800BD2B4:("func_800BD2B4",),
0x800BD384:("func_800BD384",),
0x800BD6B8:("func_800BD6B8",),
0x800BD6E4:("func_800BD6E4",),
0x800BD888:("func_800BD888",),
0x800BD2B4:("Npc_UpdateTalking",),
0x800BD384:("Npc_TrackPointWithLimits",),
0x800BD6B8:("Npc_GetTrackingPresetMaxPlayerYaw",),
0x800BD6E4:("Npc_UpdateAutoTurn",),
0x800BD888:("Npc_TrackPoint",),
0x800BD9A0:("func_800BD9A0",),
0x800BD9E0:("func_800BD9E0",),
0x800BDAA0:("func_800BDAA0",),

View File

@ -442,7 +442,7 @@
0x801AEDD4:("D_801AEDD4","UNK_TYPE4","",0x4),
0x801AEE28:("D_801AEE28","UNK_TYPE4","",0x4),
0x801AEE30:("D_801AEE30","UNK_TYPE4","",0x4),
0x801AEE38:("D_801AEE38","struct_801AEE38","[14]",0x150),
0x801AEE38:("sNpcTrackingPresets","NpcTrackingParams","[14]",0x150),
0x801AEF88:("D_801AEF88","UNK_TYPE1","",0x1),
0x801AEFA0:("D_801AEFA0","UNK_TYPE1","",0x1),
0x801AEFA8:("sElectricSparkTextures","UNK_TYPE1","",0x1),

View File

@ -382,11 +382,11 @@ asm/non_matchings/code/z_actor/Actor_SetColorFilter.s,Actor_SetColorFilter,0x800
asm/non_matchings/code/z_actor/func_800BCBF4.s,func_800BCBF4,0x800BCBF4,0x1D
asm/non_matchings/code/z_actor/func_800BCC68.s,func_800BCC68,0x800BCC68,0x1D
asm/non_matchings/code/z_actor/Actor_GetClosestPosOnPath.s,Actor_GetClosestPosOnPath,0x800BCCDC,0x176
asm/non_matchings/code/z_actor/func_800BD2B4.s,func_800BD2B4,0x800BD2B4,0x34
asm/non_matchings/code/z_actor/func_800BD384.s,func_800BD384,0x800BD384,0xCD
asm/non_matchings/code/z_actor/func_800BD6B8.s,func_800BD6B8,0x800BD6B8,0xB
asm/non_matchings/code/z_actor/func_800BD6E4.s,func_800BD6E4,0x800BD6E4,0x69
asm/non_matchings/code/z_actor/func_800BD888.s,func_800BD888,0x800BD888,0x46
asm/non_matchings/code/z_actor/Npc_UpdateTalking.s,Npc_UpdateTalking,0x800BD2B4,0x34
asm/non_matchings/code/z_actor/Npc_TrackPointWithLimits.s,Npc_TrackPointWithLimits,0x800BD384,0xCD
asm/non_matchings/code/z_actor/Npc_GetTrackingPresetMaxPlayerYaw.s,Npc_GetTrackingPresetMaxPlayerYaw,0x800BD6B8,0xB
asm/non_matchings/code/z_actor/Npc_UpdateAutoTurn.s,Npc_UpdateAutoTurn,0x800BD6E4,0x69
asm/non_matchings/code/z_actor/Npc_TrackPoint.s,Npc_TrackPoint,0x800BD888,0x46
asm/non_matchings/code/z_actor/func_800BD9A0.s,func_800BD9A0,0x800BD9A0,0x10
asm/non_matchings/code/z_actor/func_800BD9E0.s,func_800BD9E0,0x800BD9E0,0x30
asm/non_matchings/code/z_actor/func_800BDAA0.s,func_800BDAA0,0x800BDAA0,0x33

1 asm/non_matchings/code/z_en_a_keep/EnAObj_Init.s EnAObj_Init 0x800A5AC0 0x2B
382 asm/non_matchings/code/z_actor/func_800BCBF4.s func_800BCBF4 0x800BCBF4 0x1D
383 asm/non_matchings/code/z_actor/func_800BCC68.s func_800BCC68 0x800BCC68 0x1D
384 asm/non_matchings/code/z_actor/Actor_GetClosestPosOnPath.s Actor_GetClosestPosOnPath 0x800BCCDC 0x176
385 asm/non_matchings/code/z_actor/func_800BD2B4.s asm/non_matchings/code/z_actor/Npc_UpdateTalking.s func_800BD2B4 Npc_UpdateTalking 0x800BD2B4 0x34
386 asm/non_matchings/code/z_actor/func_800BD384.s asm/non_matchings/code/z_actor/Npc_TrackPointWithLimits.s func_800BD384 Npc_TrackPointWithLimits 0x800BD384 0xCD
387 asm/non_matchings/code/z_actor/func_800BD6B8.s asm/non_matchings/code/z_actor/Npc_GetTrackingPresetMaxPlayerYaw.s func_800BD6B8 Npc_GetTrackingPresetMaxPlayerYaw 0x800BD6B8 0xB
388 asm/non_matchings/code/z_actor/func_800BD6E4.s asm/non_matchings/code/z_actor/Npc_UpdateAutoTurn.s func_800BD6E4 Npc_UpdateAutoTurn 0x800BD6E4 0x69
389 asm/non_matchings/code/z_actor/func_800BD888.s asm/non_matchings/code/z_actor/Npc_TrackPoint.s func_800BD888 Npc_TrackPoint 0x800BD888 0x46
390 asm/non_matchings/code/z_actor/func_800BD9A0.s func_800BD9A0 0x800BD9A0 0x10
391 asm/non_matchings/code/z_actor/func_800BD9E0.s func_800BD9E0 0x800BD9E0 0x30
392 asm/non_matchings/code/z_actor/func_800BDAA0.s func_800BDAA0 0x800BDAA0 0x33