Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
npc.c
Go to the documentation of this file.
1#include "common.h"
2#include "npc.h"
3#include "entity.h"
4#include "effects.h"
5#include "sprite.h"
6#include "world/partners.h"
7#include "sprite/npc/WorldWatt.h"
8#include "dx/debug_menu.h"
9
11static NpcList gWorldNpcList;
12static NpcList gBattleNpcList;
13static NpcList* gCurrentNpcListPtr;
14static b8 gNpcPlayerCollisionsEnabled;
15
16#define PAL_ANIM_END 0xFF
17
24
25// palette types for watt palette animations
26enum {
30};
31
48
50}
51
53 guMtxIdentF(mtx);
54 mtx[0][0] = 1.0f;
55 mtx[1][1] = -1.0f;
56 mtx[2][2] = 1.0f;
57 mtx[3][3] = 1.0f;
58}
59
60void clear_npcs(void) {
61 s32 i;
62
64 gCurrentNpcListPtr = &gWorldNpcList;
65 } else {
66 gCurrentNpcListPtr = &gBattleNpcList;
67 }
68
69 for (i = 0; i < MAX_NPCS; i++) {
70 (*gCurrentNpcListPtr)[i] = NULL;
71 }
72
73 gNpcCount = 0;
74 gNpcPlayerCollisionsEnabled = TRUE;
75}
76
77void init_npc_list(void) {
79 gCurrentNpcListPtr = &gWorldNpcList;
80 } else {
81 gCurrentNpcListPtr = &gBattleNpcList;
82 }
83
84 gNpcCount = 0;
85 gNpcPlayerCollisionsEnabled = TRUE;
86}
87
88s32 create_npc_impl(NpcBlueprint* blueprint, AnimID* animList, s32 isPeachNpc) {
89 Npc* npc;
90 s32 i;
91 s32 j;
92
93 for (i = 0; i < MAX_NPCS; i++) {
94 if ((*gCurrentNpcListPtr)[i] == NULL) {
95 break;
96 }
97 }
98 ASSERT(i < MAX_NPCS);
99
100 (*gCurrentNpcListPtr)[i] = npc = heap_malloc(sizeof(*npc));
101 gNpcCount++;
102 ASSERT(npc != NULL);
103
105 if (isPeachNpc) {
107 }
108
109 npc->collisionDiameter = 32;
110 npc->collisionHeight = 64;
111 npc->renderMode = 13;
112 npc->blur.any = NULL;
113 npc->yaw = 0.0f;
114 npc->jumpVel = 0.0f;
115 npc->pos.x = 0.0f;
116 npc->pos.y = 0.0f;
117 npc->pos.z = 0.0f;
118 npc->colliderPos.x = 0.0f;
119 npc->colliderPos.y = 0.0f;
120 npc->colliderPos.z = 0.0f;
121 npc->rotPivotOffsetY = 0.0f;
122 npc->rot.x = 0.0f;
123 npc->rot.y = 0.0f;
124 npc->rot.z = 0.0f;
125 npc->homePos.x = 0.0f;
126 npc->homePos.y = 0.0f;
127 npc->homePos.z = 0.0f;
128 npc->unk_96 = 0; // TODO: fix
129 npc->verticalRenderOffset = 0;
130 npc->alpha = 255;
131 npc->hideAlpha = 255;
132 npc->jumpScale = 1.0f;
133 npc->moveSpeed = 4.0f;
134 npc->scale.x = 1.0f;
135 npc->scale.y = 1.0f;
136 npc->scale.z = 1.0f;
137 npc->curAnim = blueprint->initialAnim;
138 npc->animationSpeed = 1.0f;
139 npc->renderYaw = 0.0f;
140 npc->imgfxType = IMGFX_CLEAR;
141 npc->imgfxFlags = 0;
143 npc->isFacingAway = FALSE;
144 npc->yawCamOffset = 0;
146 npc->curFloor = NO_COLLIDER;
147 npc->curWall = NO_COLLIDER;
150 npc->screenSpaceOffset2D[0] = 0.0f;
151 npc->screenSpaceOffset2D[1] = 0.0f;
152 npc->verticalStretch = 1.0f;
153
154 for (j = 0; j < ARRAY_COUNT(npc->decorations); j++) {
155 npc->decorations[j] = 0;
156 npc->decorationType[j] = 0;
157 }
158
159 npc->onUpdate = blueprint->onUpdate;
160 if (npc->onUpdate == NULL) {
162 }
163
164 npc->onRender = blueprint->onRender;
165 if (npc->onRender == NULL) {
167 }
168 if (!isPeachNpc) {
169 npc->extraAnimList = animList;
170 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
171 if (!(npc->flags & NPC_FLAG_PARTNER)) {
172 npc->spriteInstanceID = spr_load_npc_sprite(npc->curAnim, animList);
173 } else {
175 }
176 } else {
178 }
179 }
180
182 npc->shadowScale = 1.0f;
183
186 }
187 return i;
188}
189
191 return create_npc_impl(blueprint, NULL, FALSE);
192}
193
194s32 create_standard_npc(NpcBlueprint* blueprint, AnimID* animList) {
195 return create_npc_impl(blueprint, animList, FALSE);
196}
197
199 return create_npc_impl(blueprint, NULL, TRUE);
200}
201
202void free_npc_by_index(s32 listIndex) {
203 Npc* npc;
204 s32 i;
205
206 listIndex &= ~BATTLE_NPC_ID_BIT;
207
208 npc = (*gCurrentNpcListPtr)[listIndex];
209 if (npc != NULL) {
210 if (npc->flags) {
211 if (npc->blur.any != NULL) {
212 heap_free(npc->blur.any);
213 npc->blur.any = NULL;
214 }
215
216 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
218 }
219
221
222 for (i = 0; i < MAX_NPC_DECORATIONS; i++) {
223 npc_remove_decoration(npc, i);
224 }
225
226 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
227 disable_npc_blur(npc);
228 }
229
230 heap_free((*gCurrentNpcListPtr)[listIndex]);
231 (*gCurrentNpcListPtr)[listIndex] = NULL;
232 gNpcCount--;
233 }
234 }
235}
236
237void free_npc(Npc* npc) {
238 s32 i;
239
240 if (npc->blur.any != NULL) {
241 heap_free(npc->blur.any);
242 npc->blur.any = NULL;
243 }
244
245 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
247 }
248
250
251 for (i = 0; i < MAX_NPC_DECORATIONS; i++) {
252 npc_remove_decoration(npc, i);
253 }
254
255 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
256 disable_npc_blur(npc);
257 }
258
259 heap_free(npc);
260
261 for (i = 0; i < MAX_NPCS; i++) {
262 if ((*gCurrentNpcListPtr)[i] == npc) {
263 break;
264 }
265 }
266
267 (*gCurrentNpcListPtr)[i] = NULL;
268 gNpcCount--;
269}
270
271Npc* get_npc_by_index(s32 listIndex) {
272 return (*gCurrentNpcListPtr)[listIndex & ~BATTLE_NPC_ID_BIT];
273}
274
275// checks for lateral collision with the world directly in front of the NPC and in an X pattern offset 45 degrees from
276// the forward direction. when a collision is detected, the NPC position is adjusted an appropriate NPC flags are set
277// to signal the collision has occurred.
279 f32 testAngle;
280 s32 hit;
281 f32 testX;
282 f32 testY;
283 f32 testZ;
284
287 } else if (
288 (npc->pos.x != npc->colliderPos.x)
289 || (npc->pos.y != npc->colliderPos.y)
290 || (npc->pos.z != npc->colliderPos.z)
292 ) {
293 npc->flags &= ~NPC_FLAG_WORLD_COLLISION_DIRTY;
294 testAngle = clamp_angle(npc->yaw);
295 testX = npc->pos.x;
296 testY = npc->pos.y;
297 testZ = npc->pos.z;
298
299 if (!(npc->flags & NPC_FLAG_PARTNER)) {
300 hit = npc_test_move_simple_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
301 } else {
302 hit = npc_test_move_complex_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
303 }
304
305 if (hit) {
308 npc->pos.x = testX;
309 npc->pos.z = testZ;
310 } else {
312 }
313
314 testAngle = clamp_angle(npc->yaw + 45.0f);
315 testX = npc->pos.x;
316 testY = npc->pos.y;
317 testZ = npc->pos.z;
318
319 if (!(npc->flags & NPC_FLAG_PARTNER)) {
320 hit = npc_test_move_simple_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
321 } else {
322 hit = npc_test_move_taller_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
323 }
324
325 if (hit) {
327 npc->pos.x = testX;
328 npc->pos.z = testZ;
329 } else {
330 npc->flags &= ~NPC_FLAG_COLLDING_WITH_WORLD;
331 }
332
333 testAngle = clamp_angle(npc->yaw - 45.0f);
334 testX = npc->pos.x;
335 testY = npc->pos.y;
336 testZ = npc->pos.z;
337 if (!(npc->flags & NPC_FLAG_PARTNER)) {
338 hit = npc_test_move_simple_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
339 } else {
340 hit = npc_test_move_taller_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight, npc->collisionDiameter);
341 }
342
343 if (hit != 0) {
345 npc->pos.x = testX;
346 npc->pos.z = testZ;
347 } else {
348 npc->flags &= ~NPC_FLAG_COLLDING_WITH_WORLD;
349 }
350
351 if (npc->flags & NPC_FLAG_PARTNER) {
352 testAngle = clamp_angle(npc->yaw + 45.0f + 180.0f);
353 testX = npc->pos.x;
354 testY = npc->pos.y;
355 testZ = npc->pos.z;
356 if (npc_test_move_simple_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight,
357 npc->collisionDiameter) != 0) {
359 npc->pos.x = testX;
360 npc->pos.z = testZ;
361 } else {
362 npc->flags &= ~NPC_FLAG_COLLDING_WITH_WORLD;
363 }
364
365 testAngle = clamp_angle((npc->yaw - 45.0f) + 180.0f);
366 testX = npc->pos.x;
367 testY = npc->pos.y;
368 testZ = npc->pos.z;
369 if (npc_test_move_simple_with_slipping(npc->collisionChannel, &testX, &testY, &testZ, 0, testAngle, npc->collisionHeight,
370 npc->collisionDiameter) != 0) {
372 npc->pos.x = testX;
373 npc->pos.z = testZ;
374 return;
375 }
376 npc->flags &= ~NPC_FLAG_COLLDING_WITH_WORLD;
377 }
378 }
379}
380
382 Npc* otherNpc;
383 f32 angle;
384 f32 thisX, thisY, thisZ;
385 f32 thisBuf;
386 f32 otherX, otherZ;
387 f32 otherBuf;
388 f32 xDiff, zDiff;
389 f32 dist;
390 s32 collision;
391 s32 i;
392
394 npc->flags &= ~NPC_FLAG_COLLIDING_WITH_NPC;
395 thisBuf = npc->collisionDiameter * 0.5f;
396 thisX = npc->pos.x;
397 thisY = npc->pos.y;
398 thisZ = npc->pos.z;
399
400 for (i = 0; i < MAX_NPCS; i++) {
401 otherNpc = get_npc_by_index(i);
402 if (otherNpc != NULL && npc != otherNpc) {
403 if (otherNpc->flags != 0 && !(otherNpc->flags & (NPC_FLAG_SUSPENDED | NPC_FLAG_IGNORE_PLAYER_COLLISION))) {
404 if (!(otherNpc->pos.y + otherNpc->collisionHeight < thisY) &&
405 !(thisY + npc->collisionHeight < otherNpc->pos.y))
406 {
407 otherX = otherNpc->pos.x;
408 xDiff = otherX - thisX;
409 otherZ = otherNpc->pos.z;
410 zDiff = otherZ - thisZ;
411 otherBuf = otherNpc->collisionDiameter * 0.5f;
412 dist = sqrtf(SQ(xDiff) + SQ(zDiff));
413
414 if (!(thisBuf + otherBuf <= dist)) {
415 collision = FALSE;
416 if (npc->flags & NPC_FLAG_PARTNER) {
418 } else if (!(otherNpc->flags & NPC_FLAG_PARTNER) ||
420 {
421 collision = TRUE;
422 }
423
424 if (collision) {
425 angle = DEG_TO_RAD(atan2(otherX, otherZ, thisX, thisZ));
426 dist = (thisBuf + otherBuf) - dist;
427 xDiff = dist * sin_rad(angle);
428 zDiff = -dist * cos_rad(angle);
429 thisX += xDiff * 0.1f;
430 thisZ += zDiff * 0.1f;
431 }
433 }
434 }
435 }
436 }
437 }
438 npc->pos.x = thisX;
439 npc->pos.z = thisZ;
440 }
441}
442
444 PlayerStatus* playerStatus = &gPlayerStatus;
445 f32 playerX, playerZ;
446 f32 playerYaw, yaw;
447 f32 npcX, npcZ;
448 f32 dist, colDist, distToNpc;
449 f32 npcColRadius, playerColRadius;
450 f32 deltaX, deltaZ;
451
453 return FALSE;
454 }
455
456 if (npc->flags & NPC_FLAG_PARTNER) {
457 return FALSE;
458 }
459
460 if (!gNpcPlayerCollisionsEnabled) {
461 return FALSE;
462 }
463
464 if (playerStatus->pos.y + playerStatus->colliderHeight < npc->pos.y) {
465 return FALSE;
466 }
467
468 if (npc->pos.y + npc->collisionHeight < playerStatus->pos.y) {
469 return FALSE;
470 }
471
472 playerX = playerStatus->pos.x;
473 playerZ = playerStatus->pos.z;
474
475 npcColRadius = npc->collisionDiameter / 2;
476 playerColRadius = playerStatus->colliderDiameter / 2;
477
478 npcX = npc->pos.x;
479 npcZ = npc->pos.z;
480
481 deltaX = playerX - npcX;
482 deltaZ = playerZ - npcZ;
483
484 distToNpc = sqrtf(SQ(deltaX) + SQ(deltaZ));
485 colDist = npcColRadius + playerColRadius;
486 if (colDist < distToNpc) {
487 return FALSE;
488 }
489
490 playerStatus->animFlags |= PA_FLAG_NPC_COLLIDED;
491
492 npcX = npc->colliderPos.x;
493 npcZ = npc->colliderPos.z;
494
495 deltaX = playerX - npcX;
496 deltaZ = playerZ - npcZ;
497
498 dist = sqrtf(SQ(deltaX) + SQ(deltaZ));
499 yaw = atan2(playerX, playerZ, npcX, npcZ);
500
501 playerYaw = playerStatus->targetYaw;
502 dist = colDist - dist;
503 deltaX = dist * sin_rad(DEG_TO_RAD(yaw));
504 deltaZ = -dist * cos_rad(DEG_TO_RAD(yaw));
505
506 if (playerStatus->animFlags & PA_FLAG_RIDING_PARTNER) {
507 if (fabsf(get_clamped_angle_diff(yaw, playerYaw)) < 45.0f) {
508 playerStatus->pos.x -= deltaX;
509 playerStatus->pos.z -= deltaZ;
510 wPartnerNpc->pos.x -= deltaX;
511 wPartnerNpc->pos.z -= deltaZ;
512 } else {
513 playerStatus->pos.x -= deltaX * 0.5f;
514 playerStatus->pos.z -= deltaZ * 0.5f;
515 wPartnerNpc->pos.x -= deltaX * 0.5f;
516 wPartnerNpc->pos.z -= deltaZ * 0.5f;
517 }
518 } else {
519 if (playerStatus->flags & (PS_FLAG_JUMPING | PS_FLAG_FALLING)) {
520 playerStatus->pos.x -= deltaX * 0.4f;
521 playerStatus->pos.z -= deltaZ * 0.4f;
522 } else {
523 dist = get_clamped_angle_diff(yaw, playerYaw); // required to match
524 if (fabsf(dist) < 45.0f) {
525 playerStatus->pos.x -= deltaX;
526 playerStatus->pos.z -= deltaZ;
527 } else {
528 playerStatus->pos.x -= deltaX * 0.5f;
529 playerStatus->pos.z -= deltaZ * 0.5f;
530 }
531 }
532 }
533 npc->pos.x = npc->colliderPos.x;
534 npc->pos.y = npc->colliderPos.y;
535 npc->pos.z = npc->colliderPos.z;
536 return TRUE;
537}
538
539// update NPC position using gravitational acceleration = 1.0
540// if the NPC is within 16 units of the floor, they are snapped to it
542 f32 x, y, z, testLength;
543 f32 length;
544 s32 hitID;
545
546 if (!(npc->flags & NPC_FLAG_GRAVITY)) {
547 return;
548 }
549
550 if (npc->flags & NPC_FLAG_JUMPING) {
551 npc->flags &= ~NPC_FLAG_GROUNDED;
552 return;
553 }
554
555 npc->jumpScale = 1.0f;
556 npc->jumpVel -= npc->jumpScale;
557 npc->pos.y += npc->jumpVel;
558
559 x = npc->pos.x;
560 y = npc->pos.y + 13;
561 z = npc->pos.z;
562 testLength = length = fabsf(npc->jumpVel) + 16;
563
564 if (!(npc->flags & NPC_FLAG_PARTNER)) {
565 hitID = npc_raycast_down_sides(npc->collisionChannel, &x, &y, &z, &length);
566 } else {
567 hitID = npc_raycast_down_around(npc->collisionChannel, &x, &y, &z, &length, npc->yaw, npc->collisionDiameter);
568 }
569
570 if (hitID && length <= testLength) {
571 npc->jumpVel = 0.0f;
572 npc->flags |= NPC_FLAG_GROUNDED;
573 npc->pos.y = y;
575 } else {
576 npc->flags &= ~NPC_FLAG_GROUNDED;
577 }
578}
579
580// perform only collision traces and snapping to ground from gravity code
581s32 npc_try_snap_to_ground(Npc* npc, f32 velocity) {
582 f32 x, y, z, testLength;
583 f32 length;
584 s32 hitID;
585
586 if (npc->flags & (NPC_FLAG_GRAVITY | NPC_FLAG_FLYING)) {
587 return FALSE;
588 }
589
590 if (npc->flags & NPC_FLAG_JUMPING) {
591 npc->flags &= ~NPC_FLAG_GROUNDED;
592 return FALSE;
593 }
594
595 length = testLength = fabsf(velocity) + 16;
596 x = npc->pos.x;
597 y = npc->pos.y + 13;
598 z = npc->pos.z;
599
600 if (!(npc->flags & NPC_FLAG_PARTNER)) {
601 hitID = npc_raycast_down_sides(npc->collisionChannel, &x, &y, &z, &length);
602 } else {
603 hitID = npc_raycast_down_around(npc->collisionChannel, &x, &y, &z, &length, npc->yaw, npc->collisionDiameter);
604 }
605
606 if (hitID != 0 && length <= testLength) {
607 npc->pos.y = y;
609 npc->flags |= NPC_FLAG_GROUNDED;
610 return TRUE;
611 }
612
613 npc->flags &= ~NPC_FLAG_GROUNDED;
614 return FALSE;
615}
616
617void update_npcs(void) {
618 PlayerStatus* playerStatus = &gPlayerStatus;
619 f32 x, y, z;
620 f32 hitYaw, hitPitch, hitLength;
621
622 playerStatus->animFlags &= ~PA_FLAG_NPC_COLLIDED;
624 s32 i;
625
626 for (i = 0; i < MAX_NPCS; i++) {
627 Npc* npc = (*gCurrentNpcListPtr)[i];
628
629 if (npc != NULL) {
630 if (npc->flags != 0) {
633 continue;
634 }
635
636 npc->onUpdate(npc);
639 } else {
640 npc->collisionChannel &= ~COLLISION_IGNORE_ENTITIES;
641 }
642
643 npc->curFloor = NO_COLLIDER;
644 npc->curWall = NO_COLLIDER;
646
649 npc_try_snap_to_ground(npc, 0.0f);
652
653 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
654 update_npc_blur(npc);
655 }
656
657 if ((npc->pos.y < -2000.0f) && !(npc->flags & NPC_FLAG_PARTNER)) {
658 npc->pos.y = playerStatus->pos.y;
659 npc->jumpVel = 0.0f;
660 npc->moveSpeed = 0.0f;
661 npc->jumpScale = 0.0f;
662 npc->flags &= ~NPC_FLAG_JUMPING;
663 }
664
665 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
666 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
667 if (npc->curAnim != 0) {
668 if (npc->spriteInstanceID >= 0) {
670 }
671 }
672 }
673 } else {
675 }
676
677 if (npc->flags & NPC_FLAG_HAS_SHADOW) {
678 Shadow* shadow = get_shadow_by_index(npc->shadowIndex);
679 EntityModel* entityModel = get_entity_model(shadow->entityModelID);
680
681 entityModel->flags &= ~ENTITY_MODEL_FLAG_REFLECT;
682 if (npc->flags & NPC_FLAG_REFLECT_WALL) {
683 entityModel->flags |= ENTITY_MODEL_FLAG_REFLECT;
684 }
685
686 x = npc->pos.x;
687 y = npc->pos.y;
688 z = npc->pos.z;
689 if (!(npc->flags & NPC_FLAG_NO_SHADOW_RAYCAST)) {
690 if ( x != npc->colliderPos.x
691 || y != npc->colliderPos.y
692 || z != npc->colliderPos.z
693 || (npc->flags & NPC_FLAG_DIRTY_SHADOW)
694 ) {
695 x = npc->pos.x;
696 y = npc->pos.y + (npc->collisionHeight / 2);
697 z = npc->pos.z;
698 hitLength = 1000.0f;
699 entity_raycast_down(&x, &y, &z, &hitYaw, &hitPitch, &hitLength);
700 set_npc_shadow_scale(shadow, hitLength, npc->collisionDiameter);
701 shadow->pos.x = x;
702 shadow->pos.y = y;
703 shadow->pos.z = z;
704 shadow->rot.x = hitYaw;
705 shadow->rot.y = npc->renderYaw;
706 shadow->rot.z = hitPitch;
707 shadow->scale.x *= npc->shadowScale;
708 npc->flags &= ~NPC_FLAG_DIRTY_SHADOW;
709 }
710 } else {
712 shadow->pos.x = npc->pos.x;
713 shadow->pos.z = npc->pos.z;
714 } else {
715 shadow->pos.x = npc->pos.x;
716 shadow->pos.y = npc->pos.y;
717 shadow->pos.z = npc->pos.z;
718 }
719 }
720 }
721
722 npc->colliderPos.x = npc->pos.x;
723 npc->colliderPos.y = npc->pos.y;
724 npc->colliderPos.z = npc->pos.z;
726
727 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
728 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
729 if (npc->spriteInstanceID < 0) {
730 npc->spriteInstanceID++;
731 if (npc->spriteInstanceID == -1) {
733 ASSERT(npc->spriteInstanceID >= 0);
735 }
736 }
737 }
738 }
739 }
740 }
741 }
742 }
743}
744
746 Camera* camera = &gCameras[gCurrentCamID];
747 f32 cameraYaw;
748 f32 camRelativeYaw;
749 f32 yaw;
750 s32 direction;
751
753 cameraYaw = camera->curYaw;
754 camRelativeYaw = get_clamped_angle_diff(cameraYaw, npc->yaw);
755
756 if (camRelativeYaw < -5.0f && camRelativeYaw > -175.0f) {
757 direction = 0;
758 camRelativeYaw = 0.0f;
759 } else if (camRelativeYaw > 5.0f && camRelativeYaw < 175.0f) {
760 direction = 1;
761 camRelativeYaw = 180.0f;
762 } else {
763 // direction is close to flipping, use saved value
764 direction = 2;
765 camRelativeYaw = npc->yawCamOffset;
766 }
767
768 npc->yawCamOffset = yaw = clamp_angle(camRelativeYaw);
769
771 if (npc->isFacingAway != direction && direction != 2) {
772 npc->isFacingAway = direction;
773
774 if (npc->isFacingAway) {
775 npc->turnAroundYawAdjustment = 180;
776 } else {
777 npc->turnAroundYawAdjustment = -180;
778 }
779
780 if (fabsf(get_clamped_angle_diff(cameraYaw, npc->yaw)) >= 90.0f) {
782 }
783 }
784
785 if (npc->turnAroundYawAdjustment != 0) {
786 if (npc->turnAroundYawAdjustment < 0) {
787 npc->turnAroundYawAdjustment += 20;
788 }
789 if (npc->turnAroundYawAdjustment > 0) {
790 npc->turnAroundYawAdjustment -= 20;
791 }
792 }
793
794 if (npc->flags & NPC_FLAG_FLIP_INSTANTLY) {
796 }
797
798 npc->renderYaw = clamp_angle(clamp_angle(npc->turnAroundYawAdjustment + yaw) - cameraYaw);
799 yaw = npc->renderYaw;
800 } else {
801 yaw = npc->renderYaw;
802 }
803 } else {
804 yaw = npc->renderYaw;
805 }
806 return yaw;
807}
808
809void appendGfx_npc(void* data) {
810 Npc* npc = data;
811 Matrix4f mtx1, mtx2;
812 f32 renderYaw = npc_get_render_yaw(npc);
813
814 guTranslateF(mtx1, npc->pos.x, npc->pos.y + npc->verticalRenderOffset, npc->pos.z);
815 if (npc->flags & NPC_FLAG_UPSIDE_DOWN) {
816 mtx_ident_mirror_y(mtx2);
817 guMtxCatF(mtx2, mtx1, mtx1);
818 }
819
820 if (npc->rotPivotOffsetY != 0.0f) {
821 guTranslateF(mtx2, 0.0f, npc->rotPivotOffsetY, 0.0f);
822 guMtxCatF(mtx2, mtx1, mtx1);
823 }
824
825 if (npc->rot.y != 0.0f) {
826 guRotateF(mtx2, npc->rot.y, 0.0f, 1.0f, 0.0f);
827 guMtxCatF(mtx2, mtx1, mtx1);
828 }
829
830 if (npc->rot.x != 0.0f) {
831 guRotateF(mtx2, npc->rot.x, 1.0f, 0.0f, 0.0f);
832 guMtxCatF(mtx2, mtx1, mtx1);
833 }
834
835 if (npc->rot.z != 0.0f) {
836 guRotateF(mtx2, npc->rot.z, 0.0f, 0.0f, 1.0f);
837 guMtxCatF(mtx2, mtx1, mtx1);
838 }
839
840 if (npc->rotPivotOffsetY != 0.0f) {
841 guTranslateF(mtx2, 0.0f, -npc->rotPivotOffsetY, 0.0f);
842 guMtxCatF(mtx2, mtx1, mtx1);
843 }
844
845 if ((npc->screenSpaceOffset2D[0] != 0.0f) || (npc->screenSpaceOffset2D[1] != 0.0f)) {
846 guTranslateF(mtx1, npc->screenSpaceOffset2D[0], npc->screenSpaceOffset2D[1], 0.0f);
847 guMtxCatF(mtx2, mtx1, mtx1);
848 }
849
850 if (npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f
851 || (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f
852 || npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f
853 ) {
856 guMtxCatF(mtx2, mtx1, mtx1);
857 }
858
859 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
860 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->curAnim != 0) && (npc->spriteInstanceID >= 0)) {
861 npc_draw_with_palswap(npc, renderYaw, mtx1);
863 }
864 } else {
865 npc_draw_with_palswap(npc, renderYaw, mtx1);
867 }
868
869 if (npc->flags & NPC_FLAG_REFLECT_WALL) {
870 guTranslateF(mtx1, npc->pos.x, npc->pos.y + npc->verticalRenderOffset, -npc->pos.z);
871 if (npc->flags & NPC_FLAG_UPSIDE_DOWN) {
872 mtx_ident_mirror_y(mtx2);
873 guMtxCatF(mtx2, mtx1, mtx1);
874 }
875 if ((npc->rot.y != 0.0f) || (npc->rot.x != 0.0f) || (npc->rot.z != 0.0f)) {
876 guRotateRPYF(mtx2, npc->rot.x, npc->rot.y, npc->rot.z);
877 guMtxCatF(mtx2, mtx1, mtx1);
878 }
879
880
881 if (npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f
882 || (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f
883 || npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f
884 ) {
885 guScaleF(mtx2,
889 guMtxCatF(mtx2, mtx1, mtx1);
890
891 }
892
893 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
894 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->curAnim != 0)) {
895 spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
896 }
897 } else {
899 }
900 }
901
902 if (npc->flags & NPC_FLAG_REFLECT_FLOOR) {
903 guTranslateF(mtx1, npc->pos.x, -(npc->pos.y + npc->verticalRenderOffset), npc->pos.z);
904 mtx_ident_mirror_y(mtx2);
905 guMtxCatF(mtx2, mtx1, mtx1);
906
907 if (npc->rot.y != 0.0f || npc->rot.x != 0.0f || npc->rot.z != 0.0f) {
908 guRotateRPYF(mtx2, npc->rot.x, npc->rot.y, npc->rot.z);
909 guMtxCatF(mtx2, mtx1, mtx1);
910 }
911
912 if (npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f
913 || (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f
914 || npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f
915 ) {
916 guScaleF(mtx2,
920 guMtxCatF(mtx2, mtx1, mtx1);
921 }
922 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
923 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->curAnim != 0)) {
924 spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
925 }
926 } else {
928 }
929 }
930 npc->onRender(npc);
931}
932
933void render_npcs(void) {
934 Npc* npc;
935 RenderTask renderTask;
936 RenderTask* renderTaskPtr = &renderTask;
938 f32 x, y, z, s;
939 f32 renderDist;
940 s32 i;
941
942 for (i = 0; i < MAX_NPCS; i++) {
943 Npc* npc = (*gCurrentNpcListPtr)[i];
944 if ((npc != NULL)
945 && (npc->flags != 0)
947 ) {
948 transform_point(cam->mtxPerspective, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &x, &y, &z, &s);
949 if (!(s < 0.01) || !(s > -0.01)) {
950 renderDist = ((z * 5000.0f) / s) + 5000.0f;
951 if (renderDist < 0.0f) {
952 renderDist = 0.0f;
953 } else if (renderDist > 10000.0f) {
954 renderDist = 10000.0f;
955 }
956
957 renderTaskPtr->dist = -renderDist;
958 renderTaskPtr->appendGfxArg = npc;
959 renderTaskPtr->appendGfx = appendGfx_npc;
960 renderTaskPtr->renderMode = npc->renderMode;
961
962 if (npc->flags & NPC_FLAG_HIDING) {
963 u8 r, g, b, a;
964 mdl_get_shroud_tint_params(&r, &g, &b, &a);
965 npc->hideAlpha = 255 - a;
966 } else {
967 npc->hideAlpha = 255;
968 }
969
970 if (npc->hideAlpha != 0) {
971 queue_render_task(renderTaskPtr);
972 }
973
974 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
975 renderTaskPtr->dist = -renderDist;
976 renderTaskPtr->appendGfx = appendGfx_npc_blur;
977 renderTaskPtr->appendGfxArg = npc;
979 queue_render_task(renderTaskPtr);
980 }
981 }
982 }
983 }
984}
985
986void npc_move_heading(Npc* npc, f32 speed, f32 yaw) {
987 f32 angle = DEG_TO_RAD(yaw);
988 f32 sin = sin_rad(angle);
989 f32 cos = cos_rad(angle);
990
991 npc->pos.x += speed * sin;
992 npc->pos.z += -speed * cos;
993}
994
995Npc* get_npc_unsafe(s32 npcID) {
996 s32 i;
997 Npc* npc;
998
999 for (i = 0; i < MAX_NPCS; i++) {
1000 npc = (*gCurrentNpcListPtr)[i];
1001 if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
1002 break;
1003 }
1004 }
1005 ASSERT(i < MAX_NPCS);
1006
1007 return npc;
1008}
1009
1010Npc* get_npc_safe(s32 npcID) {
1011 s32 i;
1012 Npc* npc;
1013
1014 for (i = 0; i < MAX_NPCS; i++) {
1015 npc = (*gCurrentNpcListPtr)[i];
1016 if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
1017 break;
1018 }
1019 }
1020 if (i >= MAX_NPCS) {
1021 return NULL;
1022 }
1023
1024 return npc;
1025}
1026
1028 Shadow* shadow;
1029
1030 if (!(npc->flags & NPC_FLAG_HAS_SHADOW)) {
1031 shadow = get_shadow_by_index(npc->shadowIndex);
1032 shadow->flags &= ~ENTITY_FLAG_HIDDEN;
1034 }
1035}
1036
1038 Shadow* shadow;
1039
1040 if (npc->flags & NPC_FLAG_HAS_SHADOW) {
1041 shadow = get_shadow_by_index(npc->shadowIndex);
1042 shadow->flags |= ENTITY_FLAG_HIDDEN;
1043 npc->flags &= ~NPC_FLAG_HAS_SHADOW;
1044 npc->flags &= ~NPC_FLAG_DIRTY_SHADOW;
1045 }
1046}
1047
1048void set_npc_sprite(Npc* npc, s32 anim, AnimID* extraAnimList) {
1050
1051 npc->extraAnimList = extraAnimList;
1052
1053 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1054 npc->spriteInstanceID = spr_load_npc_sprite(anim, extraAnimList);
1055 ASSERT(npc->spriteInstanceID >= 0);
1056 }
1057
1058 npc->curAnim = anim;
1059
1060 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1061 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1063 }
1064 }
1065}
1066
1068 if (!(npc->flags & NPC_FLAG_MOTION_BLUR)) {
1069 NpcMotionBlur* motionBlur;
1070 s32 i;
1071
1073
1074 motionBlur = heap_malloc(sizeof(*motionBlur));
1075 npc->blur.motion = motionBlur;
1076 ASSERT(motionBlur != NULL);
1077 motionBlur->unused = 0;
1078 motionBlur->index = 0;
1079
1080 for (i = 0; i < ARRAY_COUNT(motionBlur->posX); i++) {
1081 motionBlur->posX[i] = npc->pos.x;
1082 motionBlur->posY[i] = npc->pos.y;
1083 motionBlur->posZ[i] = npc->pos.z;
1084 }
1085 }
1086}
1087
1089 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
1090 npc->flags &= ~NPC_FLAG_MOTION_BLUR;
1091
1092 heap_free(npc->blur.motion);
1093 npc->blur.motion = NULL;
1094 }
1095}
1096
1098 NpcMotionBlur* motionBlur = npc->blur.motion;
1099 s32 index = motionBlur->index;
1100
1101 motionBlur->posX[index] = npc->pos.x;
1102 motionBlur->posY[index] = npc->pos.y;
1103 motionBlur->posZ[index] = npc->pos.z;
1104
1105 index++;
1106 if (index >= 20) {
1107 index = 0;
1108 }
1109
1110 motionBlur->index = index;
1111}
1112
1113void appendGfx_npc_blur(void* data) {
1114 Npc* npc = (Npc*) data;
1115 Matrix4f mtx, tempMtx;
1116 f32 x, y, z;
1117 f32 yaw;
1118 s32 strideIdx;
1119 s32 drawIdx;
1120 s32 bufPos;
1121 NpcMotionBlur* blur;
1122
1123 strideIdx = 0;
1124 drawIdx = 0;
1125 blur = npc->blur.motion;
1126 bufPos = blur->index;
1127
1128 while (TRUE) {
1129 bufPos--;
1130 strideIdx++;
1131
1132 if (bufPos < 0) {
1133 bufPos = NPC_BLUR_FRAMES - 1;
1134 }
1135
1136 if (bufPos == blur->index) {
1137 break;
1138 }
1139
1140 // only draw every third blur frame
1141 if (strideIdx < 3) {
1142 continue;
1143 }
1144
1145 strideIdx = 0;
1146 drawIdx++;
1147
1148 // draw three blur samples
1149 if (drawIdx > 3) {
1150 break;
1151 }
1152
1153 x = blur->posX[bufPos];
1154 y = blur->posY[bufPos];
1155 z = blur->posZ[bufPos];
1156 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ALPHA, 255, 255, 255, 120 - (drawIdx * 20), 0);
1157 yaw = npc->renderYaw;
1158 guTranslateF(mtx, x, y, z);
1159
1160 if (npc->rot.y != 0.0f) {
1161 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1162 guMtxCatF(tempMtx, mtx, mtx);
1163 }
1164 if (npc->rot.x != 0.0f) {
1165 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1166 guMtxCatF(tempMtx, mtx, mtx);
1167 }
1168 if (npc->rot.z != 0.0f) {
1169 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1170 guMtxCatF(tempMtx, mtx, mtx);
1171 }
1172
1173 if ((npc->scale.x * SPRITE_WORLD_SCALE_D) != 1.0
1174 || ((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D) != 1.0
1175 || (npc->scale.z * SPRITE_WORLD_SCALE_D) != 1.0
1176 ) {
1177 guScaleF(
1178 tempMtx,
1182 );
1183 guMtxCatF(tempMtx, mtx, mtx);
1184 }
1185
1186 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1187 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1188 spr_draw_npc_sprite(npc->spriteInstanceID, yaw, 0, 0, mtx);
1189 }
1190 } else {
1192 }
1193 }
1194 npc_imgfx_update(npc);
1195}
1196
1198 gNpcPlayerCollisionsEnabled = TRUE;
1199}
1200
1202 gNpcPlayerCollisionsEnabled = FALSE;
1203}
1204
1205void func_8003B1A8(void) {
1206}
1207
1208void npc_reload_all(void) {
1209 s32 i;
1210 s32 j;
1211
1212 for (i = 0; i < MAX_NPCS; i++) {
1213 Npc* npc = (*gCurrentNpcListPtr)[i];
1214 if (npc != NULL) {
1215 if (npc->flags && !(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1216 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1217 if (!(npc->flags & NPC_FLAG_PARTNER)) {
1219 } else {
1221 }
1222 }
1223 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1224 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->palSwapType != NPC_PAL_ADJUST_NONE)) {
1226 npc->originalPalettesCount = 0;
1227 while (npc->originalPalettesList[npc->originalPalettesCount] != (PAL_PTR) -1) {
1228 npc->originalPalettesCount++;
1229 }
1231 }
1232 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1233 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1234 for (j = 0; j < MAX_NPC_DECORATIONS; j++) {
1236 }
1237 npc_imgfx_update(npc);
1238 }
1239 }
1240 }
1241 }
1242 }
1243 }
1244}
1245
1246void set_npc_yaw(Npc* npc, f32 yaw) {
1247 npc->yaw = yaw;
1248
1249 if (get_clamped_angle_diff(gCameras[gCurrentCameraID].curYaw, yaw) >= 0.0f) {
1250 npc->yawCamOffset = 180;
1251 npc->isFacingAway = TRUE;
1252 } else {
1253 npc->yawCamOffset = 0;
1254 npc->isFacingAway = FALSE;
1255 }
1256}
1257
1258void npc_set_palswap_mode_A(Npc* npc, s32 mode) {
1259 if (npc->palSwapType != mode) {
1260 npc->palSwapPrevType = npc->palSwapType;
1261 npc->palSwapType = mode;
1263 npc->resetPalAdjust = 1;
1264 }
1265}
1266
1267void npc_set_palswap_mode_B(Npc* npc, s32 mode) {
1268 if (npc->palSwapType != mode) {
1269 npc->palSwapPrevType = npc->palSwapType;
1270 npc->palSwapType = mode;
1272 npc->resetPalAdjust = -1;
1273 }
1274}
1275
1279 return;
1280 }
1281 npc->palSwapType = npc->palSwapPrevType;
1284 npc->resetPalAdjust = 1;
1285}
1286
1287void npc_set_palswap_1(Npc* npc, s32 palIndexA, s32 palIndexB, s32 timeHoldA, s32 timeAB) {
1288 npc->blendPalA = palIndexA;
1289 npc->blendPalB = palIndexB;
1290 npc->palswapTimeHoldA = timeHoldA;
1291 npc->palswapTimeAtoB = timeAB;
1292}
1293
1294void npc_set_palswap_2(Npc* npc, s32 timeHoldB, s32 timeBA, s32 palIndexC, s32 palIndexD) {
1295 npc->palswapTimeHoldB = timeHoldB;
1296 npc->palswapTimeBtoA = timeBA;
1297 npc->blendPalC = palIndexC;
1298 npc->blendPalD = palIndexD;
1299}
1300
1301void npc_draw_with_palswap(Npc* npc, s32 yaw, Matrix4f mtx) {
1302 switch (npc->palSwapType) {
1305 break;
1308 break;
1310 npc_render_with_single_pal_blending(npc, yaw, FALSE, mtx);
1311 break;
1313 npc_render_with_single_pal_blending(npc, yaw, TRUE, mtx);
1314 break;
1317 break;
1318 }
1319}
1320
1322 if (npc->resetPalAdjust != 0) {
1323 npc->verticalStretch = 1.0f;
1324 npc->screenSpaceOffset2D[0] = 0.0f;
1325 npc->screenSpaceOffset2D[1] = 0.0f;
1326 npc->resetPalAdjust = 0;
1327 }
1328
1329 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1330 s32 alpha = (npc->alpha * npc->hideAlpha / 255);
1331 u32 mask;
1332 if (alpha < 255) {
1334 } else {
1335 mask = 0;
1336 }
1337 spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, NULL, mtx);
1338 } else {
1340 }
1341}
1342
1344 s32 i, j;
1345 s32 brightness;
1346 PAL_PTR src;
1347 PAL_PTR dst;
1348
1349 if (npc->resetPalAdjust != 0) {
1351 npc->originalPalettesCount = 0;
1352 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1353 npc->originalPalettesCount++;
1354 }
1355
1357 for (i = 0; i < npc->originalPalettesCount; i++) {
1358 dst = npc->copiedPalettes[i];
1359 src = npc->originalPalettesList[i];
1360 if (src != NULL) {
1361 for (j = 0; j < SPR_PAL_SIZE; j++) {
1362 *dst++ = *src++;
1363 }
1364 }
1365 }
1366
1367 npc->palAnimState = -2;
1368 npc->palBlendAlpha = 0;
1369 npc->resetPalAdjust = 0;
1370 npc->nextPalTime = 0;
1371 }
1372
1373 if (npc->nextPalTime == 0) {
1374 npc->palAnimState += 2;
1375 brightness = wWattIdlePalettesAnim[npc->palAnimState];
1376 if (brightness == 255) {
1377 npc->palAnimState = 0;
1378 }
1379 npc->nextPalTime = wWattIdlePalettesAnim[npc->palAnimState + 1] / 2;
1380 }
1381
1382 brightness = wWattIdlePalettesAnim[npc->palAnimState];
1383 npc->nextPalTime--;
1384
1385 switch(brightness) {
1386 case WATT_DEFAULT:
1387 for (i = 0; i < npc->spriteColorVariations; i++) {
1388 dst = npc->copiedPalettes[i];
1389 src = npc->originalPalettesList[i];
1390 if (src != NULL) {
1391 for (j = 0; j < SPR_PAL_SIZE; j++) {
1392 *dst++ = *src++;
1393 }
1394 }
1395 }
1396 break;
1397 case WATT_BRIGHTEST:
1398 for (i = 0; i < npc->spriteColorVariations; i++) {
1399 // use watt's Brightest palettes
1400 dst = npc->copiedPalettes[i];
1401 src = npc->originalPalettesList[npc->spriteColorVariations * SPR_PAL_WorldWatt_Brightest + i];
1402 if (src != NULL) {
1403 for (j = 0; j < SPR_PAL_SIZE; j++) {
1404 *dst++ = *src++;
1405 }
1406 }
1407 }
1408 break;
1409 case WATT_BRIGHTER:
1410 for (i = 0; i < npc->spriteColorVariations; i++) {
1411 // use watt's Brighter palettes
1412 dst = npc->copiedPalettes[i];
1413 src = npc->originalPalettesList[npc->spriteColorVariations * SPR_PAL_WorldWatt_Brighter + i];
1414 if (src != NULL) {
1415 for (j = 0; j < SPR_PAL_SIZE; j++) {
1416 *dst++ = *src++;
1417 }
1418 }
1419 }
1420 break;
1421 }
1422
1423 for (i = 0; i < npc->originalPalettesCount; i++) {
1424 npc->adjustedPalettes[i] = npc->copiedPalettes[i];
1425 }
1426
1427 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1428 s32 alpha = npc->alpha * npc->hideAlpha / 255;
1429 u32 mask = 0;
1430 if (alpha < 255) {
1432 }
1434 spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, npc->adjustedPalettes, mtx);
1435 }
1436 npc->palBlendAlpha--;
1437}
1438
1439u16 npc_blend_palette_colors(u16 colorA, u16 colorB, s32 lerpAlpha) {
1440 u8 r = (UNPACK_PAL_R(colorA) * (255 - lerpAlpha) + UNPACK_PAL_R(colorB) * lerpAlpha) / 255;
1441 u8 g = (UNPACK_PAL_G(colorA) * (255 - lerpAlpha) + UNPACK_PAL_G(colorB) * lerpAlpha) / 255;
1442 u8 b = (UNPACK_PAL_B(colorA) * (255 - lerpAlpha) + UNPACK_PAL_B(colorB) * lerpAlpha) / 255;
1443 u8 a = UNPACK_PAL_A(colorB);
1444
1445 return PACK_PAL_RGBA(r, g, b, a);
1446}
1447
1448s32 npc_render_with_single_pal_blending(Npc* npc, s32 yaw, b32 hasDifferentIntervals, Matrix4f mtx) {
1449 PAL_PTR color1;
1450 PAL_PTR color2;
1451 PAL_PTR outColor;
1452 s32 i, j;
1453 s32 blendAlpha;
1454
1455 // copy palettes from sprite data
1456 if (npc->resetPalAdjust != 0) {
1457 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1459 }
1460
1461 npc->originalPalettesCount = 0;
1462 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1463 npc->originalPalettesCount++;
1464 }
1465
1466 if (npc->resetPalAdjust == 1) {
1468 npc->palBlendAlpha = 0;
1469 } else {
1471 npc->palBlendAlpha = 255;
1472 }
1473
1474 for (i = 0; i < npc->originalPalettesCount; i++) {
1475 color1 = npc->copiedPalettes[i];
1476 color2 = npc->originalPalettesList[i];
1477 npc->adjustedPalettes[i] = color1;
1478 if (color2 != NULL) {
1479 for (j = 0; j < SPR_PAL_SIZE; j++) {
1480 *color1++ = *color2++;
1481 }
1482 }
1483 }
1484
1485 if (!hasDifferentIntervals) {
1488 npc->palswapTimeBtoA = npc->palswapTimeAtoB;
1489 npc->palswapTimeHoldA = 0;
1490 }
1491
1492 npc->nextPalTime = npc->palswapTimeHoldA;
1493 npc->palBlendAlpha = 0;
1495 npc->resetPalAdjust = 0;
1496 }
1497
1498 // blending from A -> B
1499 switch (npc->palAnimState) {
1500 case PAL_SWAP_HOLD_A:
1501 if (npc->nextPalTime != 0) {
1502 npc->nextPalTime--;
1503 break;
1504 } else {
1505 npc->palBlendAlpha = 0;
1507 }
1508 // fallthrough
1509 case PAL_SWAP_A_TO_B:
1510 npc->palBlendAlpha += 25600 / npc->palswapTimeAtoB;
1511 if (npc->palBlendAlpha > 25500) {
1512 npc->palBlendAlpha = 25500;
1513 }
1514 blendAlpha = npc->palBlendAlpha / 100;
1515 // blend two palettes
1516 outColor = npc->copiedPalettes[0];
1517 color2 = npc->originalPalettesList[npc->blendPalA];
1518 color1 = npc->originalPalettesList[npc->blendPalB];
1519 npc->adjustedPalettes[0] = outColor;
1520
1521 for (j = 0; j < SPR_PAL_SIZE; j++) {
1522 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1523 }
1524
1525 if (blendAlpha == 255) {
1527 npc->nextPalTime = npc->palswapTimeHoldB;
1528 }
1529 break;
1530 }
1531
1532 // blending from B -> A
1533 switch (npc->palAnimState) {
1534 case PAL_SWAP_HOLD_B:
1535 if (npc->nextPalTime != 0) {
1536 npc->nextPalTime--;
1537 break;
1538 } else {
1539 npc->palBlendAlpha = 0;
1541 }
1542 // fallthrough
1543 case PAL_SWAP_B_TO_A:
1544 npc->palBlendAlpha += 25600 / npc->palswapTimeBtoA;
1545 if (npc->palBlendAlpha > 25500) {
1546 npc->palBlendAlpha = 25500;
1547 }
1548 blendAlpha = npc->palBlendAlpha / 100;
1549 // blend two palettes
1550 outColor = npc->copiedPalettes[0];
1551 color2 = npc->originalPalettesList[npc->blendPalB];
1552 color1 = npc->originalPalettesList[npc->blendPalA];
1553 npc->adjustedPalettes[0] = outColor;
1554
1555 for (j = 0; j < SPR_PAL_SIZE; j++) {
1556 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1557 }
1558
1559 if (blendAlpha == 255) {
1561 npc->nextPalTime = npc->palswapTimeHoldA;
1562 }
1563 break;
1564 }
1565
1566 switch (npc->palAnimState) {
1567 case PAL_SWAP_HOLD_A:
1568 case PAL_SWAP_A_TO_B:
1569 case PAL_SWAP_HOLD_B:
1570 case PAL_SWAP_B_TO_A:
1571 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1572 u32 mask = 0;
1573 blendAlpha = npc->alpha * npc->hideAlpha / 255;
1574 if (blendAlpha < 255) {
1576 }
1578 spr_draw_npc_sprite(npc->spriteInstanceID | mask, yaw, blendAlpha, npc->adjustedPalettes, mtx);
1579 }
1580 break;
1581 }
1582}
1583
1585 PAL_PTR color1;
1586 PAL_PTR color2;
1587 PAL_PTR outColor;
1588 s32 i, j;
1589 u8 blendAlpha;
1590
1591 // copy palettes from sprite data
1592 if (npc->resetPalAdjust != 0) {
1593 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1595 }
1596
1597 npc->originalPalettesCount = 0;
1598 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1599 npc->originalPalettesCount++;
1600 }
1601
1602 if (npc->resetPalAdjust == 1) {
1604 npc->palBlendAlpha = 0;
1605 } else {
1607 npc->palBlendAlpha = 255;
1608 }
1609
1610 for (i = 0; i < npc->originalPalettesCount; i++) {
1611 color1 = npc->copiedPalettes[i];
1612 color2 = npc->originalPalettesList[i];
1613 npc->adjustedPalettes[i] = color1;
1614 if (color2 != NULL) {
1615 for (j = 0; j < SPR_PAL_SIZE; j++) {
1616 *color1++ = *color2++;
1617 }
1618 }
1619 }
1620
1621 npc->nextPalTime = npc->palswapTimeHoldA;
1622 npc->palBlendAlpha = 0;
1624 npc->resetPalAdjust = 0;
1625 }
1626
1627 // blending from A -> B
1628 switch (npc->palAnimState) {
1629 case PAL_SWAP_HOLD_A:
1630 if (npc->nextPalTime != 0) {
1631 npc->nextPalTime--;
1632 break;
1633 }
1634 npc->palBlendAlpha = 0;
1636 // fallthrough
1637 case PAL_SWAP_A_TO_B:
1638 npc->palBlendAlpha += 25600 / npc->palswapTimeAtoB;
1639 if (npc->palBlendAlpha > 25500) {
1640 npc->palBlendAlpha = 25500;
1641 }
1642 blendAlpha = npc->palBlendAlpha / 100;
1643
1644 // blend first two palettes
1645 outColor = npc->copiedPalettes[0];
1646 color2 = npc->originalPalettesList[npc->blendPalA];
1647 color1 = npc->originalPalettesList[npc->blendPalB];
1648 npc->adjustedPalettes[0] = outColor;
1649
1650 for (j = 0; j < SPR_PAL_SIZE; j++) {
1651 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1652 }
1653
1654 // blend next palettes
1655 outColor = npc->copiedPalettes[3];
1656 color2 = npc->originalPalettesList[npc->blendPalC];
1657 color1 = npc->originalPalettesList[npc->blendPalD];
1658 npc->adjustedPalettes[3] = outColor;
1659
1660 for (j = 0; j < SPR_PAL_SIZE; j++) {
1661 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1662 }
1663
1664 if (blendAlpha == 255) {
1666 npc->nextPalTime = npc->palswapTimeHoldB;
1667 }
1668 break;
1669 }
1670
1671 // blending from B -> A
1672 switch (npc->palAnimState) {
1673 case PAL_SWAP_HOLD_B:
1674 if (npc->nextPalTime != 0) {
1675 npc->nextPalTime--;
1676 break;
1677 } else {
1678 npc->palBlendAlpha = 0;
1680 }
1681 // fallthrough
1682 case PAL_SWAP_B_TO_A:
1683 npc->palBlendAlpha += 25600 / npc->palswapTimeBtoA;
1684 if (npc->palBlendAlpha > 25500) {
1685 npc->palBlendAlpha = 25500;
1686 }
1687 blendAlpha = npc->palBlendAlpha / 100;
1688
1689 // blend first two palettes
1690 outColor = npc->copiedPalettes[0];
1691 color2 = npc->originalPalettesList[npc->blendPalB];
1692 color1 = npc->originalPalettesList[npc->blendPalA];
1693 npc->adjustedPalettes[0] = outColor;
1694
1695 for (j = 0; j < SPR_PAL_SIZE; j++) {
1696 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1697 }
1698
1699 // blend next palettes
1700 outColor = npc->copiedPalettes[1];
1701 color2 = npc->originalPalettesList[npc->blendPalD];
1702 color1 = npc->originalPalettesList[npc->blendPalC];
1703 npc->adjustedPalettes[3] = npc->copiedPalettes[3];
1704
1705 for (j = 0; j < SPR_PAL_SIZE; j++) {
1706 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1707 }
1708
1709 if (blendAlpha == 255) {
1711 npc->nextPalTime = npc->palswapTimeHoldA;
1712 }
1713 break;
1714 }
1715
1716 switch (npc->palAnimState) {
1717 case PAL_SWAP_HOLD_A:
1718 case PAL_SWAP_A_TO_B:
1719 case PAL_SWAP_HOLD_B:
1720 case PAL_SWAP_B_TO_A:
1721 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1722 u32 mask = 0;
1723 blendAlpha = npc->alpha * npc->hideAlpha / 255;
1724 if (blendAlpha < 255) {
1726 }
1728 spr_draw_npc_sprite(npc->spriteInstanceID | mask, yaw, blendAlpha, npc->adjustedPalettes, mtx);
1729 }
1730 break;
1731 }
1732}
1733
1734void npc_set_decoration(Npc* npc, s32 idx, s32 decorationType) {
1735 npc_remove_decoration(npc, idx);
1736 npc->decorationType[idx] = decorationType;
1737 npc->changedDecoration[idx] = 1;
1738 npc->decorationInitialized[idx] = 0;
1739}
1740
1741void npc_remove_decoration(Npc* npc, s32 idx) {
1742 switch (npc->decorationType[idx]) {
1745 break;
1748 break;
1751 break;
1754 break;
1757 break;
1760 break;
1763 break;
1764 }
1766}
1767
1769 s32 i;
1770
1771 for (i = 0; i < MAX_NPC_DECORATIONS; i++) {
1772 switch (npc->decorationType[i]) {
1775 break;
1778 break;
1781 break;
1784 break;
1787 break;
1790 break;
1793 break;
1794 }
1795 }
1796}
1797
1799 switch (npc->decorationType[idx]) {
1806 break;
1808 npc->decorationInitialized[idx] = 0;
1809 break;
1810 }
1811}
1812
1813void npc_update_decoration_none(Npc* npc, s32 idx) {
1814}
1815
1816void npc_remove_decoration_none(Npc* npc, s32 idx) {
1817}
1818
1820 AuraFXData* data;
1821
1822 switch (npc->decorationInitialized[idx]) {
1823 case 0:
1824 fx_aura(FX_AURA_BLUE, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &npc->decorations[idx]);
1825 npc->decorationInitialized[idx] = 1;
1826 // fallthrough
1827 case 1:
1828 data = npc->decorations[idx]->data.aura;
1829 data->posA.x = npc->pos.x;
1830 data->posA.y = npc->pos.y;
1831 data->posA.z = npc->pos.z;
1832 data->scale.x = (npc->scale.x * npc->collisionDiameter) * 0.01;
1833 data->scale.y = (npc->scale.y * npc->collisionHeight) * 0.01;
1834 data->renderYaw = npc->renderYaw;
1835 break;
1836 }
1837}
1838
1840 npc->decorations[idx]->data.aura->fadeTime = 5;
1841}
1842
1844 switch (npc->decorationInitialized[idx]) {
1845 case 0:
1846 if (npc->yawCamOffset > 90) {
1847 fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, 45.0f, 20);
1848 } else {
1849 fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, -45.0f, 20);
1850 }
1851 npc->decorationGlowPhase[idx] = 10;
1852 npc->decorationInitialized[idx] = 1;
1853 break;
1854 case 1:
1855 if (npc->decorationGlowPhase[idx] != 0) {
1856 npc->decorationGlowPhase[idx]--;
1857 } else {
1858 npc->decorationInitialized[idx] = 0;
1859 }
1860 break;
1861 }
1862}
1863
1865}
1866
1868 StarsOrbitingFXData* data;
1869
1870 switch (npc->decorationInitialized[idx]) {
1871 case 0:
1872 fx_stars_orbiting(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 20.0f, 3, &npc->decorations[idx]);
1873 npc->decorationInitialized[idx] = 1;
1874 break;
1875 case 1:
1876 data = npc->decorations[idx]->data.starsOrbiting;
1877 data->pos.x = npc->pos.x;
1878 data->pos.y = npc->pos.y + npc->collisionHeight;
1879 data->pos.z = npc->pos.z;
1880 break;
1881 }
1882}
1883
1885 remove_effect(npc->decorations[idx]);
1886}
1887
1889 EnergyOrbWaveFXData* data;
1890
1891 switch (npc->decorationInitialized[idx]) {
1892 case 0:
1893 npc->decorations[idx] = fx_energy_orb_wave(2, npc->pos.x, npc->pos.y + npc->collisionHeight * 0.5, npc->pos.z, npc->scale.x * 0.8 + 0.2f, -1);
1894 npc->decorationInitialized[idx] = 1;
1895 break;
1896 case 1:
1897 data = npc->decorations[idx]->data.energyOrbWave;
1898 data->pos.x = npc->pos.x;
1899 data->pos.y = npc->pos.y + npc->collisionHeight * 0.5 * npc->scale.x;
1900 data->pos.z = npc->pos.z;
1901 data->scale = npc->scale.x * 0.8 + 0.2f;
1902 break;
1903 }
1904}
1905
1907 remove_effect(npc->decorations[idx]);
1908}
1909
1911 EnergyOrbWaveFXData* data;
1912
1913 switch (npc->decorationInitialized[idx]) {
1914 case 0:
1915 npc->decorations[idx] = fx_energy_orb_wave(2, npc->pos.x, npc->pos.y + npc->collisionHeight * 0.5, npc->pos.z - 5.0f, 1.0f, 0);
1916 npc->decorationInitialized[idx] = 1;
1917 break;
1918 case 1:
1919 data = npc->decorations[idx]->data.energyOrbWave;
1920 data->pos.x = npc->pos.x;
1921 data->pos.y = npc->pos.y + npc->collisionHeight * 0.5;
1922 data->pos.z = npc->pos.z - 5.0f;
1923 data->scale = 1.0f;
1924 break;
1925 }
1926}
1927
1929 remove_effect(npc->decorations[idx]);
1930}
1931
1933 #define RGBA_BUF_SIZE 20
1934 u8 rbuf[RGBA_BUF_SIZE];
1935 u8 gbuf[RGBA_BUF_SIZE];
1936 u8 bbuf[RGBA_BUF_SIZE];
1937 s32 color;
1938 s32 alpha;
1939 s32 i;
1940
1941 if (npc->decorationInitialized[idx] == 0) {
1943 npc->decorationInitialized[idx] = 1;
1944 }
1945 if (npc->decorationInitialized[idx] == 1) {
1946 npc->decorationGlowPhase[idx] += 7;
1947 if (npc->decorationGlowPhase[idx] >= 360) {
1948 npc->decorationGlowPhase[idx] %= 360;
1949 }
1950
1951 for (i = 0; i < RGBA_BUF_SIZE; i++) {
1952 rbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i)) + 1.0) * 80.0f;
1953 gbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i) + 45) + 1.0) * 80.0f;
1954 bbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i) + 90) + 1.0) * 80.0f;
1955 }
1956
1957 alpha = 255;
1958 for (i = 0; i < RGBA_BUF_SIZE; i++) {
1959 color = (rbuf[i] << 24) | (gbuf[i] << 16) | (bbuf[i] << 8) | alpha;
1961 }
1962 }
1963 #undef RGBA_BUF_SIZE
1964}
1965
1967}
1968
1969Npc* npc_find_closest(f32 x, f32 y, f32 z, f32 radius) {
1970 Npc* closestNpc = NULL;
1971 f32 closestDist = radius;
1972 f32 maxDist = radius;
1973 s32 i;
1974
1975 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
1976 Npc* npc = (*gCurrentNpcListPtr)[i];
1977
1978 if (npc != NULL && npc->flags != 0 && !(npc->flags & NPC_FLAG_PARTNER)) {
1979 if (!(npc->flags & (NPC_FLAG_SUSPENDED | NPC_FLAG_INACTIVE))) {
1980 f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
1981
1982 if (distance <= maxDist) {
1983 if (distance < closestDist) {
1984 closestDist = distance;
1985 closestNpc = npc;
1986 }
1987 }
1988 }
1989 }
1990 }
1991
1992 return closestNpc;
1993}
1994
1995Npc* npc_find_closest_simple(f32 x, f32 y, f32 z, f32 radius) {
1996 Npc* closestNpc = NULL;
1997 f32 closestDist = radius;
1998 f32 maxDist = radius;
1999 s32 i;
2000
2001 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
2002 Npc* npc = (*gCurrentNpcListPtr)[i];
2003
2004 if (npc != NULL && npc->flags != 0 && (npc->flags & NPC_FLAG_PARTNER)) {
2005 if (!(npc->flags & (NPC_FLAG_SUSPENDED | NPC_FLAG_INACTIVE))) {
2006 f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
2007
2008 if (distance <= maxDist) {
2009 if (distance < closestDist) {
2010 closestDist = distance;
2011 closestNpc = npc;
2012 }
2013 }
2014 }
2015 }
2016 }
2017
2018 return closestNpc;
2019}
2020
2021s32 npc_find_standing_on_entity(s32 entityIndex) {
2022 s32 idx = entityIndex | COLLISION_WITH_ENTITY_BIT;
2023 s32 y = get_entity_by_index(idx)->pos.y - 10.0f;
2024 Npc* npc;
2025 s32 i;
2026 s32 var_v1;
2027
2028 npc->pos = npc->pos; // TODO required to match
2029
2030 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
2031 npc = (*gCurrentNpcListPtr)[i];
2032
2033 if (npc == NULL) {
2034 continue;
2035 }
2036 if (npc->flags == 0) {
2037 continue;
2038 }
2040 continue;
2041 }
2042 if (npc->flags & NPC_FLAG_PARTNER) {
2043 var_v1 = i; // TODO required to match (dummy if statement to load NPC_FLAG_PARTNER into s5)
2044 }
2045 if (npc->pos.y < y) {
2046 continue;
2047 }
2049 var_v1 = npc_get_collider_below(npc);
2050 if (var_v1 != 0) {
2051 if (idx == var_v1) {
2052 return i;
2053 }
2054 }
2055 } else {
2056 var_v1 = npc->curFloor;
2057 if (npc->curFloor & COLLISION_WITH_ENTITY_BIT) { // TODO required to match (can't use var_v1)
2058 if (idx == var_v1) {
2059 npc->pos = npc->pos; // TODO required to match
2060 return i;
2061 }
2062 }
2063 }
2064 }
2065
2066 return -1;
2067}
2068
2070 f32 x;
2071 f32 y;
2072 f32 z;
2073 f32 yaw;
2074
2075 if (npc->flags & NPC_FLAG_PARTNER) {
2076 y = get_shadow_by_index(npc->shadowIndex)->pos.y + 13.0f;
2077 } else {
2078 y = npc->pos.y + 13.0f;
2079 }
2080
2081 yaw = 16.0f;
2082 x = npc->pos.x;
2083 z = npc->pos.z;
2084
2086 if (yaw <= 16.0f) {
2087 return NpcHitQueryColliderID;
2088 }
2089 }
2090 return 0;
2091}
2092
2094 s32 imgfxType = npc->imgfxType;
2095 s32 imgfxArg1 = npc->imgfxArg1;
2096 s32 imgfxArg2 = npc->imgfxArg2;
2097 s32 imgfxArg3 = npc->imgfxArg3;
2098 s32 imgfxArg4 = npc->imgfxArg4;
2099 s32 imgfxFlags = npc->imgfxFlags;
2100
2101 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_CLEAR, 0, 0, 0, 0, 0);
2102
2103 switch (imgfxType) {
2104 case IMGFX_CLEAR:
2106 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_CLEAR, 0, 0, 0, 0, imgfxFlags);
2107 break;
2108 case IMGFX_UNK_2:
2109 case IMGFX_RESET:
2111 // fallthrough
2112 case IMGFX_UNK_1:
2113 set_npc_imgfx_all(npc->spriteInstanceID, imgfxType, 0, 0, 0, 0, imgfxFlags);
2114 break;
2115 case IMGFX_SET_WAVY:
2117 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_WAVY, imgfxArg1, imgfxArg2, imgfxArg3, 0, imgfxFlags);
2118 break;
2119 case IMGFX_SET_COLOR:
2121 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_COLOR, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2122 break;
2123 case IMGFX_SET_ALPHA:
2125 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ALPHA, 255, 255, 255, imgfxArg1, imgfxFlags);
2126 break;
2127 case IMGFX_SET_TINT:
2129 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_TINT, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2130 break;
2133 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_WHITE_FADE, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2134 break;
2137 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_CREDITS_FADE, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2138 break;
2139 case IMGFX_SET_ANIM:
2141 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ANIM, imgfxArg1, imgfxArg2, imgfxArg3, 0, imgfxFlags);
2142 break;
2143 case IMGFX_HOLOGRAM:
2145 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_HOLOGRAM, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2146 break;
2147 case IMGFX_FILL_COLOR:
2149 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_FILL_COLOR, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2150 break;
2151 case IMGFX_OVERLAY:
2153 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_OVERLAY, imgfxArg1, 255, 0, 255, imgfxFlags);
2154 break;
2155 case IMGFX_OVERLAY_XLU:
2157 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_OVERLAY, imgfxArg1, imgfxArg2, 0, imgfxArg2, imgfxFlags);
2158 break;
2159 }
2160}
2161
2162void npc_set_imgfx_params(Npc* npc, s32 imgfxType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6) {
2163 npc->imgfxType = imgfxType;
2164 npc->imgfxArg1 = arg2;
2165 npc->imgfxArg2 = arg3;
2166 npc->imgfxArg3 = arg4;
2167 npc->imgfxArg4 = arg5;
2168 npc->imgfxFlags = arg6;
2169 npc_imgfx_update(npc);
2170}
2171
2172void COPY_set_defeated(s32 mapID, s32 encounterID) {
2173 EncounterStatus* currentEncounter = &gCurrentEncounter;
2174 s32 encounterIdx = encounterID / 32;
2175 s32 encounterShift;
2176 s32 flag;
2177
2178 flag = encounterID % 32;
2179 encounterShift = flag;
2180 flag = currentEncounter->defeatFlags[mapID][encounterIdx];
2181 currentEncounter->defeatFlags[mapID][encounterIdx] = flag | (1 << encounterShift);
2182
2183 // TODO: The below should work but has regalloc issues:
2184 /*EncounterStatus *currentEncounter = &gCurrentEncounter;
2185 s32 encounterIdx = encounterID / 32;
2186 s32 encounterShift = encounterID % 32;
2187
2188 currentEncounter->defeatFlags[mapID][encounterIdx] |= (1 << encounterShift);*/
2189}
2190
2192 EncounterStatus* currentEncounter = &gCurrentEncounter;
2193 s32 i;
2194 s32 j;
2195
2196 for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
2197 currentEncounter->encounterList[i] = 0;
2198 }
2199
2200 currentEncounter->flags = ENCOUNTER_FLAG_NONE;
2201 currentEncounter->numEncounters = 0;
2202 currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
2203 currentEncounter->hitType = 0;
2204 currentEncounter->battleTriggerCooldown = 0;
2205 currentEncounter->npcGroupList = 0;
2206 currentEncounter->unk_08 = 0;
2207 currentEncounter->dropWhackaBump = FALSE;
2208
2209 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2210 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2211 currentEncounter->defeatFlags[i][j] = 0;
2212 }
2213 }
2214
2215 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2216 currentEncounter->recentMaps[i] = -1;
2217 }
2218
2219 func_80045AC0();
2222}
2223
2225 EncounterStatus* currentEncounter = &gCurrentEncounter;
2226 s32 i;
2227 s32 j;
2228
2229 for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
2230 currentEncounter->encounterList[i] = 0;
2231 }
2232
2234 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2235 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2236 currentEncounter->defeatFlags[i][j] = 0;
2237 }
2238 }
2239
2241 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2242 currentEncounter->recentMaps[i] = -1;
2243 }
2244 }
2245 }
2246
2247 currentEncounter->numEncounters = 0;
2248 currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
2249 currentEncounter->hitType = 0;
2250 currentEncounter->battleTriggerCooldown = 0;
2251 currentEncounter->curAreaIndex = gGameStatusPtr->areaID;
2252 currentEncounter->curMapIndex = gGameStatusPtr->mapID;
2253 currentEncounter->curEntryIndex = gGameStatusPtr->entryID;
2254 currentEncounter->npcGroupList = 0;
2255 currentEncounter->unk_08 = 0;
2256 currentEncounter->scriptedBattle = FALSE;
2257
2258 func_80045AC0();
2261}
2262
2263void func_8003E50C(void) {
2264}
2265
2266void func_8003E514(s8 arg0) {
2268}
2269
2271 switch (gEncounterState) {
2273 break;
2276 break;
2279 break;
2282 break;
2285 break;
2288 break;
2289 }
2290
2292}
2293
2295 switch (gEncounterState) {
2297 break;
2300 break;
2303 break;
2306 break;
2309 break;
2312 break;
2313 }
2314
2316}
2317
2319 switch (gEncounterState) {
2321 break;
2324 break;
2325 }
2326}
2327
2330
2331void make_npcs(s32 flags, s32 mapID, s32* npcGroupList) {
2332 EncounterStatus* currentEncounter = &gCurrentEncounter;
2333 s32 i;
2334 s32 j;
2335
2336 currentEncounter->resetMapEncounterFlags = flags;
2337 currentEncounter->mapID = mapID;
2338 currentEncounter->npcGroupList = npcGroupList;
2339
2341 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2342 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2343 currentEncounter->defeatFlags[i][j] = 0;
2344 }
2345 }
2346
2348 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2349 currentEncounter->recentMaps[i] = -1;
2350 }
2351 }
2352 }
2353
2354 if (npcGroupList != NULL) {
2356 EncounterStateChanged = TRUE;
2358 }
2359}
2360
2363 s32 i;
2364
2365 for (i = 0; i < encounter->count; i++) {
2366 Enemy* currentEnemy = encounter->enemy[i];
2367 if (currentEnemy != NULL) {
2368 kill_enemy(currentEnemy);
2369 encounter->enemy[i] = NULL;
2370 }
2371 }
2372}
2373
2374void kill_enemy(Enemy* enemy) {
2375 EncounterStatus* encounterStatus = &gCurrentEncounter;
2376 Encounter* encounter = encounterStatus->encounterList[enemy->encounterIndex];
2377 s32 i;
2378 s32 j;
2379
2380 for (i = 0; i < encounter->count; i++) {
2381 Enemy* currentEnemy = encounter->enemy[i];
2382 if (currentEnemy == enemy) {
2383 break;
2384 }
2385 }
2386
2387 if (enemy->initScript != NULL) {
2389 }
2390 if (enemy->interactScript != NULL) {
2392 }
2393 if (enemy->aiScript != NULL) {
2395 }
2396 if (enemy->hitScript != NULL) {
2398 }
2399 if (enemy->auxScript != NULL) {
2401 }
2402 if (enemy->defeatScript != NULL) {
2404 }
2405
2406 enemy->interactBytecode = NULL;
2407 enemy->aiBytecode = NULL;
2408 enemy->hitBytecode = NULL;
2409 enemy->auxBytecode = NULL;
2410 enemy->defeatBytecode = NULL;
2411
2412 #if DX_DEBUG_MENU
2413 if (enemy->npcID != (s16) DX_DEBUG_DUMMY_ID) {
2414 free_npc(get_npc_unsafe(enemy->npcID));
2415 }
2416 #else
2417 free_npc(get_npc_unsafe(enemy->npcID));
2418 #endif
2419
2420 if (enemy->unk_64 != NULL) {
2421 heap_free(enemy->unk_64);
2422 }
2423
2424 for (j = 0; j < ARRAY_COUNT(encounter->enemy); j++) {
2425 if (encounter->enemy[j] == enemy) {
2426 encounter->enemy[j] = NULL;
2427 }
2428 }
2429
2430 if (!(enemy->flags & ENEMY_FLAG_DO_NOT_KILL)
2431 && (!(enemy->flags & ENEMY_FLAG_ENABLE_HIT_SCRIPT) || (enemy == encounterStatus->curEnemy))
2432 && !(enemy->flags & ENEMY_FLAG_PASSIVE)
2433 && !(enemy->flags & ENEMY_FLAG_FLED)
2434 ) {
2435 COPY_set_defeated(encounterStatus->mapID, encounter->encounterID + i);
2436 }
2437
2438 heap_free(enemy);
2439}
2440
2441s32 bind_enemy_ai(Enemy* enemy, EvtScript* aiScriptBytecode) {
2442 Evt* aiScript;
2443 s32 id;
2444
2445 if (enemy->aiScript != NULL) {
2446 kill_script_by_ID(enemy->aiScript->id);
2447 }
2448 enemy->aiBytecode = aiScriptBytecode;
2449 aiScript = enemy->aiScript = start_script(aiScriptBytecode, EVT_PRIORITY_A, 0);
2450 id = enemy->aiScriptID = aiScript->id;
2451 aiScript->owner1.enemy = enemy;
2452 return id;
2453}
2454
2455s32 bind_enemy_aux(Enemy* enemy, EvtScript* auxScriptBytecode) {
2456 Evt* auxScript;
2457 s32 id;
2458
2459 if (enemy->auxScript != NULL) {
2461 }
2462 enemy->auxBytecode = auxScriptBytecode;
2463 auxScript = enemy->auxScript = start_script(auxScriptBytecode, EVT_PRIORITY_A, 0);
2464 id = enemy->auxScriptID = auxScript->id;
2465 auxScript->owner1.enemy = enemy;
2466 return id;
2467}
2468
2469s32 bind_enemy_interact(Enemy* enemy, EvtScript* interactScriptBytecode) {
2470 Evt* interactScript;
2471 s32 id;
2472
2473 if (enemy->interactScript != NULL) {
2475 }
2476 enemy->interactBytecode = interactScriptBytecode;
2477 interactScript = enemy->interactScript = start_script(interactScriptBytecode, EVT_PRIORITY_A, 0);
2478 id = enemy->interactScriptID = interactScript->id;
2479 interactScript->owner1.enemy = enemy;
2480 return id;
2481}
2482
2483void bind_npc_ai(s32 npcID, EvtScript* npcAiBytecode) {
2484 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2485 s32 i;
2486 s32 j;
2487
2488 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2489 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2490 if (currentEncounter != NULL) {
2491 for (j = 0; j < currentEncounter->count; j++) {
2492 Enemy* currentEnemy = currentEncounter->enemy[j];
2493 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2494 bind_enemy_ai(currentEnemy, npcAiBytecode);
2495 break;
2496 }
2497 }
2498 }
2499 }
2500}
2501
2502void bind_npc_aux(s32 npcID, EvtScript* npcAuxBytecode) {
2503 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2504 s32 i;
2505 s32 j;
2506
2507 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2508 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2509 if (currentEncounter != NULL) {
2510 for (j = 0; j < currentEncounter->count; j++) {
2511 Enemy* currentEnemy = currentEncounter->enemy[j];
2512 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2513 bind_enemy_aux(currentEnemy, npcAuxBytecode);
2514 break;
2515 }
2516 }
2517 }
2518 }
2519}
2520
2521void bind_npc_interact(s32 npcID, EvtScript* npcInteractBytecode) {
2522 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2523 s32 i;
2524 s32 j;
2525
2526 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2527 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2528 if (currentEncounter != NULL) {
2529 for (j = 0; j < currentEncounter->count; j++) {
2530 Enemy* currentEnemy = currentEncounter->enemy[j];
2531 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2532 bind_enemy_interact(currentEnemy, npcInteractBytecode);
2533 break;
2534 }
2535 }
2536 }
2537 }
2538}
2539
2540Enemy* get_enemy(s32 npcID) {
2541 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2542 s32 i;
2543 s32 j;
2544
2545 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2546 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2547 if (currentEncounter != NULL) {
2548 for (j = 0; j < currentEncounter->count; j++) {
2549 Enemy* currentEnemy = currentEncounter->enemy[j];
2550 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2551 return currentEnemy;
2552 }
2553 }
2554 }
2555 }
2556 PANIC();
2557}
2558
2560 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2561 s32 i;
2562 s32 j;
2563
2564 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2565 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2566
2567 if (currentEncounter != NULL) {
2568 for (j = 0; j < currentEncounter->count; j++) {
2569 Enemy* currentEnemy = currentEncounter->enemy[j];
2570 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2571 return currentEnemy;
2572 }
2573 }
2574 }
2575 }
2576 return NULL;
2577}
PalSwapState
Npc * NpcList[64]
#define MAX_NPC_DECORATIONS
#define NPC_BLUR_FRAMES
s16 entityModelID
#define PAL_PTR
s32 b32
f32 Matrix4f[4][4]
union Evt::@8 owner1
Initially -1.
Vec3f scale
Bytecode EvtScript[]
s8 b8
u32 AnimID
s8 index
Current blur ring buffer index.
Ring buffer of an NPC's position over the past 20 frames.
s8 flags
Definition demo_api.c:15
#define transform_point
#define guRotateF
#define queue_render_task
#define sqrtf
#define npc_raycast_down_sides
#define guTranslateF
#define guMtxCatF
#define remove_effect
#define clamp_angle
#define mdl_get_shroud_tint_params
#define atan2
#define guScaleF
f32 renderYaw
Definition effects.h:1013
s32 fadeTime
Definition effects.h:999
Vec2f scale
Definition effects.h:996
Vec3f posA
Definition effects.h:994
struct StarsOrbitingFXData * starsOrbiting
Definition effects.h:2511
@ FX_AURA_BLUE
Definition effects.h:988
struct AuraFXData * aura
Definition effects.h:2523
struct EnergyOrbWaveFXData * energyOrbWave
Definition effects.h:2546
EffectData data
Definition effects.h:2605
#define ASSERT(condition)
EntityModel * get_entity_model(s32 idx)
@ ENTITY_MODEL_FLAG_REFLECT
Definition enums.h:5019
@ IMGFX_SET_ALPHA
Definition enums.h:5124
@ IMGFX_RESET
Definition enums.h:5120
@ IMGFX_HOLOGRAM
Definition enums.h:5130
@ IMGFX_SET_COLOR
Definition enums.h:5123
@ IMGFX_OVERLAY_XLU
Definition enums.h:5133
@ IMGFX_OVERLAY
Definition enums.h:5132
@ IMGFX_CLEAR
Definition enums.h:5117
@ IMGFX_SET_WAVY
Definition enums.h:5121
@ IMGFX_ALLOC_COLOR_BUF
Definition enums.h:5134
@ IMGFX_FILL_COLOR
Definition enums.h:5131
@ IMGFX_COLOR_BUF_SET_MODULATE
Definition enums.h:5129
@ IMGFX_SET_CREDITS_FADE
Definition enums.h:5127
@ IMGFX_SET_TINT
Definition enums.h:5125
@ IMGFX_SET_WHITE_FADE
Definition enums.h:5126
@ IMGFX_SET_ANIM
Definition enums.h:5122
@ IMGFX_UNK_2
Definition enums.h:5119
@ IMGFX_UNK_1
Definition enums.h:5118
@ NPC_DECORATION_WHITE_GLOW_BEHIND
Definition enums.h:1923
@ NPC_DECORATION_BOWSER_AURA
Definition enums.h:1919
@ NPC_DECORATION_CHARGED
Definition enums.h:1924
@ NPC_DECORATION_SWEAT
Definition enums.h:1920
@ NPC_DECORATION_NONE
Definition enums.h:1918
@ NPC_DECORATION_WHITE_GLOW_FRONT
Definition enums.h:1922
@ NPC_DECORATION_SEEING_STARS
Definition enums.h:1921
@ NPC_PAL_ADJUST_NONE
Definition enums.h:1928
@ NPC_PAL_ADJUST_BLEND_DOUBLE_PALETTES
Definition enums.h:1932
@ NPC_PAL_ADJUST_BLEND_PALETTES_UNIFORM_INTERVALS
Definition enums.h:1930
@ NPC_PAL_ADJUST_BLEND_PALETTES_VARYING_INTERVALS
Definition enums.h:1931
@ NPC_PAL_ADJUST_WATT_IDLE
Definition enums.h:1929
@ ENCOUNTER_FLAG_NONE
Definition enums.h:4986
@ SHADOW_VARYING_CIRCLE
Definition enums.h:2535
@ PS_FLAG_FALLING
Definition enums.h:3036
@ PS_FLAG_JUMPING
Definition enums.h:3035
@ PARTNER_ACTION_NONE
Definition enums.h:2932
@ ENEMY_FLAG_DO_NOT_KILL
Definition enums.h:4523
@ ENEMY_FLAG_PASSIVE
Definition enums.h:4521
@ ENEMY_FLAG_FLED
Definition enums.h:4525
@ ENEMY_FLAG_ENABLE_HIT_SCRIPT
Definition enums.h:4524
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4696
@ COLLIDER_FLAG_IGNORE_SHELL
Definition enums.h:4695
@ COLLISION_IGNORE_ENTITIES
Definition enums.h:4698
@ COLLIDER_FLAG_IGNORE_NPC
Definition enums.h:4697
@ PA_FLAG_NPC_COLLIDED
Definition enums.h:3106
@ PA_FLAG_RIDING_PARTNER
Definition enums.h:3116
@ CONTEXT_WORLD
Definition enums.h:3529
@ RENDER_MODE_SURFACE_XLU_LAYER2
Definition enums.h:3287
@ RENDER_MODE_ALPHATEST
Definition enums.h:3276
@ RENDER_MODE_SURFACE_XLU_LAYER1
Definition enums.h:3282
@ ENTITY_FLAG_HIDDEN
Definition enums.h:2613
@ ENCOUNTER_STATE_POST_BATTLE
Definition enums.h:6299
@ ENCOUNTER_STATE_CONVERSATION
Definition enums.h:6298
@ ENCOUNTER_STATE_NEUTRAL
Definition enums.h:6296
@ ENCOUNTER_STATE_NONE
Definition enums.h:6294
@ ENCOUNTER_STATE_PRE_BATTLE
Definition enums.h:6297
@ ENCOUNTER_STATE_CREATE
Definition enums.h:6295
@ FIRST_STRIKE_NONE
Definition enums.h:3458
@ GLOBAL_OVERRIDES_800
Definition enums.h:4330
@ GLOBAL_OVERRIDES_PREV_400
Definition enums.h:4333
@ GLOBAL_OVERRIDES_400
Definition enums.h:4329
@ GLOBAL_OVERRIDES_PREV_800
Definition enums.h:4334
@ ENCOUNTER_SUBSTATE_CREATE_INIT
Definition enums.h:6303
@ NPC_FLAG_IGNORE_ENTITY_COLLISION
Definition enums.h:3013
@ NPC_FLAG_WORLD_COLLISION_DIRTY
Definition enums.h:3025
@ NPC_FLAG_FLYING
Definition enums.h:3001
@ NPC_FLAG_HAS_NO_SPRITE
Definition enums.h:3022
@ NPC_FLAG_HAS_SHADOW
Definition enums.h:3002
@ NPC_FLAG_SUSPENDED
Definition enums.h:3029
@ NPC_FLAG_ENABLED
Definition enums.h:2998
@ NPC_FLAG_REFLECT_WALL
Definition enums.h:3015
@ NPC_FLAG_JUMPING
Definition enums.h:3009
@ NPC_FLAG_MOTION_BLUR
Definition enums.h:3018
@ NPC_FLAG_TOUCHES_GROUND
Definition enums.h:3020
@ NPC_FLAG_IGNORE_WORLD_COLLISION
Definition enums.h:3004
@ NPC_FLAG_INACTIVE
Definition enums.h:3000
@ NPC_FLAG_IGNORE_PLAYER_COLLISION
Definition enums.h:3006
@ NPC_FLAG_COLLDING_FORWARD_WITH_WORLD
Definition enums.h:3012
@ NPC_FLAG_UPSIDE_DOWN
Definition enums.h:3005
@ NPC_FLAG_FLIP_INSTANTLY
Definition enums.h:3019
@ NPC_FLAG_COLLIDING_WITH_NPC
Definition enums.h:3023
@ NPC_FLAG_DIRTY_SHADOW
Definition enums.h:3014
@ NPC_FLAG_GRAVITY
Definition enums.h:3007
@ NPC_FLAG_PARTNER
Definition enums.h:3024
@ NPC_FLAG_INVISIBLE
Definition enums.h:2999
@ NPC_FLAG_NO_SHADOW_RAYCAST
Definition enums.h:3003
@ NPC_FLAG_HIDING
Definition enums.h:3021
@ NPC_FLAG_GROUNDED
Definition enums.h:3010
@ NPC_FLAG_IGNORE_CAMERA_FOR_YAW
Definition enums.h:3016
@ NPC_FLAG_COLLDING_WITH_WORLD
Definition enums.h:3011
@ NPC_FLAG_DONT_UPDATE_SHADOW_Y
Definition enums.h:3008
@ NPC_FLAG_NO_ANIMS_LOADED
Definition enums.h:3028
@ NPC_FLAG_REFLECT_FLOOR
Definition enums.h:3017
@ EVT_PRIORITY_A
Definition evt.h:153
void create_encounters(void)
Definition encounter.c:2461
void update_encounters_conversation(void)
Definition encounter.c:2263
s32 create_worker_world(WorldArgs, WorldArgs)
b32 entity_raycast_down(f32 *, f32 *, f32 *, f32 *, f32 *, f32 *)
Mostly used for shadows.
Definition entity.c:1637
Entity * get_entity_by_index(s32 index)
Definition entity.c:530
void update_encounters_neutral(void)
Definition encounter.c:481
f32 fabsf(f32 f)
b32 npc_raycast_down_around(s32, f32 *, f32 *, f32 *, f32 *, f32, f32)
void show_first_strike_message(void)
Definition encounter.c:1563
void update_encounters_post_battle(void)
Definition encounter.c:1619
s32 npc_test_move_complex_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
Shadow * get_shadow_by_index(s32 index)
Definition entity.c:534
void init_encounters_ui(void)
Definition encounter.c:2815
void func_80045AC0(void)
f32 cosine(s16 arg0)
Definition 43F0.c:354
f32 cos_rad(f32 x)
Definition 43F0.c:717
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:670
void update_encounters_pre_battle(void)
Definition encounter.c:1261
s32 heap_free(void *ptr)
Definition heap.c:42
b32 npc_test_move_simple_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
Evt * start_script(EvtScript *source, s32 priority, s32 initialState)
b32 npc_test_move_taller_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
void draw_encounters_pre_battle(void)
Definition encounter.c:1487
void kill_script_by_ID(s32 id)
s32 create_shadow_type(s32 type, f32 x, f32 y, f32 z)
Definition entity.c:1528
void draw_merlee_messages(void)
void draw_encounters_conversation(void)
Definition encounter.c:2319
void update_merlee_messages(void)
void draw_encounters_neutral(void)
Definition encounter.c:1258
f32 sin_rad(f32 x)
Definition 43F0.c:713
void draw_encounters_post_battle(void)
Definition encounter.c:2253
void delete_shadow(s32)
Definition entity.c:626
void set_npc_shadow_scale(Shadow *shadow, f32 height, f32 npcRadius)
Definition entity.c:1687
f32 get_clamped_angle_diff(f32, f32)
Definition 43F0.c:606
void * heap_malloc(s32 size)
Definition heap.c:34
void npc_render_without_adjusted_palettes(Npc *npc, s32 arg1, Matrix4f mtx)
Definition npc.c:1321
void STUB_npc_callback(Npc *npc)
The default Npc::onUpdate and Npc::onRender callback.
Definition npc.c:49
s32 npc_try_snap_to_ground(Npc *npc, f32 velocity)
Definition npc.c:581
void npc_update_decoration_charged(Npc *npc, s32 idx)
Definition npc.c:1932
void free_npc(Npc *npc)
Definition npc.c:237
s32 create_basic_npc(NpcBlueprint *blueprint)
Definition npc.c:190
void npc_update_decoration_seeing_stars(Npc *npc, s32 idx)
Definition npc.c:1867
void npc_remove_decoration_glow_in_front(Npc *npc, s32 idx)
Definition npc.c:1906
void npc_imgfx_update(Npc *npc)
Definition npc.c:2093
s32 npc_render_with_single_pal_blending(Npc *npc, s32 yaw, b32 hasDifferentIntervals, Matrix4f mtx)
Definition npc.c:1448
void disable_npc_blur(Npc *npc)
Definition npc.c:1088
@ WATT_BRIGHTER
Definition npc.c:29
@ WATT_DEFAULT
Definition npc.c:27
@ WATT_BRIGHTEST
Definition npc.c:28
s32 create_npc_impl(NpcBlueprint *blueprint, AnimID *animList, s32 isPeachNpc)
Definition npc.c:88
s32 bind_enemy_ai(Enemy *enemy, EvtScript *aiScriptBytecode)
Binds the specified ai script to the specified enemy.
Definition npc.c:2441
void npc_reload_all(void)
Definition npc.c:1208
s32 bind_enemy_aux(Enemy *enemy, EvtScript *auxScriptBytecode)
Binds the specified auxillary script to the specified enemy.
Definition npc.c:2455
s32 npc_render_with_watt_idle_palettes(Npc *npc, s32 arg1, Matrix4f mtx)
Definition npc.c:1343
void appendGfx_npc_blur(void *data)
Definition npc.c:1113
Enemy * get_enemy_safe(s32 npcID)
Same as get_enemy(), with the exception of always returning a value if an enemy is not found.
Definition npc.c:2559
s32 npc_find_standing_on_entity(s32 entityIndex)
Definition npc.c:2021
void npc_set_imgfx_params(Npc *npc, s32 imgfxType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6)
Definition npc.c:2162
void npc_remove_decoration_sweat(Npc *npc, s32 idx)
Definition npc.c:1864
void kill_enemy(Enemy *enemy)
Definition npc.c:2374
Enemy * get_enemy(s32 npcID)
Looks for an enemy matching the specified npcID.
Definition npc.c:2540
void npc_do_other_npc_collision(Npc *npc)
Definition npc.c:381
void func_8003E50C(void)
Definition npc.c:2263
void bind_npc_ai(s32 npcID, EvtScript *npcAiBytecode)
Binds the specified ai script to the npc matching the specified npcId.
Definition npc.c:2483
#define RGBA_BUF_SIZE
void npc_disable_collisions(void)
Definition npc.c:1201
void npc_set_palswap_1(Npc *npc, s32 palIndexA, s32 palIndexB, s32 timeHoldA, s32 timeAB)
Definition npc.c:1287
u8 wWattIdlePalettesAnim[]
Definition npc.c:32
void enable_npc_shadow(Npc *npc)
Definition npc.c:1027
void npc_remove_decoration_bowser_aura(Npc *npc, s32 idx)
Definition npc.c:1839
s32 npc_render_with_double_pal_blending(Npc *npc, s32 yaw, Matrix4f mtx)
Definition npc.c:1584
s32 create_peach_npc(NpcBlueprint *blueprint)
Definition npc.c:198
void npc_try_apply_gravity(Npc *npc)
Definition npc.c:541
void update_encounters(void)
Definition npc.c:2270
Npc * npc_find_closest_simple(f32 x, f32 y, f32 z, f32 radius)
Finds the closest simple-hitbox NPC to a given point within a radius.
Definition npc.c:1995
void enable_npc_blur(Npc *npc)
Definition npc.c:1067
@ PAL_SWAP_HOLD_A
Definition npc.c:19
@ PAL_SWAP_HOLD_B
Definition npc.c:21
@ PAL_SWAP_B_TO_A
Definition npc.c:22
@ PAL_SWAP_A_TO_B
Definition npc.c:20
s32 create_standard_npc(NpcBlueprint *blueprint, AnimID *animList)
Definition npc.c:194
void init_npc_list(void)
Points the current NPC list to the world or battle lists depending on game state.
Definition npc.c:77
void disable_npc_shadow(Npc *npc)
Definition npc.c:1037
void npc_draw_with_palswap(Npc *npc, s32 yaw, Matrix4f mtx)
Definition npc.c:1301
void free_npc_by_index(s32 listIndex)
Definition npc.c:202
void func_8003E514(s8 arg0)
Definition npc.c:2266
void clear_npcs(void)
Definition npc.c:60
void npc_revert_palswap_mode(Npc *npc)
Definition npc.c:1276
void make_npcs(s32 flags, s32 mapID, s32 *npcGroupList)
Definition npc.c:2331
void npc_set_decoration(Npc *npc, s32 idx, s32 decorationType)
Definition npc.c:1734
void render_npcs(void)
Renders all NPCs.
Definition npc.c:933
void npc_set_palswap_mode_A(Npc *npc, s32 mode)
Definition npc.c:1258
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:995
void npc_set_palswap_2(Npc *npc, s32 timeHoldB, s32 timeBA, s32 palIndexC, s32 palIndexD)
Definition npc.c:1294
void npc_enable_collisions(void)
Definition npc.c:1197
void npc_render_worker_do_nothing(void)
Definition npc.c:2328
void npc_remove_decoration_none(Npc *npc, s32 idx)
Definition npc.c:1816
void npc_update_decoration_glow_in_front(Npc *npc, s32 idx)
Definition npc.c:1888
Npc * npc_find_closest(f32 x, f32 y, f32 z, f32 radius)
Finds the closest NPC to a given point within a radius.
Definition npc.c:1969
void npc_reset_current_decoration(Npc *npc, s32 idx)
Definition npc.c:1798
s32 npc_update_decorations(Npc *npc)
Definition npc.c:1768
#define PAL_ANIM_END
Definition npc.c:16
void mtx_ident_mirror_y(Matrix4f mtx)
Definition npc.c:52
void npc_do_world_collision(Npc *npc)
Definition npc.c:278
void bind_npc_aux(s32 npcID, EvtScript *npcAuxBytecode)
Binds the specified auxillary script to the npc matching the specified npcId.
Definition npc.c:2502
void update_npcs(void)
Updates all NPCs.
Definition npc.c:617
void npc_set_palswap_mode_B(Npc *npc, s32 mode)
Definition npc.c:1267
s32 kill_encounter(Enemy *enemy)
Definition npc.c:2361
void bind_npc_interact(s32 npcID, EvtScript *npcInteractBytecode)
Binds the specified interact script to the npc matching the specified npcId.
Definition npc.c:2521
Npc * get_npc_by_index(s32 listIndex)
Definition npc.c:271
void clear_encounter_status(void)
Definition npc.c:2224
void draw_first_strike_ui(void)
Definition npc.c:2318
void npc_remove_decoration(Npc *npc, s32 idx)
Definition npc.c:1741
void npc_update_decoration_bowser_aura(Npc *npc, s32 idx)
Definition npc.c:1819
void npc_remove_decoration_glow_behind(Npc *npc, s32 idx)
Definition npc.c:1928
f32 npc_get_render_yaw(Npc *npc)
Definition npc.c:745
s32 npc_do_player_collision(Npc *npc)
Definition npc.c:443
void npc_remove_decoration_charged(Npc *npc, s32 idx)
Definition npc.c:1966
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:986
void update_npc_blur(Npc *npc)
Definition npc.c:1097
void appendGfx_npc(void *data)
Definition npc.c:809
void COPY_set_defeated(s32 mapID, s32 encounterID)
Duplicate of set_defeated().
Definition npc.c:2172
void func_8003B1A8(void)
Definition npc.c:1205
u16 npc_blend_palette_colors(u16 colorA, u16 colorB, s32 lerpAlpha)
Definition npc.c:1439
void draw_encounter_ui(void)
Definition npc.c:2294
void set_npc_yaw(Npc *npc, f32 yaw)
Definition npc.c:1246
s32 npc_get_collider_below(Npc *npc)
Definition npc.c:2069
void set_npc_sprite(Npc *npc, s32 anim, AnimID *extraAnimList)
Definition npc.c:1048
void init_encounter_status(void)
Definition npc.c:2191
void npc_update_decoration_glow_behind(Npc *npc, s32 idx)
Definition npc.c:1910
s16 gNpcCount
Definition npc.c:10
void npc_update_decoration_sweat(Npc *npc, s32 idx)
Definition npc.c:1843
void npc_remove_decoration_seeing_stars(Npc *npc, s32 idx)
Definition npc.c:1884
s32 bind_enemy_interact(Enemy *enemy, EvtScript *interactScriptBytecode)
Binds the specified interact script to the specified enemy.
Definition npc.c:2469
void npc_update_decoration_none(Npc *npc, s32 idx)
Definition npc.c:1813
Npc * get_npc_safe(s32 npcID)
Definition npc.c:1010
s8 resetMapEncounterFlags
Definition npc.h:389
struct Evt * interactScript
Definition npc.h:312
s8 scriptedBattle
battle started by StartBattle but not by encounter
Definition npc.h:380
s32 flags
Definition npc.h:295
u8 curMapIndex
Definition npc.h:386
s16 npcID
Definition npc.h:300
s32 interactScriptID
Definition npc.h:318
s16 encounterID
Definition npc.h:355
struct Evt * hitScript
Definition npc.h:314
s16 recentMaps[2]
Definition npc.h:404
EvtScript * hitBytecode
Definition npc.h:308
s8 encounterIndex
Definition npc.h:296
s32 auxScriptID
Definition npc.h:321
s32 initScriptID
Definition npc.h:317
Encounter * encounterList[24]
Definition npc.h:392
s8 battleTriggerCooldown
set to 15 after victory, 45 after fleeing
Definition npc.h:373
s32 * npcGroupList
Definition npc.h:391
Enemy * curEnemy
Definition npc.h:394
struct Evt * defeatScript
Definition npc.h:316
s8 numEncounters
Definition npc.h:384
Enemy * enemy[16]
Definition npc.h:352
u8 curEntryIndex
Definition npc.h:387
s32 count
Definition npc.h:351
EvtScript * interactBytecode
Definition npc.h:306
s32 aiScriptID
Definition npc.h:319
struct Evt * initScript
Definition npc.h:311
s32 defeatScriptID
Definition npc.h:322
EncounterStatus gCurrentEncounter
Definition encounter.c:176
s8 curAreaIndex
Definition npc.h:385
s8 dropWhackaBump
Definition npc.h:381
struct Evt * auxScript
Definition npc.h:315
s32 defeatFlags[60][12]
Definition npc.h:403
void * unk_64
Definition npc.h:323
s8 firstStrikeType
Definition npc.h:367
EvtScript * defeatBytecode
Definition npc.h:310
EvtScript * aiBytecode
Definition npc.h:307
struct Evt * aiScript
Definition npc.h:313
EvtScript * auxBytecode
Definition npc.h:309
s32 hitScriptID
Definition npc.h:320
Definition npc.h:294
Npc * wPartnerNpc
Definition partners.c:43
#define UNPACK_PAL_B(color)
Definition macros.h:269
#define UNPACK_PAL_R(color)
Definition macros.h:267
#define SPRITE_WORLD_SCALE_D
Definition macros.h:140
#define UNPACK_PAL_A(color)
Definition macros.h:270
#define COLLISION_WITH_ENTITY_BIT
Definition macros.h:152
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define UNPACK_PAL_G(color)
Definition macros.h:268
#define SPR_PAL_SIZE
Definition macros.h:142
#define PACK_PAL_RGBA(r, g, b, a)
Definition macros.h:272
#define PANIC()
Definition macros.h:55
#define DEG_TO_RAD(deg)
Definition macros.h:134
#define BATTLE_NPC_ID_BIT
Definition macros.h:145
#define SQ(x)
Definition macros.h:166
#define MAX_NPCS
Definition macros.h:91
#define NO_COLLIDER
Definition macros.h:156
s32 spr_draw_npc_sprite(s32 spriteInstanceID, s32 yaw, s32 arg2, PAL_PTR *paletteList, Matrix4f mtx)
Definition sprite.c:1106
s32 spr_update_sprite(s32 spriteInstanceID, s32 animID, f32 timeScale)
Definition sprite.c:1072
s32 spr_free_sprite(s32 spriteInstanceID)
Definition sprite.c:1178
s32 spr_get_notify_value(s32 spriteIndex)
Definition sprite.c:1174
void set_npc_imgfx_all(s32 spriteIdx, ImgFXType imgfxType, s32 imgfxArg1, s32 imgfxArg2, s32 imgfxArg3, s32 imgfxArg4, s32 imgfxArg5)
Definition sprite.c:1254
s32 spr_get_npc_color_variations(s32 npcSpriteID)
Definition sprite.c:1329
PAL_PTR * spr_get_npc_palettes(s32 npcSpriteID)
Definition sprite.c:1319
s32 func_802DDEC4(s32 spriteIdx)
Definition sprite.c:965
s32 spr_load_npc_sprite(s32 animID, u32 *extraAnimList)
Definition sprite.c:1026
s32 spr_draw_player_sprite(s32 spriteInstanceID, s32 yaw, s32 alphaIn, PAL_PTR *paletteList, Matrix4f mtx)
Definition sprite.c:872
s32 spr_update_player_sprite(s32 spriteInstanceID, s32 animID, f32 timeScale)
Definition sprite.c:823
@ PLAYER_SPRITE_AUX1
Definition sprite.h:27
@ DRAW_SPRITE_OVERRIDE_YAW
Definition sprite.h:21
@ DRAW_SPRITE_OVERRIDE_ALPHA
Definition sprite.h:22
@ DRAW_SPRITE_OVERRIDE_PALETTES
Definition sprite.h:20
@ SPRITE_ID_TAIL_ALLOCATE
Definition sprite.h:14
Matrix4f mtxPerspective
s32 flags
Definition entity.h:448
void(* onRender)(struct Npc *)
Definition npc.h:89
void(* onUpdate)(struct Npc *)
Definition npc.h:88
s32 initialAnim
Definition npc.h:87
s32 flags
Definition npc.h:86
struct EffectInstance * decorations[2]
s8 palAnimState
s16 palswapTimeBtoA
s16 collisionDiameter
void(* onUpdate)(struct Npc *)
Run before anything else for this NPC in update_npcs()
s16 imgfxArg2
f32 jumpScale
Vec3f scale
s16 blendPalB
s16 imgfxArg3
s16 nextPalTime
f32 jumpVel
f32 animationSpeed
s16 palswapTimeAtoB
s8 renderMode
s16 unk_96
s16 imgfxType
s32 flags
f32 renderYaw
s16 blendPalC
s8 changedDecoration[2]
s8 decorationType[2]
s32 spriteInstanceID
AnimID curAnim
s8 palSwapType
f32 shadowScale
s16 palBlendAlpha
u8 hideAlpha
Used when hiding NPCs; Multiplied with Npc::alpha.
f32 screenSpaceOffset2D[2]
s8 originalPalettesCount
s16 blendPalA
s32 collisionChannel
b16 isFacingAway
u16 ** originalPalettesList
u16 * adjustedPalettes[16]
Vec3f colliderPos
s16 collisionHeight
s8 resetPalAdjust
s16 turnAroundYawAdjustment
Vec3f rot
s8 verticalRenderOffset
s16 yawCamOffset
u16 imgfxFlags
s8 palSwapPrevType
s16 decorationGlowPhase[2]
s32 animNotifyValue
Vec3f pos
f32 verticalStretch
AnimID * extraAnimList
s16 curFloor
f32 rotPivotOffsetY
s16 imgfxArg4
f32 moveSpeed
Vec3s homePos
s16 imgfxArg1
s8 decorationInitialized[2]
u16 palswapTimeHoldA
s16 blendPalD
union Npc::@0 blur
s16 curWall
s8 spriteColorVariations
s32 shadowIndex
s16 palswapTimeHoldB
void(* onRender)(struct Npc *)
Run after the display list for this NPC is built.
u16 copiedPalettes[16][16]
void * appendGfxArg
void(* appendGfx)(void *)
s32 gOverrideFlags
Definition main_loop.c:11
PartnerStatus gPartnerStatus
Definition partners.c:42
GameStatus * gGameStatusPtr
Definition main_loop.c:32
s32 NpcHitQueryColliderID
Camera gCameras[4]
Definition cam_main.c:17
PlayerStatus gPlayerStatus
Definition 77480.c:39
s32 gCurrentCameraID
Definition cam_math.c:4
s32 gEncounterState
Definition encounter.c:174
b32 EncounterStateChanged
Definition encounter.c:24
s16 gCurrentCamID
Definition cam_main.c:13
s32 gEncounterSubState
Definition encounter.c:175