Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documet bottle using actions #2360

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/z64player.h
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ typedef struct Player {
s16 csDelayTimer; // Player_Action_WaitForCutscene: Number of frames to wait before responding to a cutscene
s16 playedLandingSfx; // Player_Action_BlueWarpArrive: Played sfx when landing on the ground
s16 appearTimer; // Player_Action_FaroresWindArrive: Counts up, appear at 20 frames (1 second)
s16 drinkingState; // Player_Action_DrinkFromBottle: Uses values 0-2 to determine which part of the drinking action is currently active
Pepe20129 marked this conversation as resolved.
Show resolved Hide resolved
} av2; // "Action Variable 2": context dependent variable that has different meanings depending on what action is currently running

/* 0x0854 */ f32 unk_854;
Expand Down
100 changes: 62 additions & 38 deletions src/overlays/actors/ovl_player_actor/z_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ typedef struct ExplosiveInfo {
/* 0x02 */ s16 actorId;
} ExplosiveInfo; // size = 0x04

typedef struct BottleDropInfo {
/* 0x00 */ s16 actorId;
/* 0x02 */ s16 actorParams;
} BottleDropInfo; // size = 0x04

typedef struct FallImpactInfo {
/* 0x00 */ s8 damage;
/* 0x01 */ u8 rumbleStrength;
Expand Down Expand Up @@ -304,10 +299,10 @@ void Player_Action_8084E3C4(Player* this, PlayState* play);
void Player_Action_8084E604(Player* this, PlayState* play);
void Player_Action_8084E6D4(Player* this, PlayState* play);
void Player_Action_TimeTravelEnd(Player* this, PlayState* play);
void Player_Action_8084EAC0(Player* this, PlayState* play);
void Player_Action_DrinkFromBottle(Player* this, PlayState* play);
void Player_Action_SwingBottle(Player* this, PlayState* play);
void Player_Action_8084EED8(Player* this, PlayState* play);
void Player_Action_8084EFC0(Player* this, PlayState* play);
void Player_Action_UseFairyFromBottle(Player* this, PlayState* play);
void Player_Action_DropActorFromBottle(Player* this, PlayState* play);
void Player_Action_ExchangeItem(Player* this, PlayState* play);
void Player_Action_SlideOnSlope(Player* this, PlayState* play);
void Player_Action_WaitForCutscene(Player* this, PlayState* play);
Expand Down Expand Up @@ -6087,17 +6082,19 @@ s32 Player_ActionHandler_13(Player* this, PlayState* play) {
}

sp2C = Player_ActionToBottle(this, this->itemAction);
if (sp2C >= 0) {
if (sp2C == 0xC) {
Player_SetupActionPreserveItemAction(play, this, Player_Action_8084EED8, 0);
#define ACTION_TO_BOTTLE_ACTION(action) (action - PLAYER_IA_BOTTLE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really prefer if this define was at top-level instead of in the middle of a function. Maybe in z64player.h? Then it could be used in Player_ActionToBottle as well.

(PS: I'm not really sure what to do about these "sub-enums" like with Player_ActionToMagicSpell and Player_ActionToMeleeWeapon too. Maybe they deserve a separate enum? I think we can figure that out later though)

(PPS: maybe it should be called ACTION_TO_BOTTLE to match the function name?)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I would prefer to handle all these in a consistent manner at some point in the future. But if we want to introduce this now I guess we can change other examples of it later.

But there are so many of these id offset situations in player.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there are so many of these id offset situations in player.

yeah, I kinda think this is a bigger project and not too relevant to this PR (where the goal is just to name some action funcs). Could also revert ACTION_TO_BOTTLE_ACTION here to really punt on it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I moved it to z64player.h and used it in Player_ActionToBottle.
I think that either this or a PlayerBottle enum of some kind is needed since without it it's harder to understand how it chooses an action (sp2C >= ACTION_TO_BOTTLE(PLAYER_IA_BOTTLE_FISH) && sp2C <= ACTION_TO_BOTTLE(PLAYER_IA_BOTTLE_BUG) vs sp2C >= 1 && sp2C <= 3).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not saying that it isn't helpful, but rather that this pattern is a much larger thing that needs to be handled within player. And that it makes more sense to do it separately as a larger project.
I would prefer if it was taken out temporarily, with the understanding that this enum-range pattern will be handled in the future at a larger scale.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine keeping it as-is, I just meant I didn't want to spend too much time right now trying to get it right. I don't think it'll be hard to undo later if we wanted to, and it does make the code a little clearer now IMO

if (sp2C >= ACTION_TO_BOTTLE_ACTION(PLAYER_IA_BOTTLE)) {
if (sp2C == ACTION_TO_BOTTLE_ACTION(PLAYER_IA_BOTTLE_FAIRY)) {
Player_SetupActionPreserveItemAction(play, this, Player_Action_UseFairyFromBottle, 0);
Player_AnimPlayOnceAdjusted(play, this, &gPlayerAnim_link_bottle_bug_out);
func_80835EA4(play, 3);
} else if ((sp2C > 0) && (sp2C < 4)) {
Player_SetupActionPreserveItemAction(play, this, Player_Action_8084EFC0, 0);
} else if ((sp2C >= ACTION_TO_BOTTLE_ACTION(PLAYER_IA_BOTTLE_FISH)) &&
(sp2C <= ACTION_TO_BOTTLE_ACTION(PLAYER_IA_BOTTLE_BUG))) {
Player_SetupActionPreserveItemAction(play, this, Player_Action_DropActorFromBottle, 0);
Player_AnimPlayOnceAdjusted(play, this, &gPlayerAnim_link_bottle_fish_out);
func_80835EA4(play, (sp2C == 1) ? 1 : 5);
} else {
Player_SetupActionPreserveItemAction(play, this, Player_Action_8084EAC0, 0);
Player_SetupActionPreserveItemAction(play, this, Player_Action_DrinkFromBottle, 0);
Player_AnimChangeOnceMorphAdjusted(play, this, &gPlayerAnim_link_bottle_drink_demo_start);
func_80835EA4(play, 2);
}
Expand Down Expand Up @@ -13955,20 +13952,42 @@ void Player_Action_TimeTravelEnd(Player* this, PlayState* play) {
}
}

void Player_Action_8084EAC0(Player* this, PlayState* play) {
// Restores 14 hearts, is overriden by BOTTLE_CONTENT_DRINK_FLAG_HEALTH_SMALL
#define BOTTLE_CONTENT_DRINK_FLAG_HEALTH_BIG 0x01
// Fully restores magic
#define BOTTLE_CONTENT_DRINK_FLAG_MAGIC 0x02
// Restores 5 hearts, overrides BOTTLE_CONTENT_DRINK_FLAG_HEALTH_BIG
#define BOTTLE_CONTENT_DRINK_FLAG_HEALTH_SMALL 0x04

typedef enum DrinkingState {
/* 0 */ DRINGING_STATE_SETUP,
/* 1 */ DRINGING_STATE_DRINKING,
/* 2 */ DRINGING_STATE_FINISHED
} DrinkingState;

void Player_Action_DrinkFromBottle(Player* this, PlayState* play) {
// When an animation finishes (gPlayerAnim_link_bottle_drink_demo_start when drinkingState == DRINGING_STATE_SETUP,
// gPlayerAnim_link_bottle_drink_demo_end otherwise)
if (LinkAnimation_Update(play, &this->skelAnime)) {
if (this->av2.actionVar2 == 0) {
static u8 D_808549FC[] = {
0x01, 0x03, 0x02, 0x04, 0x04,
if (this->av2.drinkingState == DRINGING_STATE_SETUP) {
static u8 sBottleContentDrinkFlags[] = {
/* PLAYER_IA_BOTTLE_POTION_RED */ BOTTLE_CONTENT_DRINK_FLAG_HEALTH_BIG,
/* PLAYER_IA_BOTTLE_POTION_BLUE */ BOTTLE_CONTENT_DRINK_FLAG_HEALTH_BIG |
BOTTLE_CONTENT_DRINK_FLAG_MAGIC,
/* PLAYER_IA_BOTTLE_POTION_GREEN */ BOTTLE_CONTENT_DRINK_FLAG_MAGIC,
/* PLAYER_IA_BOTTLE_MILK_FULL */ BOTTLE_CONTENT_DRINK_FLAG_HEALTH_SMALL,
/* PLAYER_IA_BOTTLE_MILK_HALF */ BOTTLE_CONTENT_DRINK_FLAG_HEALTH_SMALL,
};

// Special handling for the poe bottle
if (this->itemAction == PLAYER_IA_BOTTLE_POE) {
s32 rand = Rand_S16Offset(-1, 3);

if (rand == 0) {
rand = 3;
}

// Prevents the drinking the poe from killing you
if ((rand < 0) && (gSaveContext.save.info.playerData.health <= 0x10)) {
rand = 3;
}
Expand All @@ -13979,35 +13998,35 @@ void Player_Action_8084EAC0(Player* this, PlayState* play) {
gSaveContext.healthAccumulator = rand * 0x10;
}
} else {
s32 sp28 = D_808549FC[this->itemAction - PLAYER_IA_BOTTLE_POTION_RED];
s32 flags = sBottleContentDrinkFlags[this->itemAction - PLAYER_IA_BOTTLE_POTION_RED];

if (sp28 & 1) {
if (flags & BOTTLE_CONTENT_DRINK_FLAG_HEALTH_BIG) {
gSaveContext.healthAccumulator = 0x140;
}

if (sp28 & 2) {
if (flags & BOTTLE_CONTENT_DRINK_FLAG_MAGIC) {
Magic_Fill(play);
}

if (sp28 & 4) {
if (flags & BOTTLE_CONTENT_DRINK_FLAG_HEALTH_SMALL) {
gSaveContext.healthAccumulator = 0x50;
}
}

Player_AnimPlayLoopAdjusted(play, this, &gPlayerAnim_link_bottle_drink_demo_wait);
this->av2.actionVar2 = 1;
this->av2.drinkingState = DRINGING_STATE_DRINKING;
} else {
func_8083C0E8(this, play);
Camera_SetFinishedFlag(Play_GetCamera(play, CAM_ID_MAIN));
}
} else if (this->av2.actionVar2 == 1) {
} else if (this->av2.drinkingState == DRINGING_STATE_DRINKING) {
if ((gSaveContext.healthAccumulator == 0) && (gSaveContext.magicState != MAGIC_STATE_FILL)) {
Player_AnimChangeOnceMorphAdjusted(play, this, &gPlayerAnim_link_bottle_drink_demo_end);
this->av2.actionVar2 = 2;
this->av2.drinkingState = DRINGING_STATE_FINISHED;
Player_UpdateBottleHeld(play, this, ITEM_BOTTLE_EMPTY, PLAYER_IA_BOTTLE);
}
Player_PlayVoiceSfx(this, NA_SE_VO_LI_DRINK - SFX_FLAG);
} else if ((this->av2.actionVar2 == 2) && LinkAnimation_OnFrame(&this->skelAnime, 29.0f)) {
} else if ((this->av2.drinkingState == DRINGING_STATE_FINISHED) && LinkAnimation_OnFrame(&this->skelAnime, 29.0f)) {
Player_PlayVoiceSfx(this, NA_SE_VO_LI_BREATH_DRINK);
}
}
Expand Down Expand Up @@ -14101,17 +14120,17 @@ void Player_Action_SwingBottle(Player* this, PlayState* play) {
}
}

static Vec3f D_80854A1C = { 0.0f, 0.0f, 5.0f };
static Vec3f sBottleFairyPositionOffset = { 0.0f, 0.0f, 5.0f };

void Player_Action_8084EED8(Player* this, PlayState* play) {
void Player_Action_UseFairyFromBottle(Player* this, PlayState* play) {
if (LinkAnimation_Update(play, &this->skelAnime)) {
func_8083C0E8(this, play);
Camera_SetFinishedFlag(Play_GetCamera(play, CAM_ID_MAIN));
return;
}

if (LinkAnimation_OnFrame(&this->skelAnime, 37.0f)) {
Player_SpawnFairy(play, this, &this->leftHandPos, &D_80854A1C, FAIRY_REVIVE_BOTTLE);
Player_SpawnFairy(play, this, &this->leftHandPos, &sBottleFairyPositionOffset, FAIRY_REVIVE_BOTTLE);
Player_UpdateBottleHeld(play, this, ITEM_BOTTLE_EMPTY, PLAYER_IA_BOTTLE);
Player_PlaySfx(this, NA_SE_EV_BOTTLE_CAP_OPEN);
Player_PlaySfx(this, NA_SE_EV_FIATY_HEAL - SFX_FLAG);
Expand All @@ -14120,25 +14139,30 @@ void Player_Action_8084EED8(Player* this, PlayState* play) {
}
}

static BottleDropInfo D_80854A28[] = {
{ ACTOR_EN_FISH, FISH_DROPPED },
{ ACTOR_EN_ICE_HONO, 0 },
{ ACTOR_EN_INSECT, INSECT_TYPE_FIRST_DROPPED },
typedef struct BottleDropInfo {
/* 0x00 */ s16 actorId;
/* 0x02 */ s16 actorParams;
} BottleDropInfo; // size = 0x04

static BottleDropInfo sBottleDropInfos[] = {
/* PLAYER_IA_BOTTLE_FISH */ { ACTOR_EN_FISH, FISH_DROPPED },
/* PLAYER_IA_BOTTLE_FIRE */ { ACTOR_EN_ICE_HONO, 0 },
/* PLAYER_IA_BOTTLE_BUG */ { ACTOR_EN_INSECT, INSECT_TYPE_FIRST_DROPPED },
};

static AnimSfxEntry D_80854A34[] = {
static AnimSfxEntry sBottleDropAnimSfx[] = {
{ NA_SE_VO_LI_AUTO_JUMP, ANIMSFX_DATA(ANIMSFX_TYPE_VOICE, 38) },
{ NA_SE_EV_BOTTLE_CAP_OPEN, -ANIMSFX_DATA(ANIMSFX_TYPE_GENERAL, 40) },
};

void Player_Action_8084EFC0(Player* this, PlayState* play) {
void Player_Action_DropActorFromBottle(Player* this, PlayState* play) {
Player_DecelerateToZero(this);

if (LinkAnimation_Update(play, &this->skelAnime)) {
func_8083C0E8(this, play);
Camera_SetFinishedFlag(Play_GetCamera(play, CAM_ID_MAIN));
} else if (LinkAnimation_OnFrame(&this->skelAnime, 76.0f)) {
BottleDropInfo* dropInfo = &D_80854A28[this->itemAction - PLAYER_IA_BOTTLE_FISH];
BottleDropInfo* dropInfo = &sBottleDropInfos[this->itemAction - PLAYER_IA_BOTTLE_FISH];

Actor_Spawn(&play->actorCtx, play, dropInfo->actorId,
(Math_SinS(this->actor.shape.rot.y) * 5.0f) + this->leftHandPos.x, this->leftHandPos.y,
Expand All @@ -14147,7 +14171,7 @@ void Player_Action_8084EFC0(Player* this, PlayState* play) {

Player_UpdateBottleHeld(play, this, ITEM_BOTTLE_EMPTY, PLAYER_IA_BOTTLE);
} else {
Player_ProcessAnimSfxList(this, D_80854A34);
Player_ProcessAnimSfxList(this, sBottleDropAnimSfx);
}
}

Expand Down Expand Up @@ -16047,7 +16071,7 @@ void Player_Action_CsAction(Player* this, PlayState* play) {
int Player_IsDroppingFish(PlayState* play) {
Player* this = GET_PLAYER(play);

return (Player_Action_8084EFC0 == this->actionFunc) && (this->itemAction == PLAYER_IA_BOTTLE_FISH);
return (Player_Action_DropActorFromBottle == this->actionFunc) && (this->itemAction == PLAYER_IA_BOTTLE_FISH);
}

s32 Player_StartFishing(PlayState* play) {
Expand Down