summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Hensley <hensley.derek58@gmail.com>2021-07-28 19:26:40 -0700
committerGitHub <noreply@github.com>2021-07-28 22:26:40 -0400
commit8e2f2b4cdb2b0ea7cc3588710ddb0a71f13eb4d9 (patch)
tree4fa26cc9f21163d58b06dba0186c57de41423279
parentb292647ea29e321649dbb9e52275f345157b16e8 (diff)
ovl en sob1 OK and Documented (#224)
* All but two match * format * Matched the last two functions * Merge updates * Bring data over as a comment * Brought data over * Cleanup and start documenting * Documented * Removed NON_MATCHING define * Actually save the .h file * Format and add items comment * Add comment * Add header to .c file * Cleanup * Rename EnSob1_GetGoodbyeBombShop * Update items comment * Final cleanup * Rename InitialUpdate * PR suggestions except enum for objIndices * Add todo about objIndices index enum * Change char to UNK_TYPE1 for padding * Textures and convert weekEvents to hex * PR suggestions * Format * Cleanup function declaration and add cutscene state enum * Update src/overlays/actors/ovl_En_Sob1/z_en_sob1.c Co-authored-by: Kenix3 <kenixwhisperwind@gmail.com> * Update src/overlays/actors/ovl_En_Sob1/z_en_sob1.c Co-authored-by: Kenix3 <kenixwhisperwind@gmail.com> * Update src/overlays/actors/ovl_En_Sob1/z_en_sob1.c Co-authored-by: Kenix3 <kenixwhisperwind@gmail.com> Co-authored-by: Derek Hensley <d.hensley@tempered.io> Co-authored-by: Kenix3 <kenixwhisperwind@gmail.com>
-rw-r--r--include/z64object.h3
-rw-r--r--linker_scripts/code_script.txt5
-rw-r--r--linker_scripts/object_script.txt15
-rw-r--r--src/overlays/actors/ovl_En_In/z_en_in.h2
-rw-r--r--src/overlays/actors/ovl_En_Sob1/z_en_sob1.c1817
-rw-r--r--src/overlays/actors/ovl_En_Sob1/z_en_sob1.h80
-rw-r--r--tables/functions.txt146
-rw-r--r--tables/variables.txt40
8 files changed, 1864 insertions, 244 deletions
diff --git a/include/z64object.h b/include/z64object.h
index 659548b11..920a9e5dd 100644
--- a/include/z64object.h
+++ b/include/z64object.h
@@ -651,7 +651,8 @@ typedef enum {
/* 0x27F */ OBJECT_LBFSHOT,
/* 0x280 */ OBJECT_FUSEN,
/* 0x281 */ OBJECT_ENDING_OBJ,
- /* 0x282 */ OBJECT_GI_MASK13
+ /* 0x282 */ OBJECT_GI_MASK13,
+ /* 0x283 */ OBJECT_ID_MAX
} ObjectID;
#endif
diff --git a/linker_scripts/code_script.txt b/linker_scripts/code_script.txt
index a28bb887d..99936f851 100644
--- a/linker_scripts/code_script.txt
+++ b/linker_scripts/code_script.txt
@@ -4142,10 +4142,9 @@ SECTIONS
ovl_En_Sob1 : AT(RomLocation)
{
build/src/overlays/actors/ovl_En_Sob1/z_en_sob1.o(.text)
- build/asm/overlays/ovl_En_Sob1_data.o(.data)
+ build/src/overlays/actors/ovl_En_Sob1/z_en_sob1.o(.data)
build/src/overlays/actors/ovl_En_Sob1/z_en_sob1.o(.rodata)
- build/asm/overlays/ovl_En_Sob1_rodata.o(.rodata)
- build/asm/overlays/ovl_En_Sob1_late_rodata.o(.rodata)
+ build/src/overlays/actors/ovl_En_Sob1/z_en_sob1_overlay.o(.ovl)
}
SegmentEnd = .;
SegmentSize = SegmentEnd - SegmentStart;
diff --git a/linker_scripts/object_script.txt b/linker_scripts/object_script.txt
index 37de76346..2e12e7e8b 100644
--- a/linker_scripts/object_script.txt
+++ b/linker_scripts/object_script.txt
@@ -640,6 +640,21 @@ D_06002C8C = 0x06002C8C;
D_060000B4 = 0x060000B4;
D_06002BF0 = 0x06002BF0;
+/* z_en_sob1 */
+D_06008268 = 0x06008268;
+D_0600D208 = 0x0600D208;
+D_0600078C = 0x0600078C;
+D_06011AC8 = 0x06011AC8;
+D_060000FC = 0x060000FC;
+D_06000970 = 0x06000970;
+D_060087BC = 0x060087BC;
+D_060050A0 = 0x060050A0;
+D_060058A0 = 0x060058A0;
+D_060060A0 = 0x060060A0;
+D_06010438 = 0x06010438;
+D_06010C38 = 0x06010C38;
+D_06011038 = 0x06011038;
+
/* z_en_suttari */
D_0600C240 = 0x0600C240;
D_0600071C = 0x0600071C;
diff --git a/src/overlays/actors/ovl_En_In/z_en_in.h b/src/overlays/actors/ovl_En_In/z_en_in.h
index 78c3b9340..f4b1ef378 100644
--- a/src/overlays/actors/ovl_En_In/z_en_in.h
+++ b/src/overlays/actors/ovl_En_In/z_en_in.h
@@ -28,7 +28,7 @@ typedef struct EnIn {
/* 0x238 */ char unk238[0x4];
/* 0x23C */ u8 unk23C;
/* 0x23D */ u8 unk23D;
- /* 0x240 */ Path *path;
+ /* 0x240 */ Path* path;
/* 0x244 */ s16 unk244;
/* 0x248 */ Vec3f unk248;
/* 0x254 */ Vec3f unk254;
diff --git a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c
index 5a0712acd..def543b52 100644
--- a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c
+++ b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c
@@ -1,3 +1,9 @@
+/*
+ * File: z_en_sob1.c
+ * Overlay: ovl_En_Sob1
+ * Description: Shops (Zora, Goron, and Bomb)
+ */
+
#include "z_en_sob1.h"
#define FLAGS 0x00000019
@@ -8,7 +14,66 @@ void EnSob1_Init(Actor* thisx, GlobalContext* globalCtx);
void EnSob1_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnSob1_Update(Actor* thisx, GlobalContext* globalCtx);
-#if 0
+void EnSob1_DrawZoraShopkeeper(Actor* thisx, GlobalContext* globalCtx);
+void EnSob1_DrawGoronShopkeeper(Actor* thisx, GlobalContext* globalCtx);
+void EnSob1_DrawBombShopkeeper(Actor* thisx, GlobalContext* globalCtx);
+
+void EnSob1_InitZoraShopkeeper(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_InitGoronShopkeeper(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_InitBombShopkeeper(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_InitShop(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_Idle(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_Walk(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_Walking(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_Hello(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_StartShopping(GlobalContext* globalCtx, EnSob1* this);
+void EnSob1_SetupIdle(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_FaceShopkeeper(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_LookToShelf(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_EndingInteraction(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_BrowseShelf(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_TalkingToShopkeeper(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_SelectItem(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_LookToShopkeeperFromShelf(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_BuyItemWithFanfare(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_CanBuy(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_CannotBuy(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_SetupItemPurchased(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_ContinueShopping(EnSob1* this, GlobalContext* globalCtx);
+void EnSob1_ResetItemPosition(EnSob1* this);
+
+void EnSob1_Blink(EnSob1* this);
+
+s32 EnSob1_TakeItemOffShelf(EnSob1* this);
+s32 EnSob1_ReturnItemToShelf(EnSob1* this);
+s16 EnSob1_GetXZAngleAndDistanceSqToPoint(Path* path, s32 pointIdx, Vec3f* pos, f32* distSq);
+
+extern UNK_TYPE D_0401F740;
+extern UNK_TYPE D_0401F8C0;
+extern UNK_TYPE D_0401F7C0;
+extern AnimationHeader D_06009120;
+extern AnimationHeader D_06008268;
+extern FlexSkeletonHeader D_0600D208;
+extern AnimationHeader D_0600078C;
+extern AnimationHeader D_060087BC;
+extern FlexSkeletonHeader D_06011AC8;
+extern AnimationHeader D_060000FC;
+extern FlexSkeletonHeader D_06009220;
+extern Gfx D_06000970[];
+extern UNK_TYPE D_06005458;
+extern TexturePtr D_060050A0;
+extern TexturePtr D_060058A0;
+extern TexturePtr D_060060A0;
+extern TexturePtr D_06010438;
+extern TexturePtr D_06010C38;
+extern TexturePtr D_06011038;
+
+static ActorAnimationEntryS sAnimationsBombShopkeeper[] = {
+ { &D_06009120, 2.0f, 0, -1, 0, 20 },
+ { &D_06008268, 1.0f, 0, -1, 2, 0 },
+ { &D_060087BC, 1.0f, 0, -1, 0, 0 },
+};
+
const ActorInit En_Sob1_InitVars = {
ACTOR_EN_OSSAN,
ACTORCAT_NPC,
@@ -21,164 +86,1626 @@ const ActorInit En_Sob1_InitVars = {
(ActorFunc)NULL,
};
-
-// static InitChainEntry sInitChain[] = {
-static InitChainEntry D_80A109E8[] = {
- ICHAIN_F32(targetArrowOffset, 500, ICHAIN_STOP),
+static s16 sObjectIds[][3] = {
+ { OBJECT_ZO, OBJECT_ID_MAX, OBJECT_MASTERZOORA },
+ { OBJECT_OF1D_MAP, OBJECT_ID_MAX, OBJECT_MASTERGOLON },
+ { OBJECT_RS, OBJECT_ID_MAX, OBJECT_ID_MAX },
+ { OBJECT_OF1D_MAP, OBJECT_ID_MAX, OBJECT_MASTERGOLON },
};
+static u16 sFacingShopkeeperTextIds[] = { 0x12D6, 0x0BC0, 0x0640, 0x0BC0 };
-extern InitChainEntry D_80A109E8[];
-#endif
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0C810.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0C8AC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0C8B8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0C938.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0CA38.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0CC88.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0CCEC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0CD48.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0CE10.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/EnSob1_Init.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/EnSob1_Destroy.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D034.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D0B8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D188.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D1F4.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D258.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D2B8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D320.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D388.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D3C4.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D414.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D4A0.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D628.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D74C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D77C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D850.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0D904.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DA5C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DAAC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DB78.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DCC4.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DD40.asm")
+static u16 sNoRoomTextIds[] = { 0x12E3, 0x0BD3, 0x0641, 0x0BD3 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DE64.asm")
+static u16 sBuySuccessTextIds[] = { 0x12E6, 0x0BD6, 0x0647, 0x0BD6 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0DFD0.asm")
+static u16 sCannotGetNowTextIds[] = { 0x12E1, 0x0BD2, 0x0645, 0x0BD2 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E0C0.asm")
+static u16 sNeedRupeesTextIds[] = { 0x12E5, 0x0BD5, 0x0646, 0x0BD5 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E1B8.asm")
+static u16 sNeedEmptyBottleTextIds[] = { 0x12E4, 0x0BD4, 0x0645, 0x0BD4 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E258.asm")
+static u16 sCannotGetNow2TextIds[] = { 0x12E1, 0x0BD1, 0x0641, 0x0BD1 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E330.asm")
+static u16 sNoRoom2TextIds[] = { 0x12E3, 0x0BD3, 0x0641, 0x0BD3 };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E420.asm")
+static f32 sActorScales[] = { 0.01f, 0.01f, 0.01f, 0.01f };
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E4DC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E518.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E554.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E884.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E96C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0E9E0.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EA84.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EAF8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EBC0.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EC98.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0ED7C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EDA0.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EE3C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EEC8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0EF48.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F014.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F1C4.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F284.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F2C8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F2FC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F39C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F3D4.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F470.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F554.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F638.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0F6B0.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/EnSob1_Update.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0FADC.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0FD4C.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A0FEE8.asm")
-
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A10290.asm")
+static ShopItem sShops[][3] = {
+ {
+ { SI_POTION_RED_4, { 1258, 42, 325 } },
+ { SI_ARROWS_SMALL_1, { 1240, 42, 325 } },
+ { SI_SHIELD_HERO_3, { 1222, 42, 325 } },
+ },
+ {
+ { SI_POTION_RED_5, { -57, 42, -62 } },
+ { SI_ARROWS_SMALL_2, { -75, 42, -62 } },
+ { SI_BOMB_2, { -93, 42, -62 } },
+ },
+ {
+ { SI_BOMB_BAG_20_2, { 221, -7, 73 } },
+ { SI_BOMBCHU, { 203, -7, 69 } },
+ { SI_BOMB_1, { 185, -7, 65 } },
+ },
+ {
+ { SI_POTION_RED_6, { -57, 42, -62 } },
+ { SI_ARROWS_SMALL_3, { -75, 42, -62 } },
+ { SI_BOMB_3, { -93, 42, -62 } },
+ },
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A102C8.asm")
+static EnSob1XZRange sPosXZRanges[] = {
+ { 1170.0f, 1230.0f, 360.0f, 380.0f },
+ { -142.0f, -72.0f, -20.0f, 0.0f },
+ { 138.0f, 200.0f, 72.0f, 160.0f },
+ { -142.0f, -72.0f, -20.0f, 0.0f },
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A10308.asm")
+static Vec3f sSelectedItemPositions[] = {
+ { 1240.0f, 45.0f, 349.0f },
+ { -75.0f, 45.0f, -38.0f },
+ { 197.0f, -4.0f, 93.0f },
+ { -75.0f, 45.0f, -38.0f },
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A10344.asm")
+static InitChainEntry sInitChain[] = {
+ ICHAIN_F32(targetArrowOffset, 500, ICHAIN_STOP),
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A10368.asm")
+static EnSob1ActionFunc sInitFuncs[] = {
+ EnSob1_InitZoraShopkeeper,
+ EnSob1_InitGoronShopkeeper,
+ EnSob1_InitBombShopkeeper,
+ EnSob1_InitGoronShopkeeper,
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A104E4.asm")
+extern Vec3f sPosOffset[] = {
+ { 0.0f, 0.0f, 0.0f },
+ { 0.0f, -4.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f },
+ { 0.0f, -4.0f, 0.0f },
+};
-#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Sob1_0x80A0C810/func_80A10608.asm")
+void EnSob1_ChangeAnim(SkelAnime* skelAnime, ActorAnimationEntryS* animations, s32 idx) {
+ f32 frameCount;
+
+ animations += idx;
+ if (animations->frameCount < 0) {
+ frameCount = SkelAnime_GetFrameCount(&animations->animationSeg->common);
+ } else {
+ frameCount = animations->frameCount;
+ }
+ SkelAnime_ChangeAnim(skelAnime, animations->animationSeg, animations->playbackSpeed, animations->frame, frameCount,
+ animations->mode, animations->transitionRate);
+}
+
+void EnSob1_SetupAction(EnSob1* this, EnSob1ActionFunc action) {
+ this->actionFunc = action;
+}
+
+s32 EnSob1_TestItemSelected(GlobalContext* globalCtx) {
+ MessageContext* msgCtx = &globalCtx->msgCtx;
+
+ if (msgCtx->unk12020 == 0x10 || msgCtx->unk12020 == 0x11) {
+ return CHECK_BTN_ALL(CONTROLLER1(globalCtx)->press.button, BTN_A);
+ }
+ return CHECK_BTN_ALL(CONTROLLER1(globalCtx)->press.button, BTN_A) ||
+ CHECK_BTN_ALL(CONTROLLER1(globalCtx)->press.button, BTN_B) ||
+ CHECK_BTN_ALL(CONTROLLER1(globalCtx)->press.button, BTN_CUP);
+}
+
+u16 EnSob1_GetTalkOption(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ if (this->shopType == BOMB_SHOP) {
+ if (gSaveContext.day == 1 && gSaveContext.time >= CLOCK_TIME(6, 00)) {
+ return 0x648;
+ } else if (gSaveContext.weekEventReg[0x21] & 8) {
+ return 0x649;
+ } else {
+ return 0x64A;
+ }
+ } else if (this->shopType == ZORA_SHOP) {
+ switch (player->transformation) {
+ case PLAYER_FORM_DEKU:
+ return 0x12D8;
+ case PLAYER_FORM_GORON:
+ return 0x12D9;
+ case PLAYER_FORM_ZORA:
+ return 0x12DA;
+ default:
+ return 0x12D7;
+ }
+ } else if (this->shopType == GORON_SHOP) {
+ if (player->transformation != PLAYER_FORM_GORON) {
+ return 0xBC1;
+ }
+ return 0xBC2;
+ } else if (this->shopType == GORON_SHOP_SPRING) {
+ if (player->transformation != PLAYER_FORM_GORON) {
+ return 0xBC3;
+ }
+ return 0xBC4;
+ }
+ return 0;
+}
+
+u16 EnSob1_GetWelcome(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ if (this->shopType == BOMB_SHOP) {
+ switch (Player_GetMask(globalCtx)) {
+ case PLAYER_MASK_NONE:
+ case PLAYER_MASK_BUNNY_HOOD:
+ case PLAYER_MASK_POSTMANS_HAT:
+ return 0x644;
+ case PLAYER_MASK_GORON_MASK:
+ case PLAYER_MASK_ZORA_MASK:
+ case PLAYER_MASK_DEKU_MASK:
+ return 0x64B;
+ case PLAYER_MASK_MASK_OF_TRUTH:
+ case PLAYER_MASK_ALL_NIGHT_MASK:
+ case PLAYER_MASK_KEATON_MASK:
+ case PLAYER_MASK_ROMANIS_MASK:
+ case PLAYER_MASK_GREAT_FAIRYS_MASK:
+ case PLAYER_MASK_DON_GEROS_MASK:
+ case PLAYER_MASK_KAMAROS_MASK:
+ case PLAYER_MASK_BREMEN_MASK:
+ case PLAYER_MASK_MASK_OF_SCENTS:
+ return 0x685;
+ case PLAYER_MASK_GAROS_MASK:
+ case PLAYER_MASK_CIRCUS_LEADERS_MASK:
+ case PLAYER_MASK_GIBDO_MASK:
+ case PLAYER_MASK_CAPTAINS_HAT:
+ return 0x686;
+ case PLAYER_MASK_COUPLES_MASK:
+ return 0x687;
+ case PLAYER_MASK_STONE_MASK:
+ return 0x688;
+ case PLAYER_MASK_BLAST_MASK:
+ return 0x689;
+ case PLAYER_MASK_KAFEIS_MASK:
+ return 0x68A;
+ }
+ } else if (this->shopType == ZORA_SHOP) {
+ switch (player->transformation) {
+ case PLAYER_FORM_HUMAN:
+ if (gSaveContext.weekEventReg[0x39] & 0x10) {
+ return 0x12CF;
+ }
+ gSaveContext.weekEventReg[0x39] |= 0x10;
+ return 0x12CE;
+ case PLAYER_FORM_DEKU:
+ if (gSaveContext.weekEventReg[0x39] & 0x20) {
+ return 0x12D1;
+ }
+ gSaveContext.weekEventReg[0x39] |= 0x20;
+ return 0x12D0;
+ case PLAYER_FORM_GORON:
+ if (gSaveContext.weekEventReg[0x39] & 0x40) {
+ return 0x12D3;
+ }
+ gSaveContext.weekEventReg[0x39] |= 0x40;
+ return 0x12D2;
+ case PLAYER_FORM_ZORA:
+ if (gSaveContext.weekEventReg[0x39] & 0x80) {
+ return 0x12D5;
+ }
+ gSaveContext.weekEventReg[0x39] |= 0x80;
+ return 0x12D4;
+ default:
+ return 0x12CE;
+ }
+ } else if (this->shopType == GORON_SHOP) {
+ if (player->transformation != PLAYER_FORM_GORON) {
+ if (gSaveContext.weekEventReg[0x3A] & 4) {
+ return 0xBB9;
+ }
+ gSaveContext.weekEventReg[0x3A] |= 4;
+ return 0xBB8;
+ } else {
+ if (gSaveContext.weekEventReg[0x3A] & 8) {
+ return 0xBBB;
+ }
+ gSaveContext.weekEventReg[0x3A] |= 8;
+ return 0xBBA;
+ }
+ } else if (this->shopType == GORON_SHOP_SPRING) {
+ if (player->transformation != PLAYER_FORM_GORON) {
+ if (gSaveContext.weekEventReg[0x3A] & 0x10) {
+ return 0xBBD;
+ }
+ gSaveContext.weekEventReg[0x3A] |= 0x10;
+ return 0xBBC;
+ } else {
+ if (gSaveContext.weekEventReg[0x3A] & 0x20) {
+ return 0xBBF;
+ }
+ gSaveContext.weekEventReg[0x3A] |= 0x20;
+ return 0xBBE;
+ }
+ }
+ return 0;
+}
+
+u16 EnSob1_GetGoodbye(EnSob1* this) {
+ if (this->shopType == BOMB_SHOP) {
+ if (gSaveContext.day == 1) {
+ return 0x64C;
+ } else if (gSaveContext.day == 2) {
+ return 0x64D;
+ } else if (!gSaveContext.isNight) {
+ return 0x64E;
+ } else {
+ return 0x64F;
+ }
+ }
+ return 0x64C;
+}
+
+void EnSob1_EndInteractionBombShop(EnSob1* this, GlobalContext* globalCtx) {
+ this->drawCursor = 0;
+ this->stickLeftPrompt.isEnabled = false;
+ this->stickRightPrompt.isEnabled = false;
+ this->goodbyeTextId = EnSob1_GetGoodbye(this);
+ func_801518B0(globalCtx, this->goodbyeTextId, &this->actor);
+ EnSob1_SetupAction(this, EnSob1_EndingInteraction);
+}
+
+void EnSob1_SpawnShopItems(EnSob1* this, GlobalContext* globalCtx, ShopItem* shopItem) {
+ s32 i;
+
+ for (i = 0; i < ARRAY_COUNT(this->items); i++, shopItem++) {
+ if (shopItem->shopItemId < 0) {
+ this->items[i] = NULL;
+ } else {
+ this->items[i] =
+ (EnGirlA*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_GIRLA, shopItem->spawnPos.x,
+ shopItem->spawnPos.y, shopItem->spawnPos.z, 0, 0, 0, shopItem->shopItemId);
+ }
+ }
+}
+
+s32 EnSob1_GetObjIndices(EnSob1* this, GlobalContext* globalCtx, s16* objIds) {
+ if (objIds[1] != OBJECT_ID_MAX) {
+ this->objIndices[1] = Object_GetIndex(&globalCtx->objectCtx, objIds[1]);
+ if (this->objIndices[1] < 0) {
+ return false;
+ }
+ } else {
+ this->objIndices[1] = -1;
+ }
+ if (objIds[2] != OBJECT_ID_MAX) {
+ this->objIndices[2] = Object_GetIndex(&globalCtx->objectCtx, objIds[2]);
+ if (this->objIndices[2] < 0) {
+ return false;
+ }
+ } else {
+ this->objIndices[2] = -1;
+ }
+ return true;
+}
+
+void EnSob1_Init(Actor* thisx, GlobalContext* globalCtx) {
+ EnSob1* this = THIS;
+ s32 pad;
+ s16* objIds;
+
+ switch (ENSOB1_GET_SHOPTYPE(thisx)) {
+ case ZORA_SHOP:
+ this->shopType = ZORA_SHOP;
+ break;
+ case GORON_SHOP:
+ if (gSaveContext.weekEventReg[0x21] & 0x80) {
+ this->shopType = GORON_SHOP_SPRING;
+ } else {
+ this->shopType = GORON_SHOP;
+ }
+ break;
+ case BOMB_SHOP:
+ this->shopType = BOMB_SHOP;
+ break;
+ default:
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+
+ objIds = sObjectIds[this->shopType];
+ this->objIndices[0] = Object_GetIndex(&globalCtx->objectCtx, objIds[0]);
+ if (this->objIndices[0] < 0) {
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+ if (!EnSob1_GetObjIndices(this, globalCtx, objIds)) {
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+ Actor_ProcessInitChain(&this->actor, sInitChain);
+ EnSob1_SetupAction(this, EnSob1_InitShop);
+}
+
+void EnSob1_Destroy(Actor* thisx, GlobalContext* globalCtx) {
+ EnSob1* this = THIS;
+
+ Collider_DestroyCylinder(globalCtx, &this->collider);
+}
+
+void EnSob1_UpdateCursorPos(GlobalContext* globalCtx, EnSob1* this) {
+ s16 x;
+ s16 y;
+ f32 xOffset = 0.0f;
+ f32 yOffset = 17.0f;
+
+ func_800B8898(globalCtx, &this->items[this->cursorIdx]->actor, &x, &y);
+ this->cursorX = x + xOffset;
+ this->cursorY = y + yOffset;
+ this->cursorZ = 1.2f;
+}
+
+void EnSob1_EndInteraction(GlobalContext* globalCtx, EnSob1* this) {
+ Player* player = PLAYER;
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_PLAYING) {
+ ActorCutscene_Stop(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_STOPPED;
+ }
+ func_800B84D0(&this->actor, globalCtx);
+ globalCtx->msgCtx.unk11F22 = 0x43;
+ globalCtx->msgCtx.unk12023 = 4;
+ Interface_ChangeAlpha(50);
+ this->drawCursor = 0;
+ this->stickLeftPrompt.isEnabled = false;
+ this->stickRightPrompt.isEnabled = false;
+ player->stateFlags2 &= ~0x20000000;
+ globalCtx->interfaceCtx.unk_222 = 0;
+ globalCtx->interfaceCtx.unk_224 = 0;
+ EnSob1_SetupAction(this, EnSob1_Idle);
+}
+
+s32 EnSob1_TestEndInteraction(EnSob1* this, GlobalContext* globalCtx, Input* input) {
+ if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
+ if (this->shopType == BOMB_SHOP) {
+ EnSob1_EndInteractionBombShop(this, globalCtx);
+ } else {
+ EnSob1_EndInteraction(globalCtx, this);
+ }
+ return true;
+ }
+ return false;
+}
+
+s32 EnSob1_TestCancelOption(EnSob1* this, GlobalContext* globalCtx, Input* input) {
+ if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
+ this->actionFunc = this->tmpActionFunc;
+ func_80151938(globalCtx, this->items[this->cursorIdx]->actor.textId);
+ return true;
+ }
+ return false;
+}
+
+void EnSob1_SetupStartShopping(GlobalContext* globalCtx, EnSob1* this, u8 skipHello) {
+ func_8011552C(globalCtx, 16);
+ if (!skipHello) {
+ EnSob1_SetupAction(this, EnSob1_Hello);
+ } else {
+ EnSob1_StartShopping(globalCtx, this);
+ }
+}
+
+void EnSob1_StartShopping(GlobalContext* globalCtx, EnSob1* this) {
+ EnSob1_SetupAction(this, EnSob1_FaceShopkeeper);
+ func_80151938(globalCtx, sFacingShopkeeperTextIds[this->shopType]);
+ func_8011552C(globalCtx, 6);
+ this->stickLeftPrompt.isEnabled = false;
+ this->stickRightPrompt.isEnabled = true;
+}
+
+void EnSob1_TalkToShopkeeper(GlobalContext* globalCtx, EnSob1* this) {
+ EnSob1_SetupAction(this, EnSob1_TalkingToShopkeeper);
+ this->talkOptionTextId = EnSob1_GetTalkOption(this, globalCtx);
+ func_80151938(globalCtx, this->talkOptionTextId);
+ func_8011552C(globalCtx, 6);
+ this->stickLeftPrompt.isEnabled = false;
+ this->stickRightPrompt.isEnabled = false;
+}
+
+void EnSob1_SetupLookToShopkeeperFromShelf(GlobalContext* globalCtx, EnSob1* this) {
+ play_sound(NA_SE_SY_CURSOR);
+ this->drawCursor = 0;
+ EnSob1_SetupAction(this, EnSob1_LookToShopkeeperFromShelf);
+}
+
+void EnSob1_EndingInteraction(EnSob1* this, GlobalContext* globalCtx) {
+ if (func_80152498(&globalCtx->msgCtx) == 6 && func_80147624(globalCtx)) {
+ EnSob1_EndInteraction(globalCtx, this);
+ }
+}
+
+void EnSob1_SetupWalk(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ if ((player->actor.world.pos.x >= 0.0f && player->actor.world.pos.x <= 390.0f) &&
+ (player->actor.world.pos.z >= 72.0f && player->actor.world.pos.z <= 365.0f)) {
+ EnSob1_SetupAction(this, EnSob1_Walk);
+ }
+}
+
+void EnSob1_Idle(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ this->headRotTarget = this->actor.yawTowardsPlayer - this->actor.shape.rot.y;
+ if (func_800B84D0(&this->actor, globalCtx)) {
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookFowardCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_WAITING;
+ }
+ player->stateFlags2 |= 0x20000000;
+ this->welcomeTextId = EnSob1_GetWelcome(this, globalCtx);
+ func_801518B0(globalCtx, this->welcomeTextId, &this->actor);
+ if (ENSOB1_GET_SHOPTYPE(&this->actor) == BOMB_SHOP) {
+ this->headRotTarget = -0x2000;
+ }
+ EnSob1_SetupStartShopping(globalCtx, this, false);
+ } else {
+ if ((player->actor.world.pos.x >= this->posXZRange.xMin &&
+ player->actor.world.pos.x <= this->posXZRange.xMax) &&
+ (player->actor.world.pos.z >= this->posXZRange.zMin &&
+ player->actor.world.pos.z <= this->posXZRange.zMax)) {
+ func_800B8614(&this->actor, globalCtx, 400.0f);
+ }
+ if (this->wasTalkedToWhileWalking == true) {
+ this->wasTalkedToWhileWalking = false;
+ EnSob1_SetupStartShopping(globalCtx, this, false);
+ }
+ }
+}
+
+void EnSob1_UpdateJoystickInputState(GlobalContext* globalCtx, EnSob1* this) {
+ s8 stickX = CONTROLLER1(globalCtx)->rel.stick_x;
+ s8 stickY = CONTROLLER1(globalCtx)->rel.stick_y;
+
+ if (this->stickAccumX == 0) {
+ if (stickX > 30 || stickX < -30) {
+ this->stickAccumX = stickX;
+ }
+ } else if (stickX <= 30 && stickX >= -30) {
+ this->stickAccumX = 0;
+ } else if ((this->stickAccumX * stickX) < 0) { // Stick has swapped directions
+ this->stickAccumX = stickX;
+ } else {
+ this->stickAccumX += stickX;
+ if (this->stickAccumX > 2000) {
+ this->stickAccumX = 2000;
+ } else if (this->stickAccumX < -2000) {
+ this->stickAccumX = -2000;
+ }
+ }
+ if (this->stickAccumY == 0) {
+ if (stickY > 30 || stickY < -30) {
+ this->stickAccumY = stickY;
+ }
+ } else if (stickY <= 30 && stickY >= -30) {
+ this->stickAccumY = 0;
+ } else if ((this->stickAccumY * stickY) < 0) { // Stick has swapped directions
+ this->stickAccumY = stickY;
+ } else {
+ this->stickAccumY += stickY;
+ if (this->stickAccumY > 2000) {
+ this->stickAccumY = 2000;
+ } else if (this->stickAccumY < -2000) {
+ this->stickAccumY = -2000;
+ }
+ }
+}
+
+u8 EnSob1_SetCursorIndexFromNeutral(EnSob1* this, u8 shelfOffset) {
+ if (this->items[shelfOffset] != NULL) {
+ return shelfOffset;
+ }
+ return CURSOR_INVALID;
+}
+
+void EnSob1_Hello(EnSob1* this, GlobalContext* globalCtx) {
+ u8 talkState = func_80152498(&globalCtx->msgCtx);
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+ if ((talkState == 5) && (func_80147624(globalCtx)) &&
+ (!EnSob1_TestEndInteraction(this, globalCtx, CONTROLLER1(globalCtx)))) {
+ if (this->welcomeTextId == 0x68A) { // Welcome text when wearing Kafei's mask
+ EnSob1_EndInteraction(globalCtx, this);
+ } else {
+ EnSob1_StartShopping(globalCtx, this);
+ }
+ }
+}
+
+s32 EnSob1_FacingShopkeeperDialogResult(EnSob1* this, GlobalContext* globalCtx) {
+ switch (globalCtx->msgCtx.choiceIndex) {
+ case 0:
+ func_8019F208();
+ EnSob1_TalkToShopkeeper(globalCtx, this);
+ return true;
+ case 1:
+ func_8019F230();
+ if (this->shopType == BOMB_SHOP) {
+ EnSob1_EndInteractionBombShop(this, globalCtx);
+ } else {
+ EnSob1_EndInteraction(globalCtx, this);
+ }
+ return true;
+ }
+ return false;
+}
+
+void EnSob1_FaceShopkeeper(EnSob1* this, GlobalContext* globalCtx) {
+ s32 pad[2];
+ u8 talkState = func_80152498(&globalCtx->msgCtx);
+ u8 cursorIdx;
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookFowardCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_WAITING;
+ } else {
+ if (talkState == 4) {
+ func_8011552C(globalCtx, 6);
+ if (!EnSob1_TestEndInteraction(this, globalCtx, CONTROLLER1(globalCtx))) {
+ if (!func_80147624(globalCtx) || !EnSob1_FacingShopkeeperDialogResult(this, globalCtx)) {
+ if (this->stickAccumX > 0) {
+ cursorIdx = EnSob1_SetCursorIndexFromNeutral(this, 2);
+ if (cursorIdx != CURSOR_INVALID) {
+ this->cursorIdx = cursorIdx;
+ EnSob1_SetupAction(this, EnSob1_LookToShelf);
+ func_8011552C(globalCtx, 6);
+ this->stickRightPrompt.isEnabled = false;
+ play_sound(NA_SE_SY_CURSOR);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void EnSob1_TalkingToShopkeeper(EnSob1* this, GlobalContext* globalCtx) {
+ if (func_80152498(&globalCtx->msgCtx) == 5 && func_80147624(globalCtx)) {
+ EnSob1_StartShopping(globalCtx, this);
+ }
+}
+
+void EnSob1_LookToShopkeeperFromShelf(EnSob1* this, GlobalContext* globalCtx) {
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_PLAYING) {
+ ActorCutscene_Stop(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_STOPPED;
+ }
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookToShopkeeperCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_WAITING;
+ } else if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ EnSob1_StartShopping(globalCtx, this);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+}
+
+void EnSob1_EndWalk(EnSob1* this, GlobalContext* globalCtx) {
+ s32 pad;
+ f32 distSq;
+ s16 animCurrentFrame = this->skelAnime.animCurrentFrame / this->skelAnime.animPlaybackSpeed;
+ s16 animLastFrame = SkelAnime_GetFrameCount(&D_06009120.common) / (s16)this->skelAnime.animPlaybackSpeed;
+
+ Math_SmoothStepToS(
+ &this->actor.world.rot.y,
+ EnSob1_GetXZAngleAndDistanceSqToPoint(this->path, this->pathPointsIdx - 1, &this->actor.world.pos, &distSq), 4,
+ 1000, 1);
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ Math_ApproachF(&this->actor.speedXZ, 0.5f, 0.2f, 1.0f);
+ if (distSq < 12.0f) {
+ this->actor.speedXZ = 0.0f;
+ if (animLastFrame == animCurrentFrame) {
+ EnSob1_ChangeAnim(&this->skelAnime, sAnimationsBombShopkeeper, 1);
+ EnSob1_SetupAction(this, EnSob1_SetupIdle);
+ }
+ }
+ Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor);
+}
+
+void EnSob1_SetupIdle(EnSob1* this, GlobalContext* globalCtx) {
+ s16 animCurrentFrame = this->skelAnime.animCurrentFrame;
+
+ if (SkelAnime_GetFrameCount(&D_06008268.common) == animCurrentFrame) {
+ EnSob1_ChangeAnim(&this->skelAnime, sAnimationsBombShopkeeper, 2);
+ EnSob1_SetupAction(this, EnSob1_Idle);
+ }
+ EnSob1_Walking(this, globalCtx);
+}
+
+void EnSob1_Walk(EnSob1* this, GlobalContext* globalCtx) {
+ s32 pad;
+ f32 distSq;
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+ if (this->path != NULL) {
+ Math_SmoothStepToS(
+ &this->actor.world.rot.y,
+ EnSob1_GetXZAngleAndDistanceSqToPoint(this->path, this->pathPointsIdx, &this->actor.world.pos, &distSq), 4,
+ 1000, 1);
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ this->actor.speedXZ = 2.0f;
+ if (distSq < SQ(5.0f)) {
+ this->pathPointsIdx++;
+ if ((this->path->count - 1) < this->pathPointsIdx) {
+ this->actor.speedXZ = 0.0f;
+ EnSob1_SetupAction(this, EnSob1_EndWalk);
+ }
+ }
+ }
+ Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor);
+ EnSob1_Walking(this, globalCtx);
+}
+
+void EnSob1_Walking(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+ if (func_800B84D0(&this->actor, globalCtx)) {
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookFowardCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_WAITING;
+ }
+ player->stateFlags2 |= 0x20000000;
+ this->welcomeTextId = EnSob1_GetWelcome(this, globalCtx);
+ func_801518B0(globalCtx, this->welcomeTextId, &this->actor);
+ this->wasTalkedToWhileWalking = true;
+ } else {
+ if ((player->actor.world.pos.x >= this->posXZRange.xMin &&
+ player->actor.world.pos.x <= this->posXZRange.xMax) &&
+ (player->actor.world.pos.z >= this->posXZRange.zMin &&
+ player->actor.world.pos.z <= this->posXZRange.zMax)) {
+ func_800B8614(&this->actor, globalCtx, 400.0f);
+ }
+ }
+}
+
+void EnSob1_ItemPurchased(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene)) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ player->stateFlags2 |= 0x20000000;
+ EnSob1_SetupAction(this, EnSob1_ContinueShopping);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ } else {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookToShopkeeperCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+ if (func_800B84D0(&this->actor, globalCtx)) {
+ func_80151938(globalCtx, 0x647);
+ } else {
+ func_800B85E0(&this->actor, globalCtx, 400.0f, -1);
+ }
+}
+
+void EnSob1_LookToShelf(EnSob1* this, GlobalContext* globalCtx) {
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_PLAYING) {
+ ActorCutscene_Stop(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_STOPPED;
+ }
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookToShelfCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_WAITING;
+ } else if (this->cutsceneState == ENSOB1_CUTSCENESTATE_WAITING) {
+ if (ActorCutscene_GetCanPlayNext(this->cutscene) != 0) {
+ ActorCutscene_StartAndSetFlag(this->cutscene, &this->actor);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_PLAYING;
+ EnSob1_UpdateCursorPos(globalCtx, this);
+ EnSob1_SetupAction(this, EnSob1_BrowseShelf);
+ func_80151938(globalCtx, this->items[this->cursorIdx]->actor.textId);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ }
+}
+
+void EnSob1_CursorLeftRight(GlobalContext* globalCtx, EnSob1* this) {
+ u8 curTemp = this->cursorIdx;
+
+ if (this->stickAccumX < 0) {
+ if (curTemp != 2) {
+ curTemp++;
+ } else {
+ EnSob1_SetupLookToShopkeeperFromShelf(globalCtx, this);
+ }
+ if (this->items[curTemp] != NULL) {
+ this->cursorIdx = curTemp;
+ }
+ } else if (this->stickAccumX > 0) {
+ if (curTemp != 0) {
+ curTemp--;
+ }
+ if (this->items[curTemp] != NULL) {
+ this->cursorIdx = curTemp;
+ }
+ }
+}
+
+s32 EnSob1_HasPlayerSelectedItem(GlobalContext* globalCtx, EnSob1* this, Input* input) {
+ EnGirlA* item = this->items[this->cursorIdx];
+
+ if (EnSob1_TestEndInteraction(this, globalCtx, input)) {
+ return true;
+ }
+ if (EnSob1_TestItemSelected(globalCtx)) {
+ if (!item->isOutOfStock) {
+ this->tmpActionFunc = this->actionFunc;
+ func_80151938(globalCtx, this->items[this->cursorIdx]->choiceTextId);
+ play_sound(NA_SE_SY_DECIDE);
+ this->stickLeftPrompt.isEnabled = false;
+ this->stickRightPrompt.isEnabled = false;
+ this->drawCursor = 0;
+ EnSob1_SetupAction(this, EnSob1_SelectItem);
+ } else {
+ play_sound(NA_SE_SY_ERROR);
+ }
+ return true;
+ }
+ return false;
+}
+
+void EnSob1_BrowseShelf(EnSob1* this, GlobalContext* globalCtx) {
+ u8 talkState = func_80152498(&globalCtx->msgCtx);
+ s32 pad;
+ u8 prevCursorIdx = this->cursorIdx;
+ u8 cursorIdx;
+
+ if (!EnSob1_ReturnItemToShelf(this)) {
+ this->delayTimer = 3;
+ } else if (this->delayTimer != 0) {
+ this->delayTimer--;
+ } else {
+ this->drawCursor = 0xFF;
+ this->stickLeftPrompt.isEnabled = true;
+ EnSob1_UpdateCursorPos(globalCtx, this);
+ if (talkState == 5) {
+ func_8011552C(globalCtx, 6);
+ if (!EnSob1_HasPlayerSelectedItem(globalCtx, this, CONTROLLER1(globalCtx))) {
+ EnSob1_CursorLeftRight(globalCtx, this);
+ cursorIdx = this->cursorIdx;
+ if (cursorIdx != prevCursorIdx) {
+ func_80151938(globalCtx, this->items[cursorIdx]->actor.textId);
+ play_sound(NA_SE_SY_CURSOR);
+ }
+ }
+ }
+ }
+}
+
+void EnSob1_SetupBuyItemWithFanfare(GlobalContext* globalCtx, EnSob1* this) {
+ Player* player = PLAYER;
+
+ func_800B8A1C(&this->actor, globalCtx, this->items[this->cursorIdx]->getItemId, 300.0f, 300.0f);
+ globalCtx->msgCtx.unk11F22 = 0x43;
+ globalCtx->msgCtx.unk12023 = 4;
+ player->stateFlags2 &= ~0x20000000;
+ Interface_ChangeAlpha(50);
+ this->drawCursor = 0;
+ EnSob1_SetupAction(this, EnSob1_BuyItemWithFanfare);
+}
+
+void EnSob1_SetupCannotBuy(GlobalContext* globalCtx, EnSob1* this, u16 textId) {
+ func_80151938(globalCtx, textId);
+ EnSob1_SetupAction(this, EnSob1_CannotBuy);
+}
+
+void EnSob1_SetupCanBuy(GlobalContext* globalCtx, EnSob1* this, u16 textId) {
+ func_80151938(globalCtx, textId);
+ EnSob1_SetupAction(this, EnSob1_CanBuy);
+}
+
+void EnSob1_HandleCanBuyItem(GlobalContext* globalCtx, EnSob1* this) {
+ EnGirlA* item = this->items[this->cursorIdx];
+ EnGirlA* item2;
+
+ switch (item->canBuyFunc(globalCtx, item)) {
+ case CANBUY_RESULT_SUCCESS_1:
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_PLAYING) {
+ ActorCutscene_Stop(this->cutscene);
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_STOPPED;
+ }
+ func_8019F208();
+ item2 = this->items[this->cursorIdx];
+ item2->buyFanfareFunc(globalCtx, item2);
+ EnSob1_SetupBuyItemWithFanfare(globalCtx, this);
+ this->drawCursor = 0;
+ this->shopItemSelectedTween = 0.0f;
+ item->boughtFunc(globalCtx, item);
+ break;
+ case CANBUY_RESULT_SUCCESS_2:
+ func_8019F208();
+ item->buyFunc(globalCtx, item);
+ if ((this->shopType == GORON_SHOP) && (item->actor.params == SI_POTION_RED_5)) {
+ EnSob1_SetupCanBuy(globalCtx, this, 0xBD7);
+ } else if ((this->shopType == ZORA_SHOP) && (item->actor.params == SI_POTION_RED_4)) {
+ EnSob1_SetupCanBuy(globalCtx, this, 0x12E7);
+ } else if ((this->shopType == GORON_SHOP_SPRING) && (item->actor.params == SI_POTION_RED_6)) {
+ EnSob1_SetupCanBuy(globalCtx, this, 0xBD7);
+ } else {
+ EnSob1_SetupCanBuy(globalCtx, this, sBuySuccessTextIds[this->shopType]);
+ }
+ this->drawCursor = 0;
+ this->shopItemSelectedTween = 0.0f;
+ item->boughtFunc(globalCtx, item);
+ break;
+ case CANBUY_RESULT_NO_ROOM:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sNoRoomTextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_NEED_EMPTY_BOTTLE:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sNeedEmptyBottleTextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_NEED_RUPEES:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sNeedRupeesTextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_CANNOT_GET_NOW:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sCannotGetNowTextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_CANNOT_GET_NOW_2:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sCannotGetNow2TextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_NO_ROOM_2:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, sNoRoom2TextIds[this->shopType]);
+ break;
+ case CANBUY_RESULT_ALREADY_HAVE:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, 0x658);
+ break;
+ case CANBUY_RESULT_HAVE_BETTER:
+ play_sound(NA_SE_SY_ERROR);
+ EnSob1_SetupCannotBuy(globalCtx, this, 0x659);
+ break;
+ }
+}
+
+void EnSob1_SelectItem(EnSob1* this, GlobalContext* globalCtx) {
+ u8 talkState = func_80152498(&globalCtx->msgCtx);
+
+ if (EnSob1_TakeItemOffShelf(this) && talkState == 4) {
+ func_8011552C(globalCtx, 6);
+ if (!EnSob1_TestCancelOption(this, globalCtx, CONTROLLER1(globalCtx)) && func_80147624(globalCtx)) {
+ switch (globalCtx->msgCtx.choiceIndex) {
+ case 0:
+ EnSob1_HandleCanBuyItem(globalCtx, this);
+ break;
+ case 1:
+ func_8019F230();
+ this->actionFunc = this->tmpActionFunc;
+ func_80151938(globalCtx, this->items[this->cursorIdx]->actor.textId);
+ break;
+ }
+ }
+ }
+}
+
+void EnSob1_CannotBuy(EnSob1* this, GlobalContext* globalCtx) {
+ if (func_80152498(&globalCtx->msgCtx) == 5) {
+ if (func_80147624(globalCtx)) {
+ this->actionFunc = this->tmpActionFunc;
+ func_80151938(globalCtx, this->items[this->cursorIdx]->actor.textId);
+ }
+ }
+}
+
+void EnSob1_CanBuy(EnSob1* this, GlobalContext* globalCtx) {
+ EnGirlA* item;
+
+ if (func_80152498(&globalCtx->msgCtx) == 5 && func_80147624(globalCtx)) {
+ this->shopItemSelectedTween = 0.0f;
+ EnSob1_ResetItemPosition(this);
+ item = this->items[this->cursorIdx];
+ item->restockFunc(globalCtx, item);
+ this->actionFunc = this->tmpActionFunc;
+ func_80151938(globalCtx, this->items[this->cursorIdx]->actor.textId);
+ }
+}
+
+void EnSob1_BuyItemWithFanfare(EnSob1* this, GlobalContext* globalCtx) {
+ if (Actor_HasParent(&this->actor, globalCtx)) {
+ this->actor.parent = NULL;
+ EnSob1_SetupAction(this, EnSob1_SetupItemPurchased);
+ } else {
+ func_800B8A1C(&this->actor, globalCtx, this->items[this->cursorIdx]->getItemId, 300.0f, 300.0f);
+ }
+}
+
+void EnSob1_SetupItemPurchased(EnSob1* this, GlobalContext* globalCtx) {
+ if (func_80152498(&globalCtx->msgCtx) == 6 && func_80147624(globalCtx)) {
+ globalCtx->msgCtx.unk11F22 = 0x43;
+ globalCtx->msgCtx.unk12023 = 4;
+ EnSob1_SetupAction(this, EnSob1_ItemPurchased);
+ if (this->cutsceneState == ENSOB1_CUTSCENESTATE_STOPPED) {
+ if (ActorCutscene_GetCurrentIndex() == 0x7C) {
+ ActorCutscene_Stop(0x7C);
+ }
+ this->cutscene = this->lookToShopkeeperCutscene;
+ ActorCutscene_SetIntentToPlay(this->cutscene);
+ }
+ func_800B85E0(&this->actor, globalCtx, 400.0f, -1);
+ }
+}
+
+void EnSob1_ContinueShopping(EnSob1* this, GlobalContext* globalCtx) {
+ Player* player = PLAYER;
+ EnGirlA* item;
+
+ if ((func_80152498(&globalCtx->msgCtx) == 5) && (func_80147624(globalCtx))) {
+ EnSob1_ResetItemPosition(this);
+ item = this->items[this->cursorIdx];
+ item->restockFunc(globalCtx, item);
+ player->actor.shape.rot.y += 0x8000;
+ player->stateFlags2 |= 0x20000000;
+ func_801518B0(globalCtx, this->welcomeTextId, &this->actor);
+ EnSob1_SetupStartShopping(globalCtx, this, true);
+ func_800B85E0(&this->actor, globalCtx, 200.0f, -1);
+ }
+}
+
+void EnSob1_PositionSelectedItem(EnSob1* this) {
+ Vec3f selectedItemPosition = sSelectedItemPositions[this->shopType];
+ u8 i = this->cursorIdx;
+ EnGirlA* item;
+ ShopItem* shopItem = &sShops[this->shopType][i];
+ Vec3f worldPos;
+
+ item = this->items[i];
+
+ VEC3F_LERPIMPDST(&worldPos, &shopItem->spawnPos, &selectedItemPosition, this->shopItemSelectedTween);
+
+ item->actor.world.pos.x = worldPos.x;
+ item->actor.world.pos.y = worldPos.y;
+ item->actor.world.pos.z = worldPos.z;
+}
+
+void EnSob1_ResetItemPosition(EnSob1* this) {
+ this->shopItemSelectedTween = 0.0f;
+ EnSob1_PositionSelectedItem(this);
+}
+
+/*
+ * Returns true when animation has completed
+ */
+s32 EnSob1_TakeItemOffShelf(EnSob1* this) {
+ Math_ApproachF(&this->shopItemSelectedTween, 1.0f, 1.0f, 0.15f);
+ if (this->shopItemSelectedTween >= 0.85f) {
+ this->shopItemSelectedTween = 1.0f;
+ }
+ EnSob1_PositionSelectedItem(this);
+ if (this->shopItemSelectedTween == 1.0f) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Returns true when animation has completed
+ */
+s32 EnSob1_ReturnItemToShelf(EnSob1* this) {
+ Math_ApproachF(&this->shopItemSelectedTween, 0.0f, 1.0f, 0.15f);
+ if (this->shopItemSelectedTween <= 0.15f) {
+ this->shopItemSelectedTween = 0.0f;
+ }
+ EnSob1_PositionSelectedItem(this);
+ if (this->shopItemSelectedTween == 0.0f) {
+ return true;
+ }
+ return false;
+}
+
+void EnSob1_UpdateItemSelectedProperty(EnSob1* this) {
+ EnGirlA** items = this->items;
+ EnGirlA* item;
+ s32 i;
+
+ for (i = 0; i < ARRAY_COUNT(this->items); i++, items++) {
+ item = *items;
+ if (item != NULL) {
+ if (this->actionFunc != EnSob1_SelectItem && this->actionFunc != EnSob1_CannotBuy &&
+ this->drawCursor == 0) {
+ item->isSelected = false;
+ } else {
+ item->isSelected = this->cursorIdx == i ? true : false;
+ }
+ }
+ }
+}
+
+void EnSob1_UpdateCursorAnim(EnSob1* this) {
+ f32 t = this->cursorAnimTween;
+
+ if (this->cursorAnimState == 0) {
+ t += 0.05f;
+ if (t >= 1.0f) {
+ t = 1.0f;
+ this->cursorAnimState = 1;
+ }
+ } else {
+ t -= 0.05f;
+ if (t <= 0.0f) {
+ t = 0.0f;
+ this->cursorAnimState = 0;
+ }
+ }
+ this->cursorColorR = COL_CHAN_MIX(0, 0.0f, t);
+ this->cursorColorG = COL_CHAN_MIX(80, 80.0f, t);
+ this->cursorColorB = COL_CHAN_MIX(255, 0.0f, t);
+ this->cursorColorA = COL_CHAN_MIX(255, 0.0f, t);
+ this->cursorAnimTween = t;
+}
+
+void EnSob1_UpdateStickDirectionPromptAnim(EnSob1* this) {
+ f32 arrowAnimTween = this->arrowAnimTween;
+ f32 stickAnimTween = this->stickAnimTween;
+
+ // Possbily fake temps
+ s32 maxColor = 255;
+ f32 tmp;
+
+ if (this->arrowAnimState == 0) {
+ arrowAnimTween += 0.05f;
+ if (arrowAnimTween > 1.0f) {
+ arrowAnimTween = 1.0f;
+ this->arrowAnimState = 1;
+ }
+ } else {
+ arrowAnimTween -= 0.05f;
+ if (arrowAnimTween < 0.0f) {
+ arrowAnimTween = 0.0f;
+ this->arrowAnimState = 0;
+ }
+ }
+ this->arrowAnimTween = arrowAnimTween;
+
+ if (this->stickAnimState == 0) {
+ stickAnimTween += 0.1f;
+ if (stickAnimTween > 1.0f) {
+ stickAnimTween = 1.0f;
+ this->stickAnimState = 1;
+ }
+ } else {
+ stickAnimTween = 0.0f;
+ this->stickAnimState = 0;
+ }
+
+ tmp = 155.0f * arrowAnimTween;
+
+ this->stickAnimTween = stickAnimTween;
+
+ this->stickLeftPrompt.arrowColorR = COL_CHAN_MIX(255, 155.0f, arrowAnimTween);
+ this->stickLeftPrompt.arrowColorG = COL_CHAN_MIX(maxColor, 155.0f, arrowAnimTween);
+ this->stickLeftPrompt.arrowColorB = COL_CHAN_MIX(0, -100, arrowAnimTween);
+ this->stickLeftPrompt.arrowColorA = COL_CHAN_MIX(200, 50.0f, arrowAnimTween);
+
+ this->stickRightPrompt.arrowColorR = (maxColor - ((s32)tmp)) & 0xFF;
+ this->stickRightPrompt.arrowColorG = (255 - ((s32)tmp)) & 0xFF;
+ this->stickRightPrompt.arrowColorB = COL_CHAN_MIX(0, -100.0f, arrowAnimTween);
+ this->stickRightPrompt.arrowColorA = COL_CHAN_MIX(200, 50.0f, arrowAnimTween);
+
+ this->stickRightPrompt.arrowTexX = 290.0f;
+ this->stickLeftPrompt.arrowTexX = 33.0f;
+
+ this->stickRightPrompt.stickTexX = 274.0f;
+ this->stickRightPrompt.stickTexX += 8.0f * stickAnimTween;
+ this->stickLeftPrompt.stickTexX = 49.0f;
+ this->stickLeftPrompt.stickTexX -= 8.0f * stickAnimTween;
+
+ this->stickLeftPrompt.arrowTexY = this->stickRightPrompt.arrowTexY = 91.0f;
+ this->stickLeftPrompt.stickTexY = this->stickRightPrompt.stickTexY = 95.0f;
+}
+
+s16 EnSob1_GetXZAngleAndDistanceSqToPoint(Path* path, s32 pointIdx, Vec3f* pos, f32* distSq) {
+ Vec3s* points;
+ f32 diffX;
+ f32 diffZ;
+
+ if (path != NULL) {
+ points = (Vec3s*)Lib_SegmentedToVirtual(path->points);
+ points = &points[pointIdx];
+ diffX = points->x - pos->x;
+ diffZ = points->z - pos->z;
+ } else {
+ diffX = 0.0f;
+ diffZ = 0.0f;
+ }
+ *distSq = SQ(diffX) + SQ(diffZ);
+ return RADF_TO_BINANG(Math_Acot2F(diffZ, diffX));
+}
+
+void EnSob1_GetCutscenes(EnSob1* this) {
+ this->lookFowardCutscene = this->actor.cutscene;
+ this->lookToShelfCutscene = ActorCutscene_GetAdditionalCutscene(this->lookFowardCutscene);
+ this->lookToShopkeeperCutscene = ActorCutscene_GetAdditionalCutscene(this->lookToShelfCutscene);
+}
+
+void EnSob1_WaitForBlink(EnSob1* this) {
+ s16 decr = this->blinkTimer - 1;
+
+ if (decr != 0) {
+ this->blinkTimer = decr;
+ } else {
+ this->blinkFunc = EnSob1_Blink;
+ }
+}
+
+void EnSob1_Blink(EnSob1* this) {
+ s16 decr = this->blinkTimer - 1;
+ s16 eyeTextureIdxTemp;
+
+ if (decr != 0) {
+ this->blinkTimer = decr;
+ return;
+ }
+ eyeTextureIdxTemp = this->eyeTexIndex + 1;
+ if (eyeTextureIdxTemp > 2) {
+ this->eyeTexIndex = 0;
+ this->blinkTimer = (s32)(Rand_ZeroOne() * 60.0f) + 20;
+ this->blinkFunc = EnSob1_WaitForBlink;
+ } else {
+ this->eyeTexIndex = eyeTextureIdxTemp;
+ this->blinkTimer = 1;
+ }
+}
+
+void EnSob1_ChangeObject(EnSob1* this, GlobalContext* globalCtx) {
+ gSegments[6] = PHYSICAL_TO_VIRTUAL(globalCtx->objectCtx.status[this->objIndices[2]].segment);
+}
+
+s32 EnSob1_AreObjectsLoaded(EnSob1* this, GlobalContext* globalCtx) {
+ if (Object_IsLoaded(&globalCtx->objectCtx, this->objIndices[0])) {
+ if (this->objIndices[1] >= 0 && !Object_IsLoaded(&globalCtx->objectCtx, this->objIndices[1])) {
+ return false;
+ }
+ if (this->objIndices[2] >= 0 && !Object_IsLoaded(&globalCtx->objectCtx, this->objIndices[2])) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void EnSob1_InitZoraShopkeeper(EnSob1* this, GlobalContext* globalCtx) {
+ SkelAnime_InitSV(globalCtx, &this->skelAnime, &D_0600D208, NULL, this->limbDrawTable, this->transitionDrawTable,
+ 20);
+ gSegments[6] = PHYSICAL_TO_VIRTUAL(globalCtx->objectCtx.status[this->objIndices[2]].segment);
+ SkelAnime_ChangeAnim(&this->skelAnime, &D_0600078C, 1.0f, 0.0f, SkelAnime_GetFrameCount(&D_0600078C.common), 0,
+ 0.0f);
+ this->actor.draw = EnSob1_DrawZoraShopkeeper;
+ this->changeObjectFunc = EnSob1_ChangeObject;
+}
+
+void EnSob1_InitGoronShopkeeper(EnSob1* this, GlobalContext* globalCtx) {
+ SkelAnime_InitSV(globalCtx, &this->skelAnime, &D_06011AC8, NULL, this->limbDrawTable, this->transitionDrawTable,
+ 18);
+ gSegments[6] = PHYSICAL_TO_VIRTUAL(globalCtx->objectCtx.status[this->objIndices[2]].segment);
+ SkelAnime_ChangeAnim(&this->skelAnime, &D_060000FC, 1.0f, 0.0f, SkelAnime_GetFrameCount(&D_060000FC.common), 0,
+ 0.0f);
+ this->actor.draw = EnSob1_DrawGoronShopkeeper;
+ this->changeObjectFunc = EnSob1_ChangeObject;
+}
+
+void EnSob1_InitBombShopkeeper(EnSob1* this, GlobalContext* globalCtx) {
+ SkelAnime_InitSV(globalCtx, &this->skelAnime, &D_06009220, &D_06009120, this->limbDrawTable,
+ this->transitionDrawTable, 16);
+ this->actor.draw = EnSob1_DrawBombShopkeeper;
+ this->changeObjectFunc = NULL;
+ this->skelAnime.animPlaybackSpeed = 2.0f;
+}
+
+void EnSob1_InitShop(EnSob1* this, GlobalContext* globalCtx) {
+ ShopItem* shopItems;
+ EnSob1XZRange* unkStruct;
+ Vec3f* posOffset;
+
+ // Possibly fake temps
+ EnSob1* this2;
+ u32 maxColor = 255;
+
+ if (EnSob1_AreObjectsLoaded(this, globalCtx)) {
+ this->actor.flags &= ~0x10;
+ this->actor.objBankIndex = this->objIndices[0];
+ Actor_SetObjectSegment(globalCtx, &this->actor);
+ posOffset = &sPosOffset[this->shopType];
+ this->actor.world.pos.x += posOffset->x;
+ this->actor.world.pos.y += posOffset->y;
+ this->actor.world.pos.z += posOffset->z;
+ shopItems = sShops[this->shopType];
+ if ((this->shopType == BOMB_SHOP) && (gSaveContext.weekEventReg[0x21] & 8)) {
+ sShops[this->shopType][0].shopItemId = SI_BOMB_BAG_30_2;
+ }
+
+ this->cutsceneState = ENSOB1_CUTSCENESTATE_STOPPED;
+ EnSob1_GetCutscenes(this);
+ this->cutscene = this->lookFowardCutscene;
+ ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 20.0f);
+ sInitFuncs[this->shopType](this, globalCtx);
+ this->actor.colChkInfo.mass = MASS_IMMOVABLE;
+ this->actor.colChkInfo.cylRadius = 50;
+ this->wasTalkedToWhileWalking = false;
+ this->pathPointsIdx = 0;
+
+ if (this->shopType == BOMB_SHOP) {
+ this->path = func_8013D648(globalCtx, ENSOB1_GET_PATH(&this->actor), 0x1F);
+ }
+ if (this->shopType == BOMB_SHOP) {
+ EnSob1_SetupAction(this, EnSob1_SetupWalk);
+ } else {
+ EnSob1_SetupAction(this, EnSob1_Idle);
+ }
+
+ this->cursorY = (this->cursorX = 100.0f);
+ this->stickAccumX = (this->stickAccumY = 0);
+ this->cursorIdx = 0;
+ this->cursorZ = 1.2f;
+ this->cursorColorR = 0;
+ this->cursorColorG = 80;
+ this->cursorColorB = maxColor;
+ this->cursorColorA = maxColor;
+ this->cursorAnimTween = 0.0f;
+ this->cursorAnimState = 0;
+ this->drawCursor = 0;
+
+ this2 = this;
+
+ this2->stickLeftPrompt.stickColorR = 200;
+ this2->stickLeftPrompt.stickColorG = 200;
+ this2->stickLeftPrompt.stickColorB = 200;
+ this2->stickLeftPrompt.stickColorA = 180;
+ this2->stickLeftPrompt.stickTexX = 49.0f;
+ this2->stickLeftPrompt.stickTexY = 95.0f;
+ this2->stickLeftPrompt.arrowColorR = maxColor;
+ this2->stickLeftPrompt.arrowColorG = maxColor;
+ this2->stickLeftPrompt.arrowColorB = 0;
+ this2->stickLeftPrompt.arrowColorA = 200;
+ this2->stickLeftPrompt.arrowTexX = 33.0f;
+ this2->stickLeftPrompt.arrowTexY = 91.0f;
+ this2->stickLeftPrompt.texZ = 1.0f;
+ this2->stickLeftPrompt.isEnabled = 0;
+
+ if (1) {}
+
+ this2->stickRightPrompt.stickColorR = 200;
+ this2->stickRightPrompt.stickColorG = 200;
+ this2->stickRightPrompt.stickColorB = 200;
+ this2->stickRightPrompt.stickColorA = 180;
+ this2->stickRightPrompt.stickTexX = 274.0f;
+ this2->stickRightPrompt.stickTexY = 95.0f;
+ this2->stickRightPrompt.arrowColorR = maxColor;
+ this2->stickRightPrompt.arrowColorG = 0;
+ this2->stickRightPrompt.arrowColorB = 0;
+ this2->stickRightPrompt.arrowColorA = 200;
+ this2->stickRightPrompt.arrowTexX = 290.0f;
+ this2->stickRightPrompt.arrowTexY = 91.0f;
+ this2->stickRightPrompt.texZ = 1.0f;
+ this2->stickRightPrompt.isEnabled = 0;
+
+ this2->arrowAnimState = 0;
+ this2->stickAnimState = 0;
+ this2->arrowAnimTween = 0.0f;
+ this2->stickAnimTween = 0.0f;
+ this2->shopItemSelectedTween = 0.0f;
+
+ this2->actor.gravity = 0.0f;
+ this2->posXZRange = sPosXZRanges[this2->shopType];
+ Actor_SetScale(&this2->actor, sActorScales[this2->shopType]);
+ EnSob1_SpawnShopItems(this2, globalCtx, shopItems);
+ this->headRot = this->headRotTarget = 0;
+ this2->blinkTimer = 20;
+ this2->eyeTexIndex = 0;
+ this->blinkFunc = EnSob1_WaitForBlink;
+ this->actor.flags &= ~1;
+ }
+}
+
+void EnSob1_Update(Actor* thisx, GlobalContext* globalCtx) {
+ EnSob1ActionFunc changeObjectFunc;
+ EnSob1* this = THIS;
+
+ if (this->actionFunc != EnSob1_InitShop) {
+ this->blinkFunc(this);
+ EnSob1_UpdateJoystickInputState(globalCtx, this);
+ EnSob1_UpdateItemSelectedProperty(this);
+ EnSob1_UpdateStickDirectionPromptAnim(this);
+ EnSob1_UpdateCursorAnim(this);
+ Math_StepToS(&this->headRot, this->headRotTarget, 0x190);
+ this->actionFunc(this, globalCtx);
+ Actor_SetHeight(&this->actor, 90.0f);
+ changeObjectFunc = this->changeObjectFunc;
+ if (changeObjectFunc != NULL) {
+ changeObjectFunc(this, globalCtx);
+ }
+ SkelAnime_FrameUpdateMatrix(&this->skelAnime);
+ } else {
+ this->actionFunc(this, globalCtx);
+ }
+}
+
+void EnSob1_DrawCursor(GlobalContext* globalCtx, EnSob1* this, f32 x, f32 y, f32 z, u8 drawCursor) {
+ s32 ulx, uly, lrx, lry;
+ f32 w;
+ s32 dsdx;
+ s32 pad;
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ if (drawCursor != 0) {
+ func_8012C654(globalCtx->state.gfxCtx);
+ gDPSetPrimColor(OVERLAY_DISP++, 0, 0, this->cursorColorR, this->cursorColorG, this->cursorColorB,
+ this->cursorColorA);
+ gDPLoadTextureBlock_4b(OVERLAY_DISP++, &D_0401F740, G_IM_FMT_IA, 16, 16, 0, G_TX_MIRROR | G_TX_WRAP,
+ G_TX_MIRROR | G_TX_WRAP, 4, 4, G_TX_NOLOD, G_TX_NOLOD);
+ w = 16.0f * z;
+ ulx = (x - w) * 4.0f;
+ uly = (y - w + -12.0f) * 4.0f;
+ lrx = (x + w) * 4.0f;
+ lry = (y + w + -12.0f) * 4.0f;
+ dsdx = (1.0f / z) * 1024.0f;
+ gSPTextureRectangle(OVERLAY_DISP++, ulx, uly, lrx, lry, G_TX_RENDERTILE, 0, 0, dsdx, dsdx);
+ }
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+void EnSob1_DrawTextRec(GlobalContext* globalCtx, s32 r, s32 g, s32 b, s32 a, f32 x, f32 y, f32 z, s32 s, s32 t, f32 dx,
+ f32 dy) {
+ f32 unk;
+ s32 ulx, uly, lrx, lry;
+ f32 w, h;
+ s32 dsdx, dtdy;
+
+ ((void)"../z_en_soB1.c"); // Unreferenced
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ gDPPipeSync(OVERLAY_DISP++);
+ gDPSetPrimColor(OVERLAY_DISP++, 0, 0, r, g, b, a);
+
+ w = 8.0f * z;
+ ulx = (x - w) * 4.0f;
+ lrx = (x + w) * 4.0f;
+
+ h = 12.0f * z;
+ uly = (y - h) * 4.0f;
+ lry = (y + h) * 4.0f;
+
+ unk = 1024 * (1.0f / z);
+ dsdx = unk * dx;
+ dtdy = dy * unk;
+
+ gSPTextureRectangle(OVERLAY_DISP++, ulx, uly, lrx, lry, G_TX_RENDERTILE, s, t, dsdx, dtdy);
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+void EnSob1_DrawStickDirectionPrompt(GlobalContext* globalCtx, EnSob1* this) {
+ s32 drawStickRightPrompt = this->stickLeftPrompt.isEnabled;
+ s32 drawStickLeftPrompt = this->stickRightPrompt.isEnabled;
+
+ ((void)"../z_en_soB1.c"); // Unreferenced
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ if (drawStickRightPrompt || drawStickLeftPrompt) {
+ func_8012C654(globalCtx->state.gfxCtx);
+ gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
+ gDPSetTextureImage(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, &D_0401F8C0);
+ gDPSetTile(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP,
+ G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOLOD);
+ gDPLoadSync(OVERLAY_DISP++);
+ gDPLoadBlock(OVERLAY_DISP++, G_TX_LOADTILE, 0, 0, 191, 1024);
+ gDPPipeSync(OVERLAY_DISP++);
+ gDPSetTile(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_8b, 2, 0x0000, G_TX_RENDERTILE, 0, G_TX_NOMIRROR | G_TX_WRAP,
+ G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOLOD);
+ gDPSetTileSize(OVERLAY_DISP++, G_TX_RENDERTILE, 0, 0, 15 * 4, 23 * 4);
+ if (drawStickRightPrompt) {
+ EnSob1_DrawTextRec(globalCtx, this->stickLeftPrompt.arrowColorR, this->stickLeftPrompt.arrowColorG,
+ this->stickLeftPrompt.arrowColorB, this->stickLeftPrompt.arrowColorA,
+ this->stickLeftPrompt.arrowTexX, this->stickLeftPrompt.arrowTexY,
+ this->stickLeftPrompt.texZ, 0, 0, -1.0f, 1.0f);
+ }
+ if (drawStickLeftPrompt) {
+ EnSob1_DrawTextRec(globalCtx, this->stickRightPrompt.arrowColorR, this->stickRightPrompt.arrowColorG,
+ this->stickRightPrompt.arrowColorB, this->stickRightPrompt.arrowColorA,
+ this->stickRightPrompt.arrowTexX, this->stickRightPrompt.arrowTexY,
+ this->stickRightPrompt.texZ, 0, 0, 1.0f, 1.0f);
+ }
+ gDPSetTextureImage(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, &D_0401F7C0);
+ gDPSetTile(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP,
+ G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOLOD);
+ gDPLoadSync(OVERLAY_DISP++);
+ gDPLoadBlock(OVERLAY_DISP++, G_TX_LOADTILE, 0, 0, 127, 1024);
+ gDPPipeSync(OVERLAY_DISP++);
+ gDPSetTile(OVERLAY_DISP++, G_IM_FMT_IA, G_IM_SIZ_8b, 2, 0x0000, G_TX_RENDERTILE, 0, G_TX_NOMIRROR | G_TX_WRAP,
+ G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOLOD);
+ gDPSetTileSize(OVERLAY_DISP++, G_TX_RENDERTILE, 0, 0, 15 * 4, 15 * 4);
+ if (drawStickRightPrompt) {
+ EnSob1_DrawTextRec(globalCtx, this->stickLeftPrompt.stickColorR, this->stickLeftPrompt.stickColorG,
+ this->stickLeftPrompt.stickColorB, this->stickLeftPrompt.stickColorA,
+ this->stickLeftPrompt.stickTexX, this->stickLeftPrompt.stickTexY,
+ this->stickLeftPrompt.texZ, 0, 0, -1.0f, 1.0f);
+ }
+ if (drawStickLeftPrompt) {
+ EnSob1_DrawTextRec(globalCtx, this->stickRightPrompt.stickColorR, this->stickRightPrompt.stickColorG,
+ this->stickRightPrompt.stickColorB, this->stickRightPrompt.stickColorA,
+ this->stickRightPrompt.stickTexX, this->stickRightPrompt.stickTexY,
+ this->stickRightPrompt.texZ, 0, 0, 1.0f, 1.0f);
+ }
+ }
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+s32 EnSob1_OverrideLimbDrawZoraShopkeeper(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
+ Actor* thisx) {
+ EnSob1* this = THIS;
+
+ if (limbIndex == 15) {
+ rot->x += this->headRot;
+ }
+ return false;
+}
+
+s32 EnSob1_OverrideLimbDrawBombShopkeeper(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
+ Actor* thisx) {
+ EnSob1* this = THIS;
+
+ if (limbIndex == 15) {
+ SysMatrix_InsertXRotation_s(this->headRot, MTXMODE_APPLY);
+ }
+ return false;
+}
+
+void EnSob1_PostLimbDrawBombShopkeeper(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ if (limbIndex == 11) {
+ gSPDisplayList(POLY_OPA_DISP++, D_06000970);
+ }
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+Gfx* EnSob1_EndDList(GraphicsContext* gfxCtx) {
+ Gfx* dList;
+ Gfx* dListHead;
+
+ dList = dListHead = GRAPH_ALLOC(gfxCtx, sizeof(Gfx) * 2);
+ gSPEndDisplayList(dListHead++);
+
+ return dList;
+}
+
+void EnSob1_DrawZoraShopkeeper(Actor* thisx, GlobalContext* globalCtx) {
+ static TexturePtr sZoraShopkeeperEyeTextures[] = { &D_060050A0, &D_060058A0, &D_060060A0 };
+ EnSob1* this = THIS;
+ s32 pad;
+ s32 i;
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ func_8012C28C(globalCtx->state.gfxCtx);
+ gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
+ gSPSegment(POLY_OPA_DISP++, 0x0C, EnSob1_EndDList(globalCtx->state.gfxCtx));
+ gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sZoraShopkeeperEyeTextures[this->eyeTexIndex]));
+ SkelAnime_DrawSV(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl, this->skelAnime.dListCount,
+ EnSob1_OverrideLimbDrawZoraShopkeeper, NULL, &this->actor);
+ for (i = 0; i < ARRAY_COUNT(this->items); i++) {
+ this->items[i]->actor.scale.x = 0.2f;
+ this->items[i]->actor.scale.y = 0.2f;
+ this->items[i]->actor.scale.z = 0.2f;
+ }
+ EnSob1_DrawCursor(globalCtx, this, this->cursorX, this->cursorY, this->cursorZ, this->drawCursor);
+ EnSob1_DrawStickDirectionPrompt(globalCtx, this);
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+void EnSob1_DrawGoronShopkeeper(Actor* thisx, GlobalContext* globalCtx) {
+ static TexturePtr sGoronShopkeeperEyeTextures[] = { &D_06010438, &D_06010C38, &D_06011038 };
+ EnSob1* this = THIS;
+ s32 pad;
+ s32 i;
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ func_8012C28C(globalCtx->state.gfxCtx);
+ gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sGoronShopkeeperEyeTextures[this->eyeTexIndex]));
+ SkelAnime_DrawSV(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl, this->skelAnime.dListCount, NULL,
+ NULL, &this->actor);
+ for (i = 0; i < ARRAY_COUNT(this->items); i++) {
+ this->items[i]->actor.scale.x = 0.2f;
+ this->items[i]->actor.scale.y = 0.2f;
+ this->items[i]->actor.scale.z = 0.2f;
+ }
+ EnSob1_DrawCursor(globalCtx, this, this->cursorX, this->cursorY, this->cursorZ, this->drawCursor);
+ EnSob1_DrawStickDirectionPrompt(globalCtx, this);
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
+
+void EnSob1_DrawBombShopkeeper(Actor* thisx, GlobalContext* globalCtx) {
+ EnSob1* this = THIS;
+ s32 pad;
+ u32 frames;
+ s32 i;
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+ func_8012C28C(globalCtx->state.gfxCtx);
+ gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(&D_06005458));
+ SkelAnime_DrawSV(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl, this->skelAnime.dListCount,
+ EnSob1_OverrideLimbDrawBombShopkeeper, EnSob1_PostLimbDrawBombShopkeeper, &this->actor);
+ for (i = 0; i < ARRAY_COUNT(this->items); i++) {
+ this->items[i]->actor.scale.x = 0.2f;
+ this->items[i]->actor.scale.y = 0.2f;
+ this->items[i]->actor.scale.z = 0.2f;
+ }
+ EnSob1_DrawCursor(globalCtx, this, this->cursorX, this->cursorY, this->cursorZ, this->drawCursor);
+ EnSob1_DrawStickDirectionPrompt(globalCtx, this);
+ frames = globalCtx->gameplayFrames;
+ func_8012C2DC(globalCtx->state.gfxCtx);
+ SysMatrix_NormalizeXYZ(&globalCtx->mf_187FC);
+ Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY);
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPSegment(POLY_XLU_DISP++, 0x08,
+ Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 32, 64, 1, 0, -frames * 20, 32, 128));
+ gDPSetPrimColor(POLY_XLU_DISP++, 128, 128, 255, 255, 0, 255);
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0);
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+}
diff --git a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.h b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.h
index 47db68a5d..38b199ba6 100644
--- a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.h
+++ b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.h
@@ -2,14 +2,92 @@
#define Z_EN_SOB1_H
#include <global.h>
+#include "overlays/actors/ovl_En_GirlA/z_en_girla.h"
struct EnSob1;
+typedef void (*EnSob1ActionFunc)(struct EnSob1*, GlobalContext*);
+typedef void (*EnSob1BlinkFunc)(struct EnSob1*);
+
+#define ENSOB1_GET_SHOPTYPE(thisx) ((thisx)->params & 0x1F)
+#define ENSOB1_GET_PATH(thisx) (((thisx)->params & 0x3E0) >> 5)
+
+typedef struct EnSob1XZRange {
+ /* 0x0 */ f32 xMin;
+ /* 0x4 */ f32 xMax;
+ /* 0x8 */ f32 zMin;
+ /* 0xC */ f32 zMax;
+} EnSob1XZRange; // size = 0x10
+
typedef struct EnSob1 {
/* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0x28C];
+ /* 0x144 */ SkelAnime skelAnime;
+ /* 0x188 */ EnSob1ActionFunc actionFunc;
+ /* 0x18C */ EnSob1ActionFunc tmpActionFunc; // Used to restore back to correct browsing function
+ /* 0x190 */ EnSob1ActionFunc changeObjectFunc;
+ /* 0x194 */ ColliderCylinder collider;
+ /* 0x1E0 */ Path* path;
+ /* 0x1E4 */ s32 pathPointsIdx;
+ /* 0x1E8 */ s16 delayTimer;
+ /* 0x1EA */ s8 objIndices[3];
+ /* 0x1EE */ s16 headRot;
+ /* 0x1F0 */ s16 headRotTarget;
+ /* 0x1F2 */ Vec3s limbDrawTable[20];
+ /* 0x26A */ Vec3s transitionDrawTable[20];
+ /* 0x2E2 */ s16 eyeTexIndex;
+ /* 0x2E4 */ s16 blinkTimer;
+ /* 0x2E8 */ EnSob1BlinkFunc blinkFunc;
+ /* 0x2EC */ EnGirlA* items[3]; // Items on shelf are indexed as: /* 2 1 0 */
+ /* 0x2F8 */ s32 stickAccumX;
+ /* 0x2FC */ s32 stickAccumY;
+ /* 0x300 */ f32 cursorX;
+ /* 0x304 */ f32 cursorY;
+ /* 0x308 */ f32 cursorZ;
+ /* 0x30C */ s32 cursorColorR;
+ /* 0x310 */ s32 cursorColorG;
+ /* 0x314 */ s32 cursorColorB;
+ /* 0x318 */ s32 cursorColorA;
+ /* 0x31C */ f32 cursorAnimTween;
+ /* 0x320 */ u8 cursorAnimState;
+ /* 0x321 */ u8 drawCursor;
+ /* 0x322 */ u8 cursorIdx;
+ /* 0x324 */ StickDirectionPrompt stickLeftPrompt;
+ /* 0x35C */ StickDirectionPrompt stickRightPrompt;
+ /* 0x394 */ f32 arrowAnimTween;
+ /* 0x398 */ f32 stickAnimTween;
+ /* 0x39C */ u8 arrowAnimState;
+ /* 0x39D */ u8 stickAnimState;
+ /* 0x39E */ s16 cutsceneState;
+ /* 0x3A0 */ s16 cutscene;
+ /* 0x3A2 */ s16 lookFowardCutscene;
+ /* 0x3A4 */ s16 lookToShelfCutscene;
+ /* 0x3A6 */ s16 lookToShopkeeperCutscene;
+ /* 0x3A8 */ UNK_TYPE1 pad3A8[0x4];
+ /* 0x3AC */ f32 shopItemSelectedTween;
+ /* 0x3B0 */ UNK_TYPE1 pad3B0[0x4];
+ /* 0x3B4 */ u16 welcomeTextId;
+ /* 0x3B6 */ u16 talkOptionTextId;
+ /* 0x3B8 */ u16 goodbyeTextId;
+ /* 0x3BA */ u8 wasTalkedToWhileWalking;
+ /* 0x3BC */ EnSob1XZRange posXZRange;
+ /* 0x3CC */ s16 shopType;
} EnSob1; // size = 0x3D0
+typedef enum EnSob1ShopType {
+ /* 0 */ ZORA_SHOP,
+ /* 1 */ GORON_SHOP,
+ /* 2 */ BOMB_SHOP,
+ /* 3 */ GORON_SHOP_SPRING
+} EnSob1ShopType;
+
+typedef enum {
+ /* 0 */ ENSOB1_CUTSCENESTATE_STOPPED,
+ /* 1 */ ENSOB1_CUTSCENESTATE_WAITING,
+ /* 2 */ ENSOB1_CUTSCENESTATE_PLAYING
+} EnSob1CutsceneState;
+
+//! @TODO: Add enum for objIndices index based on what the object is for
+
extern const ActorInit En_Sob1_InitVars;
#endif // Z_EN_SOB1_H
diff --git a/tables/functions.txt b/tables/functions.txt
index 1137a7f2f..4de950e4f 100644
--- a/tables/functions.txt
+++ b/tables/functions.txt
@@ -9612,82 +9612,82 @@
0x80A0C790:("EnBoj05_Destroy",),
0x80A0C7A0:("EnBoj05_Update",),
0x80A0C7B0:("EnBoj05_Draw",),
- 0x80A0C810:("func_80A0C810",),
- 0x80A0C8AC:("func_80A0C8AC",),
- 0x80A0C8B8:("func_80A0C8B8",),
- 0x80A0C938:("func_80A0C938",),
- 0x80A0CA38:("func_80A0CA38",),
- 0x80A0CC88:("func_80A0CC88",),
- 0x80A0CCEC:("func_80A0CCEC",),
- 0x80A0CD48:("func_80A0CD48",),
- 0x80A0CE10:("func_80A0CE10",),
+ 0x80A0C810:("EnSob1_ChangeAnim",),
+ 0x80A0C8AC:("EnSob1_SetupAction",),
+ 0x80A0C8B8:("EnSob1_TestItemSelected",),
+ 0x80A0C938:("EnSob1_GetTalkOption",),
+ 0x80A0CA38:("EnSob1_GetWelcome",),
+ 0x80A0CC88:("EnSob1_GetGoodbye",),
+ 0x80A0CCEC:("EnSob1_EndInteractionBombShop",),
+ 0x80A0CD48:("EnSob1_SpawnShopItems",),
+ 0x80A0CE10:("EnSob1_GetObjIndices",),
0x80A0CED4:("EnSob1_Init",),
0x80A0D008:("EnSob1_Destroy",),
- 0x80A0D034:("func_80A0D034",),
- 0x80A0D0B8:("func_80A0D0B8",),
- 0x80A0D188:("func_80A0D188",),
- 0x80A0D1F4:("func_80A0D1F4",),
- 0x80A0D258:("func_80A0D258",),
- 0x80A0D2B8:("func_80A0D2B8",),
- 0x80A0D320:("func_80A0D320",),
- 0x80A0D388:("func_80A0D388",),
- 0x80A0D3C4:("func_80A0D3C4",),
- 0x80A0D414:("func_80A0D414",),
- 0x80A0D4A0:("func_80A0D4A0",),
- 0x80A0D628:("func_80A0D628",),
- 0x80A0D74C:("func_80A0D74C",),
- 0x80A0D77C:("func_80A0D77C",),
- 0x80A0D850:("func_80A0D850",),
- 0x80A0D904:("func_80A0D904",),
- 0x80A0DA5C:("func_80A0DA5C",),
- 0x80A0DAAC:("func_80A0DAAC",),
- 0x80A0DB78:("func_80A0DB78",),
- 0x80A0DCC4:("func_80A0DCC4",),
- 0x80A0DD40:("func_80A0DD40",),
- 0x80A0DE64:("func_80A0DE64",),
- 0x80A0DFD0:("func_80A0DFD0",),
- 0x80A0E0C0:("func_80A0E0C0",),
- 0x80A0E1B8:("func_80A0E1B8",),
- 0x80A0E258:("func_80A0E258",),
- 0x80A0E330:("func_80A0E330",),
- 0x80A0E420:("func_80A0E420",),
- 0x80A0E4DC:("func_80A0E4DC",),
- 0x80A0E518:("func_80A0E518",),
- 0x80A0E554:("func_80A0E554",),
- 0x80A0E884:("func_80A0E884",),
- 0x80A0E96C:("func_80A0E96C",),
- 0x80A0E9E0:("func_80A0E9E0",),
- 0x80A0EA84:("func_80A0EA84",),
- 0x80A0EAF8:("func_80A0EAF8",),
- 0x80A0EBC0:("func_80A0EBC0",),
- 0x80A0EC98:("func_80A0EC98",),
- 0x80A0ED7C:("func_80A0ED7C",),
- 0x80A0EDA0:("func_80A0EDA0",),
- 0x80A0EE3C:("func_80A0EE3C",),
- 0x80A0EEC8:("func_80A0EEC8",),
- 0x80A0EF48:("func_80A0EF48",),
- 0x80A0F014:("func_80A0F014",),
- 0x80A0F1C4:("func_80A0F1C4",),
- 0x80A0F284:("func_80A0F284",),
- 0x80A0F2C8:("func_80A0F2C8",),
- 0x80A0F2FC:("func_80A0F2FC",),
- 0x80A0F39C:("func_80A0F39C",),
- 0x80A0F3D4:("func_80A0F3D4",),
- 0x80A0F470:("func_80A0F470",),
- 0x80A0F554:("func_80A0F554",),
- 0x80A0F638:("func_80A0F638",),
- 0x80A0F6B0:("func_80A0F6B0",),
+ 0x80A0D034:("EnSob1_UpdateCursorPos",),
+ 0x80A0D0B8:("EnSob1_EndInteraction",),
+ 0x80A0D188:("EnSob1_TestEndInteraction",),
+ 0x80A0D1F4:("EnSob1_TestCancelOption",),
+ 0x80A0D258:("EnSob1_SetupStartShopping",),
+ 0x80A0D2B8:("EnSob1_StartShopping",),
+ 0x80A0D320:("EnSob1_TalkToShopkeeper",),
+ 0x80A0D388:("EnSob1_SetupLookToShopkeeperFromShelf",),
+ 0x80A0D3C4:("EnSob1_EndingInteraction",),
+ 0x80A0D414:("EnSob1_SetupWalk",),
+ 0x80A0D4A0:("EnSob1_Idle",),
+ 0x80A0D628:("EnSob1_UpdateJoystickInputState",),
+ 0x80A0D74C:("EnSob1_SetCursorIndexFromNeutral",),
+ 0x80A0D77C:("EnSob1_Hello",),
+ 0x80A0D850:("EnSob1_FacingShopkeeperDialogResult",),
+ 0x80A0D904:("EnSob1_FaceShopkeeper",),
+ 0x80A0DA5C:("EnSob1_TalkingToShopkeeper",),
+ 0x80A0DAAC:("EnSob1_LookToShopkeeperFromShelf",),
+ 0x80A0DB78:("EnSob1_EndWalk",),
+ 0x80A0DCC4:("EnSob1_SetupIdle",),
+ 0x80A0DD40:("EnSob1_Walk",),
+ 0x80A0DE64:("EnSob1_Walking",),
+ 0x80A0DFD0:("EnSob1_ItemPurchased",),
+ 0x80A0E0C0:("EnSob1_LookToShelf",),
+ 0x80A0E1B8:("EnSob1_CursorLeftRight",),
+ 0x80A0E258:("EnSob1_HasPlayerSelectedItem",),
+ 0x80A0E330:("EnSob1_BrowseShelf",),
+ 0x80A0E420:("EnSob1_SetupBuyItemWithFanfare",),
+ 0x80A0E4DC:("EnSob1_SetupCannotBuy",),
+ 0x80A0E518:("EnSob1_SetupCanBuy",),
+ 0x80A0E554:("EnSob1_HandleCanBuyItem",),
+ 0x80A0E884:("EnSob1_SelectItem",),
+ 0x80A0E96C:("EnSob1_CannotBuy",),
+ 0x80A0E9E0:("EnSob1_CanBuy",),
+ 0x80A0EA84:("EnSob1_BuyItemWithFanfare",),
+ 0x80A0EAF8:("EnSob1_SetupItemPurchased",),
+ 0x80A0EBC0:("EnSob1_ContinueShopping",),
+ 0x80A0EC98:("EnSob1_PositionSelectedItem",),
+ 0x80A0ED7C:("EnSob1_ResetItemPosition",),
+ 0x80A0EDA0:("EnSob1_TakeItemOffShelf",),
+ 0x80A0EE3C:("EnSob1_ReturnItemToShelf",),
+ 0x80A0EEC8:("EnSob1_UpdateItemSelectedProperty",),
+ 0x80A0EF48:("EnSob1_UpdateCursorAnim",),
+ 0x80A0F014:("EnSob1_UpdateStickDirectionPromptAnim",),
+ 0x80A0F1C4:("EnSob1_GetXZAngleAndDistanceSqToPoint",),
+ 0x80A0F284:("EnSob1_GetCutscenes",),
+ 0x80A0F2C8:("EnSob1_WaitForBlink",),
+ 0x80A0F2FC:("EnSob1_Blink",),
+ 0x80A0F39C:("EnSob1_ChangeObject",),
+ 0x80A0F3D4:("EnSob1_AreObjectsLoaded",),
+ 0x80A0F470:("EnSob1_InitZoraShopkeeper",),
+ 0x80A0F554:("EnSob1_InitGoronShopkeeper",),
+ 0x80A0F638:("EnSob1_InitBombShopkeeper",),
+ 0x80A0F6B0:("EnSob1_InitShop",),
0x80A0FA0C:("EnSob1_Update",),
- 0x80A0FADC:("func_80A0FADC",),
- 0x80A0FD4C:("func_80A0FD4C",),
- 0x80A0FEE8:("func_80A0FEE8",),
- 0x80A10290:("func_80A10290",),
- 0x80A102C8:("func_80A102C8",),
- 0x80A10308:("func_80A10308",),
- 0x80A10344:("func_80A10344",),
- 0x80A10368:("func_80A10368",),
- 0x80A104E4:("func_80A104E4",),
- 0x80A10608:("func_80A10608",),
+ 0x80A0FADC:("EnSob1_DrawCursor",),
+ 0x80A0FD4C:("EnSob1_DrawTextRec",),
+ 0x80A0FEE8:("EnSob1_DrawStickDirectionPrompt",),
+ 0x80A10290:("EnSob1_OverrideLimbDrawZoraShopkeeper",),
+ 0x80A102C8:("EnSob1_OverrideLimbDrawBombShopkeeper",),
+ 0x80A10308:("EnSob1_PostLimbDrawBombShopkeeper",),
+ 0x80A10344:("EnSob1_EndDList",),
+ 0x80A10368:("EnSob1_DrawZoraShopkeeper",),
+ 0x80A104E4:("EnSob1_DrawGoronShopkeeper",),
+ 0x80A10608:("EnSob1_DrawBombShopkeeper",),
0x80A10FD0:("func_80A10FD0",),
0x80A11144:("func_80A11144",),
0x80A1143C:("func_80A1143C",),
diff --git a/tables/variables.txt b/tables/variables.txt
index c6d8fc54a..603b34225 100644
--- a/tables/variables.txt
+++ b/tables/variables.txt
@@ -11754,28 +11754,28 @@
0x80A0C7E0:("enBoj05OverlayInfo","OverlayRelocationSection","",0x14),
0x80A0C7F4:("enBoj05OverlayRelocations","u32","[4]",0x10),
0x80A0C80C:("enBoj05OverlayInfoOffset","u32","",0x4),
- 0x80A10860:("D_80A10860","UNK_PTR","",0x4),
+ 0x80A10860:("sAnimationsBombShopkeeper","UNK_PTR","",0x4),
0x80A10890:("En_Sob1_InitVars","UNK_TYPE1","",0x1),
- 0x80A108B0:("D_80A108B0","UNK_TYPE2","",0x2),
- 0x80A108C8:("D_80A108C8","UNK_TYPE1","",0x1),
- 0x80A108D0:("D_80A108D0","UNK_TYPE1","",0x1),
- 0x80A108D8:("D_80A108D8","UNK_TYPE1","",0x1),
- 0x80A108E0:("D_80A108E0","UNK_TYPE1","",0x1),
- 0x80A108E8:("D_80A108E8","UNK_TYPE1","",0x1),
- 0x80A108F0:("D_80A108F0","UNK_TYPE1","",0x1),
- 0x80A108F8:("D_80A108F8","UNK_TYPE1","",0x1),
- 0x80A10900:("D_80A10900","UNK_TYPE1","",0x1),
- 0x80A10908:("D_80A10908","UNK_TYPE1","",0x1),
- 0x80A10918:("D_80A10918","UNK_TYPE1","",0x1),
- 0x80A10978:("D_80A10978","UNK_TYPE1","",0x1),
- 0x80A109B8:("D_80A109B8","UNK_TYPE4","",0x4),
+ 0x80A108B0:("sObjectIds","UNK_TYPE2","",0x2),
+ 0x80A108C8:("sFacingShopkeeperTextIds","UNK_TYPE1","",0x1),
+ 0x80A108D0:("sNoRoomTextIds","UNK_TYPE1","",0x1),
+ 0x80A108D8:("sBuySuccessTextIds","UNK_TYPE1","",0x1),
+ 0x80A108E0:("sCannotGetNowTextIds","UNK_TYPE1","",0x1),
+ 0x80A108E8:("sNeedRupeesTextIds","UNK_TYPE1","",0x1),
+ 0x80A108F0:("sNeedEmptyBottleTextIds","UNK_TYPE1","",0x1),
+ 0x80A108F8:("sCannotGetNow2TextIds","UNK_TYPE1","",0x1),
+ 0x80A10900:("sNoRoom2TextIds","UNK_TYPE1","",0x1),
+ 0x80A10908:("sActorScales","UNK_TYPE1","",0x1),
+ 0x80A10918:("sShops","UNK_TYPE1","",0x1),
+ 0x80A10978:("sPosXZRanges","UNK_TYPE1","",0x1),
+ 0x80A109B8:("sSelectedItemPositions","UNK_TYPE4","",0x4),
0x80A109E8:("D_80A109E8","UNK_TYPE1","",0x1),
- 0x80A109EC:("D_80A109EC","UNK_PTR","",0x4),
- 0x80A109FC:("D_80A109FC","UNK_TYPE4","",0x4),
- 0x80A10A2C:("D_80A10A2C","UNK_TYPE1","",0x1),
- 0x80A10A38:("D_80A10A38","UNK_TYPE1","",0x1),
- 0x80A10A50:("D_80A10A50","char","[]",0x1),
- 0x80A10A60:("D_80A10A60","char","[]",0x1),
+ 0x80A109EC:("sInitFuncs","UNK_PTR","",0x4),
+ 0x80A109FC:("sPosOffset","UNK_TYPE4","",0x4),
+ 0x80A10A2C:("sZoraShopkeeperEyeTextures","UNK_TYPE1","",0x1),
+ 0x80A10A38:("sGoronShopkeeperEyeTextures","UNK_TYPE1","",0x1),
+ 0x80A10A50:("filename1","char","[]",0x1),
+ 0x80A10A60:("filename2","char","[]",0x1),
0x80A10A70:("jtbl_D_80A10A70","UNK_PTR","",0x4),
0x80A10AD4:("D_80A10AD4","f32","",0x4),
0x80A10AD8:("D_80A10AD8","f32","",0x4),