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 s8 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 if (npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f
881 || (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f
882 || npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f
883 ) {
884 guScaleF(mtx2,
888 guMtxCatF(mtx2, mtx1, mtx1);
889
890 }
891
892 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
893 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->curAnim != 0)) {
894 spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
895 }
896 } else {
898 }
899 }
900
901 if (npc->flags & NPC_FLAG_REFLECT_FLOOR) {
902 guTranslateF(mtx1, npc->pos.x, -(npc->pos.y + npc->verticalRenderOffset), npc->pos.z);
903 mtx_ident_mirror_y(mtx2);
904 guMtxCatF(mtx2, mtx1, mtx1);
905
906 if (npc->rot.y != 0.0f || npc->rot.x != 0.0f || npc->rot.z != 0.0f) {
907 guRotateRPYF(mtx2, npc->rot.x, npc->rot.y, npc->rot.z);
908 guMtxCatF(mtx2, mtx1, mtx1);
909 }
910
911 if (npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f
912 || (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f
913 || npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f
914 ) {
915 guScaleF(mtx2,
919 guMtxCatF(mtx2, mtx1, mtx1);
920 }
921 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
922 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->curAnim != 0)) {
923 spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
924 }
925 } else {
927 }
928 }
929 npc->onRender(npc);
930}
931
932void render_npcs(void) {
933 Npc* npc;
934 RenderTask renderTask;
935 RenderTask* renderTaskPtr = &renderTask;
937 f32 x, y, z, s;
938 f32 renderDist;
939 s32 i;
940
941 for (i = 0; i < MAX_NPCS; i++) {
942 Npc* npc = (*gCurrentNpcListPtr)[i];
943 if ((npc != NULL)
944 && (npc->flags != 0)
946 ) {
947 transform_point(cam->mtxPerspective, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &x, &y, &z, &s);
948 if (!(s < 0.01) || !(s > -0.01)) {
949 renderDist = ((z * 5000.0f) / s) + 5000.0f;
950 if (renderDist < 0.0f) {
951 renderDist = 0.0f;
952 } else if (renderDist > 10000.0f) {
953 renderDist = 10000.0f;
954 }
955
956 renderTaskPtr->dist = -renderDist;
957 renderTaskPtr->appendGfxArg = npc;
958 renderTaskPtr->appendGfx = appendGfx_npc;
959 renderTaskPtr->renderMode = npc->renderMode;
960
961 if (npc->flags & NPC_FLAG_HIDING) {
962 u8 r, g, b, a;
963 mdl_get_shroud_tint_params(&r, &g, &b, &a);
964 npc->hideAlpha = 255 - a;
965 } else {
966 npc->hideAlpha = 255;
967 }
968
969 if (npc->hideAlpha != 0) {
970 queue_render_task(renderTaskPtr);
971 }
972
973 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
974 renderTaskPtr->dist = -renderDist;
975 renderTaskPtr->appendGfx = appendGfx_npc_blur;
976 renderTaskPtr->appendGfxArg = npc;
978 queue_render_task(renderTaskPtr);
979 }
980 }
981 }
982 }
983}
984
985void npc_move_heading(Npc* npc, f32 speed, f32 yaw) {
986 f32 angle = DEG_TO_RAD(yaw);
987 f32 sin = sin_rad(angle);
988 f32 cos = cos_rad(angle);
989
990 npc->pos.x += speed * sin;
991 npc->pos.z += -speed * cos;
992}
993
994Npc* get_npc_unsafe(s32 npcID) {
995 s32 i;
996 Npc* npc;
997
998 for (i = 0; i < MAX_NPCS; i++) {
999 npc = (*gCurrentNpcListPtr)[i];
1000 if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
1001 break;
1002 }
1003 }
1004 ASSERT(i < MAX_NPCS);
1005
1006 return npc;
1007}
1008
1009Npc* get_npc_safe(s32 npcID) {
1010 s32 i;
1011 Npc* npc;
1012
1013 for (i = 0; i < MAX_NPCS; i++) {
1014 npc = (*gCurrentNpcListPtr)[i];
1015 if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
1016 break;
1017 }
1018 }
1019 if (i >= MAX_NPCS) {
1020 return NULL;
1021 }
1022
1023 return npc;
1024}
1025
1027 Shadow* shadow;
1028
1029 if (!(npc->flags & NPC_FLAG_HAS_SHADOW)) {
1030 shadow = get_shadow_by_index(npc->shadowIndex);
1031 shadow->flags &= ~ENTITY_FLAG_HIDDEN;
1033 }
1034}
1035
1037 Shadow* shadow;
1038
1039 if (npc->flags & NPC_FLAG_HAS_SHADOW) {
1040 shadow = get_shadow_by_index(npc->shadowIndex);
1041 shadow->flags |= ENTITY_FLAG_HIDDEN;
1042 npc->flags &= ~NPC_FLAG_HAS_SHADOW;
1043 npc->flags &= ~NPC_FLAG_DIRTY_SHADOW;
1044 }
1045}
1046
1047void set_npc_sprite(Npc* npc, s32 anim, AnimID* extraAnimList) {
1049
1050 npc->extraAnimList = extraAnimList;
1051
1052 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1053 npc->spriteInstanceID = spr_load_npc_sprite(anim, extraAnimList);
1054 ASSERT(npc->spriteInstanceID >= 0);
1055 }
1056
1057 npc->curAnim = anim;
1058
1059 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1060 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1062 }
1063 }
1064}
1065
1067 if (!(npc->flags & NPC_FLAG_MOTION_BLUR)) {
1068 NpcMotionBlur* motionBlur;
1069 s32 i;
1070
1072
1073 motionBlur = heap_malloc(sizeof(*motionBlur));
1074 npc->blur.motion = motionBlur;
1075 ASSERT(motionBlur != NULL);
1076 motionBlur->unused = 0;
1077 motionBlur->index = 0;
1078
1079 for (i = 0; i < ARRAY_COUNT(motionBlur->posX); i++) {
1080 motionBlur->posX[i] = npc->pos.x;
1081 motionBlur->posY[i] = npc->pos.y;
1082 motionBlur->posZ[i] = npc->pos.z;
1083 }
1084 }
1085}
1086
1088 if (npc->flags & NPC_FLAG_MOTION_BLUR) {
1089 npc->flags &= ~NPC_FLAG_MOTION_BLUR;
1090
1091 heap_free(npc->blur.motion);
1092 npc->blur.motion = NULL;
1093 }
1094}
1095
1097 NpcMotionBlur* motionBlur = npc->blur.motion;
1098 s32 index = motionBlur->index;
1099
1100 motionBlur->posX[index] = npc->pos.x;
1101 motionBlur->posY[index] = npc->pos.y;
1102 motionBlur->posZ[index] = npc->pos.z;
1103
1104 index++;
1105 if (index >= 20) {
1106 index = 0;
1107 }
1108
1109 motionBlur->index = index;
1110}
1111
1112void appendGfx_npc_blur(void* data) {
1113 Npc* npc = (Npc*) data;
1114 Matrix4f mtx, tempMtx;
1115 f32 x, y, z;
1116 f32 yaw;
1117 s32 strideIdx;
1118 s32 drawIdx;
1119 s32 bufPos;
1120 NpcMotionBlur* blur;
1121
1122 strideIdx = 0;
1123 drawIdx = 0;
1124 blur = npc->blur.motion;
1125 bufPos = blur->index;
1126
1127 while (TRUE) {
1128 bufPos--;
1129 strideIdx++;
1130
1131 if (bufPos < 0) {
1132 bufPos = NPC_BLUR_FRAMES - 1;
1133 }
1134
1135 if (bufPos == blur->index) {
1136 break;
1137 }
1138
1139 // only draw every third blur frame
1140 if (strideIdx < 3) {
1141 continue;
1142 }
1143
1144 strideIdx = 0;
1145 drawIdx++;
1146
1147 // draw three blur samples
1148 if (drawIdx > 3) {
1149 break;
1150 }
1151
1152 x = blur->posX[bufPos];
1153 y = blur->posY[bufPos];
1154 z = blur->posZ[bufPos];
1155 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ALPHA, 255, 255, 255, 120 - (drawIdx * 20), 0);
1156 yaw = npc->renderYaw;
1157 guTranslateF(mtx, x, y, z);
1158
1159 if (npc->rot.y != 0.0f) {
1160 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1161 guMtxCatF(tempMtx, mtx, mtx);
1162 }
1163 if (npc->rot.x != 0.0f) {
1164 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1165 guMtxCatF(tempMtx, mtx, mtx);
1166 }
1167 if (npc->rot.z != 0.0f) {
1168 guRotateF(tempMtx, npc->rot.y, 0.0f, 1.0f, 0.0f);
1169 guMtxCatF(tempMtx, mtx, mtx);
1170 }
1171
1172 if ((npc->scale.x * SPRITE_WORLD_SCALE_D) != 1.0
1173 || ((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D) != 1.0
1174 || (npc->scale.z * SPRITE_WORLD_SCALE_D) != 1.0
1175 ) {
1176 guScaleF(
1177 tempMtx,
1181 );
1182 guMtxCatF(tempMtx, mtx, mtx);
1183 }
1184
1185 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1186 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1187 spr_draw_npc_sprite(npc->spriteInstanceID, yaw, 0, 0, mtx);
1188 }
1189 } else {
1191 }
1192 }
1193 npc_imgfx_update(npc);
1194}
1195
1197 gNpcPlayerCollisionsEnabled = TRUE;
1198}
1199
1201 gNpcPlayerCollisionsEnabled = FALSE;
1202}
1203
1204void func_8003B1A8(void) {
1205}
1206
1207void npc_reload_all(void) {
1208 s32 i;
1209 s32 j;
1210
1211 for (i = 0; i < MAX_NPCS; i++) {
1212 Npc* npc = (*gCurrentNpcListPtr)[i];
1213 if (npc != NULL) {
1214 if (npc->flags && !(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1215 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1216 if (!(npc->flags & NPC_FLAG_PARTNER)) {
1218 } else {
1220 }
1221 }
1222 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1223 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE) && (npc->palSwapType != NPC_PAL_ADJUST_NONE)) {
1225 npc->originalPalettesCount = 0;
1226 while (npc->originalPalettesList[npc->originalPalettesCount] != (PAL_PTR) -1) {
1227 npc->originalPalettesCount++;
1228 }
1230 }
1231 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1232 if (!(npc->flags & NPC_FLAG_HAS_NO_SPRITE)) {
1233 for (j = 0; j < MAX_NPC_DECORATIONS; j++) {
1235 }
1236 npc_imgfx_update(npc);
1237 }
1238 }
1239 }
1240 }
1241 }
1242 }
1243}
1244
1245void set_npc_yaw(Npc* npc, f32 yaw) {
1246 npc->yaw = yaw;
1247
1248 if (get_clamped_angle_diff(gCameras[gCurrentCameraID].curYaw, yaw) >= 0.0f) {
1249 npc->yawCamOffset = 180;
1250 npc->isFacingAway = TRUE;
1251 } else {
1252 npc->yawCamOffset = 0;
1253 npc->isFacingAway = FALSE;
1254 }
1255}
1256
1257void npc_set_palswap_mode_A(Npc* npc, s32 mode) {
1258 if (npc->palSwapType != mode) {
1259 npc->palSwapPrevType = npc->palSwapType;
1260 npc->palSwapType = mode;
1262 npc->resetPalAdjust = 1;
1263 }
1264}
1265
1266void npc_set_palswap_mode_B(Npc* npc, s32 mode) {
1267 if (npc->palSwapType != mode) {
1268 npc->palSwapPrevType = npc->palSwapType;
1269 npc->palSwapType = mode;
1271 npc->resetPalAdjust = -1;
1272 }
1273}
1274
1278 return;
1279 }
1280 npc->palSwapType = npc->palSwapPrevType;
1283 npc->resetPalAdjust = 1;
1284}
1285
1286void npc_set_palswap_1(Npc* npc, s32 palIndexA, s32 palIndexB, s32 timeHoldA, s32 timeAB) {
1287 npc->blendPalA = palIndexA;
1288 npc->blendPalB = palIndexB;
1289 npc->palswapTimeHoldA = timeHoldA;
1290 npc->palswapTimeAtoB = timeAB;
1291}
1292
1293void npc_set_palswap_2(Npc* npc, s32 timeHoldB, s32 timeBA, s32 palIndexC, s32 palIndexD) {
1294 npc->palswapTimeHoldB = timeHoldB;
1295 npc->palswapTimeBtoA = timeBA;
1296 npc->blendPalC = palIndexC;
1297 npc->blendPalD = palIndexD;
1298}
1299
1300void npc_draw_with_palswap(Npc* npc, s32 yaw, Matrix4f mtx) {
1301 switch (npc->palSwapType) {
1304 break;
1307 break;
1309 npc_render_with_single_pal_blending(npc, yaw, FALSE, mtx);
1310 break;
1312 npc_render_with_single_pal_blending(npc, yaw, TRUE, mtx);
1313 break;
1316 break;
1317 }
1318}
1319
1321 if (npc->resetPalAdjust != 0) {
1322 npc->verticalStretch = 1.0f;
1323 npc->screenSpaceOffset2D[0] = 0.0f;
1324 npc->screenSpaceOffset2D[1] = 0.0f;
1325 npc->resetPalAdjust = 0;
1326 }
1327
1328 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1329 s32 alpha = (npc->alpha * npc->hideAlpha / 255);
1330 u32 mask;
1331 if (alpha < 255) {
1333 } else {
1334 mask = 0;
1335 }
1336 spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, NULL, mtx);
1337 } else {
1339 }
1340}
1341
1343 s32 i, j;
1344 s32 brightness;
1345 PAL_PTR src;
1346 PAL_PTR dst;
1347
1348 if (npc->resetPalAdjust != 0) {
1350 npc->originalPalettesCount = 0;
1351 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1352 npc->originalPalettesCount++;
1353 }
1354
1356 for (i = 0; i < npc->originalPalettesCount; i++) {
1357 dst = npc->copiedPalettes[i];
1358 src = npc->originalPalettesList[i];
1359 if (src != NULL) {
1360 for (j = 0; j < SPR_PAL_SIZE; j++) {
1361 *dst++ = *src++;
1362 }
1363 }
1364 }
1365
1366 npc->palAnimState = -2;
1367 npc->palBlendAlpha = 0;
1368 npc->resetPalAdjust = 0;
1369 npc->nextPalTime = 0;
1370 }
1371
1372 if (npc->nextPalTime == 0) {
1373 npc->palAnimState += 2;
1374 brightness = wWattIdlePalettesAnim[npc->palAnimState];
1375 if (brightness == 255) {
1376 npc->palAnimState = 0;
1377 }
1378 npc->nextPalTime = wWattIdlePalettesAnim[npc->palAnimState + 1] / 2;
1379 }
1380
1381 brightness = wWattIdlePalettesAnim[npc->palAnimState];
1382 npc->nextPalTime--;
1383
1384 switch(brightness) {
1385 case WATT_DEFAULT:
1386 for (i = 0; i < npc->spriteColorVariations; i++) {
1387 dst = npc->copiedPalettes[i];
1388 src = npc->originalPalettesList[i];
1389 if (src != NULL) {
1390 for (j = 0; j < SPR_PAL_SIZE; j++) {
1391 *dst++ = *src++;
1392 }
1393 }
1394 }
1395 break;
1396 case WATT_BRIGHTEST:
1397 for (i = 0; i < npc->spriteColorVariations; i++) {
1398 // use watt's Brightest palettes
1399 dst = npc->copiedPalettes[i];
1400 src = npc->originalPalettesList[npc->spriteColorVariations * SPR_PAL_WorldWatt_Brightest + i];
1401 if (src != NULL) {
1402 for (j = 0; j < SPR_PAL_SIZE; j++) {
1403 *dst++ = *src++;
1404 }
1405 }
1406 }
1407 break;
1408 case WATT_BRIGHTER:
1409 for (i = 0; i < npc->spriteColorVariations; i++) {
1410 // use watt's Brighter palettes
1411 dst = npc->copiedPalettes[i];
1412 src = npc->originalPalettesList[npc->spriteColorVariations * SPR_PAL_WorldWatt_Brighter + i];
1413 if (src != NULL) {
1414 for (j = 0; j < SPR_PAL_SIZE; j++) {
1415 *dst++ = *src++;
1416 }
1417 }
1418 }
1419 break;
1420 }
1421
1422 for (i = 0; i < npc->originalPalettesCount; i++) {
1423 npc->adjustedPalettes[i] = npc->copiedPalettes[i];
1424 }
1425
1426 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1427 s32 alpha = npc->alpha * npc->hideAlpha / 255;
1428 u32 mask = 0;
1429 if (alpha < 255) {
1431 }
1433 spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, npc->adjustedPalettes, mtx);
1434 }
1435 npc->palBlendAlpha--;
1436}
1437
1438u16 npc_blend_palette_colors(u16 colorA, u16 colorB, s32 lerpAlpha) {
1439 u8 r = (UNPACK_PAL_R(colorA) * (255 - lerpAlpha) + UNPACK_PAL_R(colorB) * lerpAlpha) / 255;
1440 u8 g = (UNPACK_PAL_G(colorA) * (255 - lerpAlpha) + UNPACK_PAL_G(colorB) * lerpAlpha) / 255;
1441 u8 b = (UNPACK_PAL_B(colorA) * (255 - lerpAlpha) + UNPACK_PAL_B(colorB) * lerpAlpha) / 255;
1442 u8 a = UNPACK_PAL_A(colorB);
1443
1444 return PACK_PAL_RGBA(r, g, b, a);
1445}
1446
1447s32 npc_render_with_single_pal_blending(Npc* npc, s32 yaw, b32 hasDifferentIntervals, Matrix4f mtx) {
1448 PAL_PTR color1;
1449 PAL_PTR color2;
1450 PAL_PTR outColor;
1451 s32 i, j;
1452 s32 blendAlpha;
1453
1454 // copy palettes from sprite data
1455 if (npc->resetPalAdjust != 0) {
1456 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1458 }
1459
1460 npc->originalPalettesCount = 0;
1461 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1462 npc->originalPalettesCount++;
1463 }
1464
1465 if (npc->resetPalAdjust == 1) {
1467 npc->palBlendAlpha = 0;
1468 } else {
1470 npc->palBlendAlpha = 255;
1471 }
1472
1473 for (i = 0; i < npc->originalPalettesCount; i++) {
1474 color1 = npc->copiedPalettes[i];
1475 color2 = npc->originalPalettesList[i];
1476 npc->adjustedPalettes[i] = color1;
1477 if (color2 != NULL) {
1478 for (j = 0; j < SPR_PAL_SIZE; j++) {
1479 *color1++ = *color2++;
1480 }
1481 }
1482 }
1483
1484 if (!hasDifferentIntervals) {
1487 npc->palswapTimeBtoA = npc->palswapTimeAtoB;
1488 npc->palswapTimeHoldA = 0;
1489 }
1490
1491 npc->nextPalTime = npc->palswapTimeHoldA;
1492 npc->palBlendAlpha = 0;
1494 npc->resetPalAdjust = 0;
1495 }
1496
1497 // blending from A -> B
1498 switch (npc->palAnimState) {
1499 case PAL_SWAP_HOLD_A:
1500 if (npc->nextPalTime != 0) {
1501 npc->nextPalTime--;
1502 break;
1503 } else {
1504 npc->palBlendAlpha = 0;
1506 }
1507 // fallthrough
1508 case PAL_SWAP_A_TO_B:
1509 npc->palBlendAlpha += 25600 / npc->palswapTimeAtoB;
1510 if (npc->palBlendAlpha > 25500) {
1511 npc->palBlendAlpha = 25500;
1512 }
1513 blendAlpha = npc->palBlendAlpha / 100;
1514 // blend two palettes
1515 outColor = npc->copiedPalettes[0];
1516 color2 = npc->originalPalettesList[npc->blendPalA];
1517 color1 = npc->originalPalettesList[npc->blendPalB];
1518 npc->adjustedPalettes[0] = outColor;
1519
1520 for (j = 0; j < SPR_PAL_SIZE; j++) {
1521 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1522 }
1523
1524 if (blendAlpha == 255) {
1526 npc->nextPalTime = npc->palswapTimeHoldB;
1527 }
1528 break;
1529 }
1530
1531 // blending from B -> A
1532 switch (npc->palAnimState) {
1533 case PAL_SWAP_HOLD_B:
1534 if (npc->nextPalTime != 0) {
1535 npc->nextPalTime--;
1536 break;
1537 } else {
1538 npc->palBlendAlpha = 0;
1540 }
1541 // fallthrough
1542 case PAL_SWAP_B_TO_A:
1543 npc->palBlendAlpha += 25600 / npc->palswapTimeBtoA;
1544 if (npc->palBlendAlpha > 25500) {
1545 npc->palBlendAlpha = 25500;
1546 }
1547 blendAlpha = npc->palBlendAlpha / 100;
1548 // blend two palettes
1549 outColor = npc->copiedPalettes[0];
1550 color2 = npc->originalPalettesList[npc->blendPalB];
1551 color1 = npc->originalPalettesList[npc->blendPalA];
1552 npc->adjustedPalettes[0] = outColor;
1553
1554 for (j = 0; j < SPR_PAL_SIZE; j++) {
1555 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1556 }
1557
1558 if (blendAlpha == 255) {
1560 npc->nextPalTime = npc->palswapTimeHoldA;
1561 }
1562 break;
1563 }
1564
1565 switch (npc->palAnimState) {
1566 case PAL_SWAP_HOLD_A:
1567 case PAL_SWAP_A_TO_B:
1568 case PAL_SWAP_HOLD_B:
1569 case PAL_SWAP_B_TO_A:
1570 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1571 u32 mask = 0;
1572 blendAlpha = npc->alpha * npc->hideAlpha / 255;
1573 if (blendAlpha < 255) {
1575 }
1577 spr_draw_npc_sprite(npc->spriteInstanceID | mask, yaw, blendAlpha, npc->adjustedPalettes, mtx);
1578 }
1579 break;
1580 }
1581}
1582
1584 PAL_PTR color1;
1585 PAL_PTR color2;
1586 PAL_PTR outColor;
1587 s32 i, j;
1588 u8 blendAlpha;
1589
1590 // copy palettes from sprite data
1591 if (npc->resetPalAdjust != 0) {
1592 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1594 }
1595
1596 npc->originalPalettesCount = 0;
1597 while ((s32)npc->originalPalettesList[npc->originalPalettesCount] != -1) {
1598 npc->originalPalettesCount++;
1599 }
1600
1601 if (npc->resetPalAdjust == 1) {
1603 npc->palBlendAlpha = 0;
1604 } else {
1606 npc->palBlendAlpha = 255;
1607 }
1608
1609 for (i = 0; i < npc->originalPalettesCount; i++) {
1610 color1 = npc->copiedPalettes[i];
1611 color2 = npc->originalPalettesList[i];
1612 npc->adjustedPalettes[i] = color1;
1613 if (color2 != NULL) {
1614 for (j = 0; j < SPR_PAL_SIZE; j++) {
1615 *color1++ = *color2++;
1616 }
1617 }
1618 }
1619
1620 npc->nextPalTime = npc->palswapTimeHoldA;
1621 npc->palBlendAlpha = 0;
1623 npc->resetPalAdjust = 0;
1624 }
1625
1626 // blending from A -> B
1627 switch (npc->palAnimState) {
1628 case PAL_SWAP_HOLD_A:
1629 if (npc->nextPalTime != 0) {
1630 npc->nextPalTime--;
1631 break;
1632 }
1633 npc->palBlendAlpha = 0;
1635 // fallthrough
1636 case PAL_SWAP_A_TO_B:
1637 npc->palBlendAlpha += 25600 / npc->palswapTimeAtoB;
1638 if (npc->palBlendAlpha > 25500) {
1639 npc->palBlendAlpha = 25500;
1640 }
1641 blendAlpha = npc->palBlendAlpha / 100;
1642
1643 // blend first two palettes
1644 outColor = npc->copiedPalettes[0];
1645 color2 = npc->originalPalettesList[npc->blendPalA];
1646 color1 = npc->originalPalettesList[npc->blendPalB];
1647 npc->adjustedPalettes[0] = outColor;
1648
1649 for (j = 0; j < SPR_PAL_SIZE; j++) {
1650 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1651 }
1652
1653 // blend next palettes
1654 outColor = npc->copiedPalettes[3];
1655 color2 = npc->originalPalettesList[npc->blendPalC];
1656 color1 = npc->originalPalettesList[npc->blendPalD];
1657 npc->adjustedPalettes[3] = outColor;
1658
1659 for (j = 0; j < SPR_PAL_SIZE; j++) {
1660 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1661 }
1662
1663 if (blendAlpha == 255) {
1665 npc->nextPalTime = npc->palswapTimeHoldB;
1666 }
1667 break;
1668 }
1669
1670 // blending from B -> A
1671 switch (npc->palAnimState) {
1672 case PAL_SWAP_HOLD_B:
1673 if (npc->nextPalTime != 0) {
1674 npc->nextPalTime--;
1675 break;
1676 } else {
1677 npc->palBlendAlpha = 0;
1679 }
1680 // fallthrough
1681 case PAL_SWAP_B_TO_A:
1682 npc->palBlendAlpha += 25600 / npc->palswapTimeBtoA;
1683 if (npc->palBlendAlpha > 25500) {
1684 npc->palBlendAlpha = 25500;
1685 }
1686 blendAlpha = npc->palBlendAlpha / 100;
1687
1688 // blend first two palettes
1689 outColor = npc->copiedPalettes[0];
1690 color2 = npc->originalPalettesList[npc->blendPalB];
1691 color1 = npc->originalPalettesList[npc->blendPalA];
1692 npc->adjustedPalettes[0] = outColor;
1693
1694 for (j = 0; j < SPR_PAL_SIZE; j++) {
1695 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1696 }
1697
1698 // blend next palettes
1699 outColor = npc->copiedPalettes[1];
1700 color2 = npc->originalPalettesList[npc->blendPalD];
1701 color1 = npc->originalPalettesList[npc->blendPalC];
1702 npc->adjustedPalettes[3] = npc->copiedPalettes[3];
1703
1704 for (j = 0; j < SPR_PAL_SIZE; j++) {
1705 *outColor++ = npc_blend_palette_colors(*color2++, *color1++, blendAlpha);
1706 }
1707
1708 if (blendAlpha == 255) {
1710 npc->nextPalTime = npc->palswapTimeHoldA;
1711 }
1712 break;
1713 }
1714
1715 switch (npc->palAnimState) {
1716 case PAL_SWAP_HOLD_A:
1717 case PAL_SWAP_A_TO_B:
1718 case PAL_SWAP_HOLD_B:
1719 case PAL_SWAP_B_TO_A:
1720 if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
1721 u32 mask = 0;
1722 blendAlpha = npc->alpha * npc->hideAlpha / 255;
1723 if (blendAlpha < 255) {
1725 }
1727 spr_draw_npc_sprite(npc->spriteInstanceID | mask, yaw, blendAlpha, npc->adjustedPalettes, mtx);
1728 }
1729 break;
1730 }
1731}
1732
1733void npc_set_decoration(Npc* npc, s32 idx, s32 decorationType) {
1734 npc_remove_decoration(npc, idx);
1735 npc->decorationType[idx] = decorationType;
1736 npc->changedDecoration[idx] = 1;
1737 npc->decorationInitialized[idx] = 0;
1738}
1739
1740void npc_remove_decoration(Npc* npc, s32 idx) {
1741 switch (npc->decorationType[idx]) {
1744 break;
1747 break;
1750 break;
1753 break;
1756 break;
1759 break;
1762 break;
1763 }
1765}
1766
1768 s32 i;
1769
1770 for (i = 0; i < MAX_NPC_DECORATIONS; i++) {
1771 switch (npc->decorationType[i]) {
1774 break;
1777 break;
1780 break;
1783 break;
1786 break;
1789 break;
1792 break;
1793 }
1794 }
1795}
1796
1798 switch (npc->decorationType[idx]) {
1805 break;
1807 npc->decorationInitialized[idx] = 0;
1808 break;
1809 }
1810}
1811
1812void npc_update_decoration_none(Npc* npc, s32 idx) {
1813}
1814
1815void npc_remove_decoration_none(Npc* npc, s32 idx) {
1816}
1817
1819 AuraFXData* data;
1820
1821 switch (npc->decorationInitialized[idx]) {
1822 case 0:
1823 fx_aura(FX_AURA_BLUE, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &npc->decorations[idx]);
1824 npc->decorationInitialized[idx] = 1;
1825 // fallthrough
1826 case 1:
1827 data = npc->decorations[idx]->data.aura;
1828 data->posA.x = npc->pos.x;
1829 data->posA.y = npc->pos.y;
1830 data->posA.z = npc->pos.z;
1831 data->scale.x = (npc->scale.x * npc->collisionDiameter) * 0.01;
1832 data->scale.y = (npc->scale.y * npc->collisionHeight) * 0.01;
1833 data->renderYaw = npc->renderYaw;
1834 break;
1835 }
1836}
1837
1839 npc->decorations[idx]->data.aura->fadeTime = 5;
1840}
1841
1843 switch (npc->decorationInitialized[idx]) {
1844 case 0:
1845 if (npc->yawCamOffset > 90) {
1846 fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, 45.0f, 20);
1847 } else {
1848 fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, -45.0f, 20);
1849 }
1850 npc->decorationGlowPhase[idx] = 10;
1851 npc->decorationInitialized[idx] = 1;
1852 break;
1853 case 1:
1854 if (npc->decorationGlowPhase[idx] != 0) {
1855 npc->decorationGlowPhase[idx]--;
1856 } else {
1857 npc->decorationInitialized[idx] = 0;
1858 }
1859 break;
1860 }
1861}
1862
1864}
1865
1867 StarsOrbitingFXData* data;
1868
1869 switch (npc->decorationInitialized[idx]) {
1870 case 0:
1871 fx_stars_orbiting(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 20.0f, 3, &npc->decorations[idx]);
1872 npc->decorationInitialized[idx] = 1;
1873 break;
1874 case 1:
1875 data = npc->decorations[idx]->data.starsOrbiting;
1876 data->pos.x = npc->pos.x;
1877 data->pos.y = npc->pos.y + npc->collisionHeight;
1878 data->pos.z = npc->pos.z;
1879 break;
1880 }
1881}
1882
1884 remove_effect(npc->decorations[idx]);
1885}
1886
1888 EnergyOrbWaveFXData* data;
1889
1890 switch (npc->decorationInitialized[idx]) {
1891 case 0:
1892 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);
1893 npc->decorationInitialized[idx] = 1;
1894 break;
1895 case 1:
1896 data = npc->decorations[idx]->data.energyOrbWave;
1897 data->pos.x = npc->pos.x;
1898 data->pos.y = npc->pos.y + npc->collisionHeight * 0.5 * npc->scale.x;
1899 data->pos.z = npc->pos.z;
1900 data->scale = npc->scale.x * 0.8 + 0.2f;
1901 break;
1902 }
1903}
1904
1906 remove_effect(npc->decorations[idx]);
1907}
1908
1910 EnergyOrbWaveFXData* data;
1911
1912 switch (npc->decorationInitialized[idx]) {
1913 case 0:
1914 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);
1915 npc->decorationInitialized[idx] = 1;
1916 break;
1917 case 1:
1918 data = npc->decorations[idx]->data.energyOrbWave;
1919 data->pos.x = npc->pos.x;
1920 data->pos.y = npc->pos.y + npc->collisionHeight * 0.5;
1921 data->pos.z = npc->pos.z - 5.0f;
1922 data->scale = 1.0f;
1923 break;
1924 }
1925}
1926
1928 remove_effect(npc->decorations[idx]);
1929}
1930
1932 #define RGBA_BUF_SIZE 20
1933 u8 rbuf[RGBA_BUF_SIZE];
1934 u8 gbuf[RGBA_BUF_SIZE];
1935 u8 bbuf[RGBA_BUF_SIZE];
1936 s32 color;
1937 s32 alpha;
1938 s32 i;
1939
1940 if (npc->decorationInitialized[idx] == 0) {
1942 npc->decorationInitialized[idx] = 1;
1943 }
1944 if (npc->decorationInitialized[idx] == 1) {
1945 npc->decorationGlowPhase[idx] += 7;
1946 if (npc->decorationGlowPhase[idx] >= 360) {
1947 npc->decorationGlowPhase[idx] %= 360;
1948 }
1949
1950 for (i = 0; i < RGBA_BUF_SIZE; i++) {
1951 rbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i)) + 1.0) * 80.0f;
1952 gbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i) + 45) + 1.0) * 80.0f;
1953 bbuf[i] = (cosine(npc->decorationGlowPhase[idx] + (25 * i) + 90) + 1.0) * 80.0f;
1954 }
1955
1956 alpha = 255;
1957 for (i = 0; i < RGBA_BUF_SIZE; i++) {
1958 color = (rbuf[i] << 24) | (gbuf[i] << 16) | (bbuf[i] << 8) | alpha;
1960 }
1961 }
1962 #undef RGBA_BUF_SIZE
1963}
1964
1966}
1967
1968Npc* npc_find_closest(f32 x, f32 y, f32 z, f32 radius) {
1969 Npc* closestNpc = NULL;
1970 f32 closestDist = radius;
1971 f32 maxDist = radius;
1972 s32 i;
1973
1974 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
1975 Npc* npc = (*gCurrentNpcListPtr)[i];
1976
1977 if (npc != NULL && npc->flags != 0 && !(npc->flags & NPC_FLAG_PARTNER)) {
1978 if (!(npc->flags & (NPC_FLAG_SUSPENDED | NPC_FLAG_INACTIVE))) {
1979 f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
1980
1981 if (distance <= maxDist) {
1982 if (distance < closestDist) {
1983 closestDist = distance;
1984 closestNpc = npc;
1985 }
1986 }
1987 }
1988 }
1989 }
1990
1991 return closestNpc;
1992}
1993
1994Npc* npc_find_closest_simple(f32 x, f32 y, f32 z, f32 radius) {
1995 Npc* closestNpc = NULL;
1996 f32 closestDist = radius;
1997 f32 maxDist = radius;
1998 s32 i;
1999
2000 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
2001 Npc* npc = (*gCurrentNpcListPtr)[i];
2002
2003 if (npc != NULL && npc->flags != 0 && (npc->flags & NPC_FLAG_PARTNER)) {
2004 if (!(npc->flags & (NPC_FLAG_SUSPENDED | NPC_FLAG_INACTIVE))) {
2005 f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
2006
2007 if (distance <= maxDist) {
2008 if (distance < closestDist) {
2009 closestDist = distance;
2010 closestNpc = npc;
2011 }
2012 }
2013 }
2014 }
2015 }
2016
2017 return closestNpc;
2018}
2019
2020s32 npc_find_standing_on_entity(s32 entityIndex) {
2021 s32 idx = entityIndex | COLLISION_WITH_ENTITY_BIT;
2022 s32 y = get_entity_by_index(idx)->pos.y - 10.0f;
2023 Npc* npc;
2024 s32 i;
2025 s32 var_v1;
2026
2027 npc->pos = npc->pos; // TODO required to match
2028
2029 for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
2030 npc = (*gCurrentNpcListPtr)[i];
2031
2032 if (npc == NULL) {
2033 continue;
2034 }
2035 if (npc->flags == 0) {
2036 continue;
2037 }
2039 continue;
2040 }
2041 if (npc->flags & NPC_FLAG_PARTNER) {
2042 var_v1 = i; // TODO required to match (dummy if statement to load NPC_FLAG_PARTNER into s5)
2043 }
2044 if (npc->pos.y < y) {
2045 continue;
2046 }
2048 var_v1 = npc_get_collider_below(npc);
2049 if (var_v1 != 0) {
2050 if (idx == var_v1) {
2051 return i;
2052 }
2053 }
2054 } else {
2055 var_v1 = npc->curFloor;
2056 if (npc->curFloor & COLLISION_WITH_ENTITY_BIT) { // TODO required to match (can't use var_v1)
2057 if (idx == var_v1) {
2058 npc->pos = npc->pos; // TODO required to match
2059 return i;
2060 }
2061 }
2062 }
2063 }
2064
2065 return -1;
2066}
2067
2069 f32 x;
2070 f32 y;
2071 f32 z;
2072 f32 yaw;
2073
2074 if (npc->flags & NPC_FLAG_PARTNER) {
2075 y = get_shadow_by_index(npc->shadowIndex)->pos.y + 13.0f;
2076 } else {
2077 y = npc->pos.y + 13.0f;
2078 }
2079
2080 yaw = 16.0f;
2081 x = npc->pos.x;
2082 z = npc->pos.z;
2083
2085 if (yaw <= 16.0f) {
2086 return NpcHitQueryColliderID;
2087 }
2088 }
2089 return 0;
2090}
2091
2093 s32 imgfxType = npc->imgfxType;
2094 s32 imgfxArg1 = npc->imgfxArg1;
2095 s32 imgfxArg2 = npc->imgfxArg2;
2096 s32 imgfxArg3 = npc->imgfxArg3;
2097 s32 imgfxArg4 = npc->imgfxArg4;
2098 s32 imgfxFlags = npc->imgfxFlags;
2099
2100 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_CLEAR, 0, 0, 0, 0, 0);
2101
2102 switch (imgfxType) {
2103 case IMGFX_CLEAR:
2105 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_CLEAR, 0, 0, 0, 0, imgfxFlags);
2106 break;
2107 case IMGFX_UNK_2:
2108 case IMGFX_RESET:
2110 // fallthrough
2111 case IMGFX_UNK_1:
2112 set_npc_imgfx_all(npc->spriteInstanceID, imgfxType, 0, 0, 0, 0, imgfxFlags);
2113 break;
2114 case IMGFX_SET_WAVY:
2116 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_WAVY, imgfxArg1, imgfxArg2, imgfxArg3, 0, imgfxFlags);
2117 break;
2118 case IMGFX_SET_COLOR:
2120 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_COLOR, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2121 break;
2122 case IMGFX_SET_ALPHA:
2124 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ALPHA, 255, 255, 255, imgfxArg1, imgfxFlags);
2125 break;
2126 case IMGFX_SET_TINT:
2128 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_TINT, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2129 break;
2132 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_WHITE_FADE, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2133 break;
2136 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_CREDITS_FADE, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2137 break;
2138 case IMGFX_SET_ANIM:
2140 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_SET_ANIM, imgfxArg1, imgfxArg2, imgfxArg3, 0, imgfxFlags);
2141 break;
2142 case IMGFX_HOLOGRAM:
2144 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_HOLOGRAM, imgfxArg1, imgfxArg2, imgfxArg3, imgfxArg4, imgfxFlags);
2145 break;
2146 case IMGFX_FILL_COLOR:
2148 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_FILL_COLOR, imgfxArg1, imgfxArg2, imgfxArg3, 255, imgfxFlags);
2149 break;
2150 case IMGFX_OVERLAY:
2152 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_OVERLAY, imgfxArg1, 255, 0, 255, imgfxFlags);
2153 break;
2154 case IMGFX_OVERLAY_XLU:
2156 set_npc_imgfx_all(npc->spriteInstanceID, IMGFX_OVERLAY, imgfxArg1, imgfxArg2, 0, imgfxArg2, imgfxFlags);
2157 break;
2158 }
2159}
2160
2161void npc_set_imgfx_params(Npc* npc, s32 imgfxType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6) {
2162 npc->imgfxType = imgfxType;
2163 npc->imgfxArg1 = arg2;
2164 npc->imgfxArg2 = arg3;
2165 npc->imgfxArg3 = arg4;
2166 npc->imgfxArg4 = arg5;
2167 npc->imgfxFlags = arg6;
2168 npc_imgfx_update(npc);
2169}
2170
2171void COPY_set_defeated(s32 mapID, s32 encounterID) {
2172 EncounterStatus* currentEncounter = &gCurrentEncounter;
2173 s32 encounterIdx = encounterID / 32;
2174 s32 encounterShift;
2175 s32 flag;
2176
2177 flag = encounterID % 32;
2178 encounterShift = flag;
2179 flag = currentEncounter->defeatFlags[mapID][encounterIdx];
2180 currentEncounter->defeatFlags[mapID][encounterIdx] = flag | (1 << encounterShift);
2181
2182 // TODO: The below should work but has regalloc issues:
2183 /*EncounterStatus *currentEncounter = &gCurrentEncounter;
2184 s32 encounterIdx = encounterID / 32;
2185 s32 encounterShift = encounterID % 32;
2186
2187 currentEncounter->defeatFlags[mapID][encounterIdx] |= (1 << encounterShift);*/
2188}
2189
2191 EncounterStatus* currentEncounter = &gCurrentEncounter;
2192 s32 i;
2193 s32 j;
2194
2195 for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
2196 currentEncounter->encounterList[i] = 0;
2197 }
2198
2199 currentEncounter->flags = ENCOUNTER_FLAG_NONE;
2200 currentEncounter->numEncounters = 0;
2201 currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
2202 currentEncounter->hitType = 0;
2203 currentEncounter->battleTriggerCooldown = 0;
2204 currentEncounter->npcGroupList = 0;
2205 currentEncounter->unk_08 = 0;
2206 currentEncounter->dropWhackaBump = FALSE;
2207
2208 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2209 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2210 currentEncounter->defeatFlags[i][j] = 0;
2211 }
2212 }
2213
2214 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2215 currentEncounter->recentMaps[i] = -1;
2216 }
2217
2218 func_80045AC0();
2221}
2222
2224 EncounterStatus* currentEncounter = &gCurrentEncounter;
2225 s32 i;
2226 s32 j;
2227
2228 for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
2229 currentEncounter->encounterList[i] = 0;
2230 }
2231
2233 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2234 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2235 currentEncounter->defeatFlags[i][j] = 0;
2236 }
2237 }
2238
2240 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2241 currentEncounter->recentMaps[i] = -1;
2242 }
2243 }
2244 }
2245
2246 currentEncounter->numEncounters = 0;
2247 currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
2248 currentEncounter->hitType = 0;
2249 currentEncounter->battleTriggerCooldown = 0;
2250 currentEncounter->curAreaIndex = gGameStatusPtr->areaID;
2251 currentEncounter->curMapIndex = gGameStatusPtr->mapID;
2252 currentEncounter->curEntryIndex = gGameStatusPtr->entryID;
2253 currentEncounter->npcGroupList = 0;
2254 currentEncounter->unk_08 = 0;
2255 currentEncounter->scriptedBattle = FALSE;
2256
2257 func_80045AC0();
2260}
2261
2262void func_8003E50C(void) {
2263}
2264
2265void func_8003E514(s8 arg0) {
2267}
2268
2270 switch (gEncounterState) {
2272 break;
2275 break;
2278 break;
2281 break;
2284 break;
2287 break;
2288 }
2289
2291}
2292
2294 switch (gEncounterState) {
2296 break;
2299 break;
2302 break;
2305 break;
2308 break;
2311 break;
2312 }
2313
2315}
2316
2318 switch (gEncounterState) {
2320 break;
2323 break;
2324 }
2325}
2326
2329
2330void make_npcs(s32 flags, s32 mapID, s32* npcGroupList) {
2331 EncounterStatus* currentEncounter = &gCurrentEncounter;
2332 s32 i;
2333 s32 j;
2334
2335 currentEncounter->resetMapEncounterFlags = flags;
2336 currentEncounter->mapID = mapID;
2337 currentEncounter->npcGroupList = npcGroupList;
2338
2340 for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
2341 for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
2342 currentEncounter->defeatFlags[i][j] = 0;
2343 }
2344 }
2345
2347 for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
2348 currentEncounter->recentMaps[i] = -1;
2349 }
2350 }
2351 }
2352
2353 if (npcGroupList != NULL) {
2355 EncounterStateChanged = TRUE;
2357 }
2358}
2359
2362 s32 i;
2363
2364 for (i = 0; i < encounter->count; i++) {
2365 Enemy* currentEnemy = encounter->enemy[i];
2366 if (currentEnemy != NULL) {
2367 kill_enemy(currentEnemy);
2368 encounter->enemy[i] = NULL;
2369 }
2370 }
2371}
2372
2373void kill_enemy(Enemy* enemy) {
2374 EncounterStatus* encounterStatus = &gCurrentEncounter;
2375 Encounter* encounter = encounterStatus->encounterList[enemy->encounterIndex];
2376 s32 i;
2377 s32 j;
2378
2379 for (i = 0; i < encounter->count; i++) {
2380 Enemy* currentEnemy = encounter->enemy[i];
2381 if (currentEnemy == enemy) {
2382 break;
2383 }
2384 }
2385
2386 if (enemy->initScript != NULL) {
2388 }
2389 if (enemy->interactScript != NULL) {
2391 }
2392 if (enemy->aiScript != NULL) {
2394 }
2395 if (enemy->hitScript != NULL) {
2397 }
2398 if (enemy->auxScript != NULL) {
2400 }
2401 if (enemy->defeatScript != NULL) {
2403 }
2404
2405 enemy->interactBytecode = NULL;
2406 enemy->aiBytecode = NULL;
2407 enemy->hitBytecode = NULL;
2408 enemy->auxBytecode = NULL;
2409 enemy->defeatBytecode = NULL;
2410
2411 #if DX_DEBUG_MENU
2412 if (enemy->npcID != (s16) DX_DEBUG_DUMMY_ID) {
2413 free_npc(get_npc_unsafe(enemy->npcID));
2414 }
2415 #else
2416 free_npc(get_npc_unsafe(enemy->npcID));
2417 #endif
2418
2419 if (enemy->unk_64 != NULL) {
2420 heap_free(enemy->unk_64);
2421 }
2422
2423 for (j = 0; j < ARRAY_COUNT(encounter->enemy); j++) {
2424 if (encounter->enemy[j] == enemy) {
2425 encounter->enemy[j] = NULL;
2426 }
2427 }
2428
2429 if (!(enemy->flags & ENEMY_FLAG_DO_NOT_KILL)
2430 && (!(enemy->flags & ENEMY_FLAG_ENABLE_HIT_SCRIPT) || (enemy == encounterStatus->curEnemy))
2431 && !(enemy->flags & ENEMY_FLAG_PASSIVE)
2432 && !(enemy->flags & ENEMY_FLAG_FLED)
2433 ) {
2434 COPY_set_defeated(encounterStatus->mapID, encounter->encounterID + i);
2435 }
2436
2437 heap_free(enemy);
2438}
2439
2440s32 bind_enemy_ai(Enemy* enemy, EvtScript* aiScriptBytecode) {
2441 Evt* aiScript;
2442 s32 id;
2443
2444 if (enemy->aiScript != NULL) {
2445 kill_script_by_ID(enemy->aiScript->id);
2446 }
2447 enemy->aiBytecode = aiScriptBytecode;
2448 aiScript = enemy->aiScript = start_script(aiScriptBytecode, EVT_PRIORITY_A, 0);
2449 id = enemy->aiScriptID = aiScript->id;
2450 aiScript->owner1.enemy = enemy;
2451 return id;
2452}
2453
2454s32 bind_enemy_aux(Enemy* enemy, EvtScript* auxScriptBytecode) {
2455 Evt* auxScript;
2456 s32 id;
2457
2458 if (enemy->auxScript != NULL) {
2460 }
2461 enemy->auxBytecode = auxScriptBytecode;
2462 auxScript = enemy->auxScript = start_script(auxScriptBytecode, EVT_PRIORITY_A, 0);
2463 id = enemy->auxScriptID = auxScript->id;
2464 auxScript->owner1.enemy = enemy;
2465 return id;
2466}
2467
2468s32 bind_enemy_interact(Enemy* enemy, EvtScript* interactScriptBytecode) {
2469 Evt* interactScript;
2470 s32 id;
2471
2472 if (enemy->interactScript != NULL) {
2474 }
2475 enemy->interactBytecode = interactScriptBytecode;
2476 interactScript = enemy->interactScript = start_script(interactScriptBytecode, EVT_PRIORITY_A, 0);
2477 id = enemy->interactScriptID = interactScript->id;
2478 interactScript->owner1.enemy = enemy;
2479 return id;
2480}
2481
2482void bind_npc_ai(s32 npcID, EvtScript* npcAiBytecode) {
2483 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2484 s32 i;
2485 s32 j;
2486
2487 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2488 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2489 if (currentEncounter != NULL) {
2490 for (j = 0; j < currentEncounter->count; j++) {
2491 Enemy* currentEnemy = currentEncounter->enemy[j];
2492 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2493 bind_enemy_ai(currentEnemy, npcAiBytecode);
2494 break;
2495 }
2496 }
2497 }
2498 }
2499}
2500
2501void bind_npc_aux(s32 npcID, EvtScript* npcAuxBytecode) {
2502 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2503 s32 i;
2504 s32 j;
2505
2506 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2507 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2508 if (currentEncounter != NULL) {
2509 for (j = 0; j < currentEncounter->count; j++) {
2510 Enemy* currentEnemy = currentEncounter->enemy[j];
2511 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2512 bind_enemy_aux(currentEnemy, npcAuxBytecode);
2513 break;
2514 }
2515 }
2516 }
2517 }
2518}
2519
2520void bind_npc_interact(s32 npcID, EvtScript* npcInteractBytecode) {
2521 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2522 s32 i;
2523 s32 j;
2524
2525 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2526 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2527 if (currentEncounter != NULL) {
2528 for (j = 0; j < currentEncounter->count; j++) {
2529 Enemy* currentEnemy = currentEncounter->enemy[j];
2530 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2531 bind_enemy_interact(currentEnemy, npcInteractBytecode);
2532 break;
2533 }
2534 }
2535 }
2536 }
2537}
2538
2539Enemy* get_enemy(s32 npcID) {
2540 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2541 s32 i;
2542 s32 j;
2543
2544 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2545 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2546 if (currentEncounter != NULL) {
2547 for (j = 0; j < currentEncounter->count; j++) {
2548 Enemy* currentEnemy = currentEncounter->enemy[j];
2549 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2550 return currentEnemy;
2551 }
2552 }
2553 }
2554 }
2555 PANIC();
2556}
2557
2559 EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
2560 s32 i;
2561 s32 j;
2562
2563 for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
2564 Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
2565
2566 if (currentEncounter != NULL) {
2567 for (j = 0; j < currentEncounter->count; j++) {
2568 Enemy* currentEnemy = currentEncounter->enemy[j];
2569 if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
2570 return currentEnemy;
2571 }
2572 }
2573 }
2574 }
2575 return NULL;
2576}
PalSwapState
Npc * NpcList[64]
#define MAX_NPC_DECORATIONS
#define NPC_BLUR_FRAMES
s16 entityModelID
#define PAL_PTR
s32 b32
f32 Matrix4f[4][4]
Vec3f scale
Bytecode EvtScript[]
u32 AnimID
union Evt::@10 owner1
Initially -1.
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
struct StarsOrbitingFXData * starsOrbiting
Definition effects.h:2511
s32 fadeTime
Definition effects.h:999
Vec2f scale
Definition effects.h:996
Vec3f posA
Definition effects.h:994
EffectInstanceDataPtr data
Definition effects.h:2605
@ FX_AURA_BLUE
Definition effects.h:988
struct EnergyOrbWaveFXData * energyOrbWave
Definition effects.h:2546
struct AuraFXData * aura
Definition effects.h:2523
#define ASSERT(condition)
EntityModel * get_entity_model(s32 idx)
@ ENTITY_MODEL_FLAG_REFLECT
Definition enums.h:5018
@ IMGFX_SET_ALPHA
Definition enums.h:5123
@ IMGFX_RESET
Definition enums.h:5119
@ IMGFX_HOLOGRAM
Definition enums.h:5129
@ IMGFX_SET_COLOR
Definition enums.h:5122
@ IMGFX_OVERLAY_XLU
Definition enums.h:5132
@ IMGFX_OVERLAY
Definition enums.h:5131
@ IMGFX_CLEAR
Definition enums.h:5116
@ IMGFX_SET_WAVY
Definition enums.h:5120
@ IMGFX_ALLOC_COLOR_BUF
Definition enums.h:5133
@ IMGFX_FILL_COLOR
Definition enums.h:5130
@ IMGFX_COLOR_BUF_SET_MODULATE
Definition enums.h:5128
@ IMGFX_SET_CREDITS_FADE
Definition enums.h:5126
@ IMGFX_SET_TINT
Definition enums.h:5124
@ IMGFX_SET_WHITE_FADE
Definition enums.h:5125
@ IMGFX_SET_ANIM
Definition enums.h:5121
@ IMGFX_UNK_2
Definition enums.h:5118
@ IMGFX_UNK_1
Definition enums.h:5117
@ 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:4985
@ 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:4522
@ ENEMY_FLAG_PASSIVE
Definition enums.h:4520
@ ENEMY_FLAG_FLED
Definition enums.h:4524
@ ENEMY_FLAG_ENABLE_HIT_SCRIPT
Definition enums.h:4523
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4695
@ COLLIDER_FLAG_IGNORE_SHELL
Definition enums.h:4694
@ COLLISION_IGNORE_ENTITIES
Definition enums.h:4697
@ COLLIDER_FLAG_IGNORE_NPC
Definition enums.h:4696
@ PA_FLAG_NPC_COLLIDED
Definition enums.h:3106
@ PA_FLAG_RIDING_PARTNER
Definition enums.h:3116
@ CONTEXT_WORLD
Definition enums.h:3528
@ 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:6298
@ ENCOUNTER_STATE_CONVERSATION
Definition enums.h:6297
@ ENCOUNTER_STATE_NEUTRAL
Definition enums.h:6295
@ ENCOUNTER_STATE_NONE
Definition enums.h:6293
@ ENCOUNTER_STATE_PRE_BATTLE
Definition enums.h:6296
@ ENCOUNTER_STATE_CREATE
Definition enums.h:6294
@ FIRST_STRIKE_NONE
Definition enums.h:3458
@ GLOBAL_OVERRIDES_800
Definition enums.h:4329
@ GLOBAL_OVERRIDES_PREV_400
Definition enums.h:4332
@ GLOBAL_OVERRIDES_400
Definition enums.h:4328
@ GLOBAL_OVERRIDES_PREV_800
Definition enums.h:4333
@ ENCOUNTER_SUBSTATE_CREATE_INIT
Definition enums.h:6302
@ 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
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:2814
void func_80045AC0(void)
f32 cosine(s16 arg0)
Definition 43F0.c:353
f32 cos_rad(f32 x)
Definition 43F0.c:716
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:669
void update_encounters_pre_battle(void)
Definition encounter.c:1261
s32 create_worker_scene(void(*updateFunc)(void), void(*renderFunc)(void))
Definition worker.c:32
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:712
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:605
void * heap_malloc(s32 size)
Definition heap.c:34
void npc_render_without_adjusted_palettes(Npc *npc, s32 arg1, Matrix4f mtx)
Definition npc.c:1320
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:1931
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:1866
void npc_remove_decoration_glow_in_front(Npc *npc, s32 idx)
Definition npc.c:1905
void npc_imgfx_update(Npc *npc)
Definition npc.c:2092
s32 npc_render_with_single_pal_blending(Npc *npc, s32 yaw, b32 hasDifferentIntervals, Matrix4f mtx)
Definition npc.c:1447
void disable_npc_blur(Npc *npc)
Definition npc.c:1087
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:2440
void npc_reload_all(void)
Definition npc.c:1207
s32 bind_enemy_aux(Enemy *enemy, EvtScript *auxScriptBytecode)
Binds the specified auxillary script to the specified enemy.
Definition npc.c:2454
s32 npc_render_with_watt_idle_palettes(Npc *npc, s32 arg1, Matrix4f mtx)
Definition npc.c:1342
void appendGfx_npc_blur(void *data)
Definition npc.c:1112
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:2558
s32 npc_find_standing_on_entity(s32 entityIndex)
Definition npc.c:2020
void npc_set_imgfx_params(Npc *npc, s32 imgfxType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6)
Definition npc.c:2161
void npc_remove_decoration_sweat(Npc *npc, s32 idx)
Definition npc.c:1863
void kill_enemy(Enemy *enemy)
Definition npc.c:2373
Enemy * get_enemy(s32 npcID)
Looks for an enemy matching the specified npcID.
Definition npc.c:2539
void npc_do_other_npc_collision(Npc *npc)
Definition npc.c:381
void func_8003E50C(void)
Definition npc.c:2262
void bind_npc_ai(s32 npcID, EvtScript *npcAiBytecode)
Binds the specified ai script to the npc matching the specified npcId.
Definition npc.c:2482
#define RGBA_BUF_SIZE
void npc_disable_collisions(void)
Definition npc.c:1200
void npc_set_palswap_1(Npc *npc, s32 palIndexA, s32 palIndexB, s32 timeHoldA, s32 timeAB)
Definition npc.c:1286
u8 wWattIdlePalettesAnim[]
Definition npc.c:32
void enable_npc_shadow(Npc *npc)
Definition npc.c:1026
void npc_remove_decoration_bowser_aura(Npc *npc, s32 idx)
Definition npc.c:1838
s32 npc_render_with_double_pal_blending(Npc *npc, s32 yaw, Matrix4f mtx)
Definition npc.c:1583
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:2269
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:1994
void enable_npc_blur(Npc *npc)
Definition npc.c:1066
@ 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:1036
void npc_draw_with_palswap(Npc *npc, s32 yaw, Matrix4f mtx)
Definition npc.c:1300
void free_npc_by_index(s32 listIndex)
Definition npc.c:202
void func_8003E514(s8 arg0)
Definition npc.c:2265
void clear_npcs(void)
Definition npc.c:60
void npc_revert_palswap_mode(Npc *npc)
Definition npc.c:1275
void make_npcs(s32 flags, s32 mapID, s32 *npcGroupList)
Definition npc.c:2330
void npc_set_decoration(Npc *npc, s32 idx, s32 decorationType)
Definition npc.c:1733
void render_npcs(void)
Renders all NPCs.
Definition npc.c:932
void npc_set_palswap_mode_A(Npc *npc, s32 mode)
Definition npc.c:1257
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:994
void npc_set_palswap_2(Npc *npc, s32 timeHoldB, s32 timeBA, s32 palIndexC, s32 palIndexD)
Definition npc.c:1293
void npc_enable_collisions(void)
Definition npc.c:1196
void npc_render_worker_do_nothing(void)
Definition npc.c:2327
@ WATT_BRIGHTER
Definition npc.c:29
@ WATT_DEFAULT
Definition npc.c:27
@ WATT_BRIGHTEST
Definition npc.c:28
void npc_remove_decoration_none(Npc *npc, s32 idx)
Definition npc.c:1815
void npc_update_decoration_glow_in_front(Npc *npc, s32 idx)
Definition npc.c:1887
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:1968
void npc_reset_current_decoration(Npc *npc, s32 idx)
Definition npc.c:1797
s32 npc_update_decorations(Npc *npc)
Definition npc.c:1767
#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:2501
void update_npcs(void)
Updates all NPCs.
Definition npc.c:617
void npc_set_palswap_mode_B(Npc *npc, s32 mode)
Definition npc.c:1266
s32 kill_encounter(Enemy *enemy)
Definition npc.c:2360
void bind_npc_interact(s32 npcID, EvtScript *npcInteractBytecode)
Binds the specified interact script to the npc matching the specified npcId.
Definition npc.c:2520
Npc * get_npc_by_index(s32 listIndex)
Definition npc.c:271
void clear_encounter_status(void)
Definition npc.c:2223
void draw_first_strike_ui(void)
Definition npc.c:2317
void npc_remove_decoration(Npc *npc, s32 idx)
Definition npc.c:1740
void npc_update_decoration_bowser_aura(Npc *npc, s32 idx)
Definition npc.c:1818
void npc_remove_decoration_glow_behind(Npc *npc, s32 idx)
Definition npc.c:1927
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:1965
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:985
void update_npc_blur(Npc *npc)
Definition npc.c:1096
void appendGfx_npc(void *data)
Definition npc.c:809
void COPY_set_defeated(s32 mapID, s32 encounterID)
Duplicate of set_defeated().
Definition npc.c:2171
void func_8003B1A8(void)
Definition npc.c:1204
u16 npc_blend_palette_colors(u16 colorA, u16 colorB, s32 lerpAlpha)
Definition npc.c:1438
void draw_encounter_ui(void)
Definition npc.c:2293
void set_npc_yaw(Npc *npc, f32 yaw)
Definition npc.c:1245
s32 npc_get_collider_below(Npc *npc)
Definition npc.c:2068
void set_npc_sprite(Npc *npc, s32 anim, AnimID *extraAnimList)
Definition npc.c:1047
void init_encounter_status(void)
Definition npc.c:2190
void npc_update_decoration_glow_behind(Npc *npc, s32 idx)
Definition npc.c:1909
s16 gNpcCount
Definition npc.c:10
void npc_update_decoration_sweat(Npc *npc, s32 idx)
Definition npc.c:1842
void npc_remove_decoration_seeing_stars(Npc *npc, s32 idx)
Definition npc.c:1883
s32 bind_enemy_interact(Enemy *enemy, EvtScript *interactScriptBytecode)
Binds the specified interact script to the specified enemy.
Definition npc.c:2468
void npc_update_decoration_none(Npc *npc, s32 idx)
Definition npc.c:1812
Npc * get_npc_safe(s32 npcID)
Definition npc.c:1009
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:273
#define UNPACK_PAL_R(color)
Definition macros.h:271
#define SPRITE_WORLD_SCALE_D
Definition macros.h:144
#define UNPACK_PAL_A(color)
Definition macros.h:274
#define COLLISION_WITH_ENTITY_BIT
Definition macros.h:156
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define UNPACK_PAL_G(color)
Definition macros.h:272
#define SPR_PAL_SIZE
Definition macros.h:146
#define PACK_PAL_RGBA(r, g, b, a)
Definition macros.h:276
#define PANIC()
Definition macros.h:55
#define DEG_TO_RAD(deg)
Definition macros.h:138
#define BATTLE_NPC_ID_BIT
Definition macros.h:149
#define SQ(x)
Definition macros.h:170
#define MAX_NPCS
Definition macros.h:91
#define NO_COLLIDER
Definition macros.h:160
s32 spr_draw_npc_sprite(s32 spriteInstanceID, s32 yaw, s32 arg2, PAL_PTR *paletteList, Matrix4f mtx)
Definition sprite.c:1105
s32 spr_update_sprite(s32 spriteInstanceID, s32 animID, f32 timeScale)
Definition sprite.c:1071
s32 spr_free_sprite(s32 spriteInstanceID)
Definition sprite.c:1177
s32 spr_get_notify_value(s32 spriteIndex)
Definition sprite.c:1173
void set_npc_imgfx_all(s32 spriteIdx, ImgFXType imgfxType, s32 imgfxArg1, s32 imgfxArg2, s32 imgfxArg3, s32 imgfxArg4, s32 imgfxArg5)
Definition sprite.c:1253
s32 spr_get_npc_color_variations(s32 npcSpriteID)
Definition sprite.c:1326
PAL_PTR * spr_get_npc_palettes(s32 npcSpriteID)
Definition sprite.c:1316
s32 func_802DDEC4(s32 spriteIdx)
Definition sprite.c:964
s32 spr_load_npc_sprite(s32 animID, u32 *extraAnimList)
Definition sprite.c:1025
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