Shipwright/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c

756 lines
22 KiB
C
Raw Normal View History

/*
* File: z_en_tk.c
* Overlay: ovl_En_Tk
* Description: Dampe NPC from "Dampe's Heart-Pounding Gravedigging Tour"
*/
#include "z_en_tk.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_tk/object_tk.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
Gravedigging tour fix (#388) * Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
2022-06-16 20:36:13 -04:00
#define COLLECTFLAG_GRAVEDIGGING_HEART_PIECE 0x19
#define ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE 0x1000
bool heartPieceSpawned;
void EnTk_Init(Actor* thisx, GlobalContext* globalCtx);
void EnTk_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnTk_Update(Actor* thisx, GlobalContext* globalCtx);
void EnTk_Draw(Actor* thisx, GlobalContext* globalCtx);
s32 EnTk_CheckNextSpot(EnTk* this, GlobalContext* globalCtx);
void EnTk_Rest(EnTk* this, GlobalContext* globalCtx);
void EnTk_Walk(EnTk* this, GlobalContext* globalCtx);
void EnTk_Dig(EnTk* this, GlobalContext* globalCtx);
const ActorInit En_Tk_InitVars = {
ACTOR_EN_TK,
ACTORCAT_NPC,
FLAGS,
OBJECT_TK,
sizeof(EnTk),
(ActorFunc)EnTk_Init,
(ActorFunc)EnTk_Destroy,
(ActorFunc)EnTk_Update,
(ActorFunc)EnTk_Draw,
NULL,
};
void EnTkEff_Create(EnTk* this, Vec3f* pos, Vec3f* speed, Vec3f* accel, u8 duration, f32 size, f32 growth) {
s16 i;
EnTkEff* eff = this->eff;
for (i = 0; i < ARRAY_COUNT(this->eff); i++) {
if (eff->active != 1) {
eff->size = size;
eff->growth = growth;
eff->timeTotal = eff->timeLeft = duration;
eff->active = 1;
eff->pos = *pos;
eff->accel = *accel;
eff->speed = *speed;
break;
}
eff++;
}
}
void EnTkEff_Update(EnTk* this) {
s16 i;
EnTkEff* eff;
eff = this->eff;
for (i = 0; i < ARRAY_COUNT(this->eff); i++) {
if (eff->active != 0) {
eff->timeLeft--;
if (eff->timeLeft == 0) {
eff->active = 0;
}
eff->accel.x = Rand_ZeroOne() * 0.4f - 0.2f;
eff->accel.z = Rand_ZeroOne() * 0.4f - 0.2f;
eff->pos.x += eff->speed.x;
eff->pos.y += eff->speed.y;
eff->pos.z += eff->speed.z;
eff->speed.x += eff->accel.x;
eff->speed.y += eff->accel.y;
eff->speed.z += eff->accel.z;
eff->size += eff->growth;
}
eff++;
}
}
void EnTkEff_Draw(EnTk* this, GlobalContext* globalCtx) {
static void* dustTextures[] = {
gDust8Tex, gDust7Tex, gDust6Tex, gDust5Tex, gDust4Tex, gDust3Tex, gDust2Tex, gDust1Tex,
};
EnTkEff* eff = this->eff;
s16 imageIdx;
s16 gfxSetup;
s16 alpha;
s16 i;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_tk_eff.c", 114);
gfxSetup = 0;
func_80093D84(globalCtx->state.gfxCtx);
if (1) {}
for (i = 0; i < ARRAY_COUNT(this->eff); i++) {
if (eff->active != 0) {
if (gfxSetup == 0) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPDisplayList(POLY_XLU_DISP++, gDampeEff1DL);
gDPSetEnvColor(POLY_XLU_DISP++, 100, 60, 20, 0);
gfxSetup = 1;
}
alpha = eff->timeLeft * (255.0f / eff->timeTotal);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 170, 130, 90, alpha);
gDPPipeSync(POLY_XLU_DISP++);
Matrix_Translate(eff->pos.x, eff->pos.y, eff->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
Matrix_Scale(eff->size, eff->size, 1.0f, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_tk_eff.c", 140),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
imageIdx = eff->timeLeft * ((f32)ARRAY_COUNT(dustTextures) / eff->timeTotal);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTextures[imageIdx]));
gSPDisplayList(POLY_XLU_DISP++, gDampeEff2DL);
}
eff++;
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_tk_eff.c", 154);
}
s32 EnTkEff_CreateDflt(EnTk* this, Vec3f* pos, u8 duration, f32 size, f32 growth, f32 yAccelMax) {
Vec3f speed = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.3f, 0.0f };
accel.y += Rand_ZeroOne() * yAccelMax;
EnTkEff_Create(this, pos, &speed, &accel, duration, size, growth);
return 0;
}
/** z_en_tk_eff.c ends here probably **/
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_NONE,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x00000000, 0x00, 0x00 },
TOUCH_NONE,
BUMP_NONE,
OCELEM_ON,
},
{ 30, 52, 0, { 0, 0, 0 } },
};
static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE };
void EnTk_RestAnim(EnTk* this, GlobalContext* globalCtx) {
AnimationHeader* anim = &gDampeRestAnim;
Animation_Change(&this->skelAnime, anim, 1.0f, 0.0f, Animation_GetLastFrame(&gDampeRestAnim), ANIMMODE_LOOP,
-10.0f);
this->actionCountdown = Rand_S16Offset(60, 60);
this->actor.speedXZ = 0.0f;
}
void EnTk_WalkAnim(EnTk* this, GlobalContext* globalCtx) {
AnimationHeader* anim = &gDampeWalkAnim;
Animation_Change(&this->skelAnime, anim, 1.0f, 0.0f, Animation_GetLastFrame(&gDampeRestAnim), ANIMMODE_LOOP,
-10.0f);
this->actionCountdown = Rand_S16Offset(240, 240);
}
void EnTk_DigAnim(EnTk* this, GlobalContext* globalCtx) {
AnimationHeader* anim = &gDampeDigAnim;
Animation_Change(&this->skelAnime, anim, 1.0f, 0.0f, Animation_GetLastFrame(&gDampeDigAnim), ANIMMODE_LOOP, -10.0f);
if (EnTk_CheckNextSpot(this, globalCtx) >= 0) {
this->validDigHere = 1;
}
}
void EnTk_UpdateEyes(EnTk* this) {
if (DECR(this->blinkCountdown) == 0) {
this->eyeTextureIdx++;
if (this->eyeTextureIdx > 2) {
this->blinkCycles--;
if (this->blinkCycles < 0) {
this->blinkCountdown = Rand_S16Offset(30, 30);
this->blinkCycles = 2;
if (Rand_ZeroOne() > 0.5f) {
this->blinkCycles++;
}
}
this->eyeTextureIdx = 0;
}
}
}
s32 EnTk_CheckFacingPlayer(EnTk* this) {
s16 v0;
s16 v1;
if (this->actor.xyzDistToPlayerSq > 10000.0f) {
return 0;
}
v0 = this->actor.shape.rot.y;
v0 -= this->h_21E;
v0 -= this->headRot;
v1 = this->actor.yawTowardsPlayer - v0;
if (ABS(v1) < 0x1554) {
return 1;
} else {
return 0;
}
}
s32 EnTk_CheckNextSpot(EnTk* this, GlobalContext* globalCtx) {
Actor* prop;
f32 dxz;
f32 dy;
prop = globalCtx->actorCtx.actorLists[ACTORCAT_PROP].head;
while (prop != NULL) {
if (prop->id != ACTOR_EN_IT) {
prop = prop->next;
continue;
}
if (prop == this->currentSpot) {
prop = prop->next;
continue;
}
dy = prop->world.pos.y - this->actor.floorHeight;
dxz = Actor_WorldDistXZToActor(&this->actor, prop);
if (dxz > 40.0f || dy > 10.0f) {
prop = prop->next;
continue;
}
this->currentSpot = prop;
return prop->params;
}
return -1;
}
void EnTk_CheckCurrentSpot(EnTk* this) {
f32 dxz;
f32 dy;
if (this->currentSpot != NULL) {
dy = this->currentSpot->world.pos.y - this->actor.floorHeight;
dxz = Actor_WorldDistXZToActor(&this->actor, this->currentSpot);
if (dxz > 40.0f || dy > 10.0f) {
this->currentSpot = NULL;
}
}
}
f32 EnTk_Step(EnTk* this, GlobalContext* globalCtx) {
f32 stepFrames[] = { 36.0f, 10.0f };
f32 a1_;
s32 i;
if (this->skelAnime.curFrame == 0.0f || this->skelAnime.curFrame == 25.0f) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_MORIBLIN_WALK);
}
if (this->skelAnime.animation != &gDampeWalkAnim) {
return 0.0f;
}
a1_ = this->skelAnime.curFrame;
for (i = 0; i < ARRAY_COUNT(stepFrames); i++) {
if (a1_ < stepFrames[i] + 12.0f && a1_ >= stepFrames[i]) {
break;
}
}
if (i >= ARRAY_COUNT(stepFrames)) {
return 0.0f;
} else {
a1_ = (0x8000 / 12.0f) * (a1_ - stepFrames[i]);
return Math_SinS(a1_) * 2.0f;
}
}
s32 EnTk_Orient(EnTk* this, GlobalContext* globalCtx) {
Path* path;
Vec3s* point;
f32 dx;
f32 dz;
if (this->actor.params < 0) {
return 1;
}
path = &globalCtx->setupPathList[0];
point = SEGMENTED_TO_VIRTUAL(path->points);
point += this->currentWaypoint;
dx = point->x - this->actor.world.pos.x;
dz = point->z - this->actor.world.pos.z;
Math_SmoothStepToS(&this->actor.shape.rot.y, Math_FAtan2F(dx, dz) * (0x8000 / M_PI), 10, 1000, 1);
this->actor.world.rot = this->actor.shape.rot;
if (SQ(dx) + SQ(dz) < 10.0f) {
this->currentWaypoint++;
if (this->currentWaypoint >= path->count) {
this->currentWaypoint = 0;
}
return 0;
} else {
return 1;
}
}
u16 func_80B1C54C(GlobalContext* globalCtx, Actor* thisx) {
u16 ret;
ret = Text_GetFaceReaction(globalCtx, 14);
if (ret != 0) {
return ret;
}
if (gSaveContext.infTable[13] & 0x0200) {
/* "Do you want me to dig here? ..." */
return 0x5019;
} else {
/* "Hey kid! ..." */
return 0x5018;
}
}
s16 func_80B1C5A0(GlobalContext* globalCtx, Actor* thisx) {
s32 ret = 1;
switch (Message_GetState(&globalCtx->msgCtx)) {
case TEXT_STATE_NONE:
case TEXT_STATE_DONE_HAS_NEXT:
break;
case TEXT_STATE_CLOSING:
/* "I am the boss of the carpenters ..." (wtf?) */
if (thisx->textId == 0x5028) {
gSaveContext.infTable[13] |= 0x0100;
}
ret = 0;
break;
case TEXT_STATE_DONE_FADING:
break;
case TEXT_STATE_CHOICE:
if (Message_ShouldAdvance(globalCtx) && (thisx->textId == 0x5018 || thisx->textId == 0x5019)) {
if (globalCtx->msgCtx.choiceIndex == 1) {
/* "Thanks a lot!" */
thisx->textId = 0x0084;
} else if (gSaveContext.rupees < 10) {
/* "You don't have enough Rupees!" */
thisx->textId = 0x0085;
} else {
globalCtx->msgCtx.msgMode = MSGMODE_PAUSED;
Rupees_ChangeBy(-10);
gSaveContext.infTable[13] |= 0x0200;
return 2;
}
Message_ContinueTextbox(globalCtx, thisx->textId);
gSaveContext.infTable[13] |= 0x0200;
}
break;
case TEXT_STATE_EVENT:
if (Message_ShouldAdvance(globalCtx) && (thisx->textId == 0x0084 || thisx->textId == 0x0085)) {
Message_CloseTextbox(globalCtx);
ret = 0;
}
break;
case TEXT_STATE_DONE:
case TEXT_STATE_SONG_DEMO_DONE:
case TEXT_STATE_8:
case TEXT_STATE_9:
break;
}
return ret;
}
s32 EnTk_ChooseReward(EnTk* this) {
f32 luck;
s32 reward;
luck = Rand_ZeroOne();
if (luck < 0.4f) {
reward = 0;
} else if (luck < 0.7) {
reward = 1;
} else if (luck < 0.9) {
reward = 2;
} else {
reward = 3;
}
switch (reward) {
case 0:
if (this->rewardCount[0] < 8) {
this->rewardCount[0] += 1;
return reward;
}
break;
case 1:
if (this->rewardCount[1] < 4) {
this->rewardCount[1] += 1;
return reward;
}
break;
case 2:
if (this->rewardCount[2] < 2) {
this->rewardCount[2] += 1;
return reward;
}
break;
case 3:
if (this->rewardCount[3] < 1) {
this->rewardCount[3] += 1;
return reward;
}
break;
}
if (this->rewardCount[0] < 8) {
this->rewardCount[0] += 1;
reward = 0;
} else if (this->rewardCount[1] < 4) {
this->rewardCount[1] += 1;
reward = 1;
} else if (this->rewardCount[2] < 2) {
this->rewardCount[2] += 1;
reward = 2;
} else if (this->rewardCount[3] < 1) {
this->rewardCount[3] += 1;
reward = 3;
} else {
reward = 0;
this->rewardCount[0] = 1;
this->rewardCount[1] = 0;
this->rewardCount[2] = 0;
this->rewardCount[3] = 0;
}
return reward;
}
void EnTk_DigEff(EnTk* this) {
Vec3f pos = { 0.0f, 0.0f, 0.0f };
Vec3f speed = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 0.3f, 0.0f };
if (this->skelAnime.curFrame >= 32.0f && this->skelAnime.curFrame < 40.0f) {
pos.x = (Rand_ZeroOne() - 0.5f) * 12.0f + this->v3f_304.x;
pos.y = (Rand_ZeroOne() - 0.5f) * 8.0f + this->v3f_304.y;
pos.z = (Rand_ZeroOne() - 0.5f) * 12.0f + this->v3f_304.z;
EnTkEff_CreateDflt(this, &pos, 12, 0.2f, 0.1f, 0.0f);
}
}
void EnTk_Init(Actor* thisx, GlobalContext* globalCtx) {
EnTk* this = (EnTk*)thisx;
s32 pad;
ActorShape_Init(&this->actor.shape, 0, ActorShadow_DrawCircle, 24.0f);
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gDampeSkel, NULL, this->jointTable, this->morphTable, 18);
Animation_Change(&this->skelAnime, &gDampeRestAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gDampeRestAnim),
ANIMMODE_LOOP, 0.0f);
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
CollisionCheck_SetInfo2(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
if (gSaveContext.dayTime <= 0xC000 || gSaveContext.dayTime >= 0xE000 || !!LINK_IS_ADULT ||
globalCtx->sceneNum != SCENE_SPOT02) {
Actor_Kill(&this->actor);
return;
}
Actor_SetScale(&this->actor, 0.01f);
this->actor.targetMode = 6;
this->actor.gravity = -0.1f;
this->currentReward = -1;
this->currentSpot = NULL;
this->actionFunc = EnTk_Rest;
Gravedigging tour fix (#388) * Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
2022-06-16 20:36:13 -04:00
heartPieceSpawned = false;
}
void EnTk_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnTk* this = (EnTk*)thisx;
Collider_DestroyCylinder(globalCtx, &this->collider);
}
void EnTk_Rest(EnTk* this, GlobalContext* globalCtx) {
s16 v1;
s16 a1_;
if (this->h_1E0 != 0) {
v1 = this->actor.shape.rot.y;
v1 -= this->h_21E;
v1 = this->actor.yawTowardsPlayer - v1;
if (this->h_1E0 == 2) {
EnTk_DigAnim(this, globalCtx);
this->h_1E0 = 0;
this->actionFunc = EnTk_Dig;
return;
}
func_800343CC(globalCtx, &this->actor, &this->h_1E0, this->collider.dim.radius + 30.0f, func_80B1C54C,
func_80B1C5A0);
} else if (EnTk_CheckFacingPlayer(this)) {
v1 = this->actor.shape.rot.y;
v1 -= this->h_21E;
v1 = this->actor.yawTowardsPlayer - v1;
this->actionCountdown = 0;
func_800343CC(globalCtx, &this->actor, &this->h_1E0, this->collider.dim.radius + 30.0f, func_80B1C54C,
func_80B1C5A0);
} else if (Actor_ProcessTalkRequest(&this->actor, globalCtx)) {
v1 = this->actor.shape.rot.y;
v1 -= this->h_21E;
v1 = this->actor.yawTowardsPlayer - v1;
this->actionCountdown = 0;
this->h_1E0 = 1;
} else if (DECR(this->actionCountdown) == 0) {
EnTk_WalkAnim(this, globalCtx);
this->actionFunc = EnTk_Walk;
/*! @bug v1 is uninitialized past this branch */
} else {
v1 = 0;
}
a1_ = CLAMP(-v1, 1270, 10730);
Math_SmoothStepToS(&this->headRot, a1_, 6, 1000, 1);
}
void EnTk_Walk(EnTk* this, GlobalContext* globalCtx) {
if (this->h_1E0 == 2) {
EnTk_DigAnim(this, globalCtx);
this->h_1E0 = 0;
this->actionFunc = EnTk_Dig;
} else {
this->actor.speedXZ = EnTk_Step(this, globalCtx);
EnTk_Orient(this, globalCtx);
Math_SmoothStepToS(&this->headRot, 0, 6, 1000, 1);
EnTk_CheckCurrentSpot(this);
DECR(this->actionCountdown);
if (EnTk_CheckFacingPlayer(this) || this->actionCountdown == 0) {
EnTk_RestAnim(this, globalCtx);
this->actionFunc = EnTk_Rest;
}
}
}
void EnTk_Dig(EnTk* this, GlobalContext* globalCtx) {
Vec3f rewardOrigin;
Vec3f rewardPos;
s32 rewardParams[] = {
ITEM00_RUPEE_GREEN, ITEM00_RUPEE_BLUE, ITEM00_RUPEE_RED, ITEM00_RUPEE_PURPLE, ITEM00_HEART_PIECE,
};
EnTk_DigEff(this);
if (this->skelAnime.curFrame == 32.0f) {
/* What's gonna come out? */
Audio_PlayActorSound2(&this->actor, NA_SE_EV_DIG_UP);
this->rewardTimer = 0;
if (this->validDigHere == 1) {
rewardOrigin.x = 0.0f;
rewardOrigin.y = 0.0f;
rewardOrigin.z = -40.0f;
Matrix_RotateY(this->actor.shape.rot.y, MTXMODE_NEW);
Matrix_MultVec3f(&rewardOrigin, &rewardPos);
rewardPos.x += this->actor.world.pos.x;
rewardPos.y += this->actor.world.pos.y;
rewardPos.z += this->actor.world.pos.z;
this->currentReward = EnTk_ChooseReward(this);
if (this->currentReward == 3) {
/*
* Upgrade the purple rupee reward to the heart piece if this
* is the first grand prize dig.
*/
Gravedigging tour fix (#388) * Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
2022-06-16 20:36:13 -04:00
// If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true.
// Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true.
// If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag.
if (!heartPieceSpawned &&
(!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) ||
CVar_GetS32("gGravediggingTourFix", 0) &&
!Flags_GetCollectible(globalCtx, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) {
this->currentReward = 4;
Gravedigging tour fix (#388) * Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
2022-06-16 20:36:13 -04:00
gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE;
heartPieceSpawned = true;
}
}
Gravedigging tour fix (#388) * Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
2022-06-16 20:36:13 -04:00
EnItem00* reward = Item_DropCollectible(globalCtx, &rewardPos, rewardParams[this->currentReward]);
if (this->currentReward == 4) {
reward->collectibleFlag = COLLECTFLAG_GRAVEDIGGING_HEART_PIECE;
}
}
}
if (this->skelAnime.curFrame >= 32.0f && this->rewardTimer == 10) {
/* Play a reward sound shortly after digging */
if (this->validDigHere == 0) {
/* Bad dig spot */
Audio_PlayActorSound2(&this->actor, NA_SE_SY_ERROR);
} else if (this->currentReward == 4) {
/* Heart piece */
Audio_PlaySoundGeneral(NA_SE_SY_CORRECT_CHIME, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else {
/* Rupee */
Audio_PlayActorSound2(&this->actor, NA_SE_SY_TRE_BOX_APPEAR);
}
}
this->rewardTimer++;
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
if (this->currentReward < 0) {
/* "Nope, nothing here!" */
Message_StartTextbox(globalCtx, 0x501A, NULL);
} else {
Message_CloseTextbox(globalCtx);
}
EnTk_RestAnim(this, globalCtx);
this->currentReward = -1;
this->validDigHere = 0;
this->actionFunc = EnTk_Rest;
}
}
void EnTk_Update(Actor* thisx, GlobalContext* globalCtx) {
EnTk* this = (EnTk*)thisx;
s32 pad;
Collider_UpdateCylinder(&this->actor, &this->collider);
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
SkelAnime_Update(&this->skelAnime);
Actor_MoveForward(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 40.0f, 10.0f, 0.0f, 5);
this->actionFunc(this, globalCtx);
EnTkEff_Update(this);
EnTk_UpdateEyes(this);
}
void func_80B1D200(GlobalContext* globalCtx) {
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_tk.c", 1188);
gSPDisplayList(POLY_OPA_DISP++, gDampeShovelDL);
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_tk.c", 1190);
}
s32 EnTk_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) {
EnTk* this = (EnTk*)thisx;
switch (limbIndex) {
/* Limb 15 - Head */
case 15:
this->h_21E = rot->y;
break;
/* Limb 16 - Jaw */
case 16:
this->h_21E += rot->y;
rot->y += this->headRot;
break;
}
return false;
}
void EnTk_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
EnTk* this = (EnTk*)thisx;
Vec3f sp28 = { 0.0f, 0.0f, 4600.0f };
Vec3f sp1C = { 0.0f, 0.0f, 0.0f };
/* Limb 16 - Jaw */
if (limbIndex == 16) {
Matrix_MultVec3f(&sp1C, &this->actor.focus.pos);
}
/* Limb 14 - Neck */
if (limbIndex == 14) {
Matrix_MultVec3f(&sp28, &this->v3f_304);
func_80B1D200(globalCtx);
}
}
void EnTk_Draw(Actor* thisx, GlobalContext* globalCtx) {
static void* sEyesSegments[] = {
gDampeEyeOpenTex,
gDampeEyeHalfTex,
gDampeEyeClosedTex,
};
EnTk* this = (EnTk*)thisx;
Matrix_Push();
EnTkEff_Draw(this, globalCtx);
Matrix_Pop();
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_tk.c", 1294);
func_80093D18(globalCtx->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyesSegments[this->eyeTextureIdx]));
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
EnTk_OverrideLimbDraw, EnTk_PostLimbDraw, this);
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_tk.c", 1312);
}