Shipwright/soh/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c

419 lines
14 KiB
C

/*
* File: z_obj_mure.c
* Overlay: ovl_Obj_Mure
* Description: Spawns Fish, Bug, Butterfly
*/
#include "z_obj_mure.h"
#define FLAGS 0
void ObjMure_Init(Actor* thisx, GlobalContext* globalCtx);
void ObjMure_Destroy(Actor* thisx, GlobalContext* globalCtx);
void ObjMure_Update(Actor* thisx, GlobalContext* globalCtx);
void ObjMure_InitialAction(ObjMure* this, GlobalContext* globalCtx);
void ObjMure_CulledState(ObjMure* this, GlobalContext* globalCtx);
void ObjMure_ActiveState(ObjMure* this, GlobalContext* globalCtx);
s32 ObjMure_GetMaxChildSpawns(ObjMure* this);
const ActorInit Obj_Mure_InitVars = {
ACTOR_OBJ_MURE,
ACTORCAT_ITEMACTION,
FLAGS,
OBJECT_GAMEPLAY_KEEP,
sizeof(ObjMure),
(ActorFunc)ObjMure_Init,
(ActorFunc)ObjMure_Destroy,
(ActorFunc)ObjMure_Update,
NULL,
NULL,
};
typedef enum {
/* 0 */ OBJMURE_TYPE_GRASS,
/* 1 */ OBJMURE_TYPE_UNDEFINED,
/* 2 */ OBJMURE_TYPE_FISH,
/* 3 */ OBJMURE_TYPE_BUGS,
/* 4 */ OBJMURE_TYPE_BUTTERFLY
} ObjMureType;
typedef enum {
/* 0 */ OBJMURE_CHILD_STATE_0,
/* 1 */ OBJMURE_CHILD_STATE_1, // Dead
/* 2 */ OBJMURE_CHILD_STATE_2
} ObjMureChildState;
static f32 sZClip[] = { 1600.0f, 1600.0f, 1000.0f, 1000.0f, 1000.0f };
static s32 sMaxChildSpawns[] = { 12, 9, 8, 0 };
static s16 sSpawnActorIds[] = { ACTOR_EN_KUSA, 0, ACTOR_EN_FISH, ACTOR_EN_INSECT, ACTOR_EN_BUTTE };
static s16 sSpawnParams[] = { 0, 2, -1, 0, -1 };
static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneForward, 1200, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 200, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1200, ICHAIN_STOP),
};
s32 ObjMure_SetCullingImpl(Actor* thisx, GlobalContext* globalCtx) {
ObjMure* this = (ObjMure*)thisx;
s32 result;
switch (this->type) {
case OBJMURE_TYPE_FISH:
case OBJMURE_TYPE_BUGS:
case OBJMURE_TYPE_BUTTERFLY:
Actor_ProcessInitChain(&this->actor, sInitChain);
result = true;
break;
default:
// "Error : Culling is not set.(%s %d)(arg_data 0x%04x)"
osSyncPrintf("Error : カリングの設定がされていません。(%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__,
this->actor.params);
return false;
}
return result;
}
s32 ObjMure_SetCulling(Actor* thisx, GlobalContext* globalCtx) {
if (!ObjMure_SetCullingImpl(thisx, globalCtx)) {
return false;
}
return true;
}
void ObjMure_Init(Actor* thisx, GlobalContext* globalCtx) {
ObjMure* this = (ObjMure*)thisx;
this->chNum = (thisx->params >> 0xC) & 0x0F;
this->ptn = (thisx->params >> 8) & 0x07;
this->svNum = (thisx->params >> 5) & 0x03;
this->type = thisx->params & 0x1F;
if (this->ptn >= 4) {
osSyncPrintf("Error 群れな敵 (%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__, thisx->params);
Actor_Kill(&this->actor);
return;
} else if (this->type >= 5) {
osSyncPrintf("Error 群れな敵 (%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__, thisx->params);
Actor_Kill(&this->actor);
return;
} else if (!ObjMure_SetCulling(thisx, globalCtx)) {
Actor_Kill(&this->actor);
return;
}
this->actionFunc = ObjMure_InitialAction;
osSyncPrintf("群れな敵 (arg_data 0x%04x)(chNum(%d) ptn(%d) svNum(%d) type(%d))\n", thisx->params, this->chNum,
this->ptn, this->svNum, this->type);
if (ObjMure_GetMaxChildSpawns(this) <= 0) {
osSyncPrintf("Warning : 個体数が設定されていません(%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__,
thisx->params);
}
}
void ObjMure_Destroy(Actor* thisx, GlobalContext* globalCtx) {
}
s32 ObjMure_GetMaxChildSpawns(ObjMure* this) {
if (this->chNum == 0) {
return sMaxChildSpawns[this->ptn];
}
return this->chNum;
}
void ObjMure_GetSpawnPos(Vec3f* outPos, Vec3f* inPos, s32 ptn, s32 idx) {
if (ptn >= 4) {
osSyncPrintf("おかしなの (%s %d)\n", __FILE__, __LINE__);
}
*outPos = *inPos;
}
void ObjMure_SpawnActors0(ObjMure* this, GlobalContext* globalCtx) {
ActorContext* ac;
s32 i;
Vec3f pos;
s32 pad;
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
for (i = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
// "Error: I already have a child(%s %d)(arg_data 0x%04x)"
osSyncPrintf("Error : 既に子供がいる(%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__,
this->actor.params);
}
switch (this->childrenStates[i]) {
case OBJMURE_CHILD_STATE_1:
break;
case OBJMURE_CHILD_STATE_2:
ac = &globalCtx->actorCtx;
ObjMure_GetSpawnPos(&pos, &this->actor.world.pos, this->ptn, i);
this->children[i] =
Actor_Spawn(ac, globalCtx, sSpawnActorIds[this->type], pos.x, pos.y, pos.z, this->actor.world.rot.x,
this->actor.world.rot.y, this->actor.world.rot.z, sSpawnParams[this->type]);
if (this->children[i] != NULL) {
this->children[i]->flags |= ACTOR_FLAG_ENKUSA_CUT;
this->children[i]->room = this->actor.room;
} else {
osSyncPrintf("warning 発生失敗 (%s %d)\n", __FILE__, __LINE__);
}
break;
default:
ac = &globalCtx->actorCtx;
ObjMure_GetSpawnPos(&pos, &this->actor.world.pos, this->ptn, i);
this->children[i] =
Actor_Spawn(ac, globalCtx, sSpawnActorIds[this->type], pos.x, pos.y, pos.z, this->actor.world.rot.x,
this->actor.world.rot.y, this->actor.world.rot.z, sSpawnParams[this->type]);
if (this->children[i] != NULL) {
this->children[i]->room = this->actor.room;
} else {
osSyncPrintf("warning 発生失敗 (%s %d)\n", __FILE__, __LINE__);
}
break;
}
}
}
void ObjMure_SpawnActors1(ObjMure* this, GlobalContext* globalCtx) {
ActorContext* ac = (ActorContext*)globalCtx; // fake match
Actor* actor = &this->actor;
Vec3f spawnPos;
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
s32 i;
for (i = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
osSyncPrintf("Error : 既に子供がいる(%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__, actor->params);
}
ac = &globalCtx->actorCtx;
ObjMure_GetSpawnPos(&spawnPos, &actor->world.pos, this->ptn, i);
this->children[i] = Actor_Spawn(ac, globalCtx, sSpawnActorIds[this->type], spawnPos.x, spawnPos.y, spawnPos.z,
actor->world.rot.x, actor->world.rot.y, actor->world.rot.z,
(this->type == 4 && i == 0) ? 1 : sSpawnParams[this->type]);
if (this->children[i] != NULL) {
this->childrenStates[i] = OBJMURE_CHILD_STATE_0;
this->children[i]->room = actor->room;
} else {
this->childrenStates[i] = OBJMURE_CHILD_STATE_1;
osSyncPrintf("warning 発生失敗 (%s %d)\n", __FILE__, __LINE__);
}
}
}
void ObjMure_SpawnActors(ObjMure* this, GlobalContext* globalCtx) {
switch (this->svNum) {
case 0:
ObjMure_SpawnActors0(this, globalCtx);
break;
case 1:
ObjMure_SpawnActors1(this, globalCtx);
break;
}
}
void ObjMure_KillActorsImpl(ObjMure* this, GlobalContext* globalCtx) {
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
s32 i;
for (i = 0; i < maxChildren; i++) {
switch (this->childrenStates[i]) {
case OBJMURE_CHILD_STATE_1:
this->children[i] = NULL;
break;
case OBJMURE_CHILD_STATE_2:
if (this->children[i] != NULL) {
Actor_Kill(this->children[i]);
this->children[i] = NULL;
}
break;
default:
if (this->children[i] != NULL) {
if (Actor_HasParent(this->children[i], globalCtx)) {
this->children[i] = NULL;
} else {
Actor_Kill(this->children[i]);
this->children[i] = NULL;
}
}
break;
}
}
}
void ObjMure_KillActors(ObjMure* this, GlobalContext* globalCtx) {
ObjMure_KillActorsImpl(this, globalCtx);
}
void ObjMure_CheckChildren(ObjMure* this, GlobalContext* globalCtx) {
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
s32 i;
for (i = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
if (this->childrenStates[i] == OBJMURE_CHILD_STATE_0) {
if (this->children[i]->update != NULL) {
if (this->children[i]->flags & ACTOR_FLAG_ENKUSA_CUT) {
this->childrenStates[i] = OBJMURE_CHILD_STATE_2;
}
} else {
this->childrenStates[i] = OBJMURE_CHILD_STATE_1;
this->children[i] = NULL;
}
} else if (this->childrenStates[i] == OBJMURE_CHILD_STATE_2 && this->children[i]->update == NULL) {
this->childrenStates[i] = OBJMURE_CHILD_STATE_1;
this->children[i] = NULL;
}
}
}
}
void ObjMure_InitialAction(ObjMure* this, GlobalContext* globalCtx) {
this->actionFunc = ObjMure_CulledState;
}
void ObjMure_CulledState(ObjMure* this, GlobalContext* globalCtx) {
if (fabsf(this->actor.projectedPos.z) < sZClip[this->type] || CVar_GetS32("gDisableDrawDistance", 0) != 0) {
this->actionFunc = ObjMure_ActiveState;
this->actor.flags |= ACTOR_FLAG_4;
ObjMure_SpawnActors(this, globalCtx);
}
}
void ObjMure_SetFollowTargets(ObjMure* this, f32 randMax) {
s32 index;
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
s32 i;
for (i = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
this->children[i]->child = NULL;
if (Rand_ZeroOne() <= randMax) {
index = Rand_ZeroOne() * (maxChildren - 0.5f);
if (i != index) {
this->children[i]->child = this->children[index];
}
}
}
}
}
/**
* Selects a child that will follow after the player
* `idx1` is the index + 1 of the child that will follow the player. If `idx1` is zero, no actor will follow the player
*/
void ObjMure_SetChildToFollowPlayer(ObjMure* this, s32 idx1) {
s32 maxChildren = ObjMure_GetMaxChildSpawns(this);
s32 i;
s32 i2;
s32 j;
for (i = 0, i2 = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
if (i2 < idx1) {
i2++;
this->children[i]->child = this->children[i];
for (j = 0; j < maxChildren; j++) {
if (i != j && this->children[j]->child == this->children[i]) {
this->children[j]->child = NULL;
}
}
} else if (this->children[i]->child == this->children[i]) {
this->children[i]->child = NULL;
}
}
}
}
// Fish, Bugs
void ObjMure_GroupBehavior0(ObjMure* this, GlobalContext* globalCtx) {
if (this->unk_1A4 <= 0) {
if (this->unk_1A6) {
this->unk_1A6 = false;
ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.5f) + 0.1f);
if (this->actor.xzDistToPlayer < 60.0f) {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 5.5f) + 4;
} else {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 40.5f) + 4;
}
} else {
this->unk_1A6 = true;
if (this->actor.xzDistToPlayer < 60.0f) {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 10.5f) + 4;
ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.2f) + 0.8f);
} else {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 10.5f) + 4;
ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.2f) + 0.6f);
}
}
}
if (this->actor.xzDistToPlayer < 120.0f) {
this->unk_1A8++;
} else {
this->unk_1A8 = 0;
}
if (this->unk_1A8 >= 80) {
ObjMure_SetChildToFollowPlayer(this, 1);
} else {
ObjMure_SetChildToFollowPlayer(this, 0);
}
}
// Butterflies
void ObjMure_GroupBehavior1(ObjMure* this, GlobalContext* globalCtx) {
s32 maxChildren;
s32 i;
if (this->unk_1A4 <= 0) {
if (this->unk_1A6) {
this->unk_1A6 = false;
ObjMure_SetFollowTargets(this, Rand_ZeroOne() * 0.2f);
if (this->actor.xzDistToPlayer < 60.0f) {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 5.5f) + 4;
} else {
this->unk_1A4 = (s16)(Rand_ZeroOne() * 40.5f) + 4;
}
} else {
this->unk_1A6 = true;
ObjMure_SetFollowTargets(this, Rand_ZeroOne() * 0.7f);
this->unk_1A4 = (s16)(Rand_ZeroOne() * 10.5f) + 4;
}
}
maxChildren = ObjMure_GetMaxChildSpawns(this);
for (i = 0; i < maxChildren; i++) {
if (this->children[i] != NULL) {
if (this->children[i]->child != NULL && this->children[i]->child->update == NULL) {
this->children[i]->child = NULL;
}
}
}
}
static ObjMureActionFunc sTypeGroupBehaviorFunc[] = {
NULL, NULL, ObjMure_GroupBehavior0, ObjMure_GroupBehavior0, ObjMure_GroupBehavior1,
};
void ObjMure_ActiveState(ObjMure* this, GlobalContext* globalCtx) {
ObjMure_CheckChildren(this, globalCtx);
if (sZClip[this->type] + 40.0f <= fabsf(this->actor.projectedPos.z) &&
CVar_GetS32("gDisableDrawDistance", 1) != 0) {
this->actionFunc = ObjMure_CulledState;
this->actor.flags &= ~ACTOR_FLAG_4;
ObjMure_KillActors(this, globalCtx);
} else if (sTypeGroupBehaviorFunc[this->type] != NULL) {
sTypeGroupBehaviorFunc[this->type](this, globalCtx);
}
}
void ObjMure_Update(Actor* thisx, GlobalContext* globalCtx) {
ObjMure* this = (ObjMure*)thisx;
if (this->unk_1A4 > 0) {
this->unk_1A4--;
}
this->actionFunc(this, globalCtx);
}