Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
39210_len_aa0.c
Go to the documentation of this file.
1#include "common.h"
2
9
10void get_npc_pos(s32 npcID, f32* outX, f32* outY, f32* outZ, s32* outAirborne) {
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}
37
38void npc_follow_init(Npc* npc, s32 targetNpcID, FollowAnims* anims, f32 walkSpeed, f32 runSpeed, s32 idleRadius, s32 walkRadius) {
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}
67
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}
102
103void npc_follow_npc(Npc* npc) {
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}
void get_npc_pos(s32 npcID, f32 *outX, f32 *outY, f32 *outZ, s32 *outAirborne)
void npc_update_npc_tracking(Npc *npc)
void npc_follow_init(Npc *npc, s32 targetNpcID, FollowAnims *anims, f32 walkSpeed, f32 runSpeed, s32 idleRadius, s32 walkRadius)
void npc_follow_npc(Npc *npc)
NpcFollowStates
@ NPC_FOLLOW_STATE_JUMP
@ NPC_FOLLOW_STATE_IDLE
@ NPC_FOLLOW_STATE_FALL
@ NPC_FOLLOW_STATE_RUN
NpcHistoryPoint moveHistory[40]
FollowAnims * anims
#define npc_raycast_down_sides
#define atan2
#define ASSERT(condition)
@ PS_FLAG_FALLING
Definition enums.h:3036
@ PS_FLAG_JUMPING
Definition enums.h:3035
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4696
@ NPC_SELF
Definition enums.h:2526
@ NPC_FLAG_JUMPING
Definition enums.h:3009
@ NPC_FLAG_COLLDING_FORWARD_WITH_WORLD
Definition enums.h:3012
@ NPC_FLAG_GRAVITY
Definition enums.h:3007
@ NPC_FLAG_GROUNDED
Definition enums.h:3010
f32 fabsf(f32 f)
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:670
f32 get_clamped_angle_diff(f32, f32)
Definition 43F0.c:606
void * heap_malloc(s32 size)
Definition heap.c:34
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:995
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:986
#define ARRAY_COUNT(arr)
Definition macros.h:40
f32 jumpScale
f32 jumpVel
s32 flags
AnimID curAnim
Vec3f moveToPos
f32 planarFlyDist
s32 collisionChannel
Vec3f pos
f32 moveSpeed
union Npc::@0 blur
s16 duration
PlayerStatus gPlayerStatus
Definition 77480.c:39