Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
39210_len_aa0.c File Reference

Go to the source code of this file.

Enumerations

enum  NpcFollowStates { NPC_FOLLOW_STATE_RUN = 0 , NPC_FOLLOW_STATE_JUMP = 1 , NPC_FOLLOW_STATE_FALL = 2 , NPC_FOLLOW_STATE_IDLE = 10 }
 

Functions

void get_npc_pos (s32 npcID, f32 *outX, f32 *outY, f32 *outZ, s32 *outAirborne)
 
void npc_follow_init (Npc *npc, s32 targetNpcID, FollowAnims *anims, f32 walkSpeed, f32 runSpeed, s32 idleRadius, s32 walkRadius)
 
void npc_update_npc_tracking (Npc *npc)
 
void npc_follow_npc (Npc *npc)
 

Enumeration Type Documentation

◆ NpcFollowStates

Enumerator
NPC_FOLLOW_STATE_RUN 
NPC_FOLLOW_STATE_JUMP 
NPC_FOLLOW_STATE_FALL 
NPC_FOLLOW_STATE_IDLE 

Definition at line 3 of file 39210_len_aa0.c.

3 {
8};
@ NPC_FOLLOW_STATE_JUMP
@ NPC_FOLLOW_STATE_IDLE
@ NPC_FOLLOW_STATE_FALL
@ NPC_FOLLOW_STATE_RUN

Function Documentation

◆ get_npc_pos()

void get_npc_pos ( s32 npcID,
f32 * outX,
f32 * outY,
f32 * outZ,
s32 * outAirborne )

Definition at line 10 of file 39210_len_aa0.c.

10 {
11 PlayerStatus* playerStatus = &gPlayerStatus;
12 Npc* npc;
13
14 *outX = 0.0f;
15 *outY = 0.0f;
16 *outZ = 0.0f;
17 *outAirborne = FALSE;
18
19 if (npcID == NPC_SELF) {
20 *outX = playerStatus->pos.x;
21 *outY = playerStatus->pos.y;
22 *outZ = playerStatus->pos.z;
23 if (playerStatus->flags & (PS_FLAG_FALLING | PS_FLAG_JUMPING)) {
24 *outAirborne = TRUE;
25 }
26 } else {
27 npc = get_npc_unsafe(npcID);
28 *outX = npc->pos.x;
29 *outY = npc->pos.y;
30 *outZ = npc->pos.z;
31 if (npc->flags & NPC_FLAG_JUMPING) {
32 *outAirborne = TRUE;
33 }
34 }
35
36}
@ PS_FLAG_FALLING
Definition enums.h:3036
@ PS_FLAG_JUMPING
Definition enums.h:3035
@ NPC_SELF
Definition enums.h:2526
@ NPC_FLAG_JUMPING
Definition enums.h:3009
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:995
s32 flags
Vec3f pos
PlayerStatus gPlayerStatus
Definition 77480.c:39

Referenced by npc_follow_npc(), and npc_update_npc_tracking().

◆ npc_follow_init()

void npc_follow_init ( Npc * npc,
s32 targetNpcID,
FollowAnims * anims,
f32 walkSpeed,
f32 runSpeed,
s32 idleRadius,
s32 walkRadius )

Definition at line 38 of file 39210_len_aa0.c.

38 {
39 PlayerStatus* playerStatus = &gPlayerStatus;
40 NpcFollowData* followData;
41 s32 i;
42
43 npc->blur.followData = followData = heap_malloc(sizeof(*followData));
44 ASSERT(followData != NULL);
45
46 for (i = 0; i < ARRAY_COUNT(followData->moveHistory); i++) {
47 followData->moveHistory[i].pos.x = playerStatus->pos.x;
48 followData->moveHistory[i].pos.y = playerStatus->pos.y;
49 followData->moveHistory[i].pos.z = playerStatus->pos.z;
50 followData->moveHistory[i].isAirborne = FALSE;
51 }
52 followData->lastPointIdx = 0;
53 followData->targetPointIdx = 0;
55 followData->targetNpcID = targetNpcID;
56 followData->anims = anims;
57 followData->walkSpeed = walkSpeed;
58 followData->runSpeed = runSpeed;
59 followData->idleRadius = idleRadius;
60 followData->walkRadius = walkRadius;
61 npc->curAnim = followData->anims->idle;
62 npc->jumpVel = 0.0f;
63 npc->flags |= NPC_FLAG_GRAVITY;
64 npc->flags &= ~NPC_FLAG_IGNORE_PLAYER_COLLISION;
66}
NpcHistoryPoint moveHistory[40]
FollowAnims * anims
#define ASSERT(condition)
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4696
@ NPC_FLAG_GRAVITY
Definition enums.h:3007
void * heap_malloc(s32 size)
Definition heap.c:34
#define ARRAY_COUNT(arr)
Definition macros.h:40
f32 jumpVel
AnimID curAnim
s32 collisionChannel
union Npc::@0 blur

◆ npc_update_npc_tracking()

void npc_update_npc_tracking ( Npc * npc)

Definition at line 68 of file 39210_len_aa0.c.

68 {
69 NpcFollowData* followData = npc->blur.followData;
70 f32 x, y, z;
71 s32 airborne;
72 s32 isAirborne;
73 NpcHistoryPoint* historyPoint;
74
75 get_npc_pos(followData->targetNpcID, &x, &y, &z, &airborne);
76 historyPoint = &followData->moveHistory[followData->lastPointIdx];
77 isAirborne = airborne != FALSE;
78
79 if (historyPoint->isAirborne && isAirborne) {
80 return;
81 }
82
83 if (!isAirborne && dist2D(npc->pos.x, npc->pos.z, x, z) <= followData->idleRadius && !historyPoint->isAirborne) {
84 return;
85 }
86
87 historyPoint = &followData->moveHistory[followData->lastPointIdx];
88 if (historyPoint->pos.x != x || historyPoint->pos.y != y || historyPoint->pos.z != z) {
89 if (followData->targetPointIdx != followData->lastPointIdx + 1) {
90 followData->lastPointIdx++;
91 if (followData->lastPointIdx >= ARRAY_COUNT(followData->moveHistory)) {
92 followData->lastPointIdx = 0;
93 }
94 historyPoint = &followData->moveHistory[followData->lastPointIdx];
95 historyPoint->pos.x = x;
96 historyPoint->pos.y = y;
97 historyPoint->pos.z = z;
98 historyPoint->isAirborne = isAirborne;
99 }
100 }
101}
void get_npc_pos(s32 npcID, f32 *outX, f32 *outY, f32 *outZ, s32 *outAirborne)
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:670

◆ npc_follow_npc()

void npc_follow_npc ( Npc * npc)

Definition at line 103 of file 39210_len_aa0.c.

103 {
104 NpcFollowData* followData = npc->blur.followData;
105 f32 x, y, z;
106 s32 airborne;
107 f32 currentX, currentY, currentZ;
108 f32 dist;
109 NpcHistoryPoint* historyPoint;
110 f32 targetX, targetY, targetZ;
111 f32 theta;
112 f32 yaw;
113
114 get_npc_pos(followData->targetNpcID, &x, &y, &z, &airborne);
115
116 switch (followData->followState) {
118 historyPoint = &followData->moveHistory[followData->targetPointIdx];
119 targetX = historyPoint->pos.x;
120 targetY = historyPoint->pos.y;
121 targetZ = historyPoint->pos.z;
122 currentX = npc->pos.x;
123 currentY = npc->pos.y;
124 currentZ = npc->pos.z;
125 npc->moveSpeed = followData->walkSpeed;
126
127 dist = dist2D(npc->pos.x, npc->pos.z, x, z);
128 if (dist >= followData->walkRadius) {
129 npc->moveSpeed = followData->runSpeed;
130 }
131
132 npc->curAnim = followData->anims->run;
133 if (!(npc->flags & NPC_FLAG_GROUNDED)) {
134 npc->curAnim = followData->anims->fall;
135 }
136
137 while (TRUE) {
138 dist = dist2D(currentX, currentZ, targetX, targetZ);
139 yaw = atan2(currentX, currentZ, targetX, targetZ);
140 if (dist > npc->moveSpeed) {
141 dist = dist2D(currentX, currentZ, x, z);
142 if (dist > followData->walkRadius) {
143 break;
144 }
145
146 if (dist > followData->idleRadius) {
147 npc->moveSpeed = dist - followData->idleRadius;
148 if (npc->moveSpeed > followData->walkSpeed) {
149 npc->moveSpeed = followData->walkSpeed;
150 } else {
151 npc->moveSpeed += 1.0;
152 }
153 break;
154 }
155 }
156
157 if (followData->targetPointIdx == followData->lastPointIdx) {
158 npc->moveSpeed = 0.0f;
159 yaw = npc->yaw;
160 npc->curAnim = followData->anims->idle;
161 break;
162 }
163
164 dist = dist2D(npc->pos.x, npc->pos.z, x, z);
165 if (dist <= followData->idleRadius) {
166 npc->moveSpeed = 0.0f;
167 yaw = npc->yaw;
168 npc->curAnim = followData->anims->idle;
170 break;
171 }
172
173 followData->targetPointIdx++;
174 if (followData->targetPointIdx >= ARRAY_COUNT(followData->moveHistory)) {
175 followData->targetPointIdx = 0;
176 }
177 historyPoint = &followData->moveHistory[followData->targetPointIdx];
178 targetX = historyPoint->pos.x;
179 targetZ = historyPoint->pos.z;
180 if (npc->flags & NPC_FLAG_GROUNDED) {
181 if (historyPoint->isAirborne) {
183 break;
184 }
185 }
186 }
187
188 if (!(npc->flags & NPC_FLAG_GROUNDED)) {
189 npc->moveSpeed *= 0.5f;
190 }
191 npc->yaw = yaw;
192 npc_move_heading(npc, npc->moveSpeed, yaw);
195 }
196 break;
198 if (followData->targetPointIdx != followData->lastPointIdx) {
199 followData->targetPointIdx++;
200 if (followData->targetPointIdx >= ARRAY_COUNT(followData->moveHistory)) {
201 followData->targetPointIdx = 0;
202 }
203 historyPoint = &followData->moveHistory[followData->targetPointIdx];
204 targetX = historyPoint->pos.x;
205 targetY = historyPoint->pos.y;
206 targetZ = historyPoint->pos.z;
207 npc->moveToPos.x = targetX;
208 npc->moveToPos.y = targetY;
209 npc->moveToPos.z = targetZ;
210 npc->duration = 0;
211 npc->jumpScale = 2.0f;
212 npc->moveSpeed = followData->runSpeed;
213 npc->planarFlyDist = dist2D(npc->pos.x, npc->pos.z, npc->moveToPos.x, npc->moveToPos.z);
214 npc->yaw = atan2(npc->pos.x, npc->pos.z, npc->moveToPos.x, npc->moveToPos.z);
215 dist = npc->planarFlyDist;
216 currentY = npc->moveToPos.y - npc->pos.y;
217 if (npc->planarFlyDist < currentY) {
218 dist = currentY;
219 }
220 if (dist < followData->idleRadius) {
221 npc->jumpVel = 0.0f;
222 npc->flags |= NPC_FLAG_GRAVITY;
223 npc->yaw = atan2(npc->pos.x, npc->pos.z, x, z);
224 followData->followState = NPC_FOLLOW_STATE_RUN;
225 return;
226 }
227 npc->duration = dist / npc->moveSpeed;
228 if (npc->duration < 10) {
229 npc->duration = 10;
230 }
231 npc->moveSpeed = npc->planarFlyDist / npc->duration;
232 npc->jumpVel = (currentY + (npc->jumpScale * npc->duration * npc->duration * 0.5f)) / npc->duration;
233 npc->curAnim = followData->anims->jump;
234 npc->flags &= ~NPC_FLAG_GRAVITY;
236 }
237 break;
239 npc->jumpVel -= npc->jumpScale;
240 npc->pos.y += npc->jumpVel;
241 if (npc->jumpVel <= 0.0f) {
242 npc->curAnim = followData->anims->fall;
243 }
244 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
245 if (npc->jumpVel <= 0.0f) {
246 currentX = npc->pos.x;
247 dist = fabsf(npc->jumpVel) + 8.0;
248 currentY = npc->pos.y + dist;
249 currentZ = npc->pos.z;
250 if (npc_raycast_down_sides(npc->collisionChannel, &currentX, &currentY, &currentZ, &dist) != 0 &&
251 dist <= fabsf(npc->jumpVel) + 8.0)
252 {
253 npc->curAnim = followData->anims->land;
254 npc->jumpVel = 0.0f;
255 npc->pos.y = currentY;
256 npc->flags |= NPC_FLAG_GRAVITY;
257 npc->yaw = atan2(currentX, currentZ, x, z);
258 followData->followState = NPC_FOLLOW_STATE_RUN;
259 }
260 }
261 break;
263 historyPoint = &followData->moveHistory[followData->targetPointIdx];
264 targetX = historyPoint->pos.x;
265 targetY = historyPoint->pos.y;
266 targetZ = historyPoint->pos.z;
267 currentX = npc->pos.x;
268 currentY = npc->pos.y;
269 currentZ = npc->pos.z;
270 dist = dist2D(npc->pos.x, npc->pos.z, x, z);
271 if (dist <= followData->idleRadius) {
272 break;
273 }
274
275 while (TRUE) {
276 if (historyPoint->isAirborne) {
277 break;
278 }
279
280 yaw = atan2(npc->pos.x, npc->pos.z, targetX, targetZ);
281 if (fabsf(get_clamped_angle_diff(yaw, atan2(npc->pos.x, npc->pos.z, x, z))) < 90.0f) {
282 break;
283 }
284
285 if (followData->targetPointIdx == followData->lastPointIdx) {
286 break;
287 }
288
289 followData->targetPointIdx++;
290 if (followData->targetPointIdx >= ARRAY_COUNT(followData->moveHistory)) {
291 followData->targetPointIdx = 0;
292 }
293 historyPoint = &followData->moveHistory[followData->targetPointIdx];
294 targetX = historyPoint->pos.x;
295 targetZ = historyPoint->pos.z;
296 continue;
297 }
298
299 if (!historyPoint->isAirborne) {
300 followData->followState = NPC_FOLLOW_STATE_RUN;
301 return;
302 }
303
304 while (TRUE) {
305 if (!historyPoint->isAirborne) {
306 break;
307 }
308
309 yaw = atan2(npc->pos.x, npc->pos.z, targetX, targetZ);
310 if (fabsf(get_clamped_angle_diff(yaw, atan2(npc->pos.x, npc->pos.z, x, z))) < 90.0f) {
311 break;
312 }
313
314 if (followData->targetPointIdx == followData->lastPointIdx) {
315 break;
316 }
317
318 followData->targetPointIdx++;
319 if (followData->targetPointIdx >= ARRAY_COUNT(followData->moveHistory)) {
320 followData->targetPointIdx = 0;
321 }
322 historyPoint = &followData->moveHistory[followData->targetPointIdx];
323 targetX = historyPoint->pos.x;
324 targetZ = historyPoint->pos.z;
325 }
327 break;
328 }
329}
#define npc_raycast_down_sides
#define atan2
@ NPC_FLAG_COLLDING_FORWARD_WITH_WORLD
Definition enums.h:3012
@ NPC_FLAG_GROUNDED
Definition enums.h:3010
f32 fabsf(f32 f)
f32 get_clamped_angle_diff(f32, f32)
Definition 43F0.c:606
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:986
f32 jumpScale
Vec3f moveToPos
f32 planarFlyDist
f32 moveSpeed
s16 duration