2020-08-04 08:49:11 +02:00
|
|
|
#include "common.h"
|
2021-04-13 09:47:52 +02:00
|
|
|
#include "npc.h"
|
2022-11-23 19:33:39 +01:00
|
|
|
#include "entity.h"
|
2021-07-21 16:46:58 +02:00
|
|
|
#include "effects.h"
|
2021-10-29 18:48:20 +02:00
|
|
|
#include "sprite.h"
|
2022-10-18 13:43:04 +02:00
|
|
|
#include "world/partners.h"
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-10 23:57:21 +02:00
|
|
|
u8 D_80077BF0[] = {
|
|
|
|
1, 2,
|
|
|
|
0, 52,
|
|
|
|
1, 4,
|
|
|
|
0, 54,
|
|
|
|
0, 54,
|
|
|
|
1, 2,
|
|
|
|
0, 28,
|
|
|
|
1, 2,
|
|
|
|
0, 6,
|
|
|
|
1, 2,
|
|
|
|
0, 44,
|
|
|
|
1, 2,
|
|
|
|
0, 44,
|
|
|
|
255, 0,
|
2022-09-28 22:52:12 +02:00
|
|
|
};
|
|
|
|
|
2022-10-10 23:57:21 +02:00
|
|
|
s32 D_80077C0C = 0; // padding?
|
2022-09-28 22:52:12 +02:00
|
|
|
f32 D_80077C10 = 0.0f;
|
|
|
|
s16 D_80077C14 = 4;
|
|
|
|
s16 D_80077C16 = 0; // padding?
|
|
|
|
f32 D_80077C18 = 0;
|
|
|
|
s16 D_80077C1C = 4;
|
|
|
|
s16 D_80077C1E = 5;
|
|
|
|
s32 D_80077C20 = 0;
|
2022-10-10 23:57:21 +02:00
|
|
|
f32 D_80077C24 = 0.0f;
|
2022-09-28 22:52:12 +02:00
|
|
|
s16 D_80077C28 = 4;
|
|
|
|
s16 D_80077C2A = 0; // padding?
|
2022-10-10 23:57:21 +02:00
|
|
|
f32 D_80077C2C = 0.0f;
|
2022-09-28 22:52:12 +02:00
|
|
|
s16 D_80077C30 = 4;
|
|
|
|
s16 D_80077C32 = 0; // padding?
|
|
|
|
s32 D_80077C34 = 0;
|
|
|
|
s16 D_80077C38 = 4;
|
|
|
|
s16 D_80077C3A = 4;
|
2021-03-30 19:39:44 +02:00
|
|
|
|
2022-09-28 22:52:12 +02:00
|
|
|
extern s16 D_8010C97A;
|
2021-07-17 16:45:08 +02:00
|
|
|
|
2021-12-20 16:59:25 +01:00
|
|
|
void STUB_npc_callback(Npc* npc) {
|
2020-09-25 23:18:09 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void mtx_ident_mirror_y(Matrix4f mtx) {
|
2022-03-30 14:07:13 +02:00
|
|
|
guMtxIdentF(mtx);
|
2021-04-01 20:00:29 +02:00
|
|
|
mtx[0][0] = 1.0f;
|
|
|
|
mtx[1][1] = -1.0f;
|
|
|
|
mtx[2][2] = 1.0f;
|
|
|
|
mtx[3][3] = 1.0f;
|
2020-10-08 23:45:26 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void clear_npcs(void) {
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 i;
|
|
|
|
|
|
|
|
if (!gGameStatusPtr->isBattle) {
|
|
|
|
gCurrentNpcListPtr = &gWorldNpcList;
|
|
|
|
} else {
|
|
|
|
gCurrentNpcListPtr = &gBattleNpcList;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
(*gCurrentNpcListPtr)[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gNpcCount = 0;
|
|
|
|
D_800A0B94 = 1;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void init_npc_list(void) {
|
2021-03-23 03:25:48 +01:00
|
|
|
if (!gGameStatusPtr->isBattle) {
|
2021-03-21 13:16:00 +01:00
|
|
|
gCurrentNpcListPtr = &gWorldNpcList;
|
|
|
|
} else {
|
|
|
|
gCurrentNpcListPtr = &gBattleNpcList;
|
|
|
|
}
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
gNpcCount = 0;
|
2021-03-21 13:16:00 +01:00
|
|
|
D_800A0B94 = 1;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
void npc_iter_no_op(void) {
|
|
|
|
s32 i;
|
2021-03-23 03:25:48 +01:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
|
|
|
|
// Needed to avoid loop optimization.
|
|
|
|
do {} while (FALSE);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-04 02:56:24 +02:00
|
|
|
s32 _create_npc(NpcBlueprint* blueprint, AnimID* animList, s32 skipLoadingAnims) {
|
2021-06-15 10:05:16 +02:00
|
|
|
Npc* npc;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
if ((*gCurrentNpcListPtr)[i] == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(i < MAX_NPCS);
|
|
|
|
|
2022-05-21 06:56:54 +02:00
|
|
|
(*gCurrentNpcListPtr)[i] = npc = heap_malloc(sizeof(*npc));
|
2021-06-15 10:05:16 +02:00
|
|
|
gNpcCount++;
|
|
|
|
ASSERT(npc != NULL);
|
|
|
|
|
2023-02-06 01:13:45 +01:00
|
|
|
npc->flags = blueprint->flags | (NPC_FLAG_400000 | NPC_FLAG_DIRTY_SHADOW | NPC_FLAG_HAS_SHADOW | NPC_FLAG_1);
|
2021-06-15 10:05:16 +02:00
|
|
|
if (skipLoadingAnims) {
|
|
|
|
npc->flags |= NPC_FLAG_NO_ANIMS_LOADED;
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->collisionRadius = 32;
|
|
|
|
npc->collisionHeight = 64;
|
|
|
|
npc->renderMode = 13;
|
2022-08-10 15:36:38 +02:00
|
|
|
npc->blur.any = NULL;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->yaw = 0.0f;
|
|
|
|
npc->jumpVelocity = 0.0f;
|
|
|
|
npc->pos.x = 0.0f;
|
|
|
|
npc->pos.y = 0.0f;
|
|
|
|
npc->pos.z = 0.0f;
|
|
|
|
npc->colliderPos.x = 0.0f;
|
|
|
|
npc->colliderPos.y = 0.0f;
|
|
|
|
npc->colliderPos.z = 0.0f;
|
|
|
|
npc->rotationVerticalPivotOffset = 0.0f;
|
|
|
|
npc->rotation.x = 0.0f;
|
|
|
|
npc->rotation.y = 0.0f;
|
|
|
|
npc->rotation.z = 0.0f;
|
|
|
|
npc->homePos.x = 0.0f;
|
|
|
|
npc->homePos.y = 0.0f;
|
|
|
|
npc->homePos.z = 0.0f;
|
|
|
|
npc->unk_96 = 0; // TODO: fix
|
2022-04-29 06:32:16 +02:00
|
|
|
npc->verticalRenderOffset = 0;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->alpha = 255;
|
|
|
|
npc->alpha2 = 255;
|
|
|
|
npc->jumpScale = 1.0f;
|
|
|
|
npc->moveSpeed = 4.0f;
|
|
|
|
npc->scale.x = 1.0f;
|
|
|
|
npc->scale.y = 1.0f;
|
|
|
|
npc->scale.z = 1.0f;
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->currentAnim = blueprint->initialAnim;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->animationSpeed = 1.0f;
|
|
|
|
npc->renderYaw = 0.0f;
|
|
|
|
npc->unk_98 = 0;
|
|
|
|
npc->unk_A2 = 0;
|
2022-09-24 21:34:16 +02:00
|
|
|
npc->collisionChannel = COLLISION_CHANNEL_20000;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->isFacingAway = 0;
|
|
|
|
npc->yawCamOffset = 0;
|
|
|
|
npc->turnAroundYawAdjustment = 0;
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->currentFloor = -1;
|
|
|
|
npc->currentWall = -1;
|
|
|
|
npc->palSwapType = 0;
|
|
|
|
npc->palSwapPrevType = 0;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->screenSpaceOffset2D[0] = 0.0f;
|
|
|
|
npc->screenSpaceOffset2D[1] = 0.0f;
|
|
|
|
npc->verticalStretch = 1.0f;
|
|
|
|
|
|
|
|
for (j = 0; j < ARRAY_COUNT(npc->decorations); j++) {
|
|
|
|
npc->decorations[j] = 0;
|
|
|
|
npc->decorationType[j] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->onUpdate = blueprint->onUpdate;
|
|
|
|
if (npc->onUpdate == NULL) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc->onUpdate = &STUB_npc_callback;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
npc->onRender = blueprint->onRender;
|
|
|
|
if (npc->onRender == NULL) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc->onRender = &STUB_npc_callback;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
if (!skipLoadingAnims) {
|
|
|
|
npc->extraAnimList = animList;
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(npc->currentAnim, animList);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(npc->currentAnim | SPRITE_ID_TAIL_ALLOCATE, animList);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
npc->flags |= NPC_FLAG_2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->shadowIndex = create_shadow_type(0, npc->pos.x, npc->pos.y, npc->pos.z);
|
|
|
|
npc->shadowScale = 1.0f;
|
|
|
|
|
|
|
|
if (gGameStatusPtr->isBattle) {
|
|
|
|
i |= 0x800;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
s32 _create_npc_basic(NpcBlueprint* blueprint) {
|
|
|
|
return _create_npc(blueprint, NULL, FALSE);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-04 02:56:24 +02:00
|
|
|
s32 _create_npc_standard(NpcBlueprint* blueprint, AnimID* animList) {
|
2022-09-08 14:12:26 +02:00
|
|
|
return _create_npc(blueprint, animList, FALSE);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-09-08 14:12:26 +02:00
|
|
|
s32 _create_npc_partner(NpcBlueprint* blueprint) {
|
|
|
|
return _create_npc(blueprint, NULL, TRUE);
|
2021-02-09 14:07:46 +01:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void free_npc_by_index(s32 listIndex) {
|
2021-06-15 10:05:16 +02:00
|
|
|
Npc* npc;
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
listIndex &= ~0x800;
|
|
|
|
|
|
|
|
npc = (*gCurrentNpcListPtr)[listIndex];
|
|
|
|
if (npc != NULL) {
|
|
|
|
if (npc->flags) {
|
2022-08-10 15:36:38 +02:00
|
|
|
if (npc->blur.any != NULL) {
|
|
|
|
heap_free(npc->blur.any);
|
|
|
|
npc->blur.any = NULL;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2021-07-19 10:22:43 +02:00
|
|
|
ASSERT((npc->flags & NPC_FLAG_1000000) || !spr_free_sprite(npc->spriteInstanceID));
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2021-07-19 10:22:43 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
delete_shadow(npc->shadowIndex);
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_MOTION_BLUR) {
|
|
|
|
disable_npc_blur(npc);
|
|
|
|
}
|
|
|
|
|
|
|
|
heap_free((*gCurrentNpcListPtr)[listIndex]);
|
|
|
|
(*gCurrentNpcListPtr)[listIndex] = NULL;
|
|
|
|
gNpcCount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void free_npc(Npc* npc) {
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 i;
|
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
if (npc->blur.any != NULL) {
|
|
|
|
heap_free(npc->blur.any);
|
|
|
|
npc->blur.any = NULL;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2021-07-19 10:22:43 +02:00
|
|
|
ASSERT((npc->flags & NPC_FLAG_1000000) || !spr_free_sprite(npc->spriteInstanceID));
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2021-07-19 10:22:43 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
delete_shadow(npc->shadowIndex);
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_MOTION_BLUR) {
|
|
|
|
disable_npc_blur(npc);
|
|
|
|
}
|
|
|
|
|
|
|
|
heap_free(npc);
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
if ((*gCurrentNpcListPtr)[i] == npc) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(*gCurrentNpcListPtr)[i] = NULL;
|
|
|
|
gNpcCount--;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2020-09-25 23:18:09 +02:00
|
|
|
Npc* get_npc_by_index(s32 listIndex) {
|
2021-04-13 09:47:52 +02:00
|
|
|
return (*gCurrentNpcListPtr)[listIndex & ~0x800];
|
2020-09-25 23:18:09 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
void npc_do_world_collision(Npc* npc) {
|
|
|
|
f32 temp_f0;
|
|
|
|
s32 phi_v0;
|
|
|
|
f32 temp_x;
|
|
|
|
f32 temp_y;
|
|
|
|
f32 temp_z;
|
|
|
|
|
2023-02-06 01:13:45 +01:00
|
|
|
if (npc->flags & NPC_FLAG_IGNORE_WORLD_COLLISION) {
|
|
|
|
npc->flags |= NPC_FLAG_WORLD_COLLISION_DIRTY;
|
2021-06-15 10:05:16 +02:00
|
|
|
} else if ((npc->pos.x != npc->colliderPos.x) || (npc->pos.y != npc->colliderPos.y)
|
2023-02-06 01:13:45 +01:00
|
|
|
|| (npc->pos.z != npc->colliderPos.z) || npc->flags & NPC_FLAG_WORLD_COLLISION_DIRTY) {
|
|
|
|
npc->flags &= ~NPC_FLAG_WORLD_COLLISION_DIRTY;
|
2021-06-15 10:05:16 +02:00
|
|
|
temp_f0 = clamp_angle(npc->yaw);
|
|
|
|
temp_x = npc->pos.x;
|
|
|
|
temp_y = npc->pos.y;
|
|
|
|
temp_z = npc->pos.z;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_simple_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_complex_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (phi_v0) {
|
|
|
|
npc->flags |= (NPC_FLAG_NO_PROJECT_SHADOW | NPC_FLAG_4000);
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->currentWall = D_8010C97A;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->pos.x = temp_x;
|
|
|
|
npc->pos.z = temp_z;
|
|
|
|
} else {
|
|
|
|
npc->flags &= ~(NPC_FLAG_NO_PROJECT_SHADOW | NPC_FLAG_4000);
|
|
|
|
}
|
|
|
|
|
|
|
|
temp_f0 = clamp_angle(npc->yaw + 45.0f);
|
|
|
|
temp_x = npc->pos.x;
|
|
|
|
temp_y = npc->pos.y;
|
|
|
|
temp_z = npc->pos.z;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_simple_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_taller_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (phi_v0) {
|
|
|
|
npc->flags |= NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
npc->pos.x = temp_x;
|
|
|
|
npc->pos.z = temp_z;
|
|
|
|
} else {
|
|
|
|
npc->flags &= ~NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp_f0 = clamp_angle(npc->yaw - 45.0f);
|
|
|
|
temp_x = npc->pos.x;
|
|
|
|
temp_y = npc->pos.y;
|
|
|
|
temp_z = npc->pos.z;
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_simple_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_test_move_taller_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight, npc->collisionRadius);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (phi_v0 != 0) {
|
|
|
|
npc->flags |= NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
npc->pos.x = temp_x;
|
|
|
|
npc->pos.z = temp_z;
|
|
|
|
} else {
|
|
|
|
npc->flags &= ~NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_PARTICLE) {
|
|
|
|
temp_f0 = clamp_angle(npc->yaw + 45.0f + 180.0f);
|
|
|
|
temp_x = npc->pos.x;
|
|
|
|
temp_y = npc->pos.y;
|
|
|
|
temp_z = npc->pos.z;
|
2022-01-05 12:05:49 +01:00
|
|
|
if (npc_test_move_simple_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight,
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->collisionRadius) != 0) {
|
|
|
|
npc->flags |= NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
npc->pos.x = temp_x;
|
|
|
|
npc->pos.z = temp_z;
|
|
|
|
} else {
|
|
|
|
npc->flags &= ~NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp_f0 = clamp_angle((npc->yaw - 45.0f) + 180.0f);
|
|
|
|
temp_x = npc->pos.x;
|
|
|
|
temp_y = npc->pos.y;
|
|
|
|
temp_z = npc->pos.z;
|
2022-01-05 12:05:49 +01:00
|
|
|
if (npc_test_move_simple_with_slipping(npc->collisionChannel, &temp_x, &temp_y, &temp_z, 0, temp_f0, npc->collisionHeight,
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->collisionRadius) != 0) {
|
|
|
|
npc->flags |= NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
npc->pos.x = temp_x;
|
|
|
|
npc->pos.z = temp_z;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
npc->flags &= ~NPC_FLAG_NO_PROJECT_SHADOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
// float regalloc :(
|
|
|
|
#ifdef NON_MATCHING
|
|
|
|
void npc_do_other_npc_collision(Npc* npc) {
|
|
|
|
Npc* otherNpc;
|
|
|
|
f32 temp_f20_2;
|
|
|
|
f32 temp_f22_3;
|
|
|
|
f32 temp_f24_2;
|
|
|
|
f32 temp_f22_4;
|
|
|
|
f32 temp_f2;
|
|
|
|
f32 thisX, thisY, thisZ;
|
|
|
|
f32 thisBuf;
|
|
|
|
f32 otherX, otherZ;
|
|
|
|
f32 otherBuf;
|
|
|
|
f32 xDiff, zDiff;
|
|
|
|
f32 dist;
|
|
|
|
s32 collision;
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_100)) {
|
|
|
|
npc->flags &= ~NPC_FLAG_SIMPLIFIED_PHYSICS;
|
|
|
|
thisBuf = npc->collisionRadius * 0.5f;
|
|
|
|
thisX = npc->pos.x;
|
|
|
|
thisY = npc->pos.y;
|
|
|
|
thisZ = npc->pos.z;
|
|
|
|
|
|
|
|
for (i = 0; i < 0x40; i++) {
|
|
|
|
otherNpc = get_npc_by_index(i);
|
|
|
|
if (otherNpc != NULL && npc != otherNpc) {
|
2022-09-24 22:01:49 +02:00
|
|
|
if (otherNpc->flags != 0 && !(otherNpc->flags & (NPC_FLAG_80000000 | NPC_FLAG_100))) {
|
2022-04-05 14:53:40 +02:00
|
|
|
if (!(otherNpc->pos.y + otherNpc->collisionHeight < thisY) &&
|
|
|
|
!(thisY + npc->collisionHeight < otherNpc->pos.y))
|
|
|
|
{
|
|
|
|
otherX = otherNpc->pos.x;
|
|
|
|
otherZ = otherNpc->pos.z;
|
|
|
|
xDiff = otherX - thisX;
|
|
|
|
zDiff = otherZ - thisZ;
|
|
|
|
otherBuf = otherNpc->collisionRadius * 0.5f;
|
|
|
|
dist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
|
|
|
|
|
|
if (!(thisBuf + otherBuf <= dist)) {
|
|
|
|
collision = FALSE;
|
|
|
|
if (npc->flags & NPC_FLAG_PARTICLE) {
|
2022-04-17 17:36:37 +02:00
|
|
|
collision = gPartnerActionStatus.partnerActionState == PARTNER_ACTION_NONE;
|
|
|
|
} else if (!(otherNpc->flags & NPC_FLAG_PARTICLE) || gPartnerActionStatus.partnerActionState == PARTNER_ACTION_NONE) {
|
2022-04-05 14:53:40 +02:00
|
|
|
collision = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (collision) {
|
2022-09-15 21:39:16 +02:00
|
|
|
temp_f20_2 = DEG_TO_RAD(atan2(otherX, otherZ, thisX, thisZ));
|
2022-04-05 14:53:40 +02:00
|
|
|
temp_f24_2 = thisBuf + otherBuf - dist;
|
|
|
|
temp_f22_3 = temp_f24_2 * sin_rad(temp_f20_2);
|
|
|
|
temp_f22_4 = -temp_f24_2 * cos_rad(temp_f20_2);
|
|
|
|
thisX += temp_f22_3 * 0.1f;
|
|
|
|
thisZ += temp_f22_4 * 0.1f;
|
|
|
|
}
|
|
|
|
npc->flags |= NPC_FLAG_SIMPLIFIED_PHYSICS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
npc->pos.x = thisX;
|
|
|
|
npc->pos.z = thisZ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2021-04-13 09:47:52 +02:00
|
|
|
INCLUDE_ASM(void, "npc", npc_do_other_npc_collision, Npc* npc);
|
2022-04-05 14:53:40 +02:00
|
|
|
#endif
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
INCLUDE_ASM(s32, "npc", npc_do_player_collision, Npc* npc);
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
void npc_do_gravity(Npc* npc) {
|
|
|
|
if (npc->flags & NPC_FLAG_GRAVITY) {
|
2022-04-29 06:32:16 +02:00
|
|
|
if (npc->flags & NPC_FLAG_JUMPING) {
|
2021-08-22 15:10:06 +02:00
|
|
|
npc->flags &= ~NPC_FLAG_1000;
|
|
|
|
} else {
|
|
|
|
f32 xTemp;
|
|
|
|
f32 yTemp;
|
|
|
|
f32 zTemp;
|
|
|
|
f32 length, oldLength;
|
|
|
|
s32 hit;
|
|
|
|
|
|
|
|
npc->jumpScale = 1.0f;
|
|
|
|
xTemp = npc->pos.x;
|
|
|
|
zTemp = npc->pos.z;
|
|
|
|
|
|
|
|
npc->jumpVelocity -= npc->jumpScale;
|
|
|
|
npc->pos.y += npc->jumpVelocity;
|
|
|
|
oldLength = length = fabsf(npc->jumpVelocity) + 16.0f;
|
|
|
|
|
|
|
|
yTemp = npc->pos.y + 13.0f;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
hit = npc_raycast_down_sides(npc->collisionChannel, &xTemp, &yTemp, &zTemp, &length);
|
2021-08-22 15:10:06 +02:00
|
|
|
} else {
|
2022-01-14 19:09:45 +01:00
|
|
|
hit = npc_raycast_down_around(npc->collisionChannel, &xTemp, &yTemp, &zTemp, &length, npc->yaw,
|
2021-08-22 15:10:06 +02:00
|
|
|
npc->collisionRadius);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hit && length <= oldLength) {
|
|
|
|
npc->jumpVelocity = 0.0f;
|
|
|
|
npc->flags |= NPC_FLAG_1000;
|
|
|
|
npc->pos.y = yTemp;
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->currentFloor = D_8010C97A;
|
2021-08-22 15:10:06 +02:00
|
|
|
} else {
|
|
|
|
npc->flags &= ~NPC_FLAG_1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-07-24 21:07:08 +02:00
|
|
|
s32 func_800397E8(Npc* npc, f32 arg1) {
|
2023-02-06 01:13:45 +01:00
|
|
|
if (!(npc->flags & (NPC_FLAG_GRAVITY | NPC_FLAG_8))) {
|
2021-07-24 21:07:08 +02:00
|
|
|
f32 x;
|
|
|
|
f32 y;
|
|
|
|
f32 z;
|
2021-08-22 15:10:06 +02:00
|
|
|
f32 length;
|
|
|
|
f32 oldLength;
|
2021-07-24 21:07:08 +02:00
|
|
|
s32 phi_v0;
|
|
|
|
|
2022-04-29 06:32:16 +02:00
|
|
|
if (npc->flags & NPC_FLAG_JUMPING) {
|
2021-07-24 21:07:08 +02:00
|
|
|
npc->flags &= ~NPC_FLAG_1000;
|
2022-06-13 18:34:22 +02:00
|
|
|
return FALSE;
|
2021-07-24 21:07:08 +02:00
|
|
|
}
|
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
length = oldLength = fabsf(arg1) + 16;
|
2021-07-24 21:07:08 +02:00
|
|
|
x = npc->pos.x;
|
|
|
|
y = npc->pos.y + 13;
|
|
|
|
z = npc->pos.z;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
phi_v0 = npc_raycast_down_sides(npc->collisionChannel, &x, &y, &z, &length);
|
2021-07-24 21:07:08 +02:00
|
|
|
} else {
|
2022-01-14 19:09:45 +01:00
|
|
|
phi_v0 = npc_raycast_down_around(npc->collisionChannel, &x, &y, &z, &length, npc->yaw, npc->collisionRadius);
|
2021-07-24 21:07:08 +02:00
|
|
|
}
|
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
if (phi_v0 != 0 && length <= oldLength) {
|
2021-07-24 21:07:08 +02:00
|
|
|
npc->pos.y = y;
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->currentFloor = D_8010C97A;
|
2021-07-24 21:07:08 +02:00
|
|
|
npc->flags |= NPC_FLAG_1000;
|
2022-06-13 18:34:22 +02:00
|
|
|
return TRUE;
|
2021-07-24 21:07:08 +02:00
|
|
|
}
|
|
|
|
} else {
|
2022-06-13 18:34:22 +02:00
|
|
|
return FALSE;
|
2021-07-24 21:07:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
npc->flags &= ~NPC_FLAG_1000;
|
2022-06-13 18:34:22 +02:00
|
|
|
return FALSE;
|
2021-07-24 21:07:08 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
void update_npcs(void) {
|
|
|
|
PlayerStatus* playerStatus = &gPlayerStatus;
|
|
|
|
f32 x, y, z;
|
|
|
|
f32 hitYaw, hitPitch, hitLength;
|
|
|
|
|
2023-01-12 03:09:13 +01:00
|
|
|
playerStatus->animFlags &= ~PA_FLAG_NPC_COLLIDED;
|
2022-04-05 14:53:40 +02:00
|
|
|
if (!(gOverrideFlags & (GLOBAL_OVERRIDES_800 | GLOBAL_OVERRIDES_400))) {
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < 0x40; i++) {
|
|
|
|
Npc* npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
|
|
|
|
if (npc != NULL) {
|
|
|
|
if (npc->flags != 0) {
|
|
|
|
if (npc->flags & (NPC_FLAG_80000000 | NPC_FLAG_4)) {
|
|
|
|
npc_do_world_collision(npc);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->onUpdate(npc);
|
|
|
|
if (npc->flags & NPC_FLAG_8000) {
|
2022-09-24 22:01:49 +02:00
|
|
|
npc->collisionChannel |= COLLISION_IGNORE_ENTITIES;
|
2022-04-05 14:53:40 +02:00
|
|
|
} else {
|
2022-09-24 22:01:49 +02:00
|
|
|
npc->collisionChannel &= ~COLLISION_IGNORE_ENTITIES;
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
npc->currentFloor = -1;
|
|
|
|
npc->currentWall = -1;
|
|
|
|
npc->flags &= ~(NPC_FLAG_4000 | NPC_FLAG_NO_PROJECT_SHADOW);
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_do_world_collision(npc);
|
|
|
|
npc_do_gravity(npc);
|
|
|
|
func_800397E8(npc, 0.0f);
|
|
|
|
npc_do_player_collision(npc);
|
|
|
|
npc_do_other_npc_collision(npc);
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_MOTION_BLUR) {
|
|
|
|
update_npc_blur(npc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((npc->pos.y < -2000.0f) && !(npc->flags & NPC_FLAG_PARTICLE)) {
|
|
|
|
npc->pos.y = playerStatus->position.y;
|
|
|
|
npc->jumpVelocity = 0.0f;
|
|
|
|
npc->moveSpeed = 0.0f;
|
|
|
|
npc->jumpScale = 0.0f;
|
2022-04-29 06:32:16 +02:00
|
|
|
npc->flags &= ~NPC_FLAG_JUMPING;
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
if (npc->currentAnim != 0) {
|
2022-04-05 14:53:40 +02:00
|
|
|
if (npc->spriteInstanceID >= 0) {
|
2022-09-13 08:26:57 +02:00
|
|
|
spr_update_sprite(npc->spriteInstanceID, npc->currentAnim, npc->animationSpeed);
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-01-27 23:26:26 +01:00
|
|
|
spr_update_player_sprite(PLAYER_SPRITE_AUX1, npc->currentAnim, npc->animationSpeed);
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_HAS_SHADOW) {
|
|
|
|
Shadow* shadow = get_shadow_by_index(npc->shadowIndex);
|
|
|
|
EntityModel* entityModel = get_entity_model(shadow->entityModelID);
|
|
|
|
|
2023-01-12 03:09:13 +01:00
|
|
|
entityModel->flags &= ~ENTITY_MODEL_FLAG_REFLECT;
|
2022-04-05 14:53:40 +02:00
|
|
|
if (npc->flags & NPC_FLAG_REFLECT_WALL) {
|
2023-01-12 03:09:13 +01:00
|
|
|
entityModel->flags |= ENTITY_MODEL_FLAG_REFLECT;
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
x = npc->pos.x;
|
|
|
|
y = npc->pos.y;
|
|
|
|
z = npc->pos.z;
|
2023-02-06 01:13:45 +01:00
|
|
|
if (!(npc->flags & NPC_FLAG_20)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
if (
|
|
|
|
x != npc->colliderPos.x ||
|
|
|
|
y != npc->colliderPos.y ||
|
|
|
|
z != npc->colliderPos.z ||
|
|
|
|
(npc->flags & NPC_FLAG_DIRTY_SHADOW))
|
|
|
|
{
|
|
|
|
x = npc->pos.x;
|
|
|
|
y = npc->pos.y + (npc->collisionHeight / 2);
|
|
|
|
z = npc->pos.z;
|
|
|
|
hitLength = 1000.0f;
|
|
|
|
entity_raycast_down(&x, &y, &z, &hitYaw, &hitPitch, &hitLength);
|
|
|
|
set_npc_shadow_scale(shadow, hitLength, npc->collisionRadius);
|
|
|
|
shadow->position.x = x;
|
|
|
|
shadow->position.y = y;
|
|
|
|
shadow->position.z = z;
|
|
|
|
shadow->rotation.x = hitYaw;
|
|
|
|
shadow->rotation.y = npc->renderYaw;
|
|
|
|
shadow->rotation.z = hitPitch;
|
|
|
|
shadow->scale.x *= npc->shadowScale;
|
|
|
|
npc->flags &= ~NPC_FLAG_DIRTY_SHADOW;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (npc->flags & NPC_FLAG_LOCK_ANIMS) {
|
|
|
|
shadow->position.x = npc->pos.x;
|
|
|
|
} else {
|
|
|
|
shadow->position.x = npc->pos.x;
|
|
|
|
shadow->position.y = npc->pos.y;
|
|
|
|
}
|
|
|
|
shadow->position.z = npc->pos.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->colliderPos.x = npc->pos.x;
|
|
|
|
npc->colliderPos.y = npc->pos.y;
|
|
|
|
npc->colliderPos.z = npc->pos.z;
|
|
|
|
npc_update_decorations(npc);
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
|
|
|
if (npc->spriteInstanceID < 0) {
|
|
|
|
npc->spriteInstanceID++;
|
|
|
|
if (npc->spriteInstanceID == -1) {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(npc->currentAnim, npc->extraAnimList);
|
2022-04-05 14:53:40 +02:00
|
|
|
ASSERT(npc->spriteInstanceID >= 0);
|
2022-09-13 08:26:57 +02:00
|
|
|
spr_update_sprite(npc->spriteInstanceID, npc->currentAnim, npc->animationSpeed);
|
2022-04-05 14:53:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// float regalloc, issue at the bottom with a mov.s
|
|
|
|
#ifdef NON_MATCHING
|
|
|
|
f32 npc_get_render_yaw(Npc* npc) {
|
|
|
|
Camera* camera = &gCameras[gCurrentCamID];
|
|
|
|
f32 cameraYaw;
|
|
|
|
f32 temp;
|
|
|
|
s32 phi_s0;
|
|
|
|
|
|
|
|
if (!(gOverrideFlags & (GLOBAL_OVERRIDES_8000 | GLOBAL_OVERRIDES_4000))) {
|
|
|
|
cameraYaw = camera->currentYaw;
|
|
|
|
temp = get_clamped_angle_diff(cameraYaw, npc->yaw);
|
|
|
|
|
|
|
|
if (temp < -5.0f && temp > -175.0f) {
|
|
|
|
phi_s0 = 0;
|
|
|
|
temp = clamp_angle(0.0f);
|
|
|
|
} else if (temp > 5.0f && temp < 175.0f) {
|
|
|
|
phi_s0 = 1;
|
|
|
|
temp = clamp_angle(180.0f);
|
|
|
|
} else {
|
|
|
|
phi_s0 = 2;
|
|
|
|
temp = clamp_angle(npc->yawCamOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->yawCamOffset = temp;
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_40000)) {
|
|
|
|
if (npc->isFacingAway != phi_s0 && phi_s0 != 2) {
|
|
|
|
npc->isFacingAway = phi_s0;
|
|
|
|
|
|
|
|
if (npc->isFacingAway) {
|
|
|
|
npc->turnAroundYawAdjustment = 180;
|
|
|
|
} else {
|
|
|
|
npc->turnAroundYawAdjustment = -180;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fabsf(get_clamped_angle_diff(cameraYaw, npc->yaw)) >= 90.0f) {
|
|
|
|
npc->turnAroundYawAdjustment = -npc->turnAroundYawAdjustment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->turnAroundYawAdjustment != 0) {
|
|
|
|
if (npc->turnAroundYawAdjustment < 0) {
|
|
|
|
npc->turnAroundYawAdjustment += 20;
|
|
|
|
}
|
|
|
|
if (npc->turnAroundYawAdjustment > 0) {
|
|
|
|
npc->turnAroundYawAdjustment -= 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_200000) {
|
|
|
|
npc->turnAroundYawAdjustment = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp = clamp_angle(clamp_angle(npc->turnAroundYawAdjustment + temp) - cameraYaw);
|
|
|
|
npc->renderYaw = temp;
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return npc->renderYaw;
|
|
|
|
}
|
|
|
|
#else
|
2021-06-30 04:27:12 +02:00
|
|
|
INCLUDE_ASM(f32, "npc", npc_get_render_yaw);
|
2022-04-05 14:53:40 +02:00
|
|
|
#endif
|
2021-06-15 10:05:16 +02:00
|
|
|
|
2022-10-16 16:22:18 +02:00
|
|
|
void appendGfx_npc(void* data) {
|
|
|
|
Npc* npc = data;
|
2022-04-05 14:53:40 +02:00
|
|
|
Matrix4f mtx1, mtx2;
|
|
|
|
f32 renderYaw = npc_get_render_yaw(npc);
|
2021-06-15 10:05:16 +02:00
|
|
|
|
2022-04-29 06:32:16 +02:00
|
|
|
guTranslateF(mtx1, npc->pos.x, npc->pos.y + npc->verticalRenderOffset, npc->pos.z);
|
2021-12-21 23:12:59 +01:00
|
|
|
if (npc->flags & NPC_FLAG_UPSIDE_DOWN) {
|
2022-04-05 14:53:40 +02:00
|
|
|
mtx_ident_mirror_y(mtx2);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->rotationVerticalPivotOffset != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guTranslateF(mtx2, 0.0f, npc->rotationVerticalPivotOffset, 0.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->rotation.y != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guRotateF(mtx2, npc->rotation.y, 0.0f, 1.0f, 0.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->rotation.x != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guRotateF(mtx2, npc->rotation.x, 1.0f, 0.0f, 0.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->rotation.z != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guRotateF(mtx2, npc->rotation.z, 0.0f, 0.0f, 1.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->rotationVerticalPivotOffset != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guTranslateF(mtx2, 0.0f, -npc->rotationVerticalPivotOffset, 0.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((npc->screenSpaceOffset2D[0] != 0.0f) || (npc->screenSpaceOffset2D[1] != 0.0f)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guTranslateF(mtx1, npc->screenSpaceOffset2D[0], npc->screenSpaceOffset2D[1], 0.0f);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-09-13 08:26:57 +02:00
|
|
|
if ((npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f) || ((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f)
|
|
|
|
|| (npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f)) {
|
|
|
|
guScaleF(mtx2, npc->scale.x * SPRITE_WORLD_SCALE_D, (npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D,
|
|
|
|
npc->scale.z * SPRITE_WORLD_SCALE_D);
|
2022-04-05 14:53:40 +02:00
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_1000000) && (npc->currentAnim != 0) && (npc->spriteInstanceID >= 0)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_with_palswap(npc, renderYaw, mtx1);
|
2022-09-15 21:39:16 +02:00
|
|
|
npc->animNotifyValue = spr_get_notify_value(npc->spriteInstanceID);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_with_palswap(npc, renderYaw, mtx1);
|
2022-09-15 21:39:16 +02:00
|
|
|
npc->animNotifyValue = func_802DDEC4(1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_REFLECT_WALL) {
|
2022-04-29 06:32:16 +02:00
|
|
|
guTranslateF(mtx1, npc->pos.x, npc->pos.y + npc->verticalRenderOffset, -npc->pos.z);
|
2021-12-21 23:12:59 +01:00
|
|
|
if (npc->flags & NPC_FLAG_UPSIDE_DOWN) {
|
2022-04-05 14:53:40 +02:00
|
|
|
mtx_ident_mirror_y(mtx2);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
if ((npc->rotation.y != 0.0f) || (npc->rotation.x != 0.0f) || (npc->rotation.z != 0.0f)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guRotateRPYF(mtx2, npc->rotation.x, npc->rotation.y, npc->rotation.z);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
|
2022-09-13 08:26:57 +02:00
|
|
|
if ((npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f) || ((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f)
|
|
|
|
|| (npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f))
|
2022-04-05 14:53:40 +02:00
|
|
|
{
|
|
|
|
do {
|
2022-09-13 08:26:57 +02:00
|
|
|
guScaleF(mtx2, npc->scale.x * SPRITE_WORLD_SCALE_D,
|
|
|
|
(npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D,
|
|
|
|
npc->scale.z * SPRITE_WORLD_SCALE_D);
|
2022-04-05 14:53:40 +02:00
|
|
|
} while (0); // required to match (macro?)
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_1000000) && (npc->currentAnim != 0)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-01-27 23:26:26 +01:00
|
|
|
spr_draw_player_sprite(PLAYER_SPRITE_AUX1 | DRAW_SPRITE_OVERRIDE_YAW, renderYaw, 0, 0, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_REFLECT_FLOOR) {
|
2022-04-29 06:32:16 +02:00
|
|
|
guTranslateF(mtx1, npc->pos.x, -(npc->pos.y + npc->verticalRenderOffset), npc->pos.z);
|
2022-04-05 14:53:40 +02:00
|
|
|
mtx_ident_mirror_y(mtx2);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
if (npc->rotation.y != 0.0f || npc->rotation.x != 0.0f || npc->rotation.z != 0.0f) {
|
2022-04-05 14:53:40 +02:00
|
|
|
guRotateRPYF(mtx2, npc->rotation.x, npc->rotation.y, npc->rotation.z);
|
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
2022-09-13 08:26:57 +02:00
|
|
|
if ((npc->scale.x * SPRITE_WORLD_SCALE_D != 1.0f) || ((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D != 1.0f)
|
|
|
|
|| (npc->scale.z * SPRITE_WORLD_SCALE_D != 1.0f))
|
2022-04-05 14:53:40 +02:00
|
|
|
{
|
|
|
|
do {
|
2022-09-13 08:26:57 +02:00
|
|
|
guScaleF(mtx2, npc->scale.x * SPRITE_WORLD_SCALE_D,
|
|
|
|
(npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D,
|
|
|
|
npc->scale.z * SPRITE_WORLD_SCALE_D);
|
2022-04-05 14:53:40 +02:00
|
|
|
} while (0); // required to match (macro?)
|
2021-06-15 10:05:16 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
guMtxCatF(mtx2, mtx1, mtx1);
|
|
|
|
}
|
2021-06-15 10:05:16 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_1000000) && (npc->currentAnim != 0)) {
|
2022-04-05 14:53:40 +02:00
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID, renderYaw, 0, 0, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-01-27 23:26:26 +01:00
|
|
|
spr_draw_player_sprite(PLAYER_SPRITE_AUX1 | DRAW_SPRITE_OVERRIDE_YAW, renderYaw, 0, 0, mtx1);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
npc->onRender(npc);
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void render_npcs(void) {
|
2021-06-15 10:05:16 +02:00
|
|
|
f32 temp_f20;
|
|
|
|
Npc* npc;
|
|
|
|
f32 phi_f20;
|
|
|
|
s32 i;
|
|
|
|
RenderTask renderTask;
|
2021-09-27 01:19:58 +02:00
|
|
|
RenderTask* renderTaskPtr = &renderTask;
|
2021-06-15 10:05:16 +02:00
|
|
|
f32 x;
|
|
|
|
f32 y;
|
|
|
|
f32 z;
|
|
|
|
f32 s;
|
|
|
|
Camera* cam = &gCameras[gCurrentCamID];
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
|
|
|
|
Npc* npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
if (npc != NULL) {
|
|
|
|
if (npc->flags && !(npc->flags & (NPC_FLAG_80000000 | NPC_FLAG_1000000 | NPC_FLAG_4 | NPC_FLAG_2))) {
|
2022-03-30 14:07:13 +02:00
|
|
|
transform_point(cam->perspectiveMatrix, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &x, &y, &z, &s);
|
2021-06-15 10:05:16 +02:00
|
|
|
if (!(s < 0.01) || !(s > -0.01)) {
|
|
|
|
phi_f20 = ((z * 5000.0f) / s) + 5000.0f;
|
|
|
|
if (phi_f20 < 0.0f) {
|
|
|
|
phi_f20 = 0.0f;
|
|
|
|
} else if (phi_f20 > 10000.0f) {
|
|
|
|
phi_f20 = 10000.0f;
|
|
|
|
}
|
|
|
|
|
2021-09-27 01:19:58 +02:00
|
|
|
renderTaskPtr->distance = -phi_f20;
|
|
|
|
renderTaskPtr->appendGfxArg = npc;
|
|
|
|
renderTaskPtr->appendGfx = appendGfx_npc;
|
|
|
|
renderTaskPtr->renderMode = npc->renderMode;
|
|
|
|
|
2023-02-06 01:13:45 +01:00
|
|
|
if (npc->flags & NPC_FLAG_HIDING) {
|
2021-06-15 10:05:16 +02:00
|
|
|
u8 r, g, b, a;
|
|
|
|
get_background_color_blend(&r, &g, &b, &a);
|
2023-02-06 01:13:45 +01:00
|
|
|
npc->alpha2 = 255 - a;
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2023-02-06 01:13:45 +01:00
|
|
|
npc->alpha2 = 255;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->alpha2 != 0) {
|
2021-09-27 01:19:58 +02:00
|
|
|
queue_render_task(renderTaskPtr);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
2023-02-06 01:13:45 +01:00
|
|
|
if (npc->flags & NPC_FLAG_MOTION_BLUR) {
|
2021-09-27 01:19:58 +02:00
|
|
|
renderTaskPtr->distance = -phi_f20;
|
2022-12-29 06:48:27 +01:00
|
|
|
renderTaskPtr->appendGfx = appendGfx_npc_blur;
|
2021-09-27 01:19:58 +02:00
|
|
|
renderTaskPtr->appendGfxArg = npc;
|
|
|
|
renderTaskPtr->renderMode = RENDER_MODE_SURFACE_XLU_LAYER1;
|
|
|
|
queue_render_task(renderTaskPtr);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2020-12-20 04:47:09 +01:00
|
|
|
void npc_move_heading(Npc* npc, f32 speed, f32 yaw) {
|
2022-09-15 21:39:16 +02:00
|
|
|
f32 angle = DEG_TO_RAD(yaw);
|
2020-12-20 04:47:09 +01:00
|
|
|
f32 sin = sin_rad(angle);
|
|
|
|
f32 cos = cos_rad(angle);
|
|
|
|
|
|
|
|
npc->pos.x += speed * sin;
|
|
|
|
npc->pos.z += -speed * cos;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-10-03 19:42:38 +02:00
|
|
|
Npc* get_npc_unsafe(s32 npcID) {
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 i;
|
|
|
|
Npc* npc;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(i < MAX_NPCS);
|
|
|
|
|
|
|
|
return npc;
|
|
|
|
}
|
|
|
|
|
2021-10-03 19:42:38 +02:00
|
|
|
Npc* get_npc_safe(s32 npcID) {
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 i;
|
|
|
|
Npc* npc;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
if (npc != NULL && npc->flags != 0 && npc->npcID == npcID) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= MAX_NPCS) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return npc;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-21 13:16:00 +01:00
|
|
|
void enable_npc_shadow(Npc* npc) {
|
|
|
|
Shadow* shadow;
|
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_HAS_SHADOW)) {
|
2021-03-21 13:16:00 +01:00
|
|
|
shadow = get_shadow_by_index(npc->shadowIndex);
|
2023-01-12 03:09:13 +01:00
|
|
|
shadow->flags &= ~ENTITY_FLAG_HIDDEN;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->flags = npc->flags | (NPC_FLAG_DIRTY_SHADOW | NPC_FLAG_HAS_SHADOW);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void disable_npc_shadow(Npc* npc) {
|
|
|
|
Shadow* shadow;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (npc->flags & NPC_FLAG_HAS_SHADOW) {
|
2021-03-21 13:16:00 +01:00
|
|
|
shadow = get_shadow_by_index(npc->shadowIndex);
|
2023-01-12 03:09:13 +01:00
|
|
|
shadow->flags |= ENTITY_FLAG_HIDDEN;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->flags &= ~NPC_FLAG_HAS_SHADOW;
|
|
|
|
npc->flags &= ~NPC_FLAG_DIRTY_SHADOW;
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-16 16:22:18 +02:00
|
|
|
void set_npc_sprite(Npc* npc, s32 anim, AnimID* extraAnimList) {
|
2021-06-30 04:27:12 +02:00
|
|
|
ASSERT((npc->flags & NPC_FLAG_1000000) || spr_free_sprite(npc->spriteInstanceID) == 0);
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-04-17 13:16:13 +02:00
|
|
|
npc->extraAnimList = extraAnimList;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-04-17 13:16:13 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(anim, extraAnimList);
|
2021-04-17 13:16:13 +02:00
|
|
|
ASSERT(npc->spriteInstanceID >= 0);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->currentAnim = anim;
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
2021-04-26 19:47:38 +02:00
|
|
|
spr_update_sprite(npc->spriteInstanceID, anim, npc->animationSpeed);
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 09:39:43 +01:00
|
|
|
void enable_npc_blur(Npc* npc) {
|
2021-06-15 10:05:16 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_MOTION_BLUR)) {
|
2022-08-10 15:36:38 +02:00
|
|
|
NpcMotionBlur* motionBlur;
|
2021-04-26 19:47:38 +02:00
|
|
|
s32 i;
|
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->flags |= NPC_FLAG_MOTION_BLUR;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
motionBlur = heap_malloc(sizeof(*motionBlur));
|
|
|
|
npc->blur.motion = motionBlur;
|
|
|
|
ASSERT(motionBlur != NULL);
|
|
|
|
motionBlur->unk_00 = 0;
|
|
|
|
motionBlur->index = 0;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(motionBlur->x); i++) {
|
|
|
|
motionBlur->x[i] = npc->pos.x;
|
|
|
|
motionBlur->y[i] = npc->pos.y;
|
|
|
|
motionBlur->z[i] = npc->pos.z;
|
2021-03-21 13:16:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2020-10-09 20:26:17 +02:00
|
|
|
void disable_npc_blur(Npc* npc) {
|
2021-06-15 10:05:16 +02:00
|
|
|
if (npc->flags & NPC_FLAG_MOTION_BLUR) {
|
|
|
|
npc->flags &= ~NPC_FLAG_MOTION_BLUR;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
heap_free(npc->blur.motion);
|
|
|
|
npc->blur.motion = NULL;
|
2020-10-08 23:45:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 20:26:17 +02:00
|
|
|
void update_npc_blur(Npc* npc) {
|
2022-08-10 15:36:38 +02:00
|
|
|
NpcMotionBlur* motionBlur = npc->blur.motion;
|
|
|
|
s32 index = motionBlur->index;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
motionBlur->x[index] = npc->pos.x;
|
|
|
|
motionBlur->y[index] = npc->pos.y;
|
|
|
|
motionBlur->z[index] = npc->pos.z;
|
2020-10-08 23:45:26 +02:00
|
|
|
|
|
|
|
index++;
|
|
|
|
if (index >= 20) {
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
2022-08-10 15:36:38 +02:00
|
|
|
motionBlur->index = index;
|
2020-10-08 23:45:26 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-12-29 06:48:27 +01:00
|
|
|
void appendGfx_npc_blur(void* data) {
|
|
|
|
Npc* npc = (Npc*) data;
|
2022-12-07 09:39:22 +01:00
|
|
|
Matrix4f sp20, sp60;
|
|
|
|
f32 x, y, z;
|
|
|
|
f32 yaw;
|
|
|
|
s32 var_s3;
|
|
|
|
s32 var_s5;
|
|
|
|
s32 index;
|
|
|
|
NpcMotionBlur* blur;
|
|
|
|
|
|
|
|
var_s3 = 0;
|
|
|
|
var_s5 = 0;
|
|
|
|
blur = npc->blur.motion;
|
|
|
|
index = blur->index;
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
index--;
|
|
|
|
var_s3++;
|
|
|
|
if (index < 0) {
|
|
|
|
index = ARRAY_COUNT(blur->x) - 1;
|
|
|
|
}
|
|
|
|
if (index == blur->index) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (var_s3 >= 3) {
|
|
|
|
var_s3 = 0;
|
|
|
|
var_s5++;
|
|
|
|
if (var_s5 >= 4) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = blur->x[index];
|
|
|
|
y = blur->y[index];
|
|
|
|
z = blur->z[index];
|
|
|
|
func_802DE894(npc->spriteInstanceID, 7, 255, 255, 255, 120 - (var_s5 * 20), 0);
|
|
|
|
yaw = npc->renderYaw;
|
|
|
|
guTranslateF(sp20, x, y, z);
|
|
|
|
|
|
|
|
if (npc->rotation.y != 0.0f) {
|
|
|
|
guRotateF(sp60, npc->rotation.y, 0.0f, 1.0f, 0.0f);
|
|
|
|
guMtxCatF(sp60, sp20, sp20);
|
|
|
|
}
|
|
|
|
if (npc->rotation.x != 0.0f) {
|
|
|
|
guRotateF(sp60, npc->rotation.y, 0.0f, 1.0f, 0.0f);
|
|
|
|
guMtxCatF(sp60, sp20, sp20);
|
|
|
|
}
|
|
|
|
if (npc->rotation.z != 0.0f) {
|
|
|
|
guRotateF(sp60, npc->rotation.y, 0.0f, 1.0f, 0.0f);
|
|
|
|
guMtxCatF(sp60, sp20, sp20);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
(npc->scale.x * SPRITE_WORLD_SCALE_D) != 1.0 ||
|
|
|
|
((npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D) != 1.0 ||
|
|
|
|
(npc->scale.z * SPRITE_WORLD_SCALE_D) != 1.0)
|
|
|
|
{
|
|
|
|
guScaleF(
|
|
|
|
sp60,
|
|
|
|
npc->scale.x * SPRITE_WORLD_SCALE_D,
|
|
|
|
(npc->scale.y * npc->verticalStretch) * SPRITE_WORLD_SCALE_D,
|
|
|
|
npc->scale.z * SPRITE_WORLD_SCALE_D
|
|
|
|
);
|
|
|
|
guMtxCatF(sp60, sp20, sp20);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID, (s32) yaw, 0, 0, sp20);
|
|
|
|
}
|
|
|
|
} else {
|
2023-01-27 23:26:26 +01:00
|
|
|
spr_draw_player_sprite(PLAYER_SPRITE_AUX1 | DRAW_SPRITE_OVERRIDE_YAW, (s32) yaw, 0, 0, sp20);
|
2022-12-07 09:39:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func_8003D3BC(npc);
|
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_enable_collisions(void) {
|
2021-06-15 10:05:16 +02:00
|
|
|
D_800A0B94 = 1;
|
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_disable_collisions(void) {
|
2021-06-15 10:05:16 +02:00
|
|
|
D_800A0B94 = 0;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2020-10-14 18:15:50 +02:00
|
|
|
void func_8003B1A8(void) {
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_reload_all(void) {
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_NPCS; i++) {
|
|
|
|
Npc* npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
if (npc != NULL) {
|
|
|
|
if (npc->flags && !(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_PARTICLE)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(npc->currentAnim, npc->extraAnimList);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spriteInstanceID = spr_load_npc_sprite(npc->currentAnim | SPRITE_ID_TAIL_ALLOCATE, npc->extraAnimList);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2022-01-05 12:05:49 +01:00
|
|
|
if (!(npc->flags & NPC_FLAG_1000000) && (npc->palSwapType != 0)) {
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->spritePaletteList = spr_get_npc_palettes(npc->currentAnim >> 16);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->paletteCount = 0;
|
2022-10-16 16:22:18 +02:00
|
|
|
while (npc->spritePaletteList[npc->paletteCount] != (PAL_PTR) -1) {
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->paletteCount++;
|
|
|
|
}
|
2022-09-13 08:26:57 +02:00
|
|
|
npc->unk_C0 = spr_get_npc_color_variations(npc->currentAnim >> 16);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_1000000)) {
|
|
|
|
for (j = 0; j < 2; j++) {
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_reset_current_decoration(npc, j);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
func_8003D3BC(npc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
void set_npc_yaw(Npc* npc, f32 yaw) {
|
|
|
|
npc->yaw = yaw;
|
2020-12-20 04:47:09 +01:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
if (get_clamped_angle_diff(gCameras[gCurrentCameraID].currentYaw, yaw) >= 0.0f) {
|
2020-12-20 04:47:09 +01:00
|
|
|
npc->yawCamOffset = 180;
|
|
|
|
npc->isFacingAway = TRUE;
|
|
|
|
} else {
|
|
|
|
npc->yawCamOffset = 0;
|
|
|
|
npc->isFacingAway = FALSE;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-01-05 12:05:49 +01:00
|
|
|
void npc_set_palswap_mode_A(Npc* npc, s32 mode) {
|
|
|
|
if (npc->palSwapType != mode) {
|
|
|
|
npc->palSwapPrevType = npc->palSwapType;
|
|
|
|
npc->palSwapType = mode;
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->dirtyPalettes = 1;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-01-05 12:05:49 +01:00
|
|
|
void npc_set_palswap_mode_B(Npc* npc, s32 mode) {
|
|
|
|
if (npc->palSwapType != mode) {
|
|
|
|
npc->palSwapPrevType = npc->palSwapType;
|
|
|
|
npc->palSwapType = mode;
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->dirtyPalettes = -1;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
void func_8003B420(Npc* npc) {
|
2022-01-05 12:05:49 +01:00
|
|
|
if (npc->palSwapPrevType == 0) {
|
|
|
|
npc->palSwapType = 0;
|
2021-06-15 10:05:16 +02:00
|
|
|
return;
|
|
|
|
}
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->palSwapType = npc->palSwapPrevType;
|
|
|
|
npc->palSwapPrevType = 0;
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->dirtyPalettes = 1;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
void npc_set_palswap_1(Npc* npc, s32 palIndexA, s32 palIndexB, s32 timeHoldA, s32 timeAB) {
|
|
|
|
npc->unk_308 = palIndexA;
|
|
|
|
npc->unk_30A = palIndexB;
|
|
|
|
npc->unk_30C = timeHoldA;
|
|
|
|
npc->unk_30E = timeAB;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
void npc_set_palswap_2(Npc* npc, s32 timeHoldB, s32 timeBA, s32 palIndexC, s32 palIndexD) {
|
|
|
|
npc->unk_310 = timeHoldB;
|
|
|
|
npc->unk_312 = timeBA;
|
|
|
|
npc->unk_314 = palIndexC;
|
|
|
|
npc->unk_316 = palIndexD;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
void npc_draw_with_palswap(Npc* npc, s32 arg1, Matrix4f mtx) {
|
2022-01-05 12:05:49 +01:00
|
|
|
switch (npc->palSwapType) {
|
2021-06-15 10:05:16 +02:00
|
|
|
case 0:
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_palswap_mode_0(npc, arg1, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_palswap_mode_1(npc, arg1, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_palswap_mode_2(npc, arg1, 0, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_palswap_mode_2(npc, arg1, 1, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2022-04-05 14:53:40 +02:00
|
|
|
npc_draw_palswap_mode_4(npc, arg1, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
void npc_draw_palswap_mode_0(Npc* npc, s32 arg1, Matrix4f mtx) {
|
2022-01-05 12:05:49 +01:00
|
|
|
if (npc->dirtyPalettes != 0) {
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->screenSpaceOffset2D[0] = 0.0f;
|
|
|
|
npc->screenSpaceOffset2D[1] = 0.0f;
|
2022-01-05 12:05:49 +01:00
|
|
|
npc->dirtyPalettes = 0;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->verticalStretch = 1.0f;
|
|
|
|
}
|
2021-06-16 11:52:15 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
2022-10-10 23:57:21 +02:00
|
|
|
s32 alpha = (npc->alpha * npc->alpha2 / 255);
|
|
|
|
u32 mask;
|
|
|
|
if (alpha < 255) {
|
|
|
|
mask = DRAW_SPRITE_OVERRIDE_ALPHA;
|
|
|
|
} else {
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, NULL, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2023-01-27 23:26:26 +01:00
|
|
|
spr_draw_player_sprite(PLAYER_SPRITE_AUX1 | DRAW_SPRITE_OVERRIDE_YAW, arg1, 0, 0, mtx);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-10 23:57:21 +02:00
|
|
|
s32 npc_draw_palswap_mode_1(Npc* npc, s32 arg1, Matrix4f mtx) {
|
|
|
|
s32 i, j;
|
|
|
|
s32 temp3;
|
|
|
|
PAL_PTR src;
|
|
|
|
PAL_PTR dst;
|
|
|
|
|
|
|
|
if (npc->dirtyPalettes != 0) {
|
|
|
|
npc->spritePaletteList = spr_get_npc_palettes(npc->currentAnim >> 16);
|
|
|
|
npc->paletteCount = 0;
|
|
|
|
while ((s32)npc->spritePaletteList[npc->paletteCount] != -1) {
|
|
|
|
npc->paletteCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->unk_C0 = spr_get_npc_color_variations(npc->currentAnim >> 16);
|
|
|
|
for (i = 0; i < npc->paletteCount; i++) {
|
|
|
|
dst = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[i];
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->palSwapState = -2;
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->dirtyPalettes = 0;
|
|
|
|
npc->palSwapTimer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->palSwapTimer == 0) {
|
|
|
|
npc->palSwapState += 2;
|
|
|
|
temp3 = D_80077BF0[npc->palSwapState];
|
|
|
|
if (temp3 == 255) {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
}
|
|
|
|
npc->palSwapTimer = D_80077BF0[npc->palSwapState + 1] / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp3 = D_80077BF0[npc->palSwapState];
|
|
|
|
npc->palSwapTimer--;
|
|
|
|
|
|
|
|
switch(temp3) {
|
|
|
|
case 0:
|
|
|
|
for (i = 0; i < npc->unk_C0; i++) {
|
|
|
|
dst = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[i];
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
for (i = 0; i < npc->unk_C0; i++) {
|
|
|
|
dst = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[npc->unk_C0 * 5 + i];
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
for (i = 0; i < npc->unk_C0; i++) {
|
|
|
|
dst = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[npc->unk_C0 * 6 + i];
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < npc->paletteCount; i++) {
|
|
|
|
npc->localPalettes[i] = npc->localPaletteData[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
s32 alpha = npc->alpha * npc->alpha2 / 255;
|
|
|
|
u32 mask;
|
|
|
|
if (alpha < 255) {
|
|
|
|
mask = DRAW_SPRITE_OVERRIDE_ALPHA;
|
|
|
|
} else {
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
mask |= DRAW_SPRITE_OVERRIDE_PALETTES;
|
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, alpha, npc->localPalettes, mtx);
|
|
|
|
}
|
|
|
|
npc->palSwapLerpAlpha--;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-04-05 14:53:40 +02:00
|
|
|
u16 npc_blend_palette_colors(u16 colorA, u16 colorB, s32 lerpAlpha) {
|
|
|
|
u32 r = ((((colorA >> 11) & 0x1F) * (255 - lerpAlpha)) + (((colorB >> 11) & 0x1F) * lerpAlpha)) / 255;
|
|
|
|
u32 g = ((((colorA >> 6) & 0x1F) * (255 - lerpAlpha)) + (((colorB >> 6) & 0x1F) * lerpAlpha)) / 255;
|
|
|
|
u32 b = ((((colorA >> 1) & 0x1F) * (255 - lerpAlpha)) + (((colorB >> 1) & 0x1F) * lerpAlpha)) / 255;
|
|
|
|
|
|
|
|
return (colorB & 1) | (((r & 0xFF) << 11) | ((g & 0xFF) << 6) | ((b & 0xFF) << 1));
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-10 23:57:21 +02:00
|
|
|
s32 npc_draw_palswap_mode_2(Npc* npc, s32 arg1, s32 arg2, Matrix4f mtx) {
|
|
|
|
s32 i, j;
|
|
|
|
PAL_PTR src;
|
|
|
|
PAL_PTR dst;
|
|
|
|
PAL_PTR src2;
|
|
|
|
s32 blendAlpha;
|
|
|
|
|
|
|
|
if (npc->dirtyPalettes != 0) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
npc->spritePaletteList = spr_get_npc_palettes(npc->currentAnim >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->paletteCount = 0;
|
|
|
|
while ((s32)npc->spritePaletteList[npc->paletteCount] != -1) {
|
|
|
|
npc->paletteCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->dirtyPalettes == 1) {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
} else {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapLerpAlpha = 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < npc->paletteCount; i++) {
|
|
|
|
src2 = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[i];
|
|
|
|
npc->localPalettes[i] = src2;
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*src2++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-10 23:57:21 +02:00
|
|
|
if (arg2 == 0) {
|
|
|
|
s32 temp2 = npc->unk_30C;
|
|
|
|
npc->unk_30C = 0;
|
|
|
|
npc->unk_30E = temp2;
|
|
|
|
npc->unk_310 = temp2;
|
|
|
|
npc->unk_312 = npc->unk_30E;
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->dirtyPalettes = 0;
|
|
|
|
npc->palSwapTimer = npc->unk_30C;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (npc->palSwapState) {
|
|
|
|
case 0:
|
|
|
|
if (npc->palSwapTimer != 0) {
|
|
|
|
npc->palSwapTimer--;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 1;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
case 1:
|
|
|
|
npc->palSwapLerpAlpha += 25600 / npc->unk_30E;
|
|
|
|
if (npc->palSwapLerpAlpha > 25500) {
|
|
|
|
npc->palSwapLerpAlpha = 25500;
|
|
|
|
}
|
|
|
|
blendAlpha = npc->palSwapLerpAlpha / 100;
|
|
|
|
dst = npc->localPaletteData[0];
|
|
|
|
src = npc->spritePaletteList[npc->unk_308];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_30A];
|
|
|
|
npc->localPalettes[0] = dst;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blendAlpha == 255) {
|
|
|
|
npc->palSwapState = 2;
|
|
|
|
npc->palSwapTimer = npc->unk_310;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (npc->palSwapState) {
|
|
|
|
case 2:
|
|
|
|
if (npc->palSwapTimer != 0) {
|
|
|
|
npc->palSwapTimer--;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 3;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
case 3:
|
|
|
|
npc->palSwapLerpAlpha += 25600 / npc->unk_312;
|
|
|
|
if (npc->palSwapLerpAlpha > 25500) {
|
|
|
|
npc->palSwapLerpAlpha = 25500;
|
|
|
|
}
|
|
|
|
blendAlpha = npc->palSwapLerpAlpha / 100;
|
|
|
|
dst = npc->localPaletteData[0];
|
|
|
|
src = npc->spritePaletteList[npc->unk_30A];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_308];
|
|
|
|
npc->localPalettes[0] = dst;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blendAlpha == 255) {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapTimer = npc->unk_30C;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->palSwapState < 4) {
|
|
|
|
if (npc->palSwapState >= 0) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
u32 mask;
|
|
|
|
blendAlpha = npc->alpha * npc->alpha2 / 255;
|
|
|
|
if (blendAlpha < 255) {
|
|
|
|
mask = DRAW_SPRITE_OVERRIDE_ALPHA;
|
|
|
|
} else {
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
mask |= DRAW_SPRITE_OVERRIDE_PALETTES;
|
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID | mask, arg1, blendAlpha, npc->localPalettes, mtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 npc_draw_palswap_mode_4(Npc* npc, s32 arg1, Matrix4f mtx) {
|
|
|
|
s32 i, j;
|
|
|
|
PAL_PTR src;
|
|
|
|
PAL_PTR src2;
|
|
|
|
PAL_PTR dst;
|
|
|
|
u8 blendAlpha;
|
|
|
|
|
|
|
|
if (npc->dirtyPalettes != 0) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
npc->spritePaletteList = spr_get_npc_palettes(npc->currentAnim >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->paletteCount = 0;
|
|
|
|
while ((s32)npc->spritePaletteList[npc->paletteCount] != -1) {
|
|
|
|
npc->paletteCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->dirtyPalettes == 1) {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
} else {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapLerpAlpha = 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < npc->paletteCount; i++) {
|
|
|
|
src2 = npc->localPaletteData[i];
|
|
|
|
src = npc->spritePaletteList[i];
|
|
|
|
npc->localPalettes[i] = src2;
|
|
|
|
if (src != NULL) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*src2++ = *src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->dirtyPalettes = 0;
|
|
|
|
npc->palSwapTimer = npc->unk_30C;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (npc->palSwapState) {
|
|
|
|
case 0:
|
|
|
|
if (npc->palSwapTimer != 0) {
|
|
|
|
npc->palSwapTimer--;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 1;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
case 1:
|
|
|
|
npc->palSwapLerpAlpha += 25600 / npc->unk_30E;
|
|
|
|
if (npc->palSwapLerpAlpha > 25500) {
|
|
|
|
npc->palSwapLerpAlpha = 25500;
|
|
|
|
}
|
|
|
|
blendAlpha = npc->palSwapLerpAlpha / 100;
|
|
|
|
|
|
|
|
dst = npc->localPaletteData[0];
|
|
|
|
src = npc->spritePaletteList[npc->unk_308];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_30A];
|
|
|
|
npc->localPalettes[0] = dst;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
dst = npc->localPaletteData[3];
|
|
|
|
src = npc->spritePaletteList[npc->unk_314];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_316];
|
|
|
|
npc->localPalettes[3] = dst;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blendAlpha == 255) {
|
|
|
|
npc->palSwapState = 2;
|
|
|
|
npc->palSwapTimer = npc->unk_310;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (npc->palSwapState) {
|
|
|
|
case 2:
|
|
|
|
if (npc->palSwapTimer != 0) {
|
|
|
|
npc->palSwapTimer--;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
npc->palSwapLerpAlpha = 0;
|
|
|
|
npc->palSwapState = 3;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
case 3:
|
|
|
|
npc->palSwapLerpAlpha += 25600 / npc->unk_312;
|
|
|
|
if (npc->palSwapLerpAlpha > 25500) {
|
|
|
|
npc->palSwapLerpAlpha = 25500;
|
|
|
|
}
|
|
|
|
blendAlpha = npc->palSwapLerpAlpha / 100;
|
|
|
|
|
|
|
|
dst = npc->localPaletteData[0];
|
|
|
|
src = npc->spritePaletteList[npc->unk_30A];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_308];
|
|
|
|
npc->localPalettes[0] = dst;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
dst = npc->localPaletteData[1];
|
|
|
|
src = npc->spritePaletteList[npc->unk_316];
|
|
|
|
src2 = npc->spritePaletteList[npc->unk_314];
|
|
|
|
npc->localPalettes[3] = npc->localPaletteData[3];
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
*dst++ = npc_blend_palette_colors(*src++, *src2++, blendAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blendAlpha == 255) {
|
|
|
|
npc->palSwapState = 0;
|
|
|
|
npc->palSwapTimer = npc->unk_30C;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npc->palSwapState < 4) {
|
|
|
|
if (npc->palSwapState >= 0) {
|
|
|
|
if (!(npc->flags & NPC_FLAG_NO_ANIMS_LOADED)) {
|
|
|
|
s32 temp;
|
|
|
|
u32 spriteInstanceMask;
|
|
|
|
|
|
|
|
blendAlpha = npc->alpha * npc->alpha2 / 255;
|
|
|
|
temp = blendAlpha < 255;
|
|
|
|
spriteInstanceMask = ((temp) << 31) | 0x20000000;
|
|
|
|
spr_draw_npc_sprite(npc->spriteInstanceID | spriteInstanceMask, arg1, blendAlpha, npc->localPalettes, mtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_set_decoration(Npc* npc, s32 idx, s32 decorationType) {
|
|
|
|
npc__remove_decoration(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationType[idx] = decorationType;
|
|
|
|
npc->changedDecoration[idx] = 1;
|
|
|
|
npc->decorationInitialised[idx] = 0;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration(Npc* npc, s32 idx) {
|
|
|
|
npc__remove_decoration(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 npc_update_decorations(Npc* npc) {
|
|
|
|
s32 i;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
switch (npc->decorationType[i]) {
|
|
|
|
case 0:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_none(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_bowser_aura(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_sweat(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_seeing_stars(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_glow_in_front(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_glow_behind(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 6:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_update_decoration_charged(npc, i);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc__remove_decoration(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
switch (npc->decorationType[idx]) {
|
|
|
|
case 0:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_none(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_bowser_aura(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_sweat(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_seeing_stars(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_glow_in_front(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_glow_behind(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
case 6:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc_remove_decoration_charged(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
npc->decorationType[idx] = 0;
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_reset_current_decoration(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
switch (npc->decorationType[idx]) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
break;
|
|
|
|
case 6:
|
2021-06-30 04:27:12 +02:00
|
|
|
npc__reset_current_decoration(npc, idx);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_none(Npc* npc, s32 idx) {
|
2020-10-14 18:15:50 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_none(Npc* npc, s32 idx) {
|
2020-10-14 18:15:50 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_bowser_aura(Npc* npc, s32 idx) {
|
2022-08-07 14:42:54 +02:00
|
|
|
AuraFXData* data;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
switch (npc->decorationInitialised[idx]) {
|
|
|
|
case 0:
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_aura(2, npc->pos.x, npc->pos.y, npc->pos.z, 1.0f, &npc->decorations[idx]);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationInitialised[idx] = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-07 14:42:54 +02:00
|
|
|
data = npc->decorations[idx]->data.aura;
|
|
|
|
data->posA.x = npc->pos.x;
|
|
|
|
data->posA.y = npc->pos.y;
|
|
|
|
data->posA.z = npc->pos.z;
|
|
|
|
data->scale.x = (npc->scale.x * npc->collisionRadius) * 0.01;
|
|
|
|
data->scale.y = (npc->scale.y * npc->collisionHeight) * 0.01;
|
|
|
|
data->renderYaw = npc->renderYaw;
|
2020-10-14 18:15:50 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_bowser_aura(Npc* npc, s32 idx) {
|
2022-08-07 14:42:54 +02:00
|
|
|
npc->decorations[idx]->data.aura->fadeTime = 5;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_sweat(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
switch (npc->decorationInitialised[idx]) {
|
|
|
|
case 0:
|
|
|
|
if (npc->yawCamOffset > 90) {
|
2022-06-10 20:06:12 +02:00
|
|
|
fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, 45.0f, 20);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-06-10 20:06:12 +02:00
|
|
|
fx_sweat(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 5.0f, -45.0f, 20);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
npc->decorationUnk[idx] = 10;
|
|
|
|
npc->decorationInitialised[idx] = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (npc->decorationUnk[idx] != 0) {
|
|
|
|
npc->decorationUnk[idx]--;
|
|
|
|
} else {
|
|
|
|
npc->decorationInitialised[idx] = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_sweat(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_seeing_stars(Npc* npc, s32 idx) {
|
2022-08-07 14:42:54 +02:00
|
|
|
StarsOrbitingFXData* data;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
switch (npc->decorationInitialised[idx]) {
|
|
|
|
case 0:
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_stars_orbiting(0, npc->pos.x, npc->pos.y + npc->collisionHeight, npc->pos.z, 20.0f, 3, &npc->decorations[idx]);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationInitialised[idx] = 1;
|
|
|
|
return;
|
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-08-07 14:42:54 +02:00
|
|
|
data = npc->decorations[idx]->data.starsOrbiting;
|
|
|
|
data->pos.x = npc->pos.x;
|
|
|
|
data->pos.y = npc->pos.y + npc->collisionHeight;
|
|
|
|
data->pos.z = npc->pos.z;
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_seeing_stars(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
remove_effect(npc->decorations[idx]);
|
2020-10-14 18:15:50 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_glow_in_front(Npc* npc, s32 idx) {
|
2022-08-07 14:42:54 +02:00
|
|
|
EnergyOrbWaveFXData* data;
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
switch (npc->decorationInitialised[idx]) {
|
|
|
|
case 0:
|
2022-08-07 14:42:54 +02:00
|
|
|
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);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationInitialised[idx] = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
2022-08-07 14:42:54 +02:00
|
|
|
data = npc->decorations[idx]->data.energyOrbWave;
|
|
|
|
data->pos.x = npc->pos.x;
|
|
|
|
data->pos.y = npc->pos.y + npc->collisionHeight * 0.5 * npc->scale.x;
|
|
|
|
data->pos.z = npc->pos.z;
|
|
|
|
data->scale = npc->scale.x * 0.8 + 0.2f;
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_glow_in_front(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
remove_effect(npc->decorations[idx]);
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_glow_behind(Npc* npc, s32 idx) {
|
2022-08-07 14:42:54 +02:00
|
|
|
EnergyOrbWaveFXData* data;
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
switch (npc->decorationInitialised[idx]) {
|
|
|
|
case 0:
|
2022-08-07 14:42:54 +02:00
|
|
|
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);
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationInitialised[idx] = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
2022-08-07 14:42:54 +02:00
|
|
|
data = npc->decorations[idx]->data.energyOrbWave;
|
|
|
|
data->pos.x = npc->pos.x;
|
|
|
|
data->pos.y = npc->pos.y + npc->collisionHeight * 0.5;
|
|
|
|
data->pos.z = npc->pos.z - 5.0f;
|
|
|
|
data->scale = 1.0f;
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_glow_behind(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
remove_effect(npc->decorations[idx]);
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_update_decoration_charged(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
u8 sp50[20];
|
|
|
|
u8 sp38[20];
|
|
|
|
u8 sp20[20];
|
|
|
|
s32 i;
|
|
|
|
s32 temp3;
|
|
|
|
|
|
|
|
if (!npc->decorationInitialised[idx]) {
|
|
|
|
func_802DE894(npc->spriteInstanceID, 17, 20, 0, 0, 255, 0);
|
|
|
|
npc->decorationInitialised[idx] = TRUE;
|
|
|
|
}
|
|
|
|
if (npc->decorationInitialised[idx] == TRUE) {
|
|
|
|
npc->decorationUnk[idx] += 7;
|
|
|
|
if (npc->decorationUnk[idx] >= 360) {
|
|
|
|
npc->decorationUnk[idx] = npc->decorationUnk[idx] % 360;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 20; i++) {
|
|
|
|
sp50[i] = (cosine(npc->decorationUnk[idx] + i * 25) + 1.0) * 80.0f;
|
|
|
|
sp38[i] = (cosine(npc->decorationUnk[idx] + i * 25 + 45) + 1.0) * 80.0f;
|
|
|
|
sp20[i] = (cosine(npc->decorationUnk[idx] + i * 25 + 90) + 1.0) * 80.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (temp3 = 255, i = 0; i < 20; i++) {
|
|
|
|
func_802DE894(npc->spriteInstanceID, 12, i, (sp50[i] << 24) | (sp38[i] << 16) | (sp20[i] << 8) | temp3, 0, 255, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc_remove_decoration_charged(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void npc__reset_current_decoration(Npc* npc, s32 idx) {
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->decorationInitialised[idx] = 0;
|
|
|
|
}
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
Npc* npc_find_closest(f32 x, f32 y, f32 z, f32 radius) {
|
2021-04-13 09:47:52 +02:00
|
|
|
Npc* closestNpc = NULL;
|
|
|
|
f32 closestDist = radius;
|
|
|
|
f32 maxDist = radius;
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
|
|
|
|
Npc* npc = (*gCurrentNpcListPtr)[i];
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-04-17 13:16:13 +02:00
|
|
|
if (npc != NULL && npc->flags != 0 && !(npc->flags & NPC_FLAG_PARTICLE)) {
|
2021-04-13 09:47:52 +02:00
|
|
|
if (!(npc->flags & (NPC_FLAG_80000000 | NPC_FLAG_4))) {
|
|
|
|
f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
if (distance <= maxDist) {
|
|
|
|
if (distance < closestDist) {
|
|
|
|
closestDist = distance;
|
|
|
|
closestNpc = npc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return closestNpc;
|
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
Npc* npc_find_closest_simple(f32 x, f32 y, f32 z, f32 radius) {
|
2021-04-13 09:47:52 +02:00
|
|
|
Npc* closestNpc = NULL;
|
|
|
|
f32 closestDist = radius;
|
|
|
|
f32 maxDist = radius;
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
|
|
|
|
Npc* npc = (*gCurrentNpcListPtr)[i];
|
|
|
|
|
2021-04-17 13:16:13 +02:00
|
|
|
if (npc != NULL && npc->flags != 0 && (npc->flags & NPC_FLAG_PARTICLE)) {
|
2021-04-13 09:47:52 +02:00
|
|
|
if (!(npc->flags & (NPC_FLAG_80000000 | NPC_FLAG_4))) {
|
|
|
|
f32 distance = fabsf(dist2D(npc->pos.x, npc->pos.z, x, z));
|
|
|
|
|
|
|
|
if (distance <= maxDist) {
|
|
|
|
if (distance < closestDist) {
|
|
|
|
closestDist = distance;
|
|
|
|
closestNpc = npc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return closestNpc;
|
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2023-01-22 16:35:43 +01:00
|
|
|
s32 npc_find_standing_on_entity(s32 entityIndex) {
|
2023-01-25 03:33:20 +01:00
|
|
|
s32 idx = entityIndex | COLLISION_WITH_ENTITY_BIT;
|
2023-01-22 16:35:43 +01:00
|
|
|
s32 y = get_entity_by_index(idx)->position.y - 10.0f;
|
2022-10-15 00:21:50 +02:00
|
|
|
Npc* npc;
|
2021-06-16 11:52:15 +02:00
|
|
|
s32 i;
|
2022-10-15 00:21:50 +02:00
|
|
|
s32 var_v1;
|
2021-06-16 11:52:15 +02:00
|
|
|
|
2023-01-22 16:35:43 +01:00
|
|
|
npc->pos = npc->pos; // TODO required to match
|
2021-06-16 11:52:15 +02:00
|
|
|
|
2022-10-15 00:21:50 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(*gCurrentNpcListPtr); i++) {
|
|
|
|
npc = (*gCurrentNpcListPtr)[i];
|
2022-03-30 14:07:13 +02:00
|
|
|
|
2022-10-15 00:21:50 +02:00
|
|
|
if (npc == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (npc->flags == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-01-22 16:35:43 +01:00
|
|
|
if (npc->flags & (NPC_FLAG_80000000 | NPC_FLAG_4)) {
|
2022-10-15 00:21:50 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-01-22 16:35:43 +01:00
|
|
|
if (npc->flags & NPC_FLAG_PARTICLE) {
|
|
|
|
var_v1 = i; // TODO required to match (dummy if statement to load NPC_FLAG_PARTICLE into s5)
|
|
|
|
}
|
2022-10-15 00:21:50 +02:00
|
|
|
if (npc->pos.y < y) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-02-06 01:13:45 +01:00
|
|
|
if (npc->flags & (NPC_FLAG_8000 | NPC_FLAG_8)) {
|
2022-10-15 00:21:50 +02:00
|
|
|
var_v1 = npc_get_collider_below(npc);
|
|
|
|
if (var_v1 != 0) {
|
2023-01-22 16:35:43 +01:00
|
|
|
if (idx == var_v1) {
|
2022-10-15 00:21:50 +02:00
|
|
|
return i;
|
2021-06-16 11:52:15 +02:00
|
|
|
}
|
|
|
|
}
|
2022-10-15 00:21:50 +02:00
|
|
|
} else {
|
|
|
|
var_v1 = npc->currentFloor;
|
2023-01-25 03:33:20 +01:00
|
|
|
if (npc->currentFloor & COLLISION_WITH_ENTITY_BIT) { // TODO required to match (can't use var_v1)
|
2023-01-22 16:35:43 +01:00
|
|
|
if (idx == var_v1) {
|
|
|
|
npc->pos = npc->pos; // TODO required to match
|
2022-10-15 00:21:50 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
2021-06-16 11:52:15 +02:00
|
|
|
}
|
|
|
|
}
|
2023-01-22 16:35:43 +01:00
|
|
|
|
2021-06-16 11:52:15 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
s32 npc_get_collider_below(Npc* npc) {
|
2021-06-15 10:05:16 +02:00
|
|
|
f32 x;
|
|
|
|
f32 y;
|
|
|
|
f32 z;
|
|
|
|
f32 yaw;
|
|
|
|
|
|
|
|
if (npc->flags & NPC_FLAG_PARTICLE) {
|
|
|
|
y = get_shadow_by_index(npc->shadowIndex)->position.y + 13.0f;
|
|
|
|
} else {
|
|
|
|
y = npc->pos.y + 13.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
yaw = 16.0f;
|
|
|
|
x = npc->pos.x;
|
|
|
|
z = npc->pos.z;
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
if (npc_raycast_down_sides(0x38000, &x, &y, &z, &yaw)) {
|
2021-06-15 10:05:16 +02:00
|
|
|
if (yaw <= 16.0f) {
|
|
|
|
return D_8010C978;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
void func_8003D3BC(Npc* npc) {
|
2022-12-25 06:10:23 +01:00
|
|
|
s32 foldType = npc->unk_98;
|
|
|
|
s32 foldArg1 = npc->unk_9A;
|
|
|
|
s32 foldArg2 = npc->unk_9C;
|
|
|
|
s32 foldArg3 = npc->unk_9E;
|
|
|
|
s32 foldArg4 = npc->unk_A0;
|
|
|
|
s32 foldArg5 = npc->unk_A2;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-08-26 12:13:57 +02:00
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_NONE, 0, 0, 0, 0, 0);
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-12-25 06:10:23 +01:00
|
|
|
switch (foldType) {
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_NONE:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_NONE, 0, 0, 0, 0, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_2:
|
|
|
|
case FOLD_TYPE_3:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
2022-04-05 14:53:40 +02:00
|
|
|
// fallthrough
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_1:
|
2022-12-25 06:10:23 +01:00
|
|
|
func_802DE894(npc->spriteInstanceID, foldType, 0, 0, 0, 0, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_4:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_4, foldArg1, foldArg2, foldArg3, 0, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_6:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_6, foldArg1, foldArg2, foldArg3, 255, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_7:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_SURFACE_XLU_LAYER2;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_7, 255, 255, 255, foldArg1, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_8:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_SURFACE_XLU_LAYER2;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_8, foldArg1, foldArg2, foldArg3, foldArg4, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_9:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_9, foldArg1, foldArg2, foldArg3, 255, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_A:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_SURFACE_XLU_LAYER2;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_A, foldArg1, foldArg2, foldArg3, foldArg4, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_5:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_5, foldArg1, foldArg2, foldArg3, 0, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_D:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_SURFACE_XLU_LAYER2;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_D, foldArg1, foldArg2, foldArg3, foldArg4, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_E:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_E, foldArg1, foldArg2, foldArg3, 255, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_F:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_ALPHATEST;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_F, foldArg1, 255, 0, 255, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
2022-08-26 12:13:57 +02:00
|
|
|
case FOLD_TYPE_10:
|
2022-12-25 06:10:23 +01:00
|
|
|
npc->renderMode = RENDER_MODE_SURFACE_XLU_LAYER2;
|
|
|
|
func_802DE894(npc->spriteInstanceID, FOLD_TYPE_F, foldArg1, foldArg2, 0, foldArg2, foldArg5);
|
2021-06-15 10:05:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-01 03:31:09 +01:00
|
|
|
void func_8003D624(Npc* npc, s32 foldType, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6) {
|
|
|
|
npc->unk_98 = foldType;
|
2021-06-15 10:05:16 +02:00
|
|
|
npc->unk_9A = arg2;
|
|
|
|
npc->unk_9C = arg3;
|
|
|
|
npc->unk_9E = arg4;
|
|
|
|
npc->unk_A0 = arg5;
|
|
|
|
npc->unk_A2 = arg6;
|
|
|
|
func_8003D3BC(npc);
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
void func_8003D660(Npc* npc, s32 arg1) {
|
2021-08-22 15:10:06 +02:00
|
|
|
PartnerActionStatus* temp = &gPartnerActionStatus;
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
if ((npc->flags & (NPC_FLAG_400000 | NPC_FLAG_2)) == NPC_FLAG_400000) {
|
|
|
|
if (npc->moveSpeed != 0.0f) {
|
2022-09-13 08:26:57 +02:00
|
|
|
s32 surfaceType = get_collider_flags((u16)npc->currentFloor) & COLLIDER_FLAGS_SURFACE_TYPE_MASK;
|
|
|
|
switch (surfaceType) {
|
|
|
|
case SURFACE_TYPE_FLOWERS:
|
2021-06-15 10:05:16 +02:00
|
|
|
func_8003DA38(npc, arg1);
|
|
|
|
return;
|
2022-09-13 08:26:57 +02:00
|
|
|
case SURFACE_TYPE_CLOUD:
|
2021-06-15 10:05:16 +02:00
|
|
|
func_8003DC38(npc, arg1);
|
|
|
|
return;
|
2022-09-13 08:26:57 +02:00
|
|
|
case SURFACE_TYPE_SNOW:
|
2022-04-17 17:36:37 +02:00
|
|
|
if ((temp->partnerActionState == PARTNER_ACTION_NONE) || (temp->actingPartner != PARTNER_LAKILESTER)) {
|
2021-06-15 10:05:16 +02:00
|
|
|
func_8003DFA0(npc, arg1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2022-09-13 08:26:57 +02:00
|
|
|
case SURFACE_TYPE_HEDGES:
|
2021-06-15 10:05:16 +02:00
|
|
|
func_8003E0D4(npc, arg1);
|
|
|
|
return;
|
2022-09-13 08:26:57 +02:00
|
|
|
case SURFACE_TYPE_WATER:
|
2021-06-15 10:05:16 +02:00
|
|
|
func_8003E1D0(npc, arg1);
|
|
|
|
return;
|
2022-09-13 08:26:57 +02:00
|
|
|
case SURFACE_TYPE_SPIKES:
|
|
|
|
case SURFACE_TYPE_LAVA:
|
|
|
|
case SURFACE_TYPE_DOCK_WALL:
|
|
|
|
case SURFACE_TYPE_SLIDE:
|
2021-06-15 10:05:16 +02:00
|
|
|
default:
|
|
|
|
func_8003D788(npc, arg1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-30 14:07:13 +02:00
|
|
|
|
|
|
|
static const f32 padding[2] = { 0.0f, 0.0f }; // todo remove when below funcs are decompiled
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
void func_8003D788(Npc* npc, s32 arg1) {
|
|
|
|
s32 phi_a2;
|
2022-03-30 14:07:13 +02:00
|
|
|
f32 sinTheta;
|
|
|
|
f32 cosTheta;
|
2021-06-15 10:05:16 +02:00
|
|
|
|
|
|
|
phi_a2 = 0;
|
2023-01-02 02:58:39 +01:00
|
|
|
if (gGameStatusPtr->areaID == AREA_HOS) {
|
2021-06-15 10:05:16 +02:00
|
|
|
phi_a2 = gGameStatusPtr->mapID == 2;
|
|
|
|
}
|
|
|
|
if (arg1 == 2) {
|
|
|
|
f32 x = npc->pos.x;
|
|
|
|
f32 y = npc->pos.y + 0.0f;
|
|
|
|
f32 z = npc->pos.z;
|
2021-06-16 11:52:15 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (phi_a2 == 0) {
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_landing_dust(0, x, y, z, D_80077C10);
|
2021-06-15 10:05:16 +02:00
|
|
|
D_80077C10 = clamp_angle(D_80077C10 + 35.0f);
|
2021-06-16 11:52:15 +02:00
|
|
|
} else {
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_misc_particles(3, x, y, z, 13.0f, 10.0f, 1.0f, 5, 30);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
} else if (arg1 != 0) {
|
|
|
|
if (D_80077C14++ >= 4) {
|
|
|
|
D_80077C14 = 0;
|
|
|
|
if (phi_a2 == 0) {
|
2022-09-15 21:39:16 +02:00
|
|
|
sin_cos_rad(DEG_TO_RAD(clamp_angle(-npc->yaw)), &sinTheta, &cosTheta);
|
2022-03-30 14:07:13 +02:00
|
|
|
fx_walking_dust(0, npc->pos.x + (npc->collisionRadius * sinTheta * 0.2f), npc->pos.y + 1.5f,
|
|
|
|
npc->pos.z + (npc->collisionRadius * cosTheta * 0.2f), sinTheta, cosTheta);
|
2021-06-15 10:05:16 +02:00
|
|
|
} else {
|
2022-09-15 21:39:16 +02:00
|
|
|
sin_cos_rad(DEG_TO_RAD(clamp_angle(npc->yaw)), &sinTheta, &cosTheta);
|
2022-03-30 14:07:13 +02:00
|
|
|
fx_misc_particles(3, npc->pos.x + (npc->collisionRadius * sinTheta), npc->pos.y + 1.5f,
|
|
|
|
npc->pos.z + (npc->collisionRadius * cosTheta), 5.0f, 10.0f, 1.0f, 5, 30);
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-03-30 14:07:13 +02:00
|
|
|
void func_8003DA38(Npc* npc, s32 arg1) {
|
|
|
|
f32 theta;
|
|
|
|
f32 sinTheta;
|
|
|
|
f32 cosTheta;
|
|
|
|
f32 x, y, z;
|
|
|
|
|
|
|
|
if (arg1 == 2 && D_80077C1E == 5) {
|
2022-10-18 13:43:04 +02:00
|
|
|
x = npc->pos.x;
|
|
|
|
y = npc->pos.y + + 14.0f;
|
|
|
|
z = npc->pos.z;
|
|
|
|
|
|
|
|
fx_flower_splash(x, y, z, D_80077C18);
|
2022-03-30 14:07:13 +02:00
|
|
|
D_80077C18 = clamp_angle(D_80077C18 + 35.0f);
|
|
|
|
D_80077C1E = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
D_80077C1E++;
|
|
|
|
if (D_80077C1E > 5) {
|
|
|
|
D_80077C1E = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (D_80077C1C++ > 0) {
|
|
|
|
D_80077C1C = 0;
|
2022-09-15 21:39:16 +02:00
|
|
|
theta = DEG_TO_RAD(clamp_angle(-npc->yaw));
|
2022-03-30 14:07:13 +02:00
|
|
|
sinTheta = sin_rad(theta);
|
|
|
|
cosTheta = cos_rad(theta);
|
|
|
|
|
|
|
|
x = npc->pos.x + (npc->collisionRadius * sinTheta * -0.4f);
|
|
|
|
z = npc->pos.z + (npc->collisionRadius * cosTheta * -0.4f);
|
|
|
|
y = npc->pos.y + 15.5f;
|
|
|
|
|
|
|
|
fx_flower_trail(1, x, y, z, -npc->yaw + rand_int(10) - 5.0f, D_80077C20);
|
|
|
|
D_80077C20 = D_80077C20 == 0;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-10-09 11:09:41 +02:00
|
|
|
void func_8003DC38(Npc* npc, s32 arg1) {
|
2022-10-25 12:04:54 +02:00
|
|
|
PlayerStatus* playerStatus = &gPlayerStatus;
|
|
|
|
f32 xTemp, yTemp, zTemp;
|
|
|
|
f32 xTemp2, yTemp2, zTemp2;
|
2022-10-09 11:09:41 +02:00
|
|
|
f32 theta;
|
|
|
|
f32 sinTheta;
|
|
|
|
f32 cosTheta;
|
2022-10-10 23:57:21 +02:00
|
|
|
f32 angle;
|
|
|
|
s32 i;
|
2022-10-09 11:09:41 +02:00
|
|
|
|
|
|
|
D_80077C2C += 0.1f;
|
|
|
|
if (arg1 == 2) {
|
|
|
|
fx_cloud_puff(npc->pos.x, (npc->pos.y + 14.0f) - 5.0f, npc->pos.z, D_80077C24);
|
|
|
|
|
|
|
|
D_80077C24 = clamp_angle(D_80077C24 + 35.0f);
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
xTemp = rand_int(10) - 5;
|
|
|
|
zTemp = rand_int(10) - 5;
|
2022-10-25 12:04:54 +02:00
|
|
|
yTemp = -2.0f - ((SQ(xTemp) + SQ(zTemp)) / 5.0f);
|
2022-10-09 11:09:41 +02:00
|
|
|
D_80077C28 = 0;
|
2022-10-10 23:57:21 +02:00
|
|
|
|
2022-10-25 12:04:54 +02:00
|
|
|
theta = DEG_TO_RAD(clamp_angle(-npc->yaw + (i * 90)));
|
2022-10-09 11:09:41 +02:00
|
|
|
sinTheta = sin_rad(theta);
|
|
|
|
cosTheta = cos_rad(theta);
|
2022-10-25 12:04:54 +02:00
|
|
|
|
2022-10-09 11:09:41 +02:00
|
|
|
fx_cloud_trail(
|
|
|
|
1,
|
|
|
|
npc->pos.x + (npc->collisionRadius * sinTheta * -0.3f) + xTemp,
|
|
|
|
npc->pos.y + 15.5f + yTemp,
|
|
|
|
npc->pos.z + (npc->collisionRadius * cosTheta * -0.3f) + zTemp
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-25 12:04:54 +02:00
|
|
|
xTemp2 = rand_int(10) - 5;
|
|
|
|
zTemp2 = rand_int(10) - 5;
|
|
|
|
yTemp2 = -2.0f - ((SQ(xTemp2) + SQ(zTemp2)) / 5.0f);
|
2022-10-10 23:57:21 +02:00
|
|
|
|
2022-10-09 11:09:41 +02:00
|
|
|
D_80077C28 = 0;
|
2022-10-10 23:57:21 +02:00
|
|
|
|
2022-10-09 11:09:41 +02:00
|
|
|
theta = DEG_TO_RAD(clamp_angle(-npc->yaw));
|
|
|
|
sinTheta = sin_rad(theta);
|
|
|
|
cosTheta = cos_rad(theta);
|
|
|
|
fx_cloud_trail(
|
|
|
|
1,
|
2022-10-25 12:04:54 +02:00
|
|
|
npc->pos.x + (npc->collisionRadius * sinTheta * -0.3f) + xTemp2,
|
|
|
|
npc->pos.y + 15.5f + yTemp2,
|
|
|
|
npc->pos.z + (npc->collisionRadius * cosTheta * -0.3f) + zTemp2
|
2022-10-09 11:09:41 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-03-30 14:07:13 +02:00
|
|
|
void func_8003DFA0(Npc* npc, s32 arg1) {
|
2021-07-17 16:45:08 +02:00
|
|
|
if (D_80077C30++ >= 4) {
|
|
|
|
f32 temp_f20;
|
|
|
|
f32 x;
|
|
|
|
f32 z;
|
|
|
|
|
|
|
|
D_80077C30 = 0;
|
2022-09-15 21:39:16 +02:00
|
|
|
temp_f20 = DEG_TO_RAD(clamp_angle(-npc->yaw));
|
2021-07-17 16:45:08 +02:00
|
|
|
x = sin_rad(temp_f20);
|
|
|
|
z = cos_rad(temp_f20);
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_footprint(npc->pos.x + (npc->collisionRadius * x * 0.2f), npc->pos.y + 1.5f,
|
2021-07-17 16:45:08 +02:00
|
|
|
npc->pos.z + (npc->collisionRadius * z * 0.2f), -npc->yaw, D_80077C34);
|
|
|
|
D_80077C34 = !D_80077C34;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-30 14:07:13 +02:00
|
|
|
void func_8003E0D4(Npc* npc, s32 arg1) {
|
2021-08-22 15:10:06 +02:00
|
|
|
if (D_80077C38++ >= 4) {
|
|
|
|
f32 theta;
|
|
|
|
f32 sinTheta;
|
|
|
|
f32 cosTheta;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
D_80077C38 = 0;
|
2022-09-15 21:39:16 +02:00
|
|
|
theta = DEG_TO_RAD(clamp_angle(-npc->yaw));
|
2021-08-22 15:10:06 +02:00
|
|
|
sinTheta = sin_rad(theta);
|
|
|
|
cosTheta = cos_rad(theta);
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_falling_leaves(1, npc->pos.x + (npc->collisionRadius * sinTheta * 0.2f),
|
2021-08-22 15:10:06 +02:00
|
|
|
40.0f, npc->pos.z + (npc->collisionRadius * cosTheta * 0.2f));
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-03-30 14:07:13 +02:00
|
|
|
void func_8003E1D0(Npc* npc, s32 arg1) {
|
2021-07-17 16:45:08 +02:00
|
|
|
if (D_80077C3A++ >= 4) {
|
|
|
|
f32 temp_f20;
|
|
|
|
f32 x;
|
|
|
|
f32 z;
|
|
|
|
|
|
|
|
D_80077C3A = 0;
|
2022-09-15 21:39:16 +02:00
|
|
|
temp_f20 = DEG_TO_RAD(clamp_angle(-npc->yaw));
|
2021-07-17 16:45:08 +02:00
|
|
|
x = sin_rad(temp_f20);
|
|
|
|
z = cos_rad(temp_f20);
|
2022-01-24 17:58:33 +01:00
|
|
|
fx_rising_bubble(0, npc->pos.x + (npc->collisionRadius * x * 0.2f), npc->pos.y + 0.0f,
|
2021-07-17 16:45:08 +02:00
|
|
|
npc->pos.z + (npc->collisionRadius * z * 0.2f), 0.0f);
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
void COPY_set_defeated(s32 mapID, s32 encounterID) {
|
|
|
|
EncounterStatus* currentEncounter = &gCurrentEncounter;
|
|
|
|
s32 encounterIdx = encounterID / 32;
|
|
|
|
s32 encounterShift;
|
|
|
|
s32 flag;
|
|
|
|
|
|
|
|
flag = encounterID % 32;
|
|
|
|
encounterShift = flag;
|
|
|
|
flag = currentEncounter->defeatFlags[mapID][encounterIdx];
|
|
|
|
currentEncounter->defeatFlags[mapID][encounterIdx] = flag | (1 << encounterShift);
|
2021-04-02 07:50:38 +02:00
|
|
|
|
|
|
|
// TODO: The below should work but has regalloc issues:
|
|
|
|
/*EncounterStatus *currentEncounter = &gCurrentEncounter;
|
|
|
|
s32 encounterIdx = encounterID / 32;
|
|
|
|
s32 encounterShift = encounterID % 32;
|
|
|
|
|
|
|
|
currentEncounter->defeatFlags[mapID][encounterIdx] |= (1 << encounterShift);*/
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void init_encounter_status(void) {
|
2021-03-30 19:39:44 +02:00
|
|
|
EncounterStatus* currentEncounter = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
|
|
|
|
currentEncounter->encounterList[i] = 0;
|
|
|
|
}
|
|
|
|
|
2023-01-12 03:09:13 +01:00
|
|
|
currentEncounter->flags = ENCOUNTER_STATUS_FLAG_0;
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->numEncounters = 0;
|
2022-09-08 14:21:07 +02:00
|
|
|
currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->hitType = 0;
|
2022-09-08 14:12:26 +02:00
|
|
|
currentEncounter->battleTriggerCooldown = 0;
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->npcGroupList = 0;
|
|
|
|
currentEncounter->unk_08 = 0;
|
2022-11-01 13:27:10 +01:00
|
|
|
currentEncounter->dropWhackaBump = FALSE;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
|
|
|
|
for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
|
|
|
|
currentEncounter->defeatFlags[i][j] = 0;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
|
|
|
|
currentEncounter->recentMaps[i] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
func_80045AC0();
|
2022-11-01 13:27:10 +01:00
|
|
|
gEncounterState = ENCOUNTER_STATE_NONE;
|
2022-11-22 05:12:28 +01:00
|
|
|
create_worker_world(NULL, npc_render_worker_do_nothing);
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear_encounter_status(void) {
|
|
|
|
EncounterStatus* currentEncounter = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->encounterList); i++) {
|
|
|
|
currentEncounter->encounterList[i] = 0;
|
|
|
|
}
|
|
|
|
|
2021-04-02 07:50:38 +02:00
|
|
|
if (gGameStatusPtr->didAreaChange) {
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
|
|
|
|
for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
|
|
|
|
currentEncounter->defeatFlags[i][j] = 0;
|
|
|
|
}
|
|
|
|
}
|
2021-04-02 07:50:38 +02:00
|
|
|
|
|
|
|
if (gGameStatusPtr->didAreaChange) {
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
|
|
|
|
currentEncounter->recentMaps[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->numEncounters = 0;
|
2022-09-08 14:21:07 +02:00
|
|
|
currentEncounter->firstStrikeType = FIRST_STRIKE_NONE;
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->hitType = 0;
|
2022-09-08 14:12:26 +02:00
|
|
|
currentEncounter->battleTriggerCooldown = 0;
|
2021-04-26 19:47:38 +02:00
|
|
|
currentEncounter->currentAreaIndex = gGameStatusPtr->areaID;
|
|
|
|
currentEncounter->currentMapIndex = gGameStatusPtr->mapID;
|
|
|
|
currentEncounter->currentEntryIndex = gGameStatusPtr->entryID;
|
2021-03-30 19:39:44 +02:00
|
|
|
currentEncounter->npcGroupList = 0;
|
|
|
|
currentEncounter->unk_08 = 0;
|
2022-11-01 13:27:10 +01:00
|
|
|
currentEncounter->scriptedBattle = FALSE;
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
func_80045AC0();
|
2022-11-01 13:27:10 +01:00
|
|
|
gEncounterState = ENCOUNTER_STATE_NONE;
|
2022-11-22 05:12:28 +01:00
|
|
|
create_worker_world(NULL, npc_render_worker_do_nothing);
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2020-10-14 18:15:50 +02:00
|
|
|
void func_8003E50C(void) {
|
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
void func_8003E514(s8 arg0) {
|
2021-04-26 19:47:38 +02:00
|
|
|
gCurrentEncounter.unk_08 = arg0;
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
void update_encounters(void) {
|
2022-11-01 13:27:10 +01:00
|
|
|
switch (gEncounterState) {
|
|
|
|
case ENCOUNTER_STATE_NONE:
|
2021-03-30 19:39:44 +02:00
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_CREATE:
|
2021-03-30 19:39:44 +02:00
|
|
|
create_encounters();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_NEUTRAL:
|
2021-03-30 19:39:44 +02:00
|
|
|
update_encounters_neutral();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_PRE_BATTLE:
|
2021-03-30 19:39:44 +02:00
|
|
|
update_encounters_pre_battle();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_CONVERSATION:
|
2021-03-30 19:39:44 +02:00
|
|
|
update_encounters_conversation();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_POST_BATTLE:
|
2021-03-30 19:39:44 +02:00
|
|
|
update_encounters_post_battle();
|
|
|
|
break;
|
|
|
|
}
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
update_merlee_messages();
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
void draw_encounter_ui(void) {
|
2022-11-01 13:27:10 +01:00
|
|
|
switch (gEncounterState) {
|
|
|
|
case ENCOUNTER_STATE_NONE:
|
2021-03-30 19:39:44 +02:00
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_CREATE:
|
2021-03-30 19:39:44 +02:00
|
|
|
init_encounters_ui();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_NEUTRAL:
|
2021-03-30 19:39:44 +02:00
|
|
|
draw_encounters_neutral();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_PRE_BATTLE:
|
2021-03-30 19:39:44 +02:00
|
|
|
draw_encounters_pre_battle();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_CONVERSATION:
|
2021-03-30 19:39:44 +02:00
|
|
|
draw_encounters_conversation();
|
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_POST_BATTLE:
|
2021-03-30 19:39:44 +02:00
|
|
|
draw_encounters_post_battle();
|
|
|
|
break;
|
|
|
|
}
|
2021-04-02 07:50:38 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
draw_merlee_messages();
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-03-30 19:39:44 +02:00
|
|
|
void draw_first_strike_ui(void) {
|
2022-11-01 13:27:10 +01:00
|
|
|
switch (gEncounterState) {
|
|
|
|
case ENCOUNTER_STATE_NONE:
|
2021-04-26 19:47:38 +02:00
|
|
|
break;
|
2022-11-01 13:27:10 +01:00
|
|
|
case ENCOUNTER_STATE_PRE_BATTLE:
|
2021-03-30 19:39:44 +02:00
|
|
|
show_first_strike_message();
|
2022-11-01 13:27:10 +01:00
|
|
|
break;
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-11-22 05:12:28 +01:00
|
|
|
void npc_render_worker_do_nothing(void) {
|
2020-10-14 18:15:50 +02:00
|
|
|
}
|
2020-09-24 05:16:13 +02:00
|
|
|
|
2021-10-29 19:57:15 +02:00
|
|
|
void make_npcs(s32 flags, s32 mapID, s32* npcGroupList) {
|
2021-03-30 19:39:44 +02:00
|
|
|
EncounterStatus* currentEncounter = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
currentEncounter->resetMapEncounterFlags = flags;
|
|
|
|
currentEncounter->mapID = mapID;
|
2021-04-02 07:50:38 +02:00
|
|
|
currentEncounter->npcGroupList = npcGroupList;
|
|
|
|
|
|
|
|
if (gGameStatusPtr->didAreaChange) {
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->defeatFlags); i++) {
|
|
|
|
for (j = 0; j < ARRAY_COUNT(currentEncounter->defeatFlags[i]); j++) {
|
|
|
|
currentEncounter->defeatFlags[i][j] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 07:50:38 +02:00
|
|
|
if (gGameStatusPtr->didAreaChange) {
|
2021-03-30 19:39:44 +02:00
|
|
|
for (i = 0; i < ARRAY_COUNT(currentEncounter->recentMaps); i++) {
|
|
|
|
currentEncounter->recentMaps[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 07:50:38 +02:00
|
|
|
if (npcGroupList != NULL) {
|
2022-11-01 13:27:10 +01:00
|
|
|
gEncounterState = ENCOUNTER_STATE_CREATE;
|
2021-03-30 19:39:44 +02:00
|
|
|
D_8009A678 = 1;
|
2022-11-01 13:27:10 +01:00
|
|
|
gEncounterSubState = ENCOUNTER_SUBSTATE_CREATE_INIT;
|
2021-03-30 19:39:44 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 kill_encounter(Enemy* enemy) {
|
|
|
|
Encounter* encounter = gCurrentEncounter.encounterList[enemy->encounterIndex];
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < encounter->count; i++) {
|
|
|
|
Enemy* currentEnemy = encounter->enemy[i];
|
|
|
|
if (currentEnemy != NULL) {
|
|
|
|
kill_enemy(currentEnemy);
|
|
|
|
encounter->enemy[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void kill_enemy(Enemy* enemy) {
|
|
|
|
EncounterStatus* encounterStatus = &gCurrentEncounter;
|
|
|
|
Encounter* encounter = encounterStatus->encounterList[enemy->encounterIndex];
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < encounter->count; i++) {
|
|
|
|
Enemy* currentEnemy = encounter->enemy[i];
|
|
|
|
if (currentEnemy == enemy) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enemy->initScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->initScriptID);
|
|
|
|
}
|
|
|
|
if (enemy->interactScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->interactScriptID);
|
|
|
|
}
|
|
|
|
if (enemy->aiScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->aiScriptID);
|
|
|
|
}
|
|
|
|
if (enemy->hitScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->hitScriptID);
|
|
|
|
}
|
|
|
|
if (enemy->auxScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->auxScriptID);
|
|
|
|
}
|
|
|
|
if (enemy->defeatScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->defeatScriptID);
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
enemy->interactBytecode = NULL;
|
|
|
|
enemy->aiBytecode = NULL;
|
|
|
|
enemy->hitBytecode = NULL;
|
|
|
|
enemy->auxBytecode = NULL;
|
|
|
|
enemy->defeatBytecode = NULL;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-30 04:27:12 +02:00
|
|
|
free_npc(get_npc_unsafe(enemy->npcID));
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (enemy->unk_64 != NULL) {
|
|
|
|
heap_free(enemy->unk_64);
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
for (j = 0; j < ARRAY_COUNT(encounter->enemy); j++) {
|
|
|
|
if (encounter->enemy[j] == enemy) {
|
|
|
|
encounter->enemy[j] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-03-30 14:07:13 +02:00
|
|
|
do {
|
2023-01-12 03:09:13 +01:00
|
|
|
if (!(enemy->flags & ENEMY_FLAG_4)) {
|
2023-02-06 01:13:45 +01:00
|
|
|
if (!(enemy->flags & ENEMY_FLAG_ENABLE_HIT_SCRIPT) || (enemy == encounterStatus->currentEnemy)) {
|
|
|
|
if (!(enemy->flags & ENEMY_FLAG_PASSIVE)) {
|
2023-01-12 03:09:13 +01:00
|
|
|
if (!(enemy->flags & ENEMY_FLAG_FLED)) {
|
2022-03-30 14:07:13 +02:00
|
|
|
COPY_set_defeated(encounterStatus->mapID, encounter->encounterID + i);
|
|
|
|
}
|
2021-06-15 10:05:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-30 14:07:13 +02:00
|
|
|
} while (0); // required to match
|
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
heap_free(enemy);
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
s32 bind_enemy_ai(Enemy* enemy, EvtScript* aiScriptBytecode) {
|
2021-08-22 23:50:10 +02:00
|
|
|
Evt* aiScript;
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 id;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (enemy->aiScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->aiScript->id);
|
|
|
|
}
|
|
|
|
enemy->aiBytecode = aiScriptBytecode;
|
2022-04-17 17:36:37 +02:00
|
|
|
aiScript = enemy->aiScript = start_script(aiScriptBytecode, EVT_PRIORITY_A, 0);
|
2021-06-15 10:05:16 +02:00
|
|
|
id = enemy->aiScriptID = aiScript->id;
|
|
|
|
aiScript->owner1.enemy = enemy;
|
|
|
|
return id;
|
|
|
|
}
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
s32 bind_enemy_aux(Enemy* enemy, EvtScript* auxScriptBytecode) {
|
2021-08-22 23:50:10 +02:00
|
|
|
Evt* auxScript;
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 id;
|
2020-08-04 08:49:11 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (enemy->auxScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->auxScript->id);
|
|
|
|
}
|
|
|
|
enemy->auxBytecode = auxScriptBytecode;
|
2022-04-17 17:36:37 +02:00
|
|
|
auxScript = enemy->auxScript = start_script(auxScriptBytecode, EVT_PRIORITY_A, 0);
|
2021-06-15 10:05:16 +02:00
|
|
|
id = enemy->auxScriptID = auxScript->id;
|
|
|
|
auxScript->owner1.enemy = enemy;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
s32 bind_enemy_interact(Enemy* enemy, EvtScript* interactScriptBytecode) {
|
2021-08-22 23:50:10 +02:00
|
|
|
Evt* interactScript;
|
2021-06-15 10:05:16 +02:00
|
|
|
s32 id;
|
|
|
|
|
|
|
|
if (enemy->interactScript != NULL) {
|
|
|
|
kill_script_by_ID(enemy->interactScript->id);
|
|
|
|
}
|
|
|
|
enemy->interactBytecode = interactScriptBytecode;
|
2022-04-17 17:36:37 +02:00
|
|
|
interactScript = enemy->interactScript = start_script(interactScriptBytecode, EVT_PRIORITY_A, 0);
|
2021-06-15 10:05:16 +02:00
|
|
|
id = enemy->interactScriptID = interactScript->id;
|
|
|
|
interactScript->owner1.enemy = enemy;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
void bind_npc_ai(s32 npcID, EvtScript* npcAiBytecode) {
|
2021-06-15 10:05:16 +02:00
|
|
|
EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
|
|
|
|
Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
|
|
|
|
if (currentEncounter != NULL) {
|
|
|
|
for (j = 0; j < currentEncounter->count; j++) {
|
|
|
|
Enemy* currentEnemy = currentEncounter->enemy[j];
|
|
|
|
if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
|
|
|
|
bind_enemy_ai(currentEnemy, npcAiBytecode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
void bind_npc_aux(s32 npcID, EvtScript* npcAuxBytecode) {
|
2021-06-15 10:05:16 +02:00
|
|
|
EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
|
|
|
|
Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
|
|
|
|
if (currentEncounter != NULL) {
|
|
|
|
for (j = 0; j < currentEncounter->count; j++) {
|
|
|
|
Enemy* currentEnemy = currentEncounter->enemy[j];
|
|
|
|
if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
|
|
|
|
bind_enemy_aux(currentEnemy, npcAuxBytecode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 14:28:09 +01:00
|
|
|
void bind_npc_interact(s32 npcID, EvtScript* npcInteractBytecode) {
|
2021-06-15 10:05:16 +02:00
|
|
|
EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
|
|
|
|
Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
|
|
|
|
if (currentEncounter != NULL) {
|
|
|
|
for (j = 0; j < currentEncounter->count; j++) {
|
|
|
|
Enemy* currentEnemy = currentEncounter->enemy[j];
|
|
|
|
if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
|
|
|
|
bind_enemy_interact(currentEnemy, npcInteractBytecode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Enemy* get_enemy(s32 npcID) {
|
|
|
|
EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
|
|
|
|
Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
|
|
|
|
if (currentEncounter != NULL) {
|
|
|
|
for (j = 0; j < currentEncounter->count; j++) {
|
|
|
|
Enemy* currentEnemy = currentEncounter->enemy[j];
|
|
|
|
if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
|
|
|
|
return currentEnemy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PANIC();
|
|
|
|
}
|
|
|
|
|
|
|
|
Enemy* get_enemy_safe(s32 npcID) {
|
|
|
|
EncounterStatus* currentEncounterStatus = &gCurrentEncounter;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
|
|
|
for (i = 0; i < currentEncounterStatus->numEncounters; i++) {
|
|
|
|
Encounter* currentEncounter = currentEncounterStatus->encounterList[i];
|
2021-06-21 06:30:57 +02:00
|
|
|
|
2021-06-15 10:05:16 +02:00
|
|
|
if (currentEncounter != NULL) {
|
|
|
|
for (j = 0; j < currentEncounter->count; j++) {
|
|
|
|
Enemy* currentEnemy = currentEncounter->enemy[j];
|
|
|
|
if ((currentEnemy != NULL) && (currentEnemy->npcID == npcID)) {
|
|
|
|
return currentEnemy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|