Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
sushie.c
Go to the documentation of this file.
1#include "common.h"
2#include "world/partners.h"
3#include "npc.h"
4#include "effects.h"
5#include "sprite/npc/WorldSushie.h"
6#include "sprite.h"
7#include "sprite/player.h"
8
9#define NAMESPACE world_sushie
10
12BSS s32 N(DiveState);
13BSS s32 N(DiveTime);
15BSS s32 N(TouchDockTime);
22BSS s32 N(bss_802BFF0C); // unused (padding?)
24
25enum {
30};
31
32f32 N(InputStickX) = 0.0f;
33f32 N(InputStickY) = 0.0f;
34f32 N(InertialStickX) = 0.0f;
35f32 N(InertialStickY) = 0.0f;
36
38
43 s32 angleOffset;
44
45 playerStatus->pos.x = partnerNPC->pos.x;
46 playerStatus->pos.y = partnerNPC->pos.y + 16.0f;
47 playerStatus->pos.z = partnerNPC->pos.z;
48 playerStatus->targetYaw = partnerNPC->yaw;
49
50 if (playerStatus->spriteFacingAngle < 90.0f || playerStatus->spriteFacingAngle > 270.0f) {
51 angleOffset = -8;
52 } else {
53 angleOffset = 8;
54 }
55
57 camera->curYaw + playerStatus->spriteFacingAngle - 90.0f + angleOffset)) * -4.0f;
58}
59
61 f32 moveAngle;
62 f32 moveSpeed;
63 f32 stickY = gPartnerStatus.stickY;
64 f32 stickX = gPartnerStatus.stickX;
65
66 N(InputStickX) = stickX;
67 N(InputStickY) = stickY;
68 moveAngle = clamp_angle(atan2(0.0f, 0.0f, stickX, -stickY) + gCameras[CAM_DEFAULT].curYaw);
69 moveSpeed = 0.0f;
70
71 if (dist2D(0.0f, 0.0f, N(InputStickX), -N(InputStickY)) >= 1.0) {
72 if (SQ(N(InputStickX)) + SQ(N(InputStickY)) > SQ(55)) {
73 if (N(DiveState) != DIVE_STATE_NONE) {
74 moveSpeed = 2.0f;
75 } else {
76 moveSpeed = 4.0f;
77 }
78 } else {
79 moveSpeed = 2.0f;
80 }
81 }
82
83 *outAngle = moveAngle;
84 *outSpeed = moveSpeed;
85}
86
87void N(test_for_water_level)(s32 ignoreFlags, f32 posX, f32 posY, f32 posZ, f32 yaw, f32 radius) {
89 f32 depth;
90
91 posY += 100.0f;
92 depth = 200.0f;
93
94 if (!npc_raycast_down_around(ignoreFlags, &posX, &posY, &posZ, &depth, yaw, radius)) {
96 } else {
98 N(WaterSurfaceY) = posY;
99 }
100}
101
107 f32 moveAngle, moveSpeed;
109 f32 x, y, z;
110 f32 depth;
111
112 // PART 1:
113 // determine movement speed and direction from input and inertia
114
115 N(get_movement_from_input)(&moveAngle, &moveSpeed);
116
117 if (N(DiveState) != DIVE_STATE_NONE) {
118 moveSpeedDamping = 80.0f;
119 } else {
120 moveSpeedDamping = 32.0f;
121 }
122
123 if (moveSpeed != 0.0f) {
124 f32 changeDirDamping = 8.0f;
125 f32 sameDirDamping = 32.0f;
126
127 if (N(InputStickX) * N(InertialStickX) > 0.0f) {
129 } else {
131 }
132 if (N(InputStickX) > 0.0f) {
133 if (N(InputStickX) < N(InertialStickX)) {
135 }
136 } else {
137 if (N(InertialStickX) < N(InputStickX)) {
139 }
140 }
141
142 if (N(InputStickY) * N(InertialStickY) > 0.0f) {
144 } else {
146 }
147 if (N(InputStickY) > 0.0f) {
148 if (N(InputStickY) < N(InertialStickY)) {
150 }
151 } else {
152 if (N(InertialStickY) < N(InputStickY)) {
154 }
155 }
156
157 moveAngle = clamp_angle(atan2(0.0f, 0.0f, N(InertialStickX), -N(InertialStickY)) + gCameras[CAM_DEFAULT].curYaw);
158 if (N(InertialMoveSpeed) <= moveSpeed) {
160 if (N(InertialMoveSpeed) > moveSpeed) {
161 N(InertialMoveSpeed) = moveSpeed;
162 }
163 } else {
165 }
166 moveSpeed = N(InertialMoveSpeed);
167 N(InertialMoveAngle) = moveAngle;
168 sin_cos_rad(DEG_TO_RAD(moveAngle), &sinAngle, &cosAngle);
169 N(UnusedMoveX) += ( moveSpeed * sinAngle) / moveSpeedDamping;
170 N(UnusedMoveZ) += (-moveSpeed * cosAngle) / moveSpeedDamping;
171 } else {
172 N(InertialMoveSpeed) -= 0.15;
173 if (N(InertialMoveSpeed) < 0.0f) {
174 N(InertialMoveSpeed) = 0.0f;
175 N(InertialStickY) = 0.0f;
176 N(InertialStickX) = 0.0f;
177 }
178 moveSpeed = N(InertialMoveSpeed);
179 moveAngle = N(InertialMoveAngle);
181 N(UnusedMoveX) = moveSpeed * sinAngle;
182 N(UnusedMoveZ) = -moveSpeed * cosAngle;
183 }
184
185 // PART 2:
186 // apply movement speed and direction to sushie
187
188 sushie->moveSpeed = moveSpeed;
189 if (moveSpeed != 0.0f) {
190 sushie->yaw = moveAngle;
191 x = sushie->pos.x;
192 z = sushie->pos.z;
193 y = sushie->moveToPos.y + -6.0f;
194 depth = (sushie->collisionHeight * 0.5f) + (playerStatus->colliderHeight * 0.8f);
195 if (npc_test_move_taller_with_slipping(sushie->collisionChannel, &x, &y, &z,
196 sushie->moveSpeed, moveAngle, depth, sushie->collisionDiameter))
197 {
198 collisionStatus->pushingAgainstWall = NpcHitQueryColliderID;
200 N(TouchDockTime)++;
201 } else {
202 N(TouchDockTime) = 0;
203 }
204 sushie->pos.x += (x - sushie->pos.x) * 0.5f;
205 sushie->pos.z += (z - sushie->pos.z) * 0.5f;
206 } else {
207 npc_move_heading(sushie, moveSpeed, moveAngle);
208 collisionStatus->pushingAgainstWall = NO_COLLIDER;
209 }
210 moveSpeed = 2.0f;
211 moveAngle = clamp_angle(sushie->yaw - 30.0f);
212 x = sushie->pos.x;
213 z = sushie->pos.z;
214 y = sushie->moveToPos.y + -6.0f;
215 depth = (sushie->collisionHeight * 0.5f) + (playerStatus->colliderHeight * 0.8f);
216 if (npc_test_move_taller_with_slipping(sushie->collisionChannel, &x, &y, &z,
217 moveSpeed, moveAngle, depth, sushie->collisionDiameter))
218 {
219 sushie->pos.x += (x - sushie->pos.x) / 5.0f;
220 sushie->pos.z += (z - sushie->pos.z) / 5.0f;
221 }
222 moveAngle = clamp_angle(sushie->yaw + 30.0f);
223 x = sushie->pos.x;
224 z = sushie->pos.z;
225 y = sushie->moveToPos.y + -6.0f;
226 depth = (sushie->collisionHeight * 0.5f) + (playerStatus->colliderHeight * 0.8f);
227 if (npc_test_move_taller_with_slipping(sushie->collisionChannel, &x, &y, &z,
228 moveSpeed, moveAngle, depth, sushie->collisionDiameter))
229 {
230 sushie->pos.x += (x - sushie->pos.x) / 5.0f;
231 sushie->pos.z += (z - sushie->pos.z) / 5.0f;
232 }
233 }
234
235 // PART 3:
236 // update diving state
237
238 if (N(DiveState) == DIVE_STATE_NONE) {
239 N(test_for_water_level)(sushie->collisionChannel, sushie->pos.x, sushie->pos.y, sushie->pos.z,
240 sushie->yaw, sushie->collisionDiameter * 0.5f);
241 if (N(DiveState) == DIVE_STATE_NONE) {
242 sushie->moveSpeed = 3.0f;
243 sushie->moveToPos.y = N(WaterSurfaceY) - (sushie->collisionHeight * 0.5f);
244 N(DiveTime) = 0;
245 if (partnerStatus->pressedButtons & BUTTON_C_DOWN) {
247 sushie->moveSpeed = 2.0f;
248 } else {
249 return;
250 }
251 }
252 }
253 if (N(DiveState) == DIVE_STATE_DELAY) {
254 if ((partnerStatus->curButtons & BUTTON_C_DOWN) && N(DiveTime) == 0) {
256 }
257 }
258 N(DiveTime)++;
259 if (N(DiveState) == DIVE_STATE_DIVING) {
260 x = sushie->pos.x;
261 y = sushie->pos.y;
262 z = sushie->pos.z;
263 depth = sushie->collisionHeight;
264 if (npc_raycast_down_around(sushie->collisionChannel, &x, &y, &z, &depth, sushie->yaw, sushie->collisionDiameter)) {
265 moveSpeedDamping = ((N(WaterSurfaceY) - (playerStatus->colliderHeight * 2)) - sushie->moveToPos.y) * 0.1f;
266 sushie->moveToPos.y += moveSpeedDamping;
267 if (sushie->moveToPos.y < y + 5.0f) {
268 sushie->moveToPos.y = y + 5.0f;
269 }
270 } else {
271 moveSpeedDamping = ((N(WaterSurfaceY) - (playerStatus->colliderHeight * 2)) - sushie->moveToPos.y) * 0.1f;
272 sushie->moveToPos.y += moveSpeedDamping;
273 }
274 if (N(DiveTime) % 6 == 0) {
275 fx_rising_bubble(0, sushie->pos.x, sushie->moveToPos.y + (sushie->collisionHeight * 0.5f), sushie->pos.z,
276 (N(WaterSurfaceY) - sushie->moveToPos.y) - (sushie->collisionHeight * 0.5f));
277 }
278 if (N(DiveTime) == 1) {
280 sushie->curAnim = ANIM_WorldSushie_Ride;
281 }
282 if (!N(IsUnderwater) && (playerStatus->pos.y + (playerStatus->colliderHeight * 0.5f) < N(WaterSurfaceY))) {
283 N(IsUnderwater) = TRUE;
285 set_player_imgfx_all(playerStatus->trueAnimation, IMGFX_SET_WAVY, 2, 0, 0, 0, 0);
287 }
288 if (N(DiveTime) >= 10) {
289 if (!(partnerStatus->curButtons & BUTTON_C_DOWN) || N(DiveTime) >= 30) {
290 sushie->curAnim = ANIM_WorldSushie_Rise;
293 }
294 }
295 }
296
297 x = sushie->pos.x;
298 y = sushie->moveToPos.y;
299 z = sushie->pos.z;
300 depth = (sushie->collisionHeight * 0.5f) + playerStatus->colliderHeight;
301 if (npc_raycast_up_corners(sushie->collisionChannel, &x, &y, &z, &depth, sushie->yaw, sushie->collisionDiameter * 0.3f) > NO_COLLIDER) {
302#if VERSION_JP
303 sushie->moveToPos.y = y;
304#else
305 sushie->moveToPos.y += (((sushie->moveToPos.y - y) + depth) - ((sushie->collisionHeight * 0.5f) + playerStatus->colliderHeight)) * 0.2f;
306#endif
307 if (N(DiveTime) % 9 == 0) {
308 fx_rising_bubble(0, sushie->pos.x, sushie->moveToPos.y + (sushie->collisionHeight * 0.5f), sushie->pos.z,
309 (N(WaterSurfaceY) - sushie->moveToPos.y) - (sushie->collisionHeight * 0.5f));
310 }
311 } else if (N(DiveState) == DIVE_STATE_SURFACING) {
312 N(ResurfaceVelY) += 0.14;
313 if (N(ResurfaceVelY) > 1.8) {
314 N(ResurfaceVelY) = 1.8f;
315 }
316 sushie->moveToPos.y += N(ResurfaceVelY);
317 if (N(DiveTime) % 9 == 0) {
318 fx_rising_bubble(0, sushie->pos.x, sushie->moveToPos.y + sushie->collisionHeight * 0.5f, sushie->pos.z,
319 (N(WaterSurfaceY) - sushie->moveToPos.y) - sushie->collisionHeight * 0.5f);
320 }
321 if ((N(WaterSurfaceY) - sushie->moveToPos.y) - (sushie->collisionHeight * 0.5f) <= 0.0f) {
322 if (N(IsUnderwater)) {
323 N(IsUnderwater) = FALSE;
325 npc_set_imgfx_params(sushie, IMGFX_CLEAR, 0, 0, 0, 0, 0);
326 }
328 sushie->curAnim = ANIM_WorldSushie_Ride;
329 sushie->moveToPos.y = N(WaterSurfaceY) - (sushie->collisionHeight * 0.5f);
331 }
332 }
333}
334
335HitID N(test_ray_to_wall_center)(s32 unused, f32* x, f32* y, f32* z, f32 length, f32 radius, f32* yaw) {
337 f32 hitX, hitY, hitZ;
339 s32 hitID;
340
343 totalLength = radius + length;
345 &hitX, &hitY, &hitZ, &totalLength, &hitNx, &hitNy, &hitNz);
346
347 if (hitID > NO_COLLIDER) {
348 *yaw = atan2(0.0f, 0.0f, hitNx, hitNz);
349 }
350
351 return hitID;
352}
353
354API_CALLABLE(N(UseAbility)) {
359 Npc* sushie = script->owner2.npc;
360 s32 surfaceType;
361 f32 x, y, z, dist;
362 f32 angle, speed;
364 s32 collider;
365
366 #define USE_STATE functionTemp[0]
367 enum {
368 SWIM_STATE_INIT = 0,
369 SWIM_STATE_BEGIN = 20,
380 };
381
382 if (isInitialCall) {
384 N(InertialMoveAngle) = 0.0f;
385 N(InertialMoveSpeed) = 0.0f;
386 N(UnusedMoveX) = 0.0f;
387 N(UnusedMoveZ) = 0.0f;
388 N(ResurfaceVelY) = 0.0f;
389 script->USE_STATE = SWIM_STATE_INIT;
390 }
391 playerData->partnerUsedTime[PARTNER_SUSHIE]++;
393
394 switch (script->USE_STATE) {
395 case SWIM_STATE_INIT:
397 // are we colliding with a solid (non-entity) wall?
398 collider = collisionStatus->curWall;
400 return ApiStatus_DONE1;
401 }
402 // is it a dock wall
405 return ApiStatus_DONE1;
406 }
407 script->USE_STATE = SWIM_STATE_BEGIN;
408 } else {
409 // resume riding state from previous map
410 sushie->moveToPos.y = sushie->pos.y;
411 playerStatus->pos.y = sushie->moveToPos.y + 16.0f;
412 N(IsRiding) = TRUE;
413 sushie->flags |= NPC_FLAG_FLYING;
414 sushie->flags &= ~NPC_FLAG_GRAVITY;
420 sushie->curAnim = ANIM_WorldSushie_Ride;
421 sushie->moveSpeed = playerStatus->runSpeed;
422 sushie->jumpScale = 0.0f;
423 partnerStatus->partnerActionState = PARTNER_ACTION_USE;
425 partnerStatus->actingPartner = PARTNER_SUSHIE;
427 N(DiveTime) = 0;
428 script->functionTemp[2] = 0;
429 script->USE_STATE = SWIM_STATE_RIDING;
430 }
431 break;
432
433 case SWIM_STATE_BEGIN:
434 if (collisionStatus->curWall <= NO_COLLIDER) {
435 return ApiStatus_DONE1;
436 }
437 // check for obstructions between player and center of current wall
438 get_collider_center(collisionStatus->curWall, &x, &y, &z);
439 angle = atan2(x, z, playerStatus->pos.x, playerStatus->pos.z);
440 x = playerStatus->pos.x;
441 y = playerStatus->pos.y;
442 z = playerStatus->pos.z;
443 collider = N(test_ray_to_wall_center)(0, &x, &y, &z,
444 playerStatus->colliderDiameter * 0.5f, 2.0f * playerStatus->colliderDiameter, &angle);
445 // check surface type for wall
447 if (collider > NO_COLLIDER) {
449 }
451 return ApiStatus_DONE1;
452 }
453
454 N(IsRiding) = TRUE;
458 sushie->collisionChannel = COLLIDER_FLAG_DOCK_WALL;
459 sushie->moveToPos.x = playerStatus->pos.x;
460 sushie->moveToPos.y = playerStatus->pos.y;
461 sushie->moveToPos.z = playerStatus->pos.z;
462 sushie->yaw = angle;
463 playerStatus->targetYaw = angle;
464 sushie->renderYaw = 90.0f;
465 add_vec2D_polar(&sushie->moveToPos.x, &sushie->moveToPos.z, 40.0f, sushie->yaw);
466 x = sushie->moveToPos.x;
467 y = sushie->moveToPos.y;
468 z = sushie->moveToPos.z;
469 dist = 100.0f;
470 collider = npc_raycast_down_around(sushie->collisionChannel, &x, &y, &z, &dist,
471 sushie->yaw, sushie->collisionDiameter);
472 sushie->curAnim = ANIM_WorldSushie_Run;
473 sushie->duration = 12;
474 sushie->moveToPos.y = y - (sushie->collisionHeight * 0.5f);
476 script->USE_STATE++; // SWIM_STATE_ENTER_WATER
477 break;
478
480 sushie->pos.x += (sushie->moveToPos.x - sushie->pos.x) / sushie->duration;
481 sushie->pos.y += (sushie->moveToPos.y - sushie->pos.y) / sushie->duration;
482 sushie->pos.z += (sushie->moveToPos.z - sushie->pos.z) / sushie->duration;
483 sushie->duration--;
484 if (sushie->duration != 0) {
485 if (sushie->duration == 2) {
488 }
489 break;
490 }
491 sushie->collisionChannel = COLLIDER_FLAG_IGNORE_PLAYER;
492 sushie->flags |= NPC_FLAG_FLYING;
496 sushie->curAnim = ANIM_WorldSushie_Ride;
498 dist = dist2D(playerStatus->pos.x, playerStatus->pos.z, sushie->moveToPos.x, sushie->moveToPos.z);
499 sushie->jumpVel = 5.0f;
500 sushie->jumpScale = 0.6f;
501 y = sushie->moveToPos.y - playerStatus->pos.y;
502 sushie->duration = (2.0f * sushie->jumpVel) / 0.6f;
503 sushie->moveSpeed = dist / sushie->duration;
504 sushie->jumpVel += y / sushie->duration;
506 script->USE_STATE++; // SWIM_STATE_EMBARK_1
507 fx_rising_bubble(0, sushie->pos.x, sushie->moveToPos.y + (sushie->collisionHeight * 0.5f), sushie->pos.z, 0.0f);
508 break;
509
511 fx_rising_bubble(0, sushie->pos.x, sushie->moveToPos.y + (sushie->collisionHeight * 0.5f), sushie->pos.z, 0.0f);
512 // fallthrough
515 script->USE_STATE++;
516 // fallthrough
518 playerStatus->pos.y += sushie->jumpVel;
519 sushie->jumpVel -= sushie->jumpScale;
520 add_vec2D_polar(&playerStatus->pos.x, &playerStatus->pos.z, sushie->moveSpeed, sushie->yaw);
521 if (sushie->jumpVel <= 0.0f) {
523 }
527
528 if (sushie->duration != 0) {
529 sushie->duration--;
530 break;
531 }
537 playerStatus->pos.x = sushie->pos.x;
538 playerStatus->pos.y = sushie->pos.y;
539 playerStatus->pos.z = sushie->pos.z;
540 playerStatus->targetYaw = sushie->yaw;
541 sushie->moveSpeed = 3.0f;
542 partnerStatus->partnerActionState = PARTNER_ACTION_USE;
544 partnerStatus->actingPartner = PARTNER_SUSHIE;
546 N(DiveTime) = 0;
547 script->functionTemp[2] = 0;
548 script->USE_STATE = SWIM_STATE_RIDING;
549 break;
550
554 if (N(DiveState) == DIVE_STATE_NONE) {
555 script->functionTemp[2]++;
556 if (script->functionTemp[2] > 20) {
557 script->functionTemp[2] -= 40;
558 }
559 sushie->pos.y = sushie->moveToPos.y + abs(script->functionTemp[2]) / 8.0f;
560 if (script->functionTemp[2] == 5) {
561 N(get_movement_from_input)(&angle, &speed);
562 if (N(DiveState) == DIVE_STATE_NONE) {
563 if (speed != 0.0f) {
565 } else {
567 }
568 }
569 }
570 if (N(InertialMoveSpeed) == 0.0f && !((gGameStatusPtr->frameCounter % 10) & 0xFFFF)) {
572 sushie->pos.x,
573 sushie->moveToPos.y + (sushie->collisionHeight * 0.5f),
574 sushie->pos.z,
575 0);
576 }
577 } else {
578 sushie->pos.y = sushie->moveToPos.y;
579 }
580 if (!(playerStatus->animFlags & PA_FLAG_RIDING_PARTNER)) {
582 }
583
584 if (N(DiveState) == DIVE_STATE_DELAY) {
585 if (!(gGameStatusPtr->frameCounter % 19)) {
587 sushie->pos.x,
588 sushie->moveToPos.y + (sushie->collisionHeight * 0.5f),
589 sushie->pos.z,
590 N(WaterSurfaceY) - sushie->pos.y);
591 }
592 } else if (N(InertialMoveSpeed) != 0.0f && N(DiveState) < DIVE_STATE_DIVING) {
593 if (!(gGameStatusPtr->frameCounter % 7)) {
595 sushie->pos.x,
596 sushie->moveToPos.y + (sushie->collisionHeight * 0.5f),
597 sushie->pos.z,
598 N(DiveState) != DIVE_STATE_NONE ? N(WaterSurfaceY) - sushie->pos.y : 0);
599 }
600 }
601
605 if ((partnerStatus->pressedButtons & (BUTTON_B | BUTTON_C_DOWN)) || N(TouchDockTime) >= 30) {
606 if (N(IsUnderwater)) {
607 break;
608 }
609 x = sushie->pos.x;
610 y = sushie->moveToPos.y + sushie->collisionHeight;
611 z = sushie->pos.z;
612
613 if (npc_test_move_taller_with_slipping(sushie->collisionChannel, &x, &y, &z, 10.0f,
614 sushie->yaw, sushie->collisionHeight, sushie->collisionDiameter)
615 ) {
616 collisionStatus->pushingAgainstWall = sushie->curWall = NpcHitQueryColliderID;
617 } else {
618 collisionStatus->pushingAgainstWall = NO_COLLIDER;
619 }
620
621 if (sushie->curWall < 0 || sushie->curWall & COLLISION_WITH_ENTITY_BIT) {
622 if (N(DiveState) == DIVE_STATE_DIVING && N(DiveTime) == 1) {
624 }
625 break;
626 }
629 if (N(DiveState) == DIVE_STATE_DIVING && N(DiveTime) == 1) {
631 }
632 break;
633 }
634 N(TouchDockTime) = 0;
635 x = sushie->pos.x;
636 z = sushie->pos.z;
637 y = sushie->moveToPos.y + 100.0f;
638 add_vec2D_polar(&x, &z, 40.0f, sushie->yaw);
639 dist = 100.0f;
640 // this var is a condition here
641 collider = npc_raycast_down_around(sushie->collisionChannel, &x, &y, &z, &dist, sushie->yaw, 0.0f);
642 if (collider) {
643 get_collider_center(sushie->curWall, &x, &y, &z);
644 dist = dist2D(sushie->pos.x, sushie->pos.z, x, z);
645 sin_cos_rad(DEG_TO_RAD(atan2(sushie->pos.x, sushie->pos.z, x, z)), &sinAngle, &cosAngle);
646 x = sushie->pos.x + ((sinAngle * dist) * 0.6);
647 z = sushie->pos.z - ((cosAngle * dist) * 0.6);
648 dist = 100.0f;
649 npc_raycast_down_around(sushie->collisionChannel, &x, &y, &z, &dist, sushie->yaw, 0.0f);
650 sushie->moveToPos.y = y;
651 sushie->moveToPos.x = x;
652 sushie->moveToPos.z = z;
653 playerStatus->targetYaw = atan2(playerStatus->pos.x, playerStatus->pos.z, x, z);
654 sushie->yaw = playerStatus->targetYaw;
655 dist = dist2D(playerStatus->pos.x, playerStatus->pos.z, sushie->moveToPos.x, sushie->moveToPos.z);
656 sushie->jumpVel = 5.0f;
657 sushie->jumpScale = 0.6f;
658 sushie->duration = (2.0f * sushie->jumpVel) / 0.6f;
659 sushie->moveSpeed = dist / sushie->duration;
660 sushie->jumpVel += (sushie->moveToPos.y - playerStatus->pos.y) / sushie->duration;
665 script->USE_STATE = SWIM_STATE_DISEMBARK_1;
666 }
667 }
668 break;
671 script->USE_STATE++;
672 // fallthrough
674 if (sushie->jumpVel <= 0.0f) {
676 script->USE_STATE++;
677 }
678 // fallthrough
680 if (sushie->jumpVel <= 0.0f) {
682 if (collider > 0) {
684 }
685 } else {
686 playerStatus->pos.y += sushie->jumpVel;
687 }
688 sushie->jumpVel -= sushie->jumpScale;
692 if (sushie->duration != 0) {
693 add_vec2D_polar(&playerStatus->pos.x, &playerStatus->pos.z, sushie->moveSpeed, sushie->yaw);
694 sushie->duration--;
695 break;
696 }
697 if (collider >= 0) {
701 dist = dist2D(sushie->pos.x, sushie->pos.z, sushie->moveToPos.x, sushie->moveToPos.z) +
702 (playerStatus->colliderDiameter * 0.5f);
703 sushie->jumpVel = 8.0f;
704 sushie->jumpScale = 1.0f;
705 sushie->moveSpeed = 4.0f;
706 y = sushie->moveToPos.y - sushie->pos.y;
707 sushie->duration = (2.0f * sushie->jumpVel) / sushie->jumpScale;
708 sushie->moveSpeed = dist / sushie->duration;
709 sushie->jumpVel += y / sushie->duration;
710 script->USE_STATE = SWIM_STATE_EXIT_WATER;
711 }
712 break;
714 sushie->pos.y += sushie->jumpVel;
715 sushie->jumpVel -= sushie->jumpScale;
716 add_vec2D_polar(&sushie->pos.x, &sushie->pos.z, sushie->moveSpeed, sushie->yaw);
717 if (sushie->duration == 0) {
723 N(IsRiding) = FALSE;
724 sushie->flags &= ~NPC_FLAG_FLYING;
725 sushie->flags |= NPC_FLAG_GRAVITY;
728 partnerStatus->partnerActionState = PARTNER_ACTION_NONE;
729 partnerStatus->actingPartner = 0;
731 npc_set_imgfx_params(sushie, IMGFX_CLEAR, 0, 0, 0, 0, 0);
732 return ApiStatus_DONE1;
733 }
734 sushie->duration--;
735 break;
736 }
737 return ApiStatus_BLOCK;
738}
739
745
746void N(init)(Npc* sushie) {
747 sushie->collisionHeight = 24;
748 sushie->collisionDiameter = 36;
749 sushie->collisionChannel = COLLIDER_FLAG_IGNORE_PLAYER;
750 N(IsRiding) = FALSE;
752 N(DiveTime) = 0;
753 N(TouchDockTime) = 0;
754 N(IsUnderwater) = FALSE;
755}
756
757API_CALLABLE(N(TakeOut)) {
758 Npc* sushie = script->owner2.npc;
759
760 if (isInitialCall) {
762 }
763
764 if (partner_get_out(sushie)) {
765 return ApiStatus_DONE1;
766 } else {
767 return ApiStatus_BLOCK;
768 }
769}
770
776
778
779API_CALLABLE(N(Update)) {
780 Npc* sushie = script->owner2.npc;
782 Entity* entity;
783
784 if (isInitialCall) {
788 }
789
791
792 if (entity == NULL) {
795 return ApiStatus_BLOCK;
796 }
797
798 switch (N(TweesterPhysicsPtr)->state) {
800 N(TweesterPhysicsPtr)->state++;
801 N(TweesterPhysicsPtr)->prevFlags = sushie->flags;
802 N(TweesterPhysicsPtr)->radius = fabsf(dist2D(sushie->pos.x, sushie->pos.z,
803 entity->pos.x, entity->pos.z));
804 N(TweesterPhysicsPtr)->angle = atan2(entity->pos.x, entity->pos.z, sushie->pos.x, sushie->pos.z);
805 N(TweesterPhysicsPtr)->angularVel = 6.0f;
806 N(TweesterPhysicsPtr)->liftoffVelPhase = 50.0f;
807 N(TweesterPhysicsPtr)->countdown = 120;
809 sushie->flags &= ~NPC_FLAG_GRAVITY;
812 sushie->pos.x = entity->pos.x + (sinAngle * N(TweesterPhysicsPtr)->radius);
813 sushie->pos.z = entity->pos.z - (cosAngle * N(TweesterPhysicsPtr)->radius);
814 N(TweesterPhysicsPtr)->angle = clamp_angle(N(TweesterPhysicsPtr)->angle - N(TweesterPhysicsPtr)->angularVel);
815
816 if (N(TweesterPhysicsPtr)->radius > 20.0f) {
817 N(TweesterPhysicsPtr)->radius--;
818 } else if (N(TweesterPhysicsPtr)->radius < 19.0f) {
819 N(TweesterPhysicsPtr)->radius++;
820 }
821
822 liftoffVelocity = sin_rad(DEG_TO_RAD(N(TweesterPhysicsPtr)->liftoffVelPhase)) * 3.0f;
823 N(TweesterPhysicsPtr)->liftoffVelPhase += 3.0f;
824
825 if (N(TweesterPhysicsPtr)->liftoffVelPhase > 150.0f) {
826 N(TweesterPhysicsPtr)->liftoffVelPhase = 150.0f;
827 }
828
829 sushie->pos.y += liftoffVelocity;
830 sushie->renderYaw = clamp_angle(360.0f - N(TweesterPhysicsPtr)->angle);
831 N(TweesterPhysicsPtr)->angularVel += 0.8;
832
833 if (N(TweesterPhysicsPtr)->angularVel > 40.0f) {
834 N(TweesterPhysicsPtr)->angularVel = 40.0f;
835 }
836
837 if (--N(TweesterPhysicsPtr)->countdown == 0) {
838 N(TweesterPhysicsPtr)->state++;
839 }
840 break;
842 sushie->flags = N(TweesterPhysicsPtr)->prevFlags;
843 N(TweesterPhysicsPtr)->countdown = 30;
844 N(TweesterPhysicsPtr)->state++;
845 break;
849
850 if (--N(TweesterPhysicsPtr)->countdown == 0) {
853 }
854 break;
855 }
856
857 return ApiStatus_BLOCK;
858}
859
865
874
875API_CALLABLE(N(PutAway)) {
876 Npc* sushie = script->owner2.npc;
877
878 if (isInitialCall) {
881 }
882
884}
885
891
906
909
910 if (partnerStatus->shouldResumeAbility) {
913 }
914}
915
916API_CALLABLE(N(EnterMap)) {
919
920 if (isInitialCall) {
921 script->functionTemp[0] = 0;
922 N(WaterSurfaceY) = playerStatus->pos.y;
923 }
924
925 switch (script->functionTemp[0]) {
926 case 0:
930 partnerNPC->pos.x = playerStatus->pos.x;
931 partnerNPC->pos.z = playerStatus->pos.z;
932 partnerNPC->pos.y = playerStatus->pos.y;
933 N(test_for_water_level)(partnerNPC->collisionChannel, partnerNPC->pos.x, partnerNPC->pos.y, partnerNPC->pos.z,
934 partnerNPC->yaw, partnerNPC->collisionDiameter * 0.5f);
935 partnerNPC->pos.y = N(WaterSurfaceY) - (partnerNPC->collisionHeight * 0.5f);
936 partnerNPC->yaw = atan2(partnerNPC->pos.x, partnerNPC->pos.z, script->varTable[1], script->varTable[3]);
938 partnerNPC->jumpScale = 0.0f;
939 partnerNPC->moveSpeed = 3.0f;
940 partnerNPC->moveToPos.x = partnerNPC->pos.x;
941 partnerNPC->moveToPos.y = partnerNPC->pos.y;
942 partnerNPC->moveToPos.z = partnerNPC->pos.z;
947
948 if (script->varTable[12] == 0) {
950 } else {
952 if ((partnerNPC->yaw >= 0.0f) && (partnerNPC->yaw <= 180.0f)) {
953 partnerNPC->yawCamOffset = partnerNPC->yaw;
954 partnerNPC->isFacingAway = TRUE;
955 }
956 }
957 script->functionTemp[1] = 25;
958 script->functionTemp[0] = 1;
959 break;
960 case 1:
963
964 if (!(script->functionTemp[1] & 3)) {
965 fx_rising_bubble(0, partnerNPC->pos.x, partnerNPC->moveToPos.y +
966 (partnerNPC->collisionHeight * 0.5f), partnerNPC->pos.z, 0);
967 }
968
969 script->functionTemp[1]--;
970 if (script->functionTemp[1] == 0) {
971 if (script->varTable[12] == 1) {
974 } else {
977 }
978 return ApiStatus_DONE2;
979 }
980 break;
981 }
982 return ApiStatus_BLOCK;
983}
984
s32 partner_use_ability(void)
Definition partners.c:964
BSS s32 PopupMenu_SelectedIndex
b8 keepUsingPartnerOnMapChange
s32 b32
s32 HitID
Bytecode EvtScript[]
#define clamp_angle
#define atan2
#define mem_clear
@ TWEESTER_PARTNER_HOLD
Definition enums.h:2477
@ TWEESTER_PARTNER_ATTRACT
Definition enums.h:2476
@ TWEESTER_PARTNER_INIT
Definition enums.h:2475
@ TWEESTER_PARTNER_RELEASE
Definition enums.h:2478
@ BUTTON_C_DOWN
Definition enums.h:2779
@ BUTTON_B
Definition enums.h:2789
@ IMGFX_CLEAR
Definition enums.h:5116
@ IMGFX_SET_WAVY
Definition enums.h:5120
@ SURFACE_TYPE_DOCK_WALL
Definition enums.h:4673
@ SURFACE_TYPE_INVALID
Definition enums.h:4679
@ PS_FLAG_MOVEMENT_LOCKED
Definition enums.h:3069
@ PARTNER_ACTION_NONE
Definition enums.h:2932
@ PARTNER_ACTION_USE
Definition enums.h:2933
@ COLLIDER_FLAG_DOCK_WALL
Definition enums.h:4698
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4695
@ COLLIDER_FLAGS_SURFACE_TYPE_MASK
Definition enums.h:4692
@ SOUND_ID_TRIGGER_CHANGE_SOUND
Definition enums.h:532
@ NPC_PARTNER
Definition enums.h:2528
@ PA_FLAG_RIDING_PARTNER
Definition enums.h:3116
@ SOUND_SUSHIE_RIDE_IDLE
Definition enums.h:1329
@ SOUND_SUSHIE_EMBARK
Definition enums.h:1328
@ SOUND_QUICK_PLAYER_JUMP
Definition enums.h:1424
@ SOUND_SUSHIE_RIDE_MOVING
Definition enums.h:1330
@ SOUND_SUSHIE_DIVE
Definition enums.h:1011
@ RENDER_MODE_ALPHATEST
Definition enums.h:3276
@ PARTNER_SUSHIE
Definition enums.h:2892
@ ACTION_STATE_RIDE
Definition enums.h:2461
@ ACTION_STATE_IDLE
Definition enums.h:2426
@ SOUND_SPACE_DEFAULT
Definition enums.h:1737
@ CAM_DEFAULT
Definition enums.h:1800
@ NPC_FLAG_FLYING
Definition enums.h:3001
@ NPC_FLAG_IGNORE_WORLD_COLLISION
Definition enums.h:3004
@ NPC_FLAG_IGNORE_PLAYER_COLLISION
Definition enums.h:3006
@ NPC_FLAG_GRAVITY
Definition enums.h:3007
@ NPC_FLAG_IGNORE_CAMERA_FOR_YAW
Definition enums.h:3016
#define ApiStatus_DONE2
Definition evt.h:118
#define ApiStatus_DONE1
Definition evt.h:117
#define ApiStatus_BLOCK
Definition evt.h:116
f32 fabsf(f32 f)
b32 npc_raycast_down_around(s32, f32 *, f32 *, f32 *, f32 *, f32, f32)
void suggest_player_anim_always_forward(AnimID anim)
Definition 77480.c:913
void partner_walking_update_motion(Npc *partner)
Definition partners.c:1202
void partner_clear_player_tracking(Npc *partner)
Definition partners.c:2436
s32 disable_player_input(void)
Definition 77480.c:990
s32 get_collider_flags(s32 colliderID)
Definition collision.c:481
f32 player_check_collision_below(f32, s32 *colliderID)
Definition 7BB60.c:470
void partner_walking_update_player_tracking(Npc *partner)
Definition partners.c:1175
s32 disable_player_static_collisions(void)
Definition 77480.c:972
f32 cos_rad(f32 x)
Definition 43F0.c:716
s32 enable_player_input(void)
Definition 77480.c:998
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:669
void partner_kill_ability_script(void)
Definition partners.c:1109
void enable_player_shadow(void)
Definition 77480.c:964
void set_action_state(s32 actionState)
Definition 7E9D0.c:209
HitID npc_raycast_up_corners(s32 ignoreFlags, f32 *posX, f32 *posY, f32 *posZ, f32 *hitDepth, f32 yaw, f32 radius)
b32 npc_test_move_taller_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
void get_collider_center(s32 colliderID, f32 *x, f32 *y, f32 *z)
Definition collision.c:497
void suggest_player_anim_allow_backward(AnimID anim)
Definition 77480.c:894
s32 test_ray_colliders(s32 ignoreFlags, f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ, f32 *hitX, f32 *hitY, f32 *hitZ, f32 *hitDepth, f32 *hitNx, f32 *hitNy, f32 *hitNz)
Definition collision.c:768
void partner_walking_enable(Npc *partner, s32 val)
Definition partners.c:1133
f32 sin_rad(f32 x)
Definition 43F0.c:712
s32 enable_player_static_collisions(void)
Definition 77480.c:980
void sin_cos_rad(f32 rad, f32 *outSinTheta, f32 *outCosTheta)
Definition 43F0.c:705
void add_vec2D_polar(f32 *x, f32 *y, f32 r, f32 theta)
Definition 43F0.c:684
void disable_player_shadow(void)
Definition 77480.c:968
void enable_npc_shadow(Npc *npc)
Definition npc.c:1026
void disable_npc_shadow(Npc *npc)
Definition npc.c:1036
void npc_set_imgfx_params(Npc *npc, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6)
Definition npc.c:2161
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:994
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:985
s32 partner_init_get_out(Npc *npc)
Definition partners.c:2252
s32 partner_init_put_away(Npc *partner)
Definition partners.c:2178
s32 partner_put_away(Npc *partner)
Definition partners.c:2185
s32 partner_get_out(Npc *partner)
Definition partners.c:2259
void sfx_play_sound_at_npc(s32 soundID, s32 arg1, s32 npcID)
Definition sfx.c:527
#define End
Signals the end of EVT script data. A script missing this will likely crash on load.
Definition macros.h:213
#define COLLISION_WITH_ENTITY_BIT
Definition macros.h:156
#define BSS
Definition macros.h:7
#define DEG_TO_RAD(deg)
Definition macros.h:138
#define SQ(x)
Definition macros.h:170
#define NO_COLLIDER
Definition macros.h:160
#define Call(FUNC, ARGS...)
Calls a given C EVT API function with any number of arguments.
Definition macros.h:576
#define Return
Kills the current EVT thread.
Definition macros.h:217
void set_player_imgfx_all(s32 animID, ImgFXType imgfxType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6)
Definition sprite.c:994
Vec3f targetPos
Entity * TweesterTouchingPartner
Definition 7B440.c:5
PlayerStatus * gPlayerStatusPtr
CollisionStatus gCollisionStatus
Definition 7BB60.c:6
PartnerStatus gPartnerStatus
Definition partners.c:42
GameStatus * gGameStatusPtr
Definition main_loop.c:32
s32 NpcHitQueryColliderID
Camera gCameras[4]
Definition cam_main.c:17
PlayerData gPlayerData
Definition 77480.c:40
PlayerStatus gPlayerStatus
Definition 77480.c:39
void N sync_player_position(void)
Definition lakilester.c:56
EvtScript EVS_WorldSushie_PutAway
Definition sushie.c:886
@ DIVE_STATE_DIVING
Definition sushie.c:28
@ DIVE_STATE_SURFACING
Definition sushie.c:29
@ DIVE_STATE_NONE
Definition sushie.c:26
@ DIVE_STATE_DELAY
Definition sushie.c:27
void N try_cancel_tweester(Npc *sushie)
Definition sushie.c:866
EvtScript EVS_WorldSushie_EnterMap
Definition sushie.c:985
void N post_battle(Npc *sushie)
Definition sushie.c:907
EvtScript EVS_WorldSushie_TakeOut
Definition sushie.c:771
void N test_for_water_level(s32 ignoreFlags, f32 posX, f32 posY, f32 posZ, f32 yaw, f32 radius)
Definition sushie.c:87
EvtScript EVS_WorldSushie_UseAbility
Definition sushie.c:740
void N update_riding_physics(Npc *sushie)
Definition sushie.c:102
EvtScript EVS_WorldSushie_Update
Definition sushie.c:860
HitID N test_ray_to_wall_center(s32 unused, f32 *x, f32 *y, f32 *z, f32 length, f32 radius, f32 *yaw)
Definition sushie.c:335
void N pre_battle(Npc *sushie)
Definition sushie.c:892
void N get_movement_from_input(f32 *outAngle, f32 *outSpeed)
Definition sushie.c:60
void N init(Npc *sushie)
Definition sushie.c:746