EnGe2 (Gerudo in Purple) OK and documented, object_gla documented (#1071)

* OK, data imported

* Permuter settings

* Name data, a few functions and variables, cleanup

* Small amount of cleanup on some related actors

* Oops

* Document object

* Type and other macros

* Some cutscene stuff and temporary function names

* Proper path function names

* Name a couple more functions

* A couple more function names

* Name PathStatus enum

* Name rest of functions and formalise the documentation a bit

* Apply suggestions from code review

Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>

* limbs

* Format

* Review

* format

* weekeventregconvert and format

---------

Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
Co-authored-by: angie <angheloalf95@gmail.com>
This commit is contained in:
EllipticEllipsis
2023-02-24 14:59:17 +00:00
committed by GitHub
parent 3e257354c1
commit 69f7540e33
15 changed files with 993 additions and 254 deletions
@@ -674,7 +674,7 @@ void EnArrow_Draw(Actor* thisx, PlayState* play) {
gSPMatrix(POLY_XLU_DISP++, &D_01000000, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gameplay_keep_DL_06F9F0);
} else {
func_800B8050(&this->actor, play, MTXMODE_NEW);
func_800B8050(&this->actor, play, 0);
gSPDisplayList(POLY_OPA_DISP++, gameplay_keep_DL_06F380);
gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL1, 0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0,
+28 -22
View File
@@ -189,13 +189,14 @@ void EnGe1_SetupPath(EnGe1* this, PlayState* play) {
Vec3s* point;
Vec3f nextPoint;
this->curPoint = 0;
this->curPointIndex = 0;
if (GERUDO_WHITE_GET_PATH(&this->picto.actor) != 0x3F) {
this->path = &play->setupPathList[GERUDO_WHITE_GET_PATH(&this->picto.actor)];
if (this->path != NULL) {
point = Lib_SegmentedToVirtual(this->path->points);
Math_Vec3s_ToVec3f(&this->picto.actor.world.pos, point);
this->curPoint++;
this->curPointIndex++;
point++;
Math_Vec3s_ToVec3f(&nextPoint, point);
@@ -214,7 +215,7 @@ void EnGe1_SetupPath(EnGe1* this, PlayState* play) {
s32 EnGe1_FollowPath(EnGe1* this) {
s32 pad;
Path* path = this->path;
Vec3s* points;
Vec3s* curPoint;
Vec3f point;
s16 yawTarget;
s16 pitchTarget;
@@ -223,10 +224,10 @@ s32 EnGe1_FollowPath(EnGe1* this) {
return true;
}
points = Lib_SegmentedToVirtual(this->path->points);
points += this->curPoint;
curPoint = Lib_SegmentedToVirtual(this->path->points);
curPoint += this->curPointIndex;
Math_Vec3s_ToVec3f(&point, points);
Math_Vec3s_ToVec3f(&point, curPoint);
yawTarget = Math_Vec3f_Yaw(&this->picto.actor.world.pos, &point);
pitchTarget = Math_Vec3f_Pitch(&this->picto.actor.world.pos, &point);
Math_SmoothStepToS(&this->picto.actor.world.rot.y, yawTarget, 0xA, 0x3E8, 0x64);
@@ -260,9 +261,9 @@ void EnGe1_PerformCutsceneActions(EnGe1* this, PlayState* play) {
EnGe1_ChangeAnim(this, GERUDO_WHITE_ANIM_STIFF_SHIVERING, ANIMMODE_LOOP, 0.0f);
}
if (Cutscene_CheckActorAction(play, 0x79)) {
if (Cutscene_CheckActorAction(play, 121)) {
this->picto.actor.draw = EnGe1_Draw;
csAction = play->csCtx.actorActions[Cutscene_GetActorActionIndex(play, 0x79)]->action;
csAction = play->csCtx.actorActions[Cutscene_GetActorActionIndex(play, 121)]->action;
switch (csAction) {
case 8:
this->stateFlags &= ~GERUDO_WHITE_STATE_DISABLE_MOVEMENT;
@@ -339,22 +340,27 @@ void EnGe1_PerformCutsceneActions(EnGe1* this, PlayState* play) {
this->picto.actor.draw = NULL;
}
if (this->csAction == 9) {
if ((this->curPoint < this->path->count) && EnGe1_FollowPath(this)) {
this->curPoint++;
}
switch (this->csAction) {
case 9:
if ((this->curPointIndex < this->path->count) && EnGe1_FollowPath(this)) {
this->curPointIndex++;
}
// Tumble in the air
this->picto.actor.shape.rot.x += 0x3E8;
this->picto.actor.shape.rot.y += 0x7D0;
this->picto.actor.shape.rot.z += 0x1F4;
// Tumble in the air
this->picto.actor.shape.rot.x += 0x3E8;
this->picto.actor.shape.rot.y += 0x7D0;
this->picto.actor.shape.rot.z += 0x1F4;
if (this->screamTimer > 0) {
this->screamTimer--;
} else {
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
EnGe1_Scream(this);
}
if (this->screamTimer > 0) {
this->screamTimer--;
} else {
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
EnGe1_Scream(this);
}
break;
default:
break;
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ typedef struct EnGe1 {
/* 0x2A4 */ Vec3s headRot;
/* 0x2AA */ Vec3s torsoRot;
/* 0x2B0 */ Path* path;
/* 0x2B4 */ s32 curPoint;
/* 0x2B4 */ s32 curPointIndex;
/* 0x2B8 */ s16 eyeIndex;
/* 0x2BA */ s16 blinkTimer;
/* 0x2BC */ u16 stateFlags;
+710 -51
View File
@@ -15,18 +15,14 @@ void EnGe2_Destroy(Actor* thisx, PlayState* play);
void EnGe2_Update(Actor* thisx, PlayState* play);
void EnGe2_Draw(Actor* thisx, PlayState* play);
void func_80B8BCEC(EnGe2* this, PlayState* play);
void func_80B8BD38(EnGe2* this, PlayState* play);
void func_80B8BE08(EnGe2* this, PlayState* play);
void func_80B8BF04(EnGe2* this, PlayState* play);
void func_80B8C048(EnGe2* this, PlayState* play);
void func_80B8C0B0(EnGe2* this, PlayState* play);
void func_80B8C45C(EnGe2* this, PlayState* play);
void func_80B8C59C(EnGe2* this, PlayState* play);
void func_80B8C644(EnGe2* this, PlayState* play);
void func_80B8C9B8(EnGe2* this, PlayState* play);
s32 EnGe2_SetupPath(EnGe2* this, PlayState* play);
void EnGe2_LookAround(EnGe2* this, PlayState* play);
void EnGe2_Walk(EnGe2* this, PlayState* play);
void EnGe2_GuardStationary(EnGe2* this, PlayState* play);
s32 EnGe2_ValidatePictograph(PlayState* play, Actor* thisx);
#if 0
ActorInit En_Ge2_InitVars = {
ACTOR_EN_GE2,
ACTORCAT_NPC,
@@ -39,78 +35,741 @@ ActorInit En_Ge2_InitVars = {
(ActorFunc)EnGe2_Draw,
};
// static ColliderCylinderInit sCylinderInit = {
static ColliderCylinderInit D_80B8CE40 = {
{ COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
{ ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x038BFBB3, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, },
typedef enum {
/* 0 */ GERUDO_PURPLE_DETECTION_UNDETECTED,
/* 1 */ GERUDO_PURPLE_DETECTION_HEARD,
/* 2 */ GERUDO_PURPLE_DETECTION_PROXIMITY //!< Higher priority
} GerudoPurpleDetection;
typedef enum {
/* 0 */ GERUDO_PURPLE_PATHSTATUS_NORMAL, //!< not near waypoint
/* 1 */ GERUDO_PURPLE_PATHSTATUS_AT_POINT, //!< no path or new waypoint
/* 2 */ GERUDO_PURPLE_PATHSTATUS_END //!< reached end of path
} GerudoPurplePathStatus;
#define GERUDO_PURPLE_STATE_PATH_REVERSE (1 << 0) //!< Follow path backwards instead of forwards.
#define GERUDO_PURPLE_STATE_KO (1 << 1)
#define GERUDO_PURPLE_STATE_STUNNED (1 << 2) //!< Specifically by Deku Nuts
#define GERUDO_PURPLE_STATE_DISABLE_MOVEMENT \
(1 << 3) //!< Disable normal movement to let pathing function control it completely.
#define GERUDO_PURPLE_STATE_CAPTURING (1 << 5) //!< Set but not used
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_1,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x038BFBB3, 0x00, 0x00 },
TOUCH_NONE | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_ON,
},
{ 30, 60, 0, { 0, 0, 0 } },
};
#endif
void EnGe2_Init(Actor* thisx, PlayState* play) {
s32 pad;
EnGe2* this = THIS;
extern ColliderCylinderInit D_80B8CE40;
ActorShape_Init(&this->picto.actor.shape, 0.0f, ActorShadow_DrawCircle, 36.0f);
SkelAnime_InitFlex(play, &this->skelAnime, &gGerudoPurpleSkel, NULL, this->jointTable, this->morphTable,
GERUDO_PURPLE_LIMB_MAX);
Animation_PlayLoop(&this->skelAnime, &gGerudoPurpleWalkingAnim);
extern UNK_TYPE D_06008DD8;
extern UNK_TYPE D_060091D0;
extern UNK_TYPE D_06009D1C;
extern UNK_TYPE D_0600A344;
Collider_InitAndSetCylinder(play, &this->collider, &this->picto.actor, &sCylinderInit);
this->picto.actor.colChkInfo.mass = MASS_IMMOVABLE;
Actor_SetScale(&this->picto.actor, 0.01f);
this->picto.actor.uncullZoneForward = 1200.0f;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/EnGe2_Init.s")
if (this->picto.actor.world.rot.z == 0) {
this->verticalDetectRange = 40.0f;
} else {
this->verticalDetectRange = fabsf(this->picto.actor.world.rot.z * 20.0f);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/EnGe2_Destroy.s")
this->picto.actor.world.rot.x = this->picto.actor.shape.rot.x = 0;
this->picto.actor.world.rot.z = this->picto.actor.shape.rot.z = 0;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B514.s")
this->picto.actor.targetMode = 6;
this->stateFlags = 0;
this->detectedStatus = GERUDO_PURPLE_DETECTION_UNDETECTED;
this->csAction = -1;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B5AC.s")
this->picto.actor.terminalVelocity = -9.0f;
this->picto.actor.gravity = -1.0f;
this->picto.actor.speedXZ = 1.5f;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B6B4.s")
this->actionFunc = EnGe2_Walk;
this->picto.validationFunc = EnGe2_ValidatePictograph;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B7A8.s")
EnGe2_SetupPath(this, play);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B848.s")
this->picto.actor.flags |= ACTOR_FLAG_10;
if (play->actorCtx.flags & ACTORCTX_FLAG_1) {
this->picto.actor.flags |= (ACTOR_FLAG_10 | ACTOR_FLAG_20);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8B90C.s")
switch (GERUDO_PURPLE_GET_TYPE(&this->picto.actor)) {
case GERUDO_PURPLE_TYPE_BOAT_SENTRY:
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, 0.0f);
this->actionFunc = EnGe2_GuardStationary;
this->picto.actor.speedXZ = 0.0f;
this->picto.actor.uncullZoneForward = 4000.0f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BA40.s")
case GERUDO_PURPLE_TYPE_AVEIL_GUARD:
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_83_02)) {
Actor_Kill(&this->picto.actor);
}
break;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BB3C.s")
default:
break;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BC1C.s")
void EnGe2_Destroy(Actor* thisx, PlayState* play) {
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BC78.s")
// Detect Player through hearing or proximity
GerudoPurpleDetection EnGe2_DetectPlayer(PlayState* play, EnGe2* this) {
if (this->picto.actor.xzDistToPlayer > 250.0f) {
return GERUDO_PURPLE_DETECTION_UNDETECTED;
} else if ((Player_GetMask(play) != PLAYER_MASK_STONE) && (this->picto.actor.xzDistToPlayer < 50.0f)) {
return GERUDO_PURPLE_DETECTION_PROXIMITY;
} else if (func_800B715C(play)) {
return GERUDO_PURPLE_DETECTION_HEARD;
} else {
return GERUDO_PURPLE_DETECTION_UNDETECTED;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BCEC.s")
/**
* Spotted Player with line-of-sight
*
* @param play PlayState
* @param thisx Actor to use for range and angle checks
* @param pos Position to check from
* @param yaw Center of yaw range to check
* @param yawRange Spread of angles from `yaw` to check. If 0, do not check yaw
* @param xzRange Horizontal range to check
* @param yRange Vertical range to check
* @return true if Player is visible with these settings
*/
s32 EnGe2_LookForPlayer(PlayState* play, Actor* actor, Vec3f* pos, s16 yaw, s16 yawRange, f32 xzRange, f32 yRange) {
s16 yawToPlayer;
Vec3f posResult;
CollisionPoly* outPoly;
Player* player = GET_PLAYER(play);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BD38.s")
if (Player_GetMask(play) == PLAYER_MASK_STONE) {
return false;
}
if (actor->xzDistToPlayer > xzRange) {
return false;
}
if (fabsf(actor->playerHeightRel) > yRange) {
return false;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BD90.s")
yawToPlayer = actor->yawTowardsPlayer - yaw;
if ((yawRange > 0) && (yawRange < ABS_ALT(yawToPlayer))) {
return false;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BE08.s")
if (BgCheck_AnyLineTest1(&play->colCtx, pos, &player->bodyPartsPos[7], &posResult, &outPoly, false)) {
return false;
} else {
return true;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BF04.s")
/* Path functions */
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8BFC8.s")
/**
* Set up the path if it exists, choose the end and direction
*
* @return true if path is set up in reverse
*/
s32 EnGe2_SetupPath(EnGe2* this, PlayState* play) {
if (GERUDO_PURPLE_GET_PATH(&this->picto.actor) != GERUDO_PURPLE_PATH_NONE) {
this->path = &play->setupPathList[GERUDO_PURPLE_GET_PATH(&this->picto.actor)];
if (this->path != NULL) {
Path* path = this->path;
Vec3s* points = Lib_SegmentedToVirtual(path->points);
f32 diffX = points[0].x - this->picto.actor.world.pos.x;
f32 diffZ = points[0].z - this->picto.actor.world.pos.z;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C048.s")
if ((SQ(diffX) + SQ(diffZ)) < SQ(10.0f)) {
this->curPointIndex = 0;
this->stateFlags &= ~GERUDO_PURPLE_STATE_PATH_REVERSE;
} else {
this->curPointIndex = path->count - 1;
this->stateFlags |= GERUDO_PURPLE_STATE_PATH_REVERSE;
return true;
}
}
} else {
this->path = NULL;
this->curPointIndex = 0;
}
return false;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C0B0.s")
void EnGe2_GetNextPath(EnGe2* this, PlayState* play) {
Path* curPath;
Path* nextPath;
Vec3s* points;
u8 unk1;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C13C.s")
this->curPointIndex = 0;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C45C.s")
if (GERUDO_PURPLE_GET_PATH(&this->picto.actor) != GERUDO_PURPLE_PATH_NONE) {
curPath = &play->setupPathList[GERUDO_PURPLE_GET_PATH(&this->picto.actor)];
unk1 = curPath->unk1;
nextPath = &play->setupPathList[unk1];
this->path = nextPath;
points = Lib_SegmentedToVirtual(nextPath->points);
this->picto.actor.world.pos.x = points[0].x;
this->picto.actor.world.pos.z = points[0].z;
} else {
this->path = NULL;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C59C.s")
void EnGe2_SetupBlownAwayPath(EnGe2* this, PlayState* play) {
s32 pad;
Vec3s* points;
Vec3f nextPoint;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C644.s")
this->curPointIndex = 0;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8C9B8.s")
if (GERUDO_PURPLE_GET_PATH(&this->picto.actor) != GERUDO_PURPLE_PATH_NONE) {
this->path = &play->setupPathList[GERUDO_PURPLE_GET_PATH(&this->picto.actor)];
if (this->path != NULL) {
points = Lib_SegmentedToVirtual(this->path->points);
Math_Vec3s_ToVec3f(&this->picto.actor.world.pos, points);
this->curPointIndex++;
points++;
Math_Vec3s_ToVec3f(&nextPoint, points);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/EnGe2_Update.s")
this->picto.actor.world.rot.y = Math_Vec3f_Yaw(&this->picto.actor.world.pos, &nextPoint);
this->picto.actor.world.rot.x = Math_Vec3f_Pitch(&this->picto.actor.world.pos, &nextPoint);
this->picto.actor.speedXZ = 15.0f;
}
} else {
this->path = NULL;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8CC0C.s")
GerudoPurplePathStatus EnGe2_FollowPath(EnGe2* this) {
Path* path = this->path;
Vec3s* curPoint;
f32 diffX;
f32 diffZ;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8CCB4.s")
if (path == NULL) {
return GERUDO_PURPLE_PATHSTATUS_AT_POINT;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/func_80B8CCFC.s")
curPoint = (Vec3s*)Lib_SegmentedToVirtual(path->points);
curPoint += this->curPointIndex;
diffX = curPoint->x - this->picto.actor.world.pos.x;
diffZ = curPoint->z - this->picto.actor.world.pos.z;
this->picto.actor.world.rot.y = Math_Atan2S(diffX, diffZ);
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->picto.actor.world.rot.y, 2, 0x7D0, 0xC8);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ge2/EnGe2_Draw.s")
if ((SQ(diffX) + SQ(diffZ)) < SQ(10.0f)) {
if (this->stateFlags & GERUDO_PURPLE_STATE_PATH_REVERSE) {
this->curPointIndex--;
if (this->curPointIndex < 0) {
return GERUDO_PURPLE_PATHSTATUS_END;
}
} else {
this->curPointIndex++;
if (this->curPointIndex >= path->count) {
return GERUDO_PURPLE_PATHSTATUS_END;
}
}
return GERUDO_PURPLE_PATHSTATUS_AT_POINT;
}
return GERUDO_PURPLE_PATHSTATUS_NORMAL;
}
/**
* Used for Blown Away cutscene path.
*/
s32 EnGe2_FollowPathWithoutGravity(EnGe2* this) {
s32 pad;
Vec3s* curPoint;
Path* path = this->path;
Vec3f point;
s16 yawTarget;
s16 pitchTarget;
if (this->path == NULL) {
return true;
}
curPoint = Lib_SegmentedToVirtual(path->points);
curPoint += this->curPointIndex;
Math_Vec3s_ToVec3f(&point, curPoint);
yawTarget = Math_Vec3f_Yaw(&this->picto.actor.world.pos, &point);
pitchTarget = Math_Vec3f_Pitch(&this->picto.actor.world.pos, &point);
Math_SmoothStepToS(&this->picto.actor.world.rot.y, yawTarget, 0xA, 0x3E8, 0x64);
Math_SmoothStepToS(&this->picto.actor.world.rot.x, pitchTarget, 6, 0x7D0, 0xC8);
this->picto.actor.speedXZ = 15.0f;
Actor_MoveWithoutGravityReverse(&this->picto.actor);
if (Math_Vec3f_DistXYZ(&this->picto.actor.world.pos, &point) < 40.0f) {
return true;
} else {
return false;
}
}
/* Action and helper functions */
void EnGe2_SpawnEffects(EnGe2* this, PlayState* play) {
static Vec3f effectVelocity = { 0.0f, -0.05f, 0.0f };
static Vec3f effectAccel = { 0.0f, -0.025f, 0.0f };
static Color_RGBA8 effectPrimColor = { 255, 255, 255, 0 };
static Color_RGBA8 effectEnvColor = { 255, 150, 0, 0 };
s16 effectAngle = play->state.frames * 0x2800;
Vec3f effectPos;
effectPos.x = (Math_CosS(effectAngle) * 5.0f) + this->picto.actor.focus.pos.x;
effectPos.y = this->picto.actor.focus.pos.y + 10.0f;
effectPos.z = (Math_SinS(effectAngle) * 5.0f) + this->picto.actor.focus.pos.z;
EffectSsKirakira_SpawnDispersed(play, &effectPos, &effectVelocity, &effectAccel, &effectPrimColor, &effectEnvColor,
1000, 16);
}
void EnGe2_Scream(EnGe2* this) {
if ((s32)Rand_ZeroFloat(2.0f) == 0) {
Actor_PlaySfxAtPos(&this->picto.actor, NA_SE_VO_FPVO00);
} else {
Actor_PlaySfxAtPos(&this->picto.actor, NA_SE_VO_FPVO01);
}
}
/**
* Wait for timer to finish, then set up the captured/thrown out transition.
*/
void EnGe2_ThrowPlayerOut(EnGe2* this, PlayState* play) {
if (this->timer > 0) {
this->timer--;
} else if (play->nextEntrance != play->setupExitList[GERUDO_PURPLE_GET_EXIT(&this->picto.actor)]) {
play->nextEntrance = play->setupExitList[GERUDO_PURPLE_GET_EXIT(&this->picto.actor)];
play->transitionTrigger = TRANS_TRIGGER_START;
play->transitionType = TRANS_TYPE_38;
}
}
/**
* Used if Aveil spots Player.
*/
void EnGe2_TurnToPlayerFast(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->picto.actor.yawTowardsPlayer, 2, 0x1000, 0x200);
}
void EnGe2_CapturePlayer(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->picto.actor.yawTowardsPlayer, 2, 0x400, 0x100);
EnGe2_ThrowPlayerOut(this, play);
}
void EnGe2_SetupCapturePlayer(EnGe2* this) {
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_CapturePlayer;
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
}
void EnGe2_Charge(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->picto.actor.yawTowardsPlayer, 2, 0x400, 0x100);
this->picto.actor.world.rot.y = this->picto.actor.shape.rot.y;
if (this->picto.actor.xzDistToPlayer < 50.0f) {
EnGe2_SetupCapturePlayer(this);
} else if (!(this->picto.actor.bgCheckFlags & 1)) {
this->picto.actor.world.pos = this->picto.actor.prevPos;
EnGe2_SetupCapturePlayer(this);
}
if (this->timer > 0) {
this->timer--;
} else {
EnGe2_ThrowPlayerOut(this, play);
}
if (Animation_OnFrame(&this->skelAnime, 2.0f) || Animation_OnFrame(&this->skelAnime, 6.0f)) {
Actor_PlaySfxAtPos(&this->picto.actor, NA_SE_EV_PIRATE_WALK);
}
}
void EnGe2_SetupCharge(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->picto.actor.yawTowardsPlayer, 2, 0x400, 0x100);
this->picto.actor.world.rot.y = this->picto.actor.shape.rot.y;
if (this->picto.actor.shape.rot.y == this->picto.actor.yawTowardsPlayer) {
Animation_Change(&this->skelAnime, &gGerudoPurpleChargingAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleChargingAnim), 0, -8.0f);
this->timer = 50;
this->picto.actor.speedXZ = 4.0f;
this->actionFunc = EnGe2_Charge;
}
}
void EnGe2_SetupLookAround(EnGe2* this) {
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
this->timer = 60;
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_LookAround;
}
void EnGe2_Stunned(EnGe2* this, PlayState* play) {
if (this->picto.actor.colorFilterTimer == 0) {
EnGe2_SetupLookAround(this);
this->detectedStatus = GERUDO_PURPLE_DETECTION_UNDETECTED;
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
this->stateFlags &= ~GERUDO_PURPLE_STATE_STUNNED;
}
}
void EnGe2_KnockedOut(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
EnGe2_SpawnEffects(this, play);
if (this->timer > 0) {
this->timer--;
} else {
EnGe2_SetupLookAround(this);
this->detectedStatus = GERUDO_PURPLE_DETECTION_UNDETECTED;
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
this->stateFlags &= ~GERUDO_PURPLE_STATE_KO;
this->picto.actor.flags |= ACTOR_FLAG_1;
}
}
/**
* Carries out various patrol functions:
* - Turning to Player if being arrested
* - Turning to Player if spotted by Aveil
* - Looking for Player
* - Managing collisions and collider
*/
void EnGe2_PatrolDuties(EnGe2* this, PlayState* play) {
Player* player = GET_PLAYER(play);
f32 visionRange = gSaveContext.save.isNight ? 200.0f : 280.0f;
if (player->csMode == 0x1A) {
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_SetupCharge;
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
this->stateFlags |= GERUDO_PURPLE_STATE_CAPTURING;
} else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_80_08)) {
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_TurnToPlayerFast;
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
} else if (EnGe2_LookForPlayer(play, &this->picto.actor, &this->picto.actor.focus.pos,
this->picto.actor.shape.rot.y, 0x1800, visionRange, this->verticalDetectRange)) {
if ((GERUDO_PURPLE_GET_EXIT(&this->picto.actor) != GERUDO_PURPLE_EXIT_NONE) && !Play_InCsMode(play)) {
this->picto.actor.speedXZ = 0.0f;
func_800B7298(play, &this->picto.actor, 0x1A);
func_801000A4(NA_SE_SY_FOUND);
Message_StartTextbox(play, 0x1194, &this->picto.actor);
this->actionFunc = EnGe2_SetupCharge;
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
}
} else if (this->collider.base.acFlags & AC_HIT) {
if ((this->collider.info.acHitInfo != NULL) &&
(this->collider.info.acHitInfo->toucher.dmgFlags & DMG_DEKU_NUT)) {
Actor_SetColorFilter(&this->picto.actor, 0, 120, 0, 400);
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_Stunned;
this->stateFlags |= GERUDO_PURPLE_STATE_STUNNED;
} else {
Animation_Change(&this->skelAnime, &gGerudoPurpleFallingToGroundAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleFallingToGroundAnim), 2, -8.0f);
this->timer = 200;
this->picto.actor.speedXZ = 0.0f;
this->actionFunc = EnGe2_KnockedOut;
Actor_PlaySfxAtPos(&this->picto.actor, NA_SE_EN_PIRATE_DEAD);
this->picto.actor.flags &= ~ACTOR_FLAG_1;
this->stateFlags |= GERUDO_PURPLE_STATE_KO;
}
} else if (this->picto.actor.home.rot.x == 0) {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
}
}
void EnGe2_LookAround(EnGe2* this, PlayState* play) {
u8 detectedStatus;
SkelAnime_Update(&this->skelAnime);
detectedStatus = EnGe2_DetectPlayer(play, this);
if (detectedStatus != GERUDO_PURPLE_DETECTION_UNDETECTED) {
this->timer = 100;
this->yawTarget = this->picto.actor.yawTowardsPlayer;
if (this->detectedStatus < detectedStatus) {
this->detectedStatus = detectedStatus;
}
}
if (this->timer > 0) {
this->timer--;
} else {
this->actionFunc = EnGe2_Walk;
Animation_Change(&this->skelAnime, &gGerudoPurpleWalkingAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleWalkingAnim), 0, -8.0f);
this->headRot.y = 0;
this->detectedStatus = GERUDO_PURPLE_DETECTION_UNDETECTED;
}
switch (this->detectedStatus) {
case GERUDO_PURPLE_DETECTION_HEARD:
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->yawTarget, 2, 0x3E8, 0x1F4);
break;
case GERUDO_PURPLE_DETECTION_PROXIMITY:
Math_SmoothStepToS(&this->picto.actor.shape.rot.y, this->yawTarget, 2, 0xBB8, 0x3E8);
break;
default:
break;
}
this->picto.actor.world.rot.y = this->picto.actor.shape.rot.y;
EnGe2_PatrolDuties(this, play);
}
void EnGe2_Walk(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
this->picto.actor.speedXZ = 1.5f;
switch (EnGe2_FollowPath(this)) {
case GERUDO_PURPLE_PATHSTATUS_END:
EnGe2_SetupPath(this, play);
break;
case GERUDO_PURPLE_PATHSTATUS_AT_POINT:
EnGe2_SetupLookAround(this);
this->detectedStatus = GERUDO_PURPLE_DETECTION_UNDETECTED;
break;
default: // GERUDO_PURPLE_PATHSTATUS_NORMAL
break;
}
this->detectedStatus = EnGe2_DetectPlayer(play, this);
if (this->detectedStatus != GERUDO_PURPLE_DETECTION_UNDETECTED) {
EnGe2_SetupLookAround(this);
this->yawTarget = this->picto.actor.yawTowardsPlayer;
}
EnGe2_PatrolDuties(this, play);
}
void EnGe2_PerformCutsceneActions(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
if (Cutscene_CheckActorAction(play, 476)) {
s16 csAction = play->csCtx.actorActions[Cutscene_GetActorActionIndex(play, 476)]->action;
if (this->csAction != csAction) {
this->csAction = csAction;
switch (csAction) {
case ENGE2_CSACTION_BEEHIVE_PATROL:
Animation_Change(&this->skelAnime, &gGerudoPurpleLookingAboutAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleLookingAboutAnim), 0, -8.0f);
EnGe2_GetNextPath(this, play);
break;
case ENGE2_CSACTION_BEEHIVE_RUN_AWAY:
Animation_Change(&this->skelAnime, &gGerudoPurpleRunningAwayCutsceneAnim, 1.0f, 0.0f,
Animation_GetLastFrame(&gGerudoPurpleRunningAwayCutsceneAnim), 0, -5.0f);
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
break;
case ENGE2_CSACTION_BEEHIVE_EXIT:
Actor_Kill(&this->picto.actor);
break;
case ENGE2_CSACTION_GBT_ENTR_STAND_STILL:
Animation_Change(&this->skelAnime, &gGerudoPurpleGreatBayCutsceneAnim, 0.0f, 0.0f, 0.0f, 2, 0.0f);
break;
case ENGE2_CSACTION_GBT_ENTR_BLOWN_AWAY:
Animation_Change(&this->skelAnime, &gGerudoPurpleGreatBayCutsceneAnim, 0.0f, 1.0f, 1.0f, 2, 0.0f);
EnGe2_SetupBlownAwayPath(this, play);
this->stateFlags |= GERUDO_PURPLE_STATE_DISABLE_MOVEMENT;
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
break;
default:
break;
}
}
}
switch (this->csAction) {
case ENGE2_CSACTION_BEEHIVE_RUN_AWAY:
EnGe2_FollowPath(this);
this->picto.actor.speedXZ = 5.0f;
if (Animation_OnFrame(&this->skelAnime, 2.0f) || Animation_OnFrame(&this->skelAnime, 6.0f)) {
Actor_PlaySfxAtPos(&this->picto.actor, NA_SE_EV_PIRATE_WALK);
}
if (this->screamTimer > 0) {
this->screamTimer--;
} else {
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
EnGe2_Scream(this);
}
break;
case ENGE2_CSACTION_GBT_ENTR_BLOWN_AWAY:
if ((this->curPointIndex < this->path->count) && EnGe2_FollowPathWithoutGravity(this)) {
this->curPointIndex++;
}
// Tumble in the air
this->picto.actor.shape.rot.x += 0x3E8;
this->picto.actor.shape.rot.y += 0x7D0;
this->picto.actor.shape.rot.z += 0x1F4;
if (this->screamTimer > 0) {
this->screamTimer--;
} else {
this->screamTimer = (s32)(Rand_ZeroFloat(10.0f) + 20.0f);
EnGe2_Scream(this);
}
break;
default:
break;
}
}
// Used for those on boats
void EnGe2_GuardStationary(EnGe2* this, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
if (EnGe2_LookForPlayer(play, &this->picto.actor, &this->picto.actor.focus.pos, this->picto.actor.shape.rot.y,
0x4000, 720.0f, this->verticalDetectRange)) {
if ((GERUDO_PURPLE_GET_EXIT(&this->picto.actor) != GERUDO_PURPLE_EXIT_NONE) && !Play_InCsMode(play)) {
func_800B7298(play, &this->picto.actor, 0x1A);
func_801000A4(NA_SE_SY_FOUND);
Message_StartTextbox(play, 0x1194, &this->picto.actor);
this->timer = 50;
EnGe2_SetupCapturePlayer(this);
}
}
if (this->picto.actor.playerHeightRel < -150.0f) {
this->picto.actor.draw = NULL;
} else {
this->picto.actor.draw = EnGe2_Draw;
}
}
void EnGe2_Update(Actor* thisx, PlayState* play) {
s32 pad;
EnGe2* this = THIS;
if (!(this->stateFlags & GERUDO_PURPLE_STATE_DISABLE_MOVEMENT)) {
Actor_MoveWithGravity(&this->picto.actor);
}
Actor_UpdateBgCheckInfo(play, &this->picto.actor, 40.0f, 25.0f, 40.0f, 5);
Collider_UpdateCylinder(&this->picto.actor, &this->collider);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
if (Cutscene_CheckActorAction(play, 476)) {
this->actionFunc = EnGe2_PerformCutsceneActions;
this->stateFlags &= ~GERUDO_PURPLE_STATE_KO;
this->stateFlags &= ~GERUDO_PURPLE_STATE_PATH_REVERSE;
this->picto.actor.flags |= ACTOR_FLAG_20;
this->picto.actor.speedXZ = 0.0f;
}
this->actionFunc(this, play);
// Blinking
if (this->stateFlags & GERUDO_PURPLE_STATE_KO) {
this->eyeIndex = 2;
} else if (!(this->stateFlags & GERUDO_PURPLE_STATE_STUNNED)) {
if (DECR(this->blinkTimer) == 0) {
this->blinkTimer = Rand_S16Offset(60, 60);
}
this->eyeIndex = this->blinkTimer;
if (this->eyeIndex >= 3) {
this->eyeIndex = 0;
}
}
}
s32 EnGe2_ValidatePictograph(PlayState* play, Actor* thisx) {
s32 ret = Snap_ValidatePictograph(play, thisx, PICTO_VALID_PIRATE_GOOD, &thisx->focus.pos, &thisx->shape.rot, 10.0f,
400.0f, -1);
ret |= Snap_ValidatePictograph(play, thisx, PICTO_VALID_PIRATE_TOO_FAR, &thisx->focus.pos, &thisx->shape.rot, 10.0f,
1200.0f, -1);
return ret;
}
s32 EnGe2_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
EnGe2* this = THIS;
if (limbIndex == GERUDO_PURPLE_NECK_LIMB) {
rot->x += this->headRot.y;
rot->z += this->headRot.x;
}
return false;
}
void EnGe2_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
static Vec3f sFocusOffset = { 600.0f, 700.0f, 0.0f };
if (limbIndex == GERUDO_PURPLE_HEAD_LIMB) {
Matrix_MultVec3f(&sFocusOffset, &thisx->focus.pos);
}
}
void EnGe2_Draw(Actor* thisx, PlayState* play) {
static TexturePtr sEyeTextures[] = {
gGerudoPurpleEyeOpenTex,
gGerudoPurpleEyeHalfTex,
gGerudoPurpleEyeClosedTex,
};
s32 pad;
EnGe2* this = THIS;
OPEN_DISPS(play->state.gfxCtx);
func_8012C5B0(play->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[this->eyeIndex]));
func_800B8050(&this->picto.actor, play, 0);
SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
EnGe2_OverrideLimbDraw, EnGe2_PostLimbDraw, &this->picto.actor);
CLOSE_DISPS(play->state.gfxCtx);
}
+46 -2
View File
@@ -2,14 +2,58 @@
#define Z_EN_GE2_H
#include "global.h"
#include "z64snap.h"
#include "objects/object_gla/object_gla.h"
struct EnGe2;
typedef void (*EnGe2ActionFunc)(struct EnGe2*, PlayState*);
#define GERUDO_PURPLE_GET_EXIT(thisx) (((thisx)->params) & 0x1F) //!< Exit to send Player to when caught
#define GERUDO_PURPLE_GET_TYPE(thisx) (((thisx)->params & 0xE0) >> 5)
#define GERUDO_PURPLE_GET_PATH(thisx) ((((thisx)->params) & 0xFC00) >> 10)
#define GERUDO_PURPLE_PARAMS(path, type, exit) (((path) & 0x1F) | (((type) & 7) << 5) | (((exit) & 0x3F) << 10))
#define GERUDO_PURPLE_EXIT_NONE 0x1F
#define GERUDO_PURPLE_PATH_NONE 0x3F
typedef enum {
/* 0 */ GERUDO_PURPLE_TYPE_CUTSCENE,
/* 1 */ GERUDO_PURPLE_TYPE_BOAT_SENTRY, //!< on boats
/* 2 */ GERUDO_PURPLE_TYPE_AVEIL_GUARD,
/* 7 */ GERUDO_PURPLE_TYPE_FORTRESS = 7 //!< In both courtyard and rooms
} GerudoPurpleType;
//! TODO: work out where to put this
typedef enum {
/* 1 */ ENGE2_CSACTION_BEEHIVE_PATROL = 1,
/* 2 */ ENGE2_CSACTION_BEEHIVE_RUN_AWAY,
/* 3 */ ENGE2_CSACTION_BEEHIVE_EXIT,
/* 4 */ ENGE2_CSACTION_GBT_ENTR_STAND_STILL,
/* 5 */ ENGE2_CSACTION_GBT_ENTR_BLOWN_AWAY
} EnGe2CsAction;
typedef struct EnGe2 {
/* 0x000 */ Actor actor;
/* 0x144 */ char unk_144[0x1C4];
/* 0x000 */ PictoActor picto;
/* 0x148 */ ColliderCylinder collider;
/* 0x194 */ SkelAnime skelAnime;
/* 0x1D8 */ Vec3s jointTable[GERUDO_PURPLE_LIMB_MAX];
/* 0x25C */ Vec3s morphTable[GERUDO_PURPLE_LIMB_MAX];
/* 0x2E0 */ s16 eyeIndex;
/* 0x2E2 */ s16 blinkTimer;
/* 0x2E4 */ Vec3s headRot;
/* 0x2E8 */ Vec3s torsoRot; // unused, inferred from similar usage in other actors
/* 0x2F0 */ Path* path;
/* 0x2F4 */ s32 curPointIndex;
/* 0x2F8 */ u16 stateFlags;
/* 0x2FA */ s16 yawTarget; //!< used when Player detected to fix the yaw to turn to
/* 0x2FC */ f32 verticalDetectRange; //!< vertical range to look for the player within
/* 0x300 */ u8 timer;
/* 0x301 */ u8 detectedStatus;
/* 0x302 */ s16 csAction;
/* 0x304 */ s16 unk304; // unused
/* 0x306 */ s16 screamTimer;
/* 0x308 */ EnGe2ActionFunc actionFunc;
} EnGe2; // size = 0x30C
+1 -1
View File
@@ -1134,7 +1134,7 @@ void func_80B43074(EnKgy* this, PlayState* play) {
OPEN_DISPS(play->state.gfxCtx);
func_8012C28C(play->state.gfxCtx);
func_800B8050(&this->actor, play, MTXMODE_NEW);
func_800B8050(&this->actor, play, 0);
Matrix_Push();
Matrix_Translate(-800.0f, 3100.0f, 8400.0f, MTXMODE_APPLY);
Matrix_RotateXS(0x4000, MTXMODE_APPLY);
+75 -59
View File
@@ -16,7 +16,7 @@ void ObjBoat_Destroy(Actor* thisx, PlayState* play);
void ObjBoat_Update(Actor* thisx, PlayState* play);
void ObjBoat_Draw(Actor* thisx, PlayState* play);
void func_80B9B428(Actor* thisx, PlayState* play2);
void ObjBoat_UpdateCutscene(Actor* thisx, PlayState* play2);
ActorInit Obj_Boat_InitVars = {
ACTOR_OBJ_BOAT,
@@ -37,14 +37,21 @@ static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP),
};
s16 func_80B9AF50(ObjBoat* this, Vec3f* arg0) {
/**
* Get the next point on the path and the yaw to use to get there.
*
* @param this
* @param nextPoint Position of next point on path
* @return yaw to use (or opposite of yaw if reversing)
*/
s16 ObjBoat_GetNextPoint(ObjBoat* this, Vec3f* nextPoint) {
s16 yaw;
Vec3s* temp = &this->unk_164[(s32)this->unk_15C];
Vec3s* curPoint = &this->points[(s32)this->curPointIndex];
Math_Vec3s_ToVec3f(arg0, &temp[this->unk_15D]);
yaw = Math_Vec3f_Yaw(&this->dyna.actor.world.pos, arg0);
Math_Vec3s_ToVec3f(nextPoint, &curPoint[this->direction]);
yaw = Math_Vec3f_Yaw(&this->dyna.actor.world.pos, nextPoint);
return ((this->unk_15D > 0) ? yaw : (yaw + 0x8000));
return ((this->direction > 0) ? yaw : yaw + 0x8000);
}
void ObjBoat_Init(Actor* thisx, PlayState* play) {
@@ -57,17 +64,17 @@ void ObjBoat_Init(Actor* thisx, PlayState* play) {
DynaPolyActor_Init(&this->dyna, 3);
DynaPolyActor_LoadMesh(play, &this->dyna, &object_kaizoku_obj_Colheader_009A88);
if (thisx->params < 0) {
this->dyna.actor.update = func_80B9B428;
this->dyna.actor.update = ObjBoat_UpdateCutscene;
} else {
path = &play->setupPathList[OBJBOAT_GET_PATH(thisx)];
this->unk_163 = path->count - 1;
this->unk_164 = Lib_SegmentedToVirtual(path->points);
this->unk_15D = 1;
this->dyna.actor.world.pos.x = this->unk_164[this->unk_15C].x;
this->dyna.actor.world.pos.z = this->unk_164[this->unk_15C].z;
this->dyna.actor.shape.rot.y = func_80B9AF50(this, &sp24);
this->maxPointIndex = path->count - 1;
this->points = Lib_SegmentedToVirtual(path->points);
this->direction = 1;
this->dyna.actor.world.pos.x = this->points[this->curPointIndex].x;
this->dyna.actor.world.pos.z = this->points[this->curPointIndex].z;
this->dyna.actor.shape.rot.y = ObjBoat_GetNextPoint(this, &sp24);
this->dyna.actor.world.rot.y = this->dyna.actor.shape.rot.y;
this->unk_15D = -this->unk_15D;
this->direction = -this->direction;
}
}
@@ -77,11 +84,11 @@ void ObjBoat_Destroy(Actor* thisx, PlayState* play) {
DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
}
void func_80B9B124(ObjBoat* this) {
this->unk_160 += 1000;
this->dyna.actor.world.pos.y = Math_SinS(this->unk_160) + this->dyna.actor.home.pos.y;
this->dyna.actor.shape.rot.x = Math_SinS(this->unk_160) * 100.0f;
this->dyna.actor.shape.rot.z = Math_SinS(this->unk_160 * 2) * 50.0f;
void ObjBoat_SetRotations(ObjBoat* this) {
this->angle += 0x3E8;
this->dyna.actor.world.pos.y = Math_SinS(this->angle) + this->dyna.actor.home.pos.y;
this->dyna.actor.shape.rot.x = Math_SinS(this->angle) * 100.0f;
this->dyna.actor.shape.rot.z = Math_SinS(this->angle * 2) * 50.0f;
}
void ObjBoat_Update(Actor* thisx, PlayState* play) {
@@ -89,93 +96,102 @@ void ObjBoat_Update(Actor* thisx, PlayState* play) {
ObjBoat* this = THIS;
Player* player = GET_PLAYER(play);
s32 temp = DynaPolyActor_IsInRidingMovingState(&this->dyna);
f32 sp3C = 0.0f;
s16 sp3A = this->dyna.actor.shape.rot.y;
Vec3f sp2C;
f32 speedTarget = 0.0f;
s16 yawTarget = this->dyna.actor.shape.rot.y;
Vec3f nextPoint;
if ((temp != 0) || ((DynaPolyActor_IsInRidingFallingState(&this->dyna)))) {
if ((this->unk_15F == 0) && (OBJBOAT_GET_4000(thisx) || ((temp != 0) && (this->unk_15C == this->unk_15E)))) {
this->unk_15D = -this->unk_15D;
if (this->unk_15D > 0) {
this->unk_15E = this->unk_163;
if (temp || ((DynaPolyActor_IsInRidingFallingState(&this->dyna)))) {
if ((this->timer == 0) &&
(OBJBOAT_GET_4000(thisx) || (temp && (this->curPointIndex == this->lastPointIndex)))) {
this->direction = -this->direction;
if (this->direction > 0) {
this->lastPointIndex = this->maxPointIndex;
} else {
this->unk_15E = 0;
this->lastPointIndex = 0;
}
this->unk_15F = 60;
this->timer = 60;
}
} else if (this->dyna.actor.speedXZ == 0.0f) {
if (this->unk_15F != 0) {
this->unk_15F--;
if (this->timer != 0) {
this->timer--;
}
}
if (this->unk_15C != this->unk_15E) {
sp3A = func_80B9AF50(this, &sp2C);
if (Math_Vec3f_DistXZ(&this->dyna.actor.world.pos, &sp2C) < 200.0f) {
this->unk_15C += this->unk_15D;
if (this->unk_15C == this->unk_15E) {
if (this->curPointIndex != this->lastPointIndex) {
yawTarget = ObjBoat_GetNextPoint(this, &nextPoint);
if (Math_Vec3f_DistXZ(&this->dyna.actor.world.pos, &nextPoint) < 200.0f) {
this->curPointIndex += this->direction;
if (this->curPointIndex == this->lastPointIndex) {
if (OBJBOAT_GET_4000(thisx)) {
this->unk_15C = 0;
this->curPointIndex = 0;
} else if (this->dyna.actor.speedXZ == 0.0f) {
this->unk_15C = 0;
this->unk_15D = -1;
this->curPointIndex = 0;
this->direction = -1;
}
}
} else {
sp3C = this->unk_15D * (OBJBOAT_GET_4000(thisx) ? 5.0f : 3.0f);
speedTarget = this->direction * (OBJBOAT_GET_4000(thisx) ? 5.0f : 3.0f);
}
}
if (player->csMode != PLAYER_CSMODE_26) {
Math_ScaledStepToS(&this->dyna.actor.shape.rot.y, sp3A, (s16)(s32)(fabsf(this->dyna.actor.speedXZ) * 40.0f));
Math_ScaledStepToS(&this->dyna.actor.shape.rot.y, yawTarget, (s32)(fabsf(this->dyna.actor.speedXZ) * 40.0f));
this->dyna.actor.world.rot.y = this->dyna.actor.shape.rot.y;
Math_StepToF(&this->dyna.actor.speedXZ, sp3C, 0.05f);
Math_StepToF(&this->dyna.actor.speedXZ, speedTarget, 0.05f);
Actor_MoveWithGravity(&this->dyna.actor);
if (this->dyna.actor.speedXZ != 0.0f) {
func_800B9010(&this->dyna.actor, NA_SE_EV_PIRATE_SHIP - SFX_FLAG);
}
}
func_80B9B124(this);
ObjBoat_SetRotations(this);
}
void func_80B9B428(Actor* thisx, PlayState* play2) {
// Update used in cutscenes
void ObjBoat_UpdateCutscene(Actor* thisx, PlayState* play2) {
PlayState* play = play2;
ObjBoat* this = THIS;
if (Cutscene_CheckActorAction(play, 511)) {
CsCmdActorAction* actionIndex = play->csCtx.actorActions[Cutscene_GetActorActionIndex(play, 511)];
if (this->unk_15F != actionIndex->action) {
if (this->csAction != actionIndex->action) {
this->dyna.actor.shape.rot.x = actionIndex->urot.x;
if (actionIndex->action != 1) {
Path* path = &play->setupPathList[OBJBOAT_GET_PATH(&this->dyna.actor)];
if (actionIndex->action == 3) {
path = &play->setupPathList[path->unk1];
}
this->unk_163 = path->count;
this->unk_164 = Lib_SegmentedToVirtual(path->points);
Math_Vec3s_ToVec3f(&this->dyna.actor.world.pos, this->unk_164);
this->maxPointIndex = path->count;
this->points = Lib_SegmentedToVirtual(path->points);
Math_Vec3s_ToVec3f(&this->dyna.actor.world.pos, this->points);
this->dyna.actor.speedXZ = actionIndex->urot.z * (45.0f / 0x2000);
this->unk_164++;
this->unk_15C = 1;
this->points++;
this->curPointIndex = 1;
}
this->unk_15F = actionIndex->action;
this->csAction = actionIndex->action;
} else {
if (actionIndex->action != 1) {
Vec3f vec;
f32 step;
Vec3f posTarget;
f32 distRemaining;
Math_Vec3s_ToVec3f(&vec, this->unk_164);
step = Math_Vec3f_StepTo(&this->dyna.actor.world.pos, &vec, this->dyna.actor.speedXZ);
if ((this->unk_15C < this->unk_163) && (step < this->dyna.actor.speedXZ)) {
this->unk_164++;
this->unk_15C++;
Math_Vec3s_ToVec3f(&posTarget, this->points);
distRemaining = Math_Vec3f_StepTo(&this->dyna.actor.world.pos, &posTarget, this->dyna.actor.speedXZ);
if ((this->curPointIndex < this->maxPointIndex) && (distRemaining < this->dyna.actor.speedXZ)) {
this->points++;
this->curPointIndex++;
}
}
if (actionIndex->action != 3) {
func_80B9B124(this);
ObjBoat_SetRotations(this);
if (actionIndex->action == 2) {
func_800B9010(&this->dyna.actor, NA_SE_EV_PIRATE_SHIP - SFX_FLAG);
}
} else {
// Tumble in the air
this->dyna.actor.shape.rot.y += 0x7D0;
this->dyna.actor.shape.rot.x += 0x3E8;
this->dyna.actor.shape.rot.z += 0x1F4;
+10 -7
View File
@@ -10,14 +10,17 @@ struct ObjBoat;
typedef struct ObjBoat {
/* 0x000 */ DynaPolyActor dyna;
/* 0x15C */ u8 unk_15C;
/* 0x15D */ s8 unk_15D;
/* 0x15E */ u8 unk_15E;
/* 0x15F */ u8 unk_15F;
/* 0x160 */ s16 unk_160;
/* 0x15C */ u8 curPointIndex;
/* 0x15D */ s8 direction; // To follow the path
/* 0x15E */ u8 lastPointIndex; // max point if direction is negative, first point if forwards
/* 0x15F */ union {
u8 timer;
u8 csAction;
};
/* 0x160 */ s16 angle; // Angle used to set rotations
/* 0x162 */ UNK_TYPE1 pad_162;
/* 0x163 */ u8 unk_163;
/* 0x164 */ Vec3s* unk_164;
/* 0x163 */ u8 maxPointIndex; // point at the other end from 0
/* 0x164 */ Vec3s* points;
} ObjBoat; // size = 0x168
#endif // Z_OBJ_BOAT_H
@@ -135,16 +135,16 @@ void func_80AF0514(ObjLupygamelift* this) {
}
void func_80AF0530(ObjLupygamelift* this, PlayState* play) {
f32 step;
f32 distRemaining;
Vec3f target;
target.x = this->points[this->pointIndex].x;
target.y = this->points[this->pointIndex].y;
target.z = this->points[this->pointIndex].z;
step = Math_Vec3f_StepTo(&this->dyna.actor.world.pos, &target, this->dyna.actor.speedXZ);
if (step > 30.0f) {
distRemaining = Math_Vec3f_StepTo(&this->dyna.actor.world.pos, &target, this->dyna.actor.speedXZ);
if (distRemaining > 30.0f) {
Math_SmoothStepToF(&this->dyna.actor.speedXZ, this->targetSpeedXZ, 0.5f, 5.0f, 0.1f);
} else if (step > 0.0f) {
} else if (distRemaining > 0.0f) {
Math_SmoothStepToF(&this->dyna.actor.speedXZ, 5.0f, 0.5f, 5.0f, 1.0f);
} else {
if (this->pointIndex < (this->count - 1)) {