/* * File: z_obj_kibako.c * Overlay: ovl_Obj_Kibako * Description: Small wooden box */ #include "z_obj_kibako.h" #include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h" #include "overlays/effects/ovl_Effect_Ss_Kakera/z_eff_ss_kakera.h" #define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_26) void ObjKibako_Init(Actor* thisx, GlobalContext* globalCtx); void ObjKibako_Destroy(Actor* thisx, GlobalContext* globalCtx); void ObjKibako_Update(Actor* thisx, GlobalContext* globalCtx); void ObjKibako_Draw(Actor* thisx, GlobalContext* globalCtx); void ObjKibako_SetupIdle(ObjKibako* this); void ObjKibako_Idle(ObjKibako* this, GlobalContext* globalCtx); void ObjKibako_SetupHeld(ObjKibako* this); void ObjKibako_Held(ObjKibako* this, GlobalContext* globalCtx); void ObjKibako_SetupThrown(ObjKibako* this); void ObjKibako_Thrown(ObjKibako* this, GlobalContext* globalCtx); const ActorInit Obj_Kibako_InitVars = { ACTOR_OBJ_KIBAKO, ACTORCAT_PROP, FLAGS, OBJECT_GAMEPLAY_DANGEON_KEEP, sizeof(ObjKibako), (ActorFunc)ObjKibako_Init, (ActorFunc)ObjKibako_Destroy, (ActorFunc)ObjKibako_Update, (ActorFunc)ObjKibako_Draw, NULL, }; static ColliderCylinderInit sCylinderInit = { { COLTYPE_NONE, AT_ON | AT_TYPE_PLAYER, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_2, COLSHAPE_CYLINDER, }, { ELEMTYPE_UNK0, { 0x00000002, 0x00, 0x01 }, { 0x4FC00748, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, { 12, 27, 0, { 0, 0, 0 } }, }; static CollisionCheckInfoInit sCCInfoInit = { 0, 12, 60, MASS_HEAVY }; static InitChainEntry sInitChain[] = { ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 60, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP), }; void ObjKibako_SpawnCollectible(ObjKibako* this, GlobalContext* globalCtx) { s16 collectible; collectible = this->actor.params & 0x1F; if ((collectible >= 0) && (collectible <= 0x19)) { Item_DropCollectible(globalCtx, &this->actor.world.pos, collectible | (((this->actor.params >> 8) & 0x3F) << 8)); } } void ObjKibako_ApplyGravity(ObjKibako* this) { this->actor.velocity.y += this->actor.gravity; if (this->actor.velocity.y < this->actor.minVelocityY) { this->actor.velocity.y = this->actor.minVelocityY; } } void ObjKibako_InitCollider(Actor* thisx, GlobalContext* globalCtx) { ObjKibako* this = (ObjKibako*)thisx; Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); Collider_UpdateCylinder(&this->actor, &this->collider); } void ObjKibako_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; ObjKibako* this = (ObjKibako*)thisx; Actor_ProcessInitChain(&this->actor, sInitChain); this->actor.gravity = -1.2f; this->actor.minVelocityY = -13.0f; ObjKibako_InitCollider(&this->actor, globalCtx); CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sCCInfoInit); ObjKibako_SetupIdle(this); // "wooden box" osSyncPrintf("(dungeon keep 木箱)(arg_data 0x%04x)\n", this->actor.params); } void ObjKibako_Destroy(Actor* thisx, GlobalContext* globalCtx2) { GlobalContext* globalCtx = globalCtx2; ObjKibako* this = (ObjKibako*)thisx; Collider_DestroyCylinder(globalCtx, &this->collider); } void ObjKibako_AirBreak(ObjKibako* this, GlobalContext* globalCtx) { s16 angle; s32 i; Vec3f* breakPos = &this->actor.world.pos; Vec3f pos; Vec3f velocity; for (i = 0, angle = 0; i < 12; i++, angle += 0x4E20) { f32 sn = Math_SinS(angle); f32 cs = Math_CosS(angle); f32 temp_rand; s16 phi_s0; pos.x = sn * 16.0f; pos.y = (Rand_ZeroOne() * 5.0f) + 2.0f; pos.z = cs * 16.0f; velocity.x = pos.x * 0.2f; velocity.y = (Rand_ZeroOne() * 6.0f) + 2.0f; velocity.z = pos.z * 0.2f; pos.x += breakPos->x; pos.y += breakPos->y; pos.z += breakPos->z; temp_rand = Rand_ZeroOne(); if (temp_rand < 0.1f) { phi_s0 = 0x60; } else if (temp_rand < 0.7f) { phi_s0 = 0x40; } else { phi_s0 = 0x20; } EffectSsKakera_Spawn(globalCtx, &pos, &velocity, breakPos, -200, phi_s0, 10, 10, 0, (Rand_ZeroOne() * 30.0f) + 10.0f, 0, 32, 60, KAKERA_COLOR_NONE, OBJECT_GAMEPLAY_DANGEON_KEEP, gSmallWoodenBoxFragmentDL); } func_80033480(globalCtx, &this->actor.world.pos, 40.0f, 3, 50, 140, 1); } void ObjKibako_WaterBreak(ObjKibako* this, GlobalContext* globalCtx) { s16 angle; s32 i; Vec3f* breakPos = &this->actor.world.pos; Vec3f pos; Vec3f velocity; pos = *breakPos; pos.y += this->actor.yDistToWater; EffectSsGSplash_Spawn(globalCtx, &pos, NULL, NULL, 0, 500); for (i = 0, angle = 0; i < 12; i++, angle += 0x4E20) { f32 sn = Math_SinS(angle); f32 cs = Math_CosS(angle); f32 temp_rand; s16 phi_s0; pos.x = sn * 16.0f; pos.y = (Rand_ZeroOne() * 5.0f) + 2.0f; pos.z = cs * 16.0f; velocity.x = pos.x * 0.18f; velocity.y = (Rand_ZeroOne() * 4.0f) + 2.0f; velocity.z = pos.z * 0.18f; pos.x += breakPos->x; pos.y += breakPos->y; pos.z += breakPos->z; temp_rand = Rand_ZeroOne(); phi_s0 = (temp_rand < 0.2f) ? 0x40 : 0x20; EffectSsKakera_Spawn(globalCtx, &pos, &velocity, breakPos, -180, phi_s0, 30, 30, 0, (Rand_ZeroOne() * 30.0f) + 10.0f, 0, 32, 70, KAKERA_COLOR_NONE, OBJECT_GAMEPLAY_DANGEON_KEEP, gSmallWoodenBoxFragmentDL); } } void ObjKibako_SetupIdle(ObjKibako* this) { this->actionFunc = ObjKibako_Idle; this->actor.colChkInfo.mass = MASS_HEAVY; } void ObjKibako_Idle(ObjKibako* this, GlobalContext* globalCtx) { s32 pad; if (Actor_HasParent(&this->actor, globalCtx)) { ObjKibako_SetupHeld(this); } else if ((this->actor.bgCheckFlags & 0x20) && (this->actor.yDistToWater > 19.0f)) { ObjKibako_WaterBreak(this, globalCtx); SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 20, NA_SE_EV_WOODBOX_BREAK); ObjKibako_SpawnCollectible(this, globalCtx); Actor_Kill(&this->actor); } else if (this->collider.base.acFlags & AC_HIT) { ObjKibako_AirBreak(this, globalCtx); SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 20, NA_SE_EV_WOODBOX_BREAK); ObjKibako_SpawnCollectible(this, globalCtx); Actor_Kill(&this->actor); } else { Actor_MoveForward(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 19.0f, 20.0f, 0.0f, 5); if (!(this->collider.base.ocFlags1 & OC1_TYPE_PLAYER) && (this->actor.xzDistToPlayer > 28.0f)) { this->collider.base.ocFlags1 |= OC1_TYPE_PLAYER; } if (this->actor.xzDistToPlayer < 600.0f) { Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); if (this->actor.xzDistToPlayer < 180.0f) { CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } } if (this->actor.xzDistToPlayer < 100.0f) { func_8002F580(&this->actor, globalCtx); } } } void ObjKibako_SetupHeld(ObjKibako* this) { this->actionFunc = ObjKibako_Held; this->actor.room = -1; func_8002F7DC(&this->actor, NA_SE_PL_PULL_UP_WOODBOX); } void ObjKibako_Held(ObjKibako* this, GlobalContext* globalCtx) { if (Actor_HasNoParent(&this->actor, globalCtx)) { this->actor.room = globalCtx->roomCtx.curRoom.num; if (fabsf(this->actor.speedXZ) < 0.1f) { Audio_PlayActorSound2(&this->actor, NA_SE_EV_PUT_DOWN_WOODBOX); ObjKibako_SetupIdle(this); this->collider.base.ocFlags1 &= ~OC1_TYPE_PLAYER; } else { ObjKibako_SetupThrown(this); ObjKibako_ApplyGravity(this); func_8002D7EC(&this->actor); } Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 19.0f, 20.0f, 0.0f, 5); } } void ObjKibako_SetupThrown(ObjKibako* this) { this->actor.velocity.x = Math_SinS(this->actor.world.rot.y) * this->actor.speedXZ; this->actor.velocity.z = Math_CosS(this->actor.world.rot.y) * this->actor.speedXZ; this->actor.colChkInfo.mass = 240; this->actionFunc = ObjKibako_Thrown; } void ObjKibako_Thrown(ObjKibako* this, GlobalContext* globalCtx) { s32 pad; s32 pad2; if ((this->actor.bgCheckFlags & 0xB) || (this->collider.base.atFlags & AT_HIT)) { ObjKibako_AirBreak(this, globalCtx); SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 20, NA_SE_EV_WOODBOX_BREAK); ObjKibako_SpawnCollectible(this, globalCtx); Actor_Kill(&this->actor); } else if (this->actor.bgCheckFlags & 0x40) { ObjKibako_WaterBreak(this, globalCtx); SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 20, NA_SE_EV_WOODBOX_BREAK); ObjKibako_SpawnCollectible(this, globalCtx); Actor_Kill(&this->actor); } else { ObjKibako_ApplyGravity(this); func_8002D7EC(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 19.0f, 20.0f, 0.0f, 5); Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } } void ObjKibako_Update(Actor* thisx, GlobalContext* globalCtx) { s32 pad; ObjKibako* this = (ObjKibako*)thisx; this->actionFunc(this, globalCtx); } void ObjKibako_Draw(Actor* thisx, GlobalContext* globalCtx) { s32 pad; ObjKibako* this = (ObjKibako*)thisx; Gfx_DrawDListOpa(globalCtx, gSmallWoodenBoxDL); }