Shipwright/soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c

1676 lines
58 KiB
C

#include "z_en_skj.h"
#include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h"
#include "objects/object_skj/object_skj.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_25)
void EnSkj_Init(Actor* thisx, GlobalContext* globalCtx);
void EnSkj_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnSkj_Update(Actor* thisx, GlobalContext* globalCtx);
void EnSkj_Draw(Actor* thisx, GlobalContext* globalCtx);
void EnSkj_SariasSongShortStumpUpdate(Actor* thisx, GlobalContext* globalCtx);
void EnSkj_OcarinaMinigameShortStumpUpdate(Actor* thisx, GlobalContext* globalCtx);
void func_80AFF2A0(EnSkj* this);
void func_80AFF334(EnSkj* this);
void EnSkj_CalculateCenter(EnSkj* this);
void EnSkj_OcarinaGameSetupWaitForPlayer(EnSkj* this);
void EnSkj_SetupResetFight(EnSkj* this);
void EnSkj_SetupLeaveOcarinaGame(EnSkj* this);
void EnSkj_SetupPlayOcarinaGame(EnSkj* this);
void EnSkj_Backflip(EnSkj* this);
void EnSkj_SetupNeedleRecover(EnSkj* this);
void EnSkj_SetupSpawnDeathEffect(EnSkj* this);
void EnSkj_SetupStand(EnSkj* this);
void EnSkj_SetupWaitForSong(EnSkj* this);
void EnSkj_SetupTalk(EnSkj* this);
void EnSkj_SetupMaskTrade(EnSkj* this);
void EnSkj_SetupWrongSong(EnSkj* this);
void EnSkj_SetupAfterSong(EnSkj* this);
void func_80AFFE24(EnSkj* this);
void EnSkj_SetupPostSariasSong(EnSkj* this);
void EnSkj_JumpFromStump(EnSkj* this);
void EnSkj_SetupWaitForLandAnimFinish(EnSkj* this);
void EnSkj_SetupWalkToPlayer(EnSkj* this);
void EnSkj_SetupWaitForMaskTextClear(EnSkj* this);
void EnSkj_SetupWaitForTextClear(EnSkj* this);
void EnSkj_SetupDie(EnSkj* this);
void func_80AFF1F0(EnSkj* this);
void EnSkj_OfferNextRound(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SetupAskForMask(EnSkj* this, GlobalContext* globalCtx);
f32 EnSkj_GetItemXzRange(EnSkj* this);
s32 EnSkj_CollisionCheck(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SetupTakeMask(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_TurnPlayer(EnSkj* this, Player* player);
void EnSkj_SetupWaitForOcarina(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_StartOcarinaMinigame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForOcarina(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForPlayback(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_FailedMiniGame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WonOcarinaMiniGame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitToGiveReward(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_GiveOcarinaGameReward(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_FinishOcarinaGameRound(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForNextRound(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForOfferResponse(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SetupWaitForOcarina(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_CleanupOcarinaGame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_Fade(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitToShootNeedle(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SariasSongKidIdle(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForDeathAnim(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_PickNextFightAction(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForLandAnim(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_ResetFight(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_Fight(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_NeedleRecover(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SpawnDeathEffect(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitInRange(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForSong(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_AfterSong(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SariaSongTalk(EnSkj* this, GlobalContext* globalCtx);
void func_80AFFE44(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_ChangeModeAfterSong(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_StartMaskTrade(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForLanding(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForLandAnimFinish(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WalkToPlayer(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_AskForMask(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_TakeMask(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WaitForMaskTextClear(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_WrongSong(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SariasSongWaitForTextClear(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_OcarinaGameWaitForPlayer(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_OcarinaGameIdle(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_PlayOcarinaGame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_LeaveOcarinaGame(EnSkj* this, GlobalContext* globalCtx);
void EnSkj_SpawnBlood(GlobalContext* globalCtx, Vec3f* pos);
void EnSkj_SetupWaitInRange(EnSkj* this);
#define songFailTimer multiuseTimer
#define battleExitTimer multiuseTimer
typedef enum {
/* 0 */ SKJ_ANIM_BACKFLIP,
/* 1 */ SKJ_ANIM_SHOOT_NEEDLE,
/* 2 */ SKJ_ANIM_PLAY_FLUTE,
/* 3 */ SKJ_ANIM_DIE,
/* 4 */ SKJ_ANIM_HIT,
/* 5 */ SKJ_ANIM_LAND,
/* 6 */ SKJ_ANIM_LOOK_LEFT_RIGHT,
/* 7 */ SKJ_ANIM_FIGHTING_STANCE,
/* 8 */ SKJ_ANIM_WALK_TO_PLAYER,
/* 9 */ SKJ_ANIM_WAIT
} SkullKidAnim;
typedef enum {
/* 0 */ SKULL_KID_LEFT,
/* 1 */ SKULL_KID_RIGHT
} SkullKidStumpSide;
typedef enum {
/* 0 */ SKULL_KID_OCARINA_WAIT,
/* 1 */ SKULL_KID_OCARINA_PLAY_NOTES,
/* 2 */ SKULL_KID_OCARINA_LEAVE_GAME
} SkullKidOcarinaGameState;
typedef enum {
/* 00 */ SKJ_ACTION_FADE,
/* 01 */ SKJ_ACTION_WAIT_TO_SHOOT_NEEDLE,
/* 02 */ SKJ_ACTION_SARIA_SONG_IDLE,
/* 03 */ SKJ_ACTION_WAIT_FOR_DEATH_ANIM,
/* 04 */ SKJ_ACTION_PICK_NEXT_FIHGT_ACTION,
/* 05 */ SKJ_ACTION_WAIT_FOR_LAND_ANIM,
/* 06 */ SKJ_ACTION_RESET_FIGHT,
/* 07 */ SKJ_ACTION_FIGHT,
/* 08 */ SKJ_ACTION_NEEDLE_RECOVER,
/* 09 */ SKJ_ACTION_SPAWN_DEATH_EFFECT,
/* 10 */ SKJ_ACTION_SARIA_SONG_WAIT_IN_RANGE,
/* 11 */ SKJ_ACTION_SARIA_SONG_WAIT_FOR_SONG,
/* 12 */ SKJ_ACTION_SARIA_SONG_AFTER_SONG,
/* 13 */ SKJ_ACTION_SARIA_TALK,
/* 14 */ SKJ_ACTION_UNK14,
/* 15 */ SKJ_ACTION_SARIA_SONG_CHANGE_MODE,
/* 16 */ SKJ_ACTION_SARIA_SONG_START_TRADE,
/* 17 */ SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING,
/* 18 */ SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING_ANIM,
/* 19 */ SKJ_ACTION_SARIA_SONG_WALK_TO_PLAYER,
/* 20 */ SKJ_ACTION_SARIA_SONG_ASK_FOR_MASK,
/* 21 */ SKJ_ACTION_SARIA_SONG_TAKE_MASK,
/* 22 */ SKJ_ACTION_SARIA_SONG_WAIT_MASK_TEXT,
/* 23 */ SKJ_ACTION_SARIA_SONG_WRONG_SONG,
/* 24 */ SKJ_ACTION_SARIA_SONG_WAIT_FOR_TEXT,
/* 25 */ SKJ_ACTION_OCARINA_GAME_WAIT_FOR_PLAYER,
/* 26 */ SKJ_ACTION_OCARINA_GAME_IDLE,
/* 27 */ SKJ_ACTION_OCARINA_GAME_PLAY,
/* 28 */ SKJ_ACTION_OCARINA_GAME_LEAVE
} SkullKidAction;
typedef struct {
u8 unk0;
EnSkj* skullkid;
} EnSkjUnkStruct;
static EnSkjUnkStruct sSmallStumpSkullKid = { 0, NULL };
static EnSkjUnkStruct sOcarinaMinigameSkullKids[] = { { 0, NULL }, { 0, NULL } };
const ActorInit En_Skj_InitVars = {
ACTOR_EN_SKJ,
ACTORCAT_ENEMY,
FLAGS,
OBJECT_SKJ,
sizeof(EnSkj),
(ActorFunc)EnSkj_Init,
(ActorFunc)EnSkj_Destroy,
(ActorFunc)EnSkj_Update,
(ActorFunc)EnSkj_Draw,
NULL,
};
static ColliderCylinderInitType1 D_80B01678 = {
{
COLTYPE_NONE,
AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0xFFCFFFFF, 0x0, 0x08 },
{ 0xFFCFFFFF, 0x0, 0x0 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_ON,
},
{ 8, 48, 0, { 0, 0, 0 } },
};
static DamageTable sDamageTable = {
/* Deku nut */ DMG_ENTRY(0, 0x0),
/* Deku stick */ DMG_ENTRY(0, 0x0),
/* Slingshot */ DMG_ENTRY(0, 0x0),
/* Explosive */ DMG_ENTRY(0, 0x0),
/* Boomerang */ DMG_ENTRY(0, 0x0),
/* Normal arrow */ DMG_ENTRY(0, 0x0),
/* Hammer swing */ DMG_ENTRY(2, 0x0),
/* Hookshot */ DMG_ENTRY(0, 0x0),
/* Kokiri sword */ DMG_ENTRY(1, 0xF),
/* Master sword */ DMG_ENTRY(2, 0xF),
/* Giant's Knife */ DMG_ENTRY(4, 0xF),
/* Fire arrow */ DMG_ENTRY(0, 0x0),
/* Ice arrow */ DMG_ENTRY(0, 0x0),
/* Light arrow */ DMG_ENTRY(0, 0x0),
/* Unk arrow 1 */ DMG_ENTRY(0, 0x0),
/* Unk arrow 2 */ DMG_ENTRY(0, 0x0),
/* Unk arrow 3 */ DMG_ENTRY(0, 0x0),
/* Fire magic */ DMG_ENTRY(0, 0x0),
/* Ice magic */ DMG_ENTRY(0, 0x0),
/* Light magic */ DMG_ENTRY(0, 0x0),
/* Shield */ DMG_ENTRY(0, 0x0),
/* Mirror Ray */ DMG_ENTRY(0, 0x0),
/* Kokiri spin */ DMG_ENTRY(1, 0x0),
/* Giant spin */ DMG_ENTRY(4, 0x0),
/* Master spin */ DMG_ENTRY(2, 0x0),
/* Kokiri jump */ DMG_ENTRY(2, 0x0),
/* Giant jump */ DMG_ENTRY(8, 0x0),
/* Master jump */ DMG_ENTRY(4, 0x0),
/* Unknown 1 */ DMG_ENTRY(0, 0x0),
/* Unblockable */ DMG_ENTRY(0, 0x0),
/* Hammer jump */ DMG_ENTRY(0, 0x0),
/* Unknown 2 */ DMG_ENTRY(0, 0x0),
};
static s32 sOcarinaGameRewards[] = {
GI_RUPEE_GREEN,
GI_RUPEE_BLUE,
GI_HEART_PIECE,
GI_RUPEE_RED,
};
static AnimationMinimalInfo sAnimationInfo[] = {
{ &gSkullKidBackflipAnim, ANIMMODE_ONCE, 0.0f },
{ &gSkullKidShootNeedleAnim, ANIMMODE_ONCE, 0.0f },
{ &gSkullKidPlayFluteAnim, ANIMMODE_LOOP, 0.0f },
{ &gSkullKidDieAnim, ANIMMODE_ONCE, 0.0f },
{ &gSkullKidHitAnim, ANIMMODE_ONCE, 0.0f },
{ &gSkullKidLandAnim, ANIMMODE_ONCE, 0.0f },
{ &gSkullKidLookLeftAndRightAnim, ANIMMODE_LOOP, 0.0f },
{ &gSkullKidFightingStanceAnim, ANIMMODE_LOOP, 0.0f },
{ &gSkullKidWalkToPlayerAnim, ANIMMODE_LOOP, 0.0f },
{ &gSkullKidWaitAnim, ANIMMODE_LOOP, 0.0f },
};
static EnSkjActionFunc sActionFuncs[] = {
EnSkj_Fade,
EnSkj_WaitToShootNeedle,
EnSkj_SariasSongKidIdle,
EnSkj_WaitForDeathAnim,
EnSkj_PickNextFightAction,
EnSkj_WaitForLandAnim,
EnSkj_ResetFight,
EnSkj_Fight,
EnSkj_NeedleRecover,
EnSkj_SpawnDeathEffect,
EnSkj_WaitInRange,
EnSkj_WaitForSong,
EnSkj_AfterSong,
EnSkj_SariaSongTalk,
func_80AFFE44,
EnSkj_ChangeModeAfterSong,
EnSkj_StartMaskTrade,
EnSkj_WaitForLanding,
EnSkj_WaitForLandAnimFinish,
EnSkj_WalkToPlayer,
EnSkj_AskForMask,
EnSkj_TakeMask,
EnSkj_WaitForMaskTextClear,
EnSkj_WrongSong,
EnSkj_SariasSongWaitForTextClear,
EnSkj_OcarinaGameWaitForPlayer,
EnSkj_OcarinaGameIdle,
EnSkj_PlayOcarinaGame,
EnSkj_LeaveOcarinaGame,
};
static InitChainEntry sInitChain[] = {
ICHAIN_U8(targetMode, 2, ICHAIN_CONTINUE),
ICHAIN_F32(targetArrowOffset, 30, ICHAIN_STOP),
};
static s32 D_80B01EA0; // gets set if ACTOR_FLAG_8 is set
void EnSkj_ChangeAnim(EnSkj* this, u8 index) {
f32 endFrame = Animation_GetLastFrame(sAnimationInfo[index].animation);
this->animIndex = index;
Animation_Change(&this->skelAnime, sAnimationInfo[index].animation, 1.0f, 0.0f, endFrame,
sAnimationInfo[index].mode, sAnimationInfo[index].morphFrames);
}
void EnSkj_SetupAction(EnSkj* this, u8 action) {
this->action = action;
this->actionFunc = sActionFuncs[action];
switch (action) {
case SKJ_ACTION_FADE:
case SKJ_ACTION_WAIT_FOR_DEATH_ANIM:
case SKJ_ACTION_PICK_NEXT_FIHGT_ACTION:
case SKJ_ACTION_SPAWN_DEATH_EFFECT:
case SKJ_ACTION_SARIA_SONG_START_TRADE:
case SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING:
case SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING_ANIM:
case SKJ_ACTION_SARIA_SONG_WALK_TO_PLAYER:
case SKJ_ACTION_SARIA_SONG_ASK_FOR_MASK:
case SKJ_ACTION_SARIA_SONG_TAKE_MASK:
case SKJ_ACTION_SARIA_SONG_WAIT_MASK_TEXT:
case SKJ_ACTION_SARIA_SONG_WRONG_SONG:
case SKJ_ACTION_SARIA_SONG_WAIT_FOR_TEXT:
case SKJ_ACTION_OCARINA_GAME_WAIT_FOR_PLAYER:
case SKJ_ACTION_OCARINA_GAME_IDLE:
case SKJ_ACTION_OCARINA_GAME_PLAY:
case SKJ_ACTION_OCARINA_GAME_LEAVE:
this->unk_2D3 = 0;
break;
default:
this->unk_2D3 = 1;
break;
}
}
void EnSkj_CalculateCenter(EnSkj* this) {
Vec3f mult;
mult.x = 0.0f;
mult.y = 0.0f;
mult.z = 120.0f;
Matrix_RotateY((this->actor.shape.rot.y / 32768.0f) * M_PI, MTXMODE_NEW);
Matrix_MultVec3f(&mult, &this->center);
this->center.x += this->actor.world.pos.x;
this->center.z += this->actor.world.pos.z;
}
void EnSkj_SetNaviId(EnSkj* this) {
switch (this->actor.params) {
case 0:
if (gSaveContext.itemGetInf[3] & 0x200) {
this->actor.naviEnemyId = 0x41; // Skull kid with skull mask
} else if (gSaveContext.itemGetInf[1] & 0x40) {
this->actor.naviEnemyId = 0x40; // Skull kid after Saria's song but no mask
} else {
this->actor.naviEnemyId = 0x3F; // No Sarias song no skull mask
}
break;
case 1:
case 2:
this->actor.naviEnemyId = 0x3F;
break;
default:
this->actor.naviEnemyId = 0x36; // Skull kid as adult
break;
}
}
void EnSkj_Init(Actor* thisx, GlobalContext* globalCtx2) {
s16 type = (thisx->params >> 0xA) & 0x3F;
EnSkj* this = (EnSkj*)thisx;
GlobalContext* globalCtx = globalCtx2;
s32 pad;
Player* player;
Actor_ProcessInitChain(thisx, sInitChain);
switch (type) {
case 5: // Invisible on the small stump (sarias song))
sSmallStumpSkullKid.unk0 = 1;
sSmallStumpSkullKid.skullkid = (EnSkj*)thisx;
this->actor.destroy = NULL;
this->actor.draw = NULL;
this->actor.update = EnSkj_SariasSongShortStumpUpdate;
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_2);
this->actor.flags |= 0;
Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, thisx, ACTORCAT_PROP);
break;
case 6: // Invisible on the short stump (ocarina game)
sSmallStumpSkullKid.unk0 = 1;
sSmallStumpSkullKid.skullkid = (EnSkj*)thisx;
this->actor.destroy = NULL;
this->actor.draw = NULL;
this->actor.update = EnSkj_OcarinaMinigameShortStumpUpdate;
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_2);
this->actor.flags |= 0;
Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, thisx, ACTORCAT_PROP);
this->actor.focus.pos.x = 1230.0f;
this->actor.focus.pos.y = -90.0f;
this->actor.focus.pos.z = 450.0f;
this->actionFunc = EnSkj_SetupWaitForOcarina;
break;
default:
this->actor.params = type;
if (((this->actor.params != 0) && (this->actor.params != 1)) && (this->actor.params != 2)) {
if (INV_CONTENT(ITEM_TRADE_ADULT) < ITEM_SAW) {
Actor_Kill(&this->actor);
return;
}
}
EnSkj_SetNaviId(this);
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gSkullKidSkel, &gSkullKidPlayFluteAnim, this->jointTable,
this->morphTable, 19);
if ((type >= 0) && (type < 3)) {
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_2);
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_3;
Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, &this->actor, ACTORCAT_NPC);
}
if ((type < 0) || (type >= 7)) {
this->actor.flags &= ~ACTOR_FLAG_25;
}
if ((type > 0) && (type < 3)) {
this->actor.targetMode = 7;
this->posCopy = this->actor.world.pos;
sOcarinaMinigameSkullKids[type - 1].unk0 = 1;
sOcarinaMinigameSkullKids[type - 1].skullkid = this;
this->minigameState = 0;
this->alpha = 0;
EnSkj_OcarinaGameSetupWaitForPlayer(this);
} else {
this->alpha = 255;
EnSkj_SetupResetFight(this);
}
this->actor.colChkInfo.damageTable = &sDamageTable;
this->actor.colChkInfo.health = 10;
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinderType1(globalCtx, &this->collider, &this->actor, &D_80B01678);
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 40.0f);
Actor_SetScale(thisx, 0.01f);
this->actor.textId = this->textId = 0;
this->multiuseTimer = 0;
this->backflipFlag = 0;
this->needlesToShoot = 3;
this->hitsUntilDodge = 3;
this->actor.speedXZ = 0.0f;
this->actor.velocity.y = 0.0f;
this->actor.gravity = -1.0f;
EnSkj_CalculateCenter(this);
player = GET_PLAYER(globalCtx);
osSyncPrintf("Player_X : %f\n", player->actor.world.pos.x);
osSyncPrintf("Player_Z : %f\n", player->actor.world.pos.z);
osSyncPrintf("World_X : %f\n", this->actor.world.pos.x);
osSyncPrintf("World_Z : %f\n", this->actor.world.pos.z);
osSyncPrintf("Center_X : %f\n", this->center.x);
osSyncPrintf("Center_Z : %f\n\n", this->center.z);
break;
}
}
void EnSkj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnSkj* this = (EnSkj*)thisx;
Collider_DestroyCylinder(globalCtx, &this->collider);
}
s32 EnSkj_RangeCheck(Player* player, EnSkj* this) {
f32 xDiff = player->actor.world.pos.x - this->actor.world.pos.x;
f32 zDiff = player->actor.world.pos.z - this->actor.world.pos.z;
f32 yDiff = player->actor.world.pos.y - this->actor.world.pos.y;
return (SQ(xDiff) + SQ(zDiff) <= 676.0f) && (yDiff >= 0.0f);
}
f32 EnSkj_GetItemXzRange(EnSkj* this) {
EnSkj* temp_v0;
f32 zDiff;
f32 xDiff;
temp_v0 = sSmallStumpSkullKid.skullkid;
xDiff = temp_v0->actor.world.pos.x - this->actor.world.pos.x;
zDiff = temp_v0->actor.world.pos.z - this->actor.world.pos.z;
return sqrtf(SQ(xDiff) + SQ(zDiff)) + 26.0f;
}
f32 EnSkj_GetItemYRange(EnSkj* this) {
return fabsf(sSmallStumpSkullKid.skullkid->actor.world.pos.y - this->actor.world.pos.y) + 10.0f;
}
s32 EnSkj_ShootNeedle(EnSkj* this, GlobalContext* globalCtx) {
s32 pad;
Vec3f pos;
Vec3f pos2;
EnSkjneedle* needle;
pos.x = 1.5f;
pos.y = 0.0f;
pos.z = 40.0f;
Matrix_RotateY((this->actor.shape.rot.y / 32768.0f) * M_PI, MTXMODE_NEW);
Matrix_MultVec3f(&pos, &pos2);
pos2.x += this->actor.world.pos.x;
pos2.z += this->actor.world.pos.z;
pos2.y = this->actor.world.pos.y + 27.0f;
needle = (EnSkjneedle*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_SKJNEEDLE, pos2.x, pos2.y, pos2.z,
this->actor.shape.rot.x, this->actor.shape.rot.y, this->actor.shape.rot.z, 0);
if (needle != NULL) {
needle->killTimer = 100;
needle->actor.speedXZ = 24.0f;
return 1;
}
return 0;
}
void EnSkj_SpawnBlood(GlobalContext* globalCtx, Vec3f* pos) {
EffectSparkInit effect;
s32 sp20;
effect.position.x = pos->x;
effect.position.y = pos->y;
effect.position.z = pos->z;
effect.uDiv = 5;
effect.vDiv = 5;
effect.colorStart[0].r = 0;
effect.colorStart[0].g = 0;
effect.colorStart[0].b = 128;
effect.colorStart[0].a = 255;
effect.colorStart[1].r = 0;
effect.colorStart[1].g = 0;
effect.colorStart[1].b = 128;
effect.colorStart[1].a = 255;
effect.colorStart[2].r = 0;
effect.colorStart[2].g = 0;
effect.colorStart[2].b = 128;
effect.colorStart[2].a = 255;
effect.colorStart[3].r = 0;
effect.colorStart[3].g = 0;
effect.colorStart[3].b = 128;
effect.colorStart[3].a = 255;
effect.colorEnd[0].r = 0;
effect.colorEnd[0].g = 0;
effect.colorEnd[0].b = 32;
effect.colorEnd[0].a = 0;
effect.colorEnd[1].r = 0;
effect.colorEnd[1].g = 0;
effect.colorEnd[1].b = 32;
effect.colorEnd[1].a = 0;
effect.colorEnd[2].r = 0;
effect.colorEnd[2].g = 0;
effect.colorEnd[2].b = 64;
effect.colorEnd[2].a = 0;
effect.colorEnd[3].r = 0;
effect.colorEnd[3].g = 0;
effect.colorEnd[3].b = 64;
effect.colorEnd[3].a = 0;
effect.speed = 8.0f;
effect.gravity = -1.0f;
effect.timer = 0;
effect.duration = 8;
Effect_Add(globalCtx, &sp20, EFFECT_SPARK, 0, 1, &effect);
}
s32 EnSkj_CollisionCheck(EnSkj* this, GlobalContext* globalCtx) {
s16 yawDiff;
Vec3f effectPos;
if (!((this->unk_2D3 == 0) || (D_80B01EA0 != 0) || !(this->collider.base.acFlags & AC_HIT))) {
this->collider.base.acFlags &= ~AC_HIT;
if (this->actor.colChkInfo.damageEffect != 0) {
if (this->actor.colChkInfo.damageEffect == 0xF) {
effectPos.x = this->collider.info.bumper.hitPos.x;
effectPos.y = this->collider.info.bumper.hitPos.y;
effectPos.z = this->collider.info.bumper.hitPos.z;
EnSkj_SpawnBlood(globalCtx, &effectPos);
EffectSsHitMark_SpawnFixedScale(globalCtx, 1, &effectPos);
yawDiff = this->actor.yawTowardsPlayer - this->actor.world.rot.y;
if ((this->action == 2) || (this->action == 6)) {
if ((yawDiff > 0x6000) || (yawDiff < -0x6000)) {
Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, 0, 8);
EnSkj_SetupDie(this);
return 1;
}
}
Actor_ApplyDamage(&this->actor);
Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, 0, 8);
if (this->actor.colChkInfo.health != 0) {
if (this->hitsUntilDodge != 0) {
this->hitsUntilDodge--;
}
if (this->dodgeResetTimer == 0) {
this->dodgeResetTimer = 60;
}
func_80AFF1F0(this);
return 1;
}
EnSkj_SetupDie(this);
return 1;
}
} else {
this->backflipFlag = 1;
EnSkj_Backflip(this);
return 1;
}
}
return 0;
}
s32 func_80AFEDF8(EnSkj* this, GlobalContext* globalCtx) {
s16 yawDiff;
if (this->actor.xzDistToPlayer < this->unk_2EC) {
this = this;
if (func_8002DDE4(globalCtx) != 0) {
return 1;
}
}
yawDiff = this->actor.yawTowardsPlayer - this->actor.world.rot.y;
if ((yawDiff < this->unk_2C8) && (-this->unk_2C8 < yawDiff)) {
return 1;
}
return 0;
}
void EnSkj_Backflip(EnSkj* this) {
this->actor.velocity.y = 8.0f;
this->actor.speedXZ = -8.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_BACKFLIP);
EnSkj_SetupAction(this, SKJ_ACTION_FADE);
}
void EnSkj_Fade(EnSkj* this, GlobalContext* globalCtx) {
u32 alpha = this->alpha;
if (this->unk_2D6 == 2) {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_00;
this->unk_2D6 = 0;
}
alpha -= 20;
if (this->backflipFlag != 0) {
if (alpha > 255) {
alpha = 0;
}
this->alpha = alpha;
this->actor.shape.shadowAlpha = alpha;
}
if (this->actor.velocity.y <= 0.0f) {
if (this->actor.bgCheckFlags & 2) {
this->actor.bgCheckFlags &= ~2;
func_80AFF2A0(this);
}
}
}
void EnSkj_SetupWaitToShootNeedle(EnSkj* this) {
this->needlesToShoot = 3;
this->needleShootTimer = 0;
EnSkj_ChangeAnim(this, SKJ_ANIM_SHOOT_NEEDLE);
EnSkj_SetupAction(this, SKJ_ACTION_WAIT_TO_SHOOT_NEEDLE);
}
void EnSkj_WaitToShootNeedle(EnSkj* this, GlobalContext* globalCtx) {
u8 val;
s16 lastFrame = Animation_GetLastFrame(&gSkullKidShootNeedleAnim);
if ((this->skelAnime.curFrame == lastFrame) && (this->needleShootTimer == 0)) {
val = this->needlesToShoot;
if (this->needlesToShoot != 0) {
EnSkj_ShootNeedle(this, globalCtx);
this->needleShootTimer = 4;
val--;
this->needlesToShoot = val;
} else {
EnSkj_SetupNeedleRecover(this);
}
}
}
void EnSkj_SetupResetFight(EnSkj* this) {
this->unk_2C8 = 0xAAA;
this->unk_2EC = 200.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_PLAY_FLUTE);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_IDLE);
}
void EnSkj_SariasSongKidIdle(EnSkj* this, GlobalContext* globalCtx) {
if (this->actor.params == 0) {
if (!(gSaveContext.itemGetInf[1] & 0x40) && (this->actor.xzDistToPlayer < 200.0f)) {
this->backflipFlag = 1;
EnSkj_Backflip(this);
} else if (sSmallStumpSkullKid.unk0 != 0) {
Player* player = GET_PLAYER(globalCtx);
if (EnSkj_RangeCheck(player, sSmallStumpSkullKid.skullkid)) {
EnSkj_SetupWaitInRange(this);
player->stateFlags2 |= 0x800000;
player->unk_6A8 = &sSmallStumpSkullKid.skullkid->actor;
}
}
} else {
if (func_80AFEDF8(this, globalCtx) != 0) {
func_80AFF334(this);
}
}
}
void EnSkj_SetupDie(EnSkj* this) {
EnSkj_ChangeAnim(this, SKJ_ANIM_DIE);
EnSkj_SetupAction(this, SKJ_ACTION_WAIT_FOR_DEATH_ANIM);
}
void EnSkj_WaitForDeathAnim(EnSkj* this, GlobalContext* globalCtx) {
s16 lastFrame = Animation_GetLastFrame(&gSkullKidDieAnim);
if (this->skelAnime.curFrame == lastFrame) {
EnSkj_SetupSpawnDeathEffect(this);
}
}
void func_80AFF1F0(EnSkj* this) {
EnSkj_ChangeAnim(this, SKJ_ANIM_HIT);
EnSkj_SetupAction(this, SKJ_ACTION_PICK_NEXT_FIHGT_ACTION);
}
void EnSkj_PickNextFightAction(EnSkj* this, GlobalContext* globalCtx) {
s16 lastFrame = Animation_GetLastFrame(&gSkullKidHitAnim);
if (this->skelAnime.curFrame == lastFrame) {
if (this->hitsUntilDodge == 0) {
this->hitsUntilDodge = 3;
EnSkj_Backflip(this);
} else {
EnSkj_SetupStand(this);
}
}
}
void func_80AFF2A0(EnSkj* this) {
EnSkj_CalculateCenter(this);
this->actor.speedXZ = 0.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_LAND);
EnSkj_SetupAction(this, SKJ_ACTION_WAIT_FOR_LAND_ANIM);
}
void EnSkj_WaitForLandAnim(EnSkj* this, GlobalContext* globalCtx) {
s16 lastFrame = Animation_GetLastFrame(&gSkullKidLandAnim);
if (this->skelAnime.curFrame == lastFrame) {
EnSkj_SetupStand(this);
}
}
void func_80AFF334(EnSkj* this) {
this->unk_2C8 = 0x2000;
this->battleExitTimer = 400;
this->unk_2EC = 600.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_LOOK_LEFT_RIGHT);
EnSkj_SetupAction(this, SKJ_ACTION_RESET_FIGHT);
}
void EnSkj_ResetFight(EnSkj* this, GlobalContext* globalCtx) {
if (this->battleExitTimer == 0) {
EnSkj_SetupResetFight(this);
} else if (func_80AFEDF8(this, globalCtx) != 0) {
this->battleExitTimer = 600;
EnSkj_SetupStand(this);
}
}
void EnSkj_SetupStand(EnSkj* this) {
this->needleShootTimer = 60;
this->unk_2C8 = 0x2000;
this->unk_2F0 = 0.0f;
this->unk_2EC = 600.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_FIGHTING_STANCE);
EnSkj_SetupAction(this, SKJ_ACTION_FIGHT);
}
void EnSkj_Fight(EnSkj* this, GlobalContext* globalCtx) {
Vec3f pos1;
Vec3f pos2;
s32 pad[3];
f32 prevPosX;
f32 prevPosZ;
f32 phi_f14;
s16 yawDistToPlayer;
if (this->needleShootTimer == 0) {
EnSkj_SetupWaitToShootNeedle(this);
} else if (this->battleExitTimer != 0) {
yawDistToPlayer =
Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, this->unk_2F0, 0);
this->actor.world.rot.y = this->actor.shape.rot.y;
Math_ApproachF(&this->unk_2F0, 2000.0f, 1.0f, 200.0f);
pos1.x = 0.0f;
pos1.y = 0.0f;
pos1.z = -120.0f;
Matrix_RotateY((this->actor.shape.rot.y / 32768.0f) * M_PI, MTXMODE_NEW);
Matrix_MultVec3f(&pos1, &pos2);
prevPosX = this->actor.world.pos.x;
prevPosZ = this->actor.world.pos.z;
this->actor.world.pos.x = this->center.x + pos2.x;
this->actor.world.pos.z = this->center.z + pos2.z;
phi_f14 = sqrtf(SQ(this->actor.world.pos.x - prevPosX) + SQ(this->actor.world.pos.z - prevPosZ));
phi_f14 = CLAMP_MAX(phi_f14, 10.0f);
phi_f14 /= 10.0f;
this->skelAnime.playSpeed = (yawDistToPlayer < 0) ? -(1.0f + phi_f14) : (1.0f + phi_f14);
} else if (func_80AFEDF8(this, globalCtx) != 0) {
this->backflipFlag = 1;
EnSkj_Backflip(this);
} else {
EnSkj_SetupResetFight(this);
}
}
void EnSkj_SetupNeedleRecover(EnSkj* this) {
Animation_Reverse(&this->skelAnime);
EnSkj_SetupAction(this, SKJ_ACTION_NEEDLE_RECOVER);
}
void EnSkj_NeedleRecover(EnSkj* this, GlobalContext* globalCtx) {
if (this->skelAnime.curFrame == 0.0f) {
EnSkj_SetupStand(this);
}
}
void EnSkj_SetupSpawnDeathEffect(EnSkj* this) {
this->backflipFlag = 1;
EnSkj_SetupAction(this, SKJ_ACTION_SPAWN_DEATH_EFFECT);
}
void EnSkj_SpawnDeathEffect(EnSkj* this, GlobalContext* globalCtx) {
Vec3f effectPos;
Vec3f effectVel;
Vec3f effectAccel;
u32 phi_v0;
phi_v0 = this->alpha - 4;
if (phi_v0 > 255) {
phi_v0 = 0;
}
this->alpha = phi_v0;
this->actor.shape.shadowAlpha = phi_v0;
effectPos.x = Rand_CenteredFloat(30.0f) + this->actor.world.pos.x;
effectPos.y = Rand_CenteredFloat(30.0f) + this->actor.world.pos.y;
effectPos.z = Rand_CenteredFloat(30.0f) + this->actor.world.pos.z;
effectAccel.z = 0.0f;
effectAccel.y = 0.0f;
effectAccel.x = 0.0f;
effectVel.z = 0.0f;
effectVel.y = 0.0f;
effectVel.x = 0.0f;
EffectSsDeadDb_Spawn(globalCtx, &effectPos, &effectVel, &effectAccel, 100, 10, 255, 255, 255, 255, 0, 0, 255, 1, 9,
1);
}
void EnSkj_SetupWaitInRange(EnSkj* this) {
this->textId = 0x10BC;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_IN_RANGE);
}
void EnSkj_WaitInRange(EnSkj* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
// When link pulls out the Ocarina center him on the stump
// Link was probably supposed to be pointed towards skull kid as well
if (player->stateFlags2 & 0x1000000) {
player->stateFlags2 |= 0x2000000;
player->unk_6A8 = &sSmallStumpSkullKid.skullkid->actor;
player->actor.world.pos.x = sSmallStumpSkullKid.skullkid->actor.world.pos.x;
player->actor.world.pos.y = sSmallStumpSkullKid.skullkid->actor.world.pos.y;
player->actor.world.pos.z = sSmallStumpSkullKid.skullkid->actor.world.pos.z;
EnSkj_TurnPlayer(sSmallStumpSkullKid.skullkid, player);
func_8010BD88(globalCtx, OCARINA_ACTION_CHECK_SARIA);
EnSkj_SetupWaitForSong(this);
} else if (D_80B01EA0 != 0) {
player->actor.world.pos.x = sSmallStumpSkullKid.skullkid->actor.world.pos.x;
player->actor.world.pos.y = sSmallStumpSkullKid.skullkid->actor.world.pos.y;
player->actor.world.pos.z = sSmallStumpSkullKid.skullkid->actor.world.pos.z;
if ((Player_GetMask(globalCtx) == PLAYER_MASK_SKULL) && !(gSaveContext.itemGetInf[3] & 0x200)) {
func_80078884(NA_SE_SY_TRE_BOX_APPEAR);
EnSkj_SetupMaskTrade(this);
} else {
EnSkj_SetupTalk(this);
}
} else if (!EnSkj_RangeCheck(player, sSmallStumpSkullKid.skullkid)) {
EnSkj_SetupResetFight(this);
} else {
player->stateFlags2 |= 0x800000;
if (gSaveContext.itemGetInf[1] & 0x40) {
if (gSaveContext.itemGetInf[3] & 0x200) {
this->textId = Text_GetFaceReaction(globalCtx, 0x15);
if (this->textId == 0) {
this->textId = 0x1020;
}
} else if (Player_GetMask(globalCtx) == PLAYER_MASK_NONE) {
this->textId = 0x10BC;
} else if (Player_GetMask(globalCtx) == PLAYER_MASK_SKULL) {
this->textId = 0x101B;
} else {
this->textId = Text_GetFaceReaction(globalCtx, 0x15);
}
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
}
}
}
void EnSkj_SetupWaitForSong(EnSkj* this) {
this->unk_2D6 = 0;
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_FOR_SONG);
}
void EnSkj_WaitForSong(EnSkj* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
// Played a song thats not Saria's song
if (!(gSaveContext.itemGetInf[1] & 0x40) && ((globalCtx->msgCtx.msgMode == MSGMODE_OCARINA_FAIL) ||
(globalCtx->msgCtx.msgMode == MSGMODE_OCARINA_FAIL_NO_TEXT))) {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
Message_CloseTextbox(globalCtx);
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
EnSkj_SetupWrongSong(this);
} else {
if ((globalCtx->msgCtx.msgMode == MSGMODE_OCARINA_CORRECT_PLAYBACK) && (this->unk_2D6 == 0)) {
this->unk_2D6 = 1;
EnSkj_ChangeAnim(this, SKJ_ANIM_PLAY_FLUTE);
} else if ((this->unk_2D6 != 0) && (globalCtx->msgCtx.msgMode == MSGMODE_SONG_DEMONSTRATION_DONE)) {
this->unk_2D6 = 0;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
}
if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_04) {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_00;
this->unk_2D6 = 0;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_IN_RANGE);
} else if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_03) {
if (!(gSaveContext.itemGetInf[1] & 0x40)) {
// Saria's song has been played for the first titme
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
func_80078884(NA_SE_SY_CORRECT_CHIME);
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
this->textId = 0x10BB;
EnSkj_SetupAfterSong(this);
} else {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_05;
}
} else if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_02) {
player->stateFlags2 &= ~0x1000000;
Actor_Kill(&this->actor);
} else if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_01) {
player->stateFlags2 |= 0x800000;
} else {
if (globalCtx->msgCtx.ocarinaMode >= OCARINA_MODE_05) {
gSaveContext.sunsSongState = 0;
if (gSaveContext.itemGetInf[1] & 0x40) {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
this->textId = 0x10BD;
EnSkj_SetupAfterSong(this);
} else {
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
EnSkj_SetupWrongSong(this);
}
}
}
}
}
void EnSkj_SetupAfterSong(EnSkj* this) {
this->unk_2D6 = 0;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_AFTER_SONG);
}
void EnSkj_AfterSong(EnSkj* this, GlobalContext* globalCtx) {
if (D_80B01EA0 != 0) {
EnSkj_SetupTalk(this);
} else {
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
}
}
void EnSkj_SetupTalk(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_TALK);
}
void EnSkj_SariaSongTalk(EnSkj* this, GlobalContext* globalCtx) {
s32 pad;
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
if (gSaveContext.itemGetInf[1] & 0x40) {
EnSkj_SetupWaitInRange(this);
} else {
func_80AFFE24(this);
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetItemIdFromKnownCheck(RC_LW_SKULL_KID, GI_HEART_PIECE) : GI_HEART_PIECE, EnSkj_GetItemXzRange(this),
EnSkj_GetItemYRange(this));
}
}
}
void func_80AFFE24(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_UNK14);
}
void func_80AFFE44(EnSkj* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) {
this->actor.parent = NULL;
EnSkj_SetupPostSariasSong(this);
} else {
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetItemIdFromKnownCheck(RC_LW_SKULL_KID, GI_HEART_PIECE) : GI_HEART_PIECE, EnSkj_GetItemXzRange(this), EnSkj_GetItemYRange(this));
}
}
void EnSkj_SetupPostSariasSong(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_CHANGE_MODE);
}
void EnSkj_ChangeModeAfterSong(EnSkj* this, GlobalContext* globalCtx) {
if (((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) || Randomizer_ItemIsIceTrap(RC_LW_SKULL_KID, GI_HEART_PIECE)) {
gSaveContext.itemGetInf[1] |= 0x40;
EnSkj_SetNaviId(this);
EnSkj_SetupWaitInRange(this);
}
}
void EnSkj_SetupMaskTrade(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_START_TRADE);
}
void EnSkj_StartMaskTrade(EnSkj* this, GlobalContext* globalCtx) {
u8 sp1F = Message_GetState(&globalCtx->msgCtx);
func_8002DF54(globalCtx, &this->actor, 1);
if ((sp1F == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
EnSkj_JumpFromStump(this);
}
}
void EnSkj_JumpFromStump(EnSkj* this) {
this->actor.velocity.y = 8.0f;
this->actor.speedXZ = 2.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_BACKFLIP);
Animation_Reverse(&this->skelAnime);
this->skelAnime.curFrame = this->skelAnime.startFrame;
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING);
}
void EnSkj_WaitForLanding(EnSkj* this, GlobalContext* globalCtx) {
if (this->actor.velocity.y <= 0.0f) {
if (this->actor.bgCheckFlags & 2) {
this->actor.bgCheckFlags &= ~2;
this->actor.speedXZ = 0.0f;
EnSkj_SetupWaitForLandAnimFinish(this);
}
}
}
void EnSkj_SetupWaitForLandAnimFinish(EnSkj* this) {
EnSkj_ChangeAnim(this, SKJ_ANIM_LAND);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_FOR_LANDING_ANIM);
}
void EnSkj_WaitForLandAnimFinish(EnSkj* this, GlobalContext* globalCtx) {
s16 lastFrame = Animation_GetLastFrame(&gSkullKidLandAnim);
if (this->skelAnime.curFrame == lastFrame) {
EnSkj_SetupWalkToPlayer(this);
}
}
void EnSkj_SetupWalkToPlayer(EnSkj* this) {
this->unk_2F0 = 0.0f;
this->actor.speedXZ = 2.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_WALK_TO_PLAYER);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WALK_TO_PLAYER);
}
void EnSkj_WalkToPlayer(EnSkj* this, GlobalContext* globalCtx) {
Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xA, this->unk_2F0, 0);
Math_ApproachF(&this->unk_2F0, 2000.0f, 1.0f, 100.0f);
this->actor.world.rot.y = this->actor.shape.rot.y;
if (this->actor.xzDistToPlayer < 120.0f) {
this->actor.speedXZ = 0.0f;
EnSkj_SetupAskForMask(this, globalCtx);
}
}
void EnSkj_SetupAskForMask(EnSkj* this, GlobalContext* globalCtx) {
Message_StartTextbox(globalCtx, 0x101C, &this->actor);
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_ASK_FOR_MASK);
}
void EnSkj_AskForMask(EnSkj* this, GlobalContext* globalCtx) {
if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(globalCtx)) {
switch (globalCtx->msgCtx.choiceIndex) {
case 0: // Yes
EnSkj_SetupTakeMask(this, globalCtx);
break;
case 1: // No
Message_ContinueTextbox(globalCtx, 0x101D);
EnSkj_SetupWaitForMaskTextClear(this);
break;
}
}
}
void EnSkj_SetupTakeMask(EnSkj* this, GlobalContext* globalCtx) {
Message_ContinueTextbox(globalCtx, 0x101E);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_TAKE_MASK);
}
void EnSkj_TakeMask(EnSkj* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
Rupees_ChangeBy(10);
gSaveContext.itemGetInf[3] |= 0x200;
EnSkj_SetNaviId(this);
Player_UnsetMask(globalCtx);
Item_Give(globalCtx, ITEM_SOLD_OUT);
Message_ContinueTextbox(globalCtx, 0x101F);
EnSkj_SetupWaitForMaskTextClear(this);
}
}
void EnSkj_SetupWaitForMaskTextClear(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_MASK_TEXT);
}
void EnSkj_WaitForMaskTextClear(EnSkj* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
func_8002DF54(globalCtx, &this->actor, 7);
this->backflipFlag = 1;
EnSkj_Backflip(this);
}
}
void EnSkj_SetupWrongSong(EnSkj* this) {
this->textId = 0x1041;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WRONG_SONG);
}
void EnSkj_WrongSong(EnSkj* this, GlobalContext* globalCtx) {
if (D_80B01EA0 != 0) {
EnSkj_SetupWaitForTextClear(this);
} else {
func_8002F2CC(&this->actor, globalCtx, EnSkj_GetItemXzRange(this));
}
}
void EnSkj_SetupWaitForTextClear(EnSkj* this) {
EnSkj_SetupAction(this, SKJ_ACTION_SARIA_SONG_WAIT_FOR_TEXT);
}
void EnSkj_SariasSongWaitForTextClear(EnSkj* this, GlobalContext* globalCtx) {
u8 state = Message_GetState(&globalCtx->msgCtx);
Player* player = GET_PLAYER(globalCtx);
if (state == TEXT_STATE_DONE && Message_ShouldAdvance(globalCtx)) {
EnSkj_SetupWaitInRange(this);
player->stateFlags2 |= 0x800000;
player->unk_6A8 = (Actor*)sSmallStumpSkullKid.skullkid;
}
}
void EnSkj_OcarinaGameSetupWaitForPlayer(EnSkj* this) {
this->actor.flags &= ~ACTOR_FLAG_0;
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_OCARINA_GAME_WAIT_FOR_PLAYER);
}
void EnSkj_OcarinaGameWaitForPlayer(EnSkj* this, GlobalContext* globalCtx) {
if (this->playerInRange) {
this->actor.flags |= ACTOR_FLAG_0;
EnSkj_SetupAction(this, SKJ_ACTION_OCARINA_GAME_IDLE);
}
}
s32 EnSkj_IsLeavingGame(EnSkj* this) {
s32 paramDecr = this->actor.params - 1;
if (sOcarinaMinigameSkullKids[paramDecr].unk0 == 2) {
EnSkj_SetupLeaveOcarinaGame(this);
return true;
}
return false;
}
void EnSkj_SetupIdle(EnSkj* this) {
EnSkj_ChangeAnim(this, SKJ_ANIM_WAIT);
EnSkj_SetupAction(this, SKJ_ACTION_OCARINA_GAME_IDLE);
}
void EnSkj_Appear(EnSkj* this) {
if (this->alpha != 255) {
this->alpha += 20;
if (this->alpha > 255) {
this->alpha = 255;
}
}
}
void EnSkj_OcarinaGameIdle(EnSkj* this, GlobalContext* globalCtx) {
EnSkj_Appear(this);
if ((EnSkj_IsLeavingGame(this) == false) && (this->minigameState != 0)) {
EnSkj_SetupPlayOcarinaGame(this);
}
}
void EnSkj_SetupPlayOcarinaGame(EnSkj* this) {
EnSkj_ChangeAnim(this, SKJ_ANIM_PLAY_FLUTE);
EnSkj_SetupAction(this, SKJ_ACTION_OCARINA_GAME_PLAY);
}
void EnSkj_PlayOcarinaGame(EnSkj* this, GlobalContext* globalCtx) {
EnSkj_Appear(this);
if (!EnSkj_IsLeavingGame(this) && (this->minigameState == 0)) {
EnSkj_SetupIdle(this);
}
}
void EnSkj_SetupLeaveOcarinaGame(EnSkj* this) {
this->actor.velocity.y = 8.0f;
this->actor.speedXZ = -8.0f;
EnSkj_ChangeAnim(this, SKJ_ANIM_BACKFLIP);
EnSkj_SetupAction(this, SKJ_ACTION_OCARINA_GAME_LEAVE);
}
void EnSkj_LeaveOcarinaGame(EnSkj* this, GlobalContext* globalCtx) {
s32 paramsDecr = this->actor.params - 1;
sOcarinaMinigameSkullKids[paramsDecr].unk0 = 0;
sOcarinaMinigameSkullKids[paramsDecr].skullkid = NULL;
this->backflipFlag = 1;
EnSkj_Backflip(this);
}
void EnSkj_Update(Actor* thisx, GlobalContext* globalCtx) {
Vec3f dropPos;
s32 pad;
EnSkj* this = (EnSkj*)thisx;
D_80B01EA0 = Actor_ProcessTalkRequest(&this->actor, globalCtx);
this->timer++;
if (this->multiuseTimer != 0) {
this->multiuseTimer--;
}
if (this->needleShootTimer != 0) {
this->needleShootTimer--;
}
if (this->dodgeResetTimer != 0) {
this->dodgeResetTimer--;
}
if (this->dodgeResetTimer == 0) {
this->hitsUntilDodge = 3;
}
if ((this->backflipFlag != 0) && (this->alpha == 0)) {
if (this->action == 9) {
dropPos.x = this->actor.world.pos.x;
dropPos.y = this->actor.world.pos.y;
dropPos.z = this->actor.world.pos.z;
Item_DropCollectible(globalCtx, &dropPos, ITEM00_RUPEE_ORANGE);
}
Actor_Kill(&this->actor);
return;
}
Actor_SetFocus(&this->actor, 30.0f);
Actor_SetScale(&this->actor, 0.01f);
this->actionFunc(this, globalCtx);
this->actor.textId = this->textId;
EnSkj_CollisionCheck(this, globalCtx);
Collider_UpdateCylinder(&this->actor, &this->collider);
if ((this->unk_2D3 != 0) && (D_80B01EA0 == 0)) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
if (this->actor.colorFilterTimer == 0) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
}
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
SkelAnime_Update(&this->skelAnime);
Actor_MoveForward(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 20.0f, 20.0f, 20.0f, 7);
}
void EnSkj_SariasSongShortStumpUpdate(Actor* thisx, GlobalContext* globalCtx) {
EnSkj* this = (EnSkj*)thisx;
D_80B01EA0 = Actor_ProcessTalkRequest(&this->actor, globalCtx);
if (BREG(0) != 0) {
DebugDisplay_AddObject(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f, 1.0f,
1.0f, 255, 0, 0, 255, 4, globalCtx->state.gfxCtx);
}
}
void EnSkj_TurnPlayer(EnSkj* this, Player* player) {
Math_SmoothStepToS(&player->actor.shape.rot.y, this->actor.world.rot.y, 5, 2000, 0);
player->actor.world.rot.y = player->actor.shape.rot.y;
player->currentYaw = player->actor.shape.rot.y;
}
void EnSkj_SetupWaitForOcarina(EnSkj* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if (EnSkj_RangeCheck(player, this)) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->playerInRange = true;
sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid->playerInRange = true;
if (player->stateFlags2 & 0x1000000) {
player->stateFlags2 |= 0x2000000;
func_800F5BF0(NATURE_ID_KOKIRI_REGION);
EnSkj_TurnPlayer(this, player);
player->unk_6A8 = &this->actor;
Message_StartTextbox(globalCtx, 0x10BE, &this->actor);
this->actionFunc = EnSkj_StartOcarinaMinigame;
} else {
this->actionFunc = EnSkj_WaitForOcarina;
}
}
}
void EnSkj_WaitForOcarina(EnSkj* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if (player->stateFlags2 & 0x1000000) {
player->stateFlags2 |= 0x2000000;
func_800F5BF0(NATURE_ID_KOKIRI_REGION);
EnSkj_TurnPlayer(this, player);
player->unk_6A8 = &this->actor;
Message_StartTextbox(globalCtx, 0x10BE, &this->actor);
this->actionFunc = EnSkj_StartOcarinaMinigame;
} else if (EnSkj_RangeCheck(player, this)) {
player->stateFlags2 |= 0x800000;
}
}
void EnSkj_StartOcarinaMinigame(EnSkj* this, GlobalContext* globalCtx) {
u8 dialogState = Message_GetState(&globalCtx->msgCtx);
Player* player = GET_PLAYER(globalCtx);
EnSkj_TurnPlayer(this, player);
if (dialogState == TEXT_STATE_CLOSING) {
func_8010BD58(globalCtx, OCARINA_ACTION_MEMORY_GAME);
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_PLAY_NOTES;
}
this->songFailTimer = 160;
this->actionFunc = EnSkj_WaitForPlayback;
}
}
void EnSkj_WaitForPlayback(EnSkj* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
EnSkj_TurnPlayer(this, player);
if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_03) { // failed the game
Message_CloseTextbox(globalCtx);
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, 26.0f);
this->textId = 0x102D;
this->actionFunc = EnSkj_FailedMiniGame;
} else if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_0F) { // completed the game
func_80078884(NA_SE_SY_CORRECT_CHIME);
Message_CloseTextbox(globalCtx);
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, 26.0f);
this->textId = 0x10BF;
this->actionFunc = EnSkj_WonOcarinaMiniGame;
} else { // playing the game
switch (globalCtx->msgCtx.msgMode) {
case MSGMODE_MEMORY_GAME_LEFT_SKULLKID_WAIT:
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_WAIT;
}
if (!Audio_IsSfxPlaying(NA_SE_SY_METRONOME)) {
if (sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid->minigameState =
SKULL_KID_OCARINA_PLAY_NOTES;
}
Message_UpdateOcarinaGame(globalCtx);
}
break;
case MSGMODE_MEMORY_GAME_RIGHT_SKULLKID_WAIT:
if (sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid->minigameState = SKULL_KID_OCARINA_WAIT;
}
if (!Audio_IsSfxPlaying(NA_SE_SY_METRONOME)) {
Message_UpdateOcarinaGame(globalCtx);
this->songFailTimer = 160;
}
break;
case MSGMODE_MEMORY_GAME_PLAYER_PLAYING:
if (this->songFailTimer != 0) {
this->songFailTimer--;
} else { // took too long, game failed
func_80078884(NA_SE_SY_OCARINA_ERROR);
Message_CloseTextbox(globalCtx);
globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04;
player->unk_6A8 = &this->actor;
func_8002F2CC(&this->actor, globalCtx, 26.0f);
this->textId = 0x102D;
this->actionFunc = EnSkj_FailedMiniGame;
}
break;
case MSGMODE_MEMORY_GAME_START_NEXT_ROUND:
if (!Audio_IsSfxPlaying(NA_SE_SY_METRONOME)) {
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState =
SKULL_KID_OCARINA_PLAY_NOTES;
}
this->songFailTimer = 160;
Audio_OcaSetInstrument(6); // related instrument sound (flute?)
Audio_OcaSetSongPlayback(OCARINA_SONG_MEMORY_GAME + 1, 1);
globalCtx->msgCtx.msgMode = MSGMODE_MEMORY_GAME_LEFT_SKULLKID_PLAYING;
globalCtx->msgCtx.stateTimer = 2;
}
break;
}
}
}
void EnSkj_FailedMiniGame(EnSkj* this, GlobalContext* globalCtx) {
if (D_80B01EA0) {
this->actionFunc = EnSkj_WaitForNextRound;
} else {
func_8002F2CC(&this->actor, globalCtx, 26.0f);
}
}
void EnSkj_WaitForNextRound(EnSkj* this, GlobalContext* globalCtx) {
if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE && Message_ShouldAdvance(globalCtx)) {
EnSkj_OfferNextRound(this, globalCtx);
}
}
void EnSkj_OfferNextRound(EnSkj* this, GlobalContext* globalCtx) {
Message_ContinueTextbox(globalCtx, 0x102E);
this->actionFunc = EnSkj_WaitForOfferResponse;
}
void EnSkj_WaitForOfferResponse(EnSkj* this, GlobalContext* globalCtx) {
Player* player;
if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(globalCtx)) {
switch (globalCtx->msgCtx.choiceIndex) {
case 0: // yes
player = GET_PLAYER(globalCtx);
player->stateFlags3 |= 0x20; // makes player take ocarina out right away after closing box
this->actionFunc = EnSkj_SetupWaitForOcarina;
break;
case 1: // no
this->actionFunc = EnSkj_CleanupOcarinaGame;
break;
}
}
}
void EnSkj_WonOcarinaMiniGame(EnSkj* this, GlobalContext* globalCtx) {
if (D_80B01EA0) {
this->actionFunc = EnSkj_WaitToGiveReward;
} else {
func_8002F2CC(&this->actor, globalCtx, 26.0f);
}
}
void EnSkj_WaitToGiveReward(EnSkj* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
func_8002F434(&this->actor, globalCtx,
gSaveContext.n64ddFlag && gSaveContext.ocarinaGameRoundNum != 3
? Randomizer_GetItemIdFromKnownCheck(RC_LW_OCARINA_MEMORY_GAME, GI_HEART_PIECE)
: sOcarinaGameRewards[gSaveContext.ocarinaGameRoundNum],
26.0f, 26.0f);
this->actionFunc = EnSkj_GiveOcarinaGameReward;
}
}
void EnSkj_GiveOcarinaGameReward(EnSkj* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) {
this->actor.parent = NULL;
this->actionFunc = EnSkj_FinishOcarinaGameRound;
} else {
func_8002F434(&this->actor, globalCtx,
gSaveContext.n64ddFlag && gSaveContext.ocarinaGameRoundNum != 3
? Randomizer_GetItemIdFromKnownCheck(RC_LW_OCARINA_MEMORY_GAME, GI_HEART_PIECE)
: sOcarinaGameRewards[gSaveContext.ocarinaGameRoundNum],
26.0f, 26.0f);
}
}
void EnSkj_FinishOcarinaGameRound(EnSkj* this, GlobalContext* globalCtx) {
if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_DONE) && Message_ShouldAdvance(globalCtx)) {
s32 ocarinaGameRoundNum = gSaveContext.ocarinaGameRoundNum;
if (gSaveContext.ocarinaGameRoundNum < 3) {
gSaveContext.ocarinaGameRoundNum++;
}
if (gSaveContext.n64ddFlag) {
gSaveContext.ocarinaGameRoundNum = 3;
}
if (ocarinaGameRoundNum == 2 || gSaveContext.n64ddFlag) {
gSaveContext.itemGetInf[1] |= 0x80;
this->actionFunc = EnSkj_CleanupOcarinaGame;
} else {
EnSkj_OfferNextRound(this, globalCtx);
}
}
}
void EnSkj_CleanupOcarinaGame(EnSkj* this, GlobalContext* globalCtx) {
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].unk0 = 2;
}
if (sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].unk0 = 2;
}
if ((sOcarinaMinigameSkullKids[SKULL_KID_LEFT].unk0 == 2) &&
(sOcarinaMinigameSkullKids[SKULL_KID_RIGHT].unk0 == 2)) {
func_800F5C2C();
Actor_Kill(&this->actor);
}
}
void EnSkj_OcarinaMinigameShortStumpUpdate(Actor* thisx, GlobalContext* globalCtx) {
EnSkj* this = (EnSkj*)thisx;
D_80B01EA0 = Actor_ProcessTalkRequest(&this->actor, globalCtx);
this->timer++;
this->actor.focus.pos.x = 1230.0f;
this->actor.focus.pos.y = -90.0f;
this->actor.focus.pos.z = 450.0f;
if (BREG(0) != 0) {
DebugDisplay_AddObject(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f, 1.0f,
1.0f, 255, 0, 0, 255, 4, globalCtx->state.gfxCtx);
}
this->actionFunc(this, globalCtx);
this->actor.textId = this->textId;
this->actor.xzDistToPlayer = 50.0;
}
s32 EnSkj_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) {
return 0;
}
void EnSkj_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
OPEN_DISPS(globalCtx->state.gfxCtx);
if ((limbIndex == 11) && (gSaveContext.itemGetInf[3] & 0x200)) {
func_80093D18(globalCtx->state.gfxCtx);
Matrix_Push();
Matrix_RotateZYX(-0x4000, 0, 0, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gSKJskullMaskDL);
Matrix_Pop();
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
Gfx* EnSkj_TranslucentDL(GraphicsContext* gfxCtx, u32 alpha) {
Gfx* dList;
Gfx* dListHead;
//! @bug This only allocates space for 1 command but uses 3
dList = dListHead = Graph_Alloc(gfxCtx, sizeof(Gfx));
gDPSetRenderMode(dListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2);
gDPSetEnvColor(dListHead++, 0, 0, 0, alpha);
gSPEndDisplayList(dListHead++);
return dList;
}
Gfx* EnSkj_OpaqueDL(GraphicsContext* gfxCtx, u32 alpha) {
Gfx* dList;
Gfx* dListHead;
//! @bug This only allocates space for 1 command but uses 2
dList = dListHead = Graph_Alloc(gfxCtx, sizeof(Gfx));
gDPSetEnvColor(dListHead++, 0, 0, 0, alpha);
gSPEndDisplayList(dListHead++);
return dList;
}
void EnSkj_Draw(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnSkj* this = (EnSkj*)thisx;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
if (this->alpha < 255) {
gSPSegment(POLY_OPA_DISP++, 0x0C, EnSkj_TranslucentDL(globalCtx->state.gfxCtx, this->alpha));
} else {
gSPSegment(POLY_OPA_DISP++, 0x0C, EnSkj_OpaqueDL(globalCtx->state.gfxCtx, this->alpha));
}
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
EnSkj_OverrideLimbDraw, EnSkj_PostLimbDraw, this);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}