summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEllipticEllipsis <elliptic.ellipsis@gmail.com>2022-07-22 05:17:06 +0100
committerGitHub <noreply@github.com>2022-07-22 05:17:06 +0100
commitc8c55a15d3acf459615fc54c4b542d7d16555d62 (patch)
tree65a0abb709eeed9d053bb3bad8ff7c69793269c2
parentcbeeeb172ab151be24478d2175f4cf7305ceff8c (diff)
EnBjt OK and documented (#912)
* OK, data imported * Fix some typos * Start docs * Struct almost finished * Start object, add state enum * undefined_syms * Finish object, name some more stuff * Name a few states and another function * PlayState * Minor tweaks in z_room and z_sub_s * Complete documentation * spec * Review 1 * functions.txt * Schedule result enum * Rename schedule results * Review * Remove update comments * Inventory_DeleteItem * PLAYER_STATE * Format * Review * Update struct name
-rw-r--r--README.md2
-rw-r--r--assets/xml/objects/object_bjt.xml43
-rw-r--r--include/functions.h2
-rw-r--r--include/z64item.h14
-rw-r--r--include/z64schedule.h2
-rw-r--r--spec3
-rw-r--r--src/code/z_lib.c16
-rw-r--r--src/code/z_room.c2
-rw-r--r--src/code/z_sub_s.c15
-rw-r--r--src/overlays/actors/ovl_En_Bjt/z_en_bjt.c441
-rw-r--r--src/overlays/actors/ovl_En_Bjt/z_en_bjt.h22
-rw-r--r--src/overlays/actors/ovl_En_Sellnuts/z_en_sellnuts.c6
-rw-r--r--tools/disasm/functions.txt22
-rw-r--r--undefined_syms.txt4
14 files changed, 508 insertions, 86 deletions
diff --git a/README.md b/README.md
index 24b94be99..badca09fd 100644
--- a/README.md
+++ b/README.md
@@ -129,7 +129,7 @@ md5sum: WARNING: 1 computed checksum did NOT match
This means that something is wrong with the ROM's contents. Either the baserom files are incorrect due to a bad ROM, or some of the code is not matching.
-Running `make init` will also make the `./expected` directory and copy all of the files there, which will be useful when running the diff script. The diff script is useful in decompiling functions and can be ran with this command: `./tools/asm-differ/diff.py -wmo3 <insert_function_here>`
+Running `make init` will also make the `./expected` directory and copy all of the files there, which will be useful when running the diff script. The diff script is useful in decompiling functions and can be run with this command: `./tools/asm-differ/diff.py -wmo3 <insert_function_here>`
**Note**: to speed up the build, you can pass `-jN` to `make setup` and `make`, where N is the number of threads to use in the build, e.g. `make -j4`. The generally-accepted wisdom is to use the number of virtual cores your computer has, which is the output of `nproc` (which should be installed as part of `coreutils`).
The disadvantage that the ordering of the terminal output is scrambled, so for debugging it is best to stick to one thread (i.e. not pass `-jN`).
diff --git a/assets/xml/objects/object_bjt.xml b/assets/xml/objects/object_bjt.xml
index 6266711ab..59a71dcee 100644
--- a/assets/xml/objects/object_bjt.xml
+++ b/assets/xml/objects/object_bjt.xml
@@ -1,23 +1,28 @@
<Root>
<File Name="object_bjt" Segment="6">
- <Animation Name="object_bjt_Anim_0000FC" Offset="0xFC" />
- <Animation Name="object_bjt_Anim_000218" Offset="0x218" />
- <Animation Name="object_bjt_Anim_0003A8" Offset="0x3A8" />
- <Animation Name="object_bjt_Anim_000564" Offset="0x564" />
- <Animation Name="object_bjt_Anim_0007B8" Offset="0x7B8" />
- <DList Name="object_bjt_DL_001570" Offset="0x1570" />
- <DList Name="object_bjt_DL_001690" Offset="0x1690" />
- <DList Name="object_bjt_DL_0017A0" Offset="0x17A0" />
- <DList Name="object_bjt_DL_0018C8" Offset="0x18C8" />
- <DList Name="object_bjt_DL_0019E8" Offset="0x19E8" />
- <Texture Name="object_bjt_Tex_001AB0" OutName="tex_001AB0" Format="rgba16" Width="32" Height="32" Offset="0x1AB0" />
- <Texture Name="object_bjt_Tex_0022B0" OutName="tex_0022B0" Format="rgba16" Width="8" Height="8" Offset="0x22B0" />
- <Limb Name="object_bjt_Standardlimb_002330" Type="Standard" EnumName="OBJECT_BJT_LIMB_01" Offset="0x2330" />
- <Limb Name="object_bjt_Standardlimb_00233C" Type="Standard" EnumName="OBJECT_BJT_LIMB_02" Offset="0x233C" />
- <Limb Name="object_bjt_Standardlimb_002348" Type="Standard" EnumName="OBJECT_BJT_LIMB_03" Offset="0x2348" />
- <Limb Name="object_bjt_Standardlimb_002354" Type="Standard" EnumName="OBJECT_BJT_LIMB_04" Offset="0x2354" />
- <Limb Name="object_bjt_Standardlimb_002360" Type="Standard" EnumName="OBJECT_BJT_LIMB_05" Offset="0x2360" />
- <Limb Name="object_bjt_Standardlimb_00236C" Type="Standard" EnumName="OBJECT_BJT_LIMB_06" Offset="0x236C" />
- <Skeleton Name="object_bjt_Skel_002390" Type="Flex" LimbType="Standard" LimbNone="OBJECT_BJT_LIMB_NONE" LimbMax="OBJECT_BJT_LIMB_MAX" EnumName="object_bjt_Limbs" Offset="0x2390" />
+ <!-- ??? (Hand in Toilet) assets -->
+
+ <!-- ??? animations -->
+ <Animation Name="gToiletHandWaggingFingerAnim" Offset="0xFC" /><!-- Original name: bjt_chigau ("different/wrong") -->
+ <Animation Name="gToiletHandFistAnim" Offset="0x218" /><!-- Original name: bjt_guu ("fist") -->
+ <Animation Name="gToiletHandThumbsUpAnim" Offset="0x3A8" /><!-- Original name: bjt_ok (thumbs up, correct) -->
+ <Animation Name="gToiletHandOpenHandAnim" Offset="0x564" /><!-- Original name: bjt_par ("paper"? Open hand, palm up) -->
+ <Animation Name="gToiletHandWaitingAnim" Offset="0x7B8" /><!-- Original name: bjt_wait (flopping around grasping at air) -->
+
+ <!-- ??? model -->
+ <DList Name="gToiletHandIndexFingerDL" Offset="0x1570" />
+ <DList Name="gToiletHandThumbDL" Offset="0x1690" />
+ <DList Name="gToiletHandOtherFingersDL" Offset="0x17A0" />
+ <DList Name="gToiletHandPalmDL" Offset="0x18C8" />
+ <DList Name="gToiletHandArmDL" Offset="0x19E8" />
+ <Texture Name="gToiletHandFingersTex" OutName="toilet_hand_fingers" Format="rgba16" Width="32" Height="32" Offset="0x1AB0" />
+ <Texture Name="gToiletHandArmSkinTex" OutName="toilet_hand_arm_skin" Format="rgba16" Width="8" Height="8" Offset="0x22B0" />
+ <Limb Name="gToiletHandRootLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_ROOT" Offset="0x2330" />
+ <Limb Name="gToiletHandArmLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_ARM" Offset="0x233C" />
+ <Limb Name="gToiletHandPalmLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_PALM" Offset="0x2348" />
+ <Limb Name="gToiletHandOtherFingersLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_OTHER_FINGERS" Offset="0x2354" />
+ <Limb Name="gToiletHandThumbLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_THUMB" Offset="0x2360" />
+ <Limb Name="gToiletHandIndexFingerLimb" Type="Standard" EnumName="TOILET_HAND_LIMB_INDEX_FINGER" Offset="0x236C" />
+ <Skeleton Name="gToiletHandSkel" Type="Flex" LimbType="Standard" LimbNone="TOILET_HAND_LIMB_NONE" LimbMax="TOILET_HAND_LIMB_MAX" EnumName="ToiletHandLimbs" Offset="0x2390" />
</File>
</Root>
diff --git a/include/functions.h b/include/functions.h
index 257276806..88a24eda0 100644
--- a/include/functions.h
+++ b/include/functions.h
@@ -1621,7 +1621,7 @@ void Color_RGBA8_Copy(Color_RGBA8* dst, Color_RGBA8* src);
void func_801000A4(u16 sfxId);
void func_801000CC(u16 sfxId);
void Lib_PlaySfxAtPos(Vec3f* pos, u16 sfxId);
-void Lib_Vec3f_TranslateAndRotateY(Vec3f* translation, s16 a, Vec3f* src, Vec3f* dst);
+void Lib_Vec3f_TranslateAndRotateY(Vec3f* translation, s16 rotAngle, Vec3f* src, Vec3f* dst);
void Lib_LerpRGB(Color_RGB8* a, Color_RGB8* b, f32 t, Color_RGB8* dst);
f32 Math_Vec3f_StepTo(Vec3f* start, Vec3f* target, f32 speed);
void Lib_Nop801004FC(void);
diff --git a/include/z64item.h b/include/z64item.h
index 96ecef2ec..cc05b528e 100644
--- a/include/z64item.h
+++ b/include/z64item.h
@@ -436,14 +436,24 @@ typedef enum {
/* 0x71 */ GID_71
} GetItemDrawID;
+// This enum may not be real, and actionparam is just used directly.
+// Keep using it for now.
// TODO: fill
typedef enum {
/* -1 */ EXCH_ITEM_MINUS1 = -1, // Unknown usage or function
/* 0x00 */ EXCH_ITEM_NONE,
/* 0x13 */ EXCH_ITEM_13 = 0x13,
/* 0x1E */ EXCH_ITEM_1E = 0x1E, // BOTTLE_MUSHROOM
- /* 0x2A */ EXCH_ITEM_2A = 0x2A, // MOON_TEAR?
- /* 0x2E */ EXCH_ITEM_2E = 0x2E
+ /* 0x2A */ EXCH_ITEM_MOON_TEAR = 0x2A,
+ /* 0x2B */ EXCH_ITEM_DEED_LAND,
+ /* 0x2C */ EXCH_ITEM_ROOM_KEY,
+ /* 0x2D */ EXCH_ITEM_LETTER_TO_KAFEI,
+ /* 0x2E */ EXCH_ITEM_2E,
+ /* 0x2F */ EXCH_ITEM_DEED_SWAMP,
+ /* 0x30 */ EXCH_ITEM_DEED_MOUNTAIN,
+ /* 0x31 */ EXCH_ITEM_DEED_OCEAN,
+ /* 0x32 */ EXCH_ITEM_32,
+ /* 0x33 */ EXCH_ITEM_LETTER_MAMA
} ExchangeItemID;
#endif
diff --git a/include/z64schedule.h b/include/z64schedule.h
index 6a0a32638..8dba85d4d 100644
--- a/include/z64schedule.h
+++ b/include/z64schedule.h
@@ -6,7 +6,7 @@
/**
* Schedule is a subsystem that acts as a way to make decisions based on the
* time and scene (and a limited selection of items). It is utilized by writing
- * a script that is encoded into bytecode and ran, returning the result in a
+ * a script that is encoded into bytecode and run, returning the result in a
* struct. The returned result can be a value or a encoded time value.
*
* The scripts contain 2 kinds of instructions:
diff --git a/spec b/spec
index 52fca49e7..10bd6f295 100644
--- a/spec
+++ b/spec
@@ -4826,8 +4826,7 @@ beginseg
name "ovl_En_Bjt"
compress
include "build/src/overlays/actors/ovl_En_Bjt/z_en_bjt.o"
- include "build/data/ovl_En_Bjt/ovl_En_Bjt.data.o"
- include "build/data/ovl_En_Bjt/ovl_En_Bjt.reloc.o"
+ include "build/src/overlays/actors/ovl_En_Bjt/ovl_En_Bjt_reloc.o"
endseg
beginseg
diff --git a/src/code/z_lib.c b/src/code/z_lib.c
index aaf4bc7d9..03e6c395c 100644
--- a/src/code/z_lib.c
+++ b/src/code/z_lib.c
@@ -651,15 +651,15 @@ void Lib_PlaySfxAtPos(Vec3f* pos, u16 sfxId) {
Audio_PlaySfxAtPos(pos, sfxId);
}
-void Lib_Vec3f_TranslateAndRotateY(Vec3f* translation, s16 a, Vec3f* src, Vec3f* dst) {
- f32 sp1C;
- f32 f0;
+void Lib_Vec3f_TranslateAndRotateY(Vec3f* translation, s16 rotAngle, Vec3f* src, Vec3f* dst) {
+ f32 cos;
+ f32 sin;
- sp1C = Math_CosS(a);
- f0 = Math_SinS(a);
- dst->x = translation->x + (src->x * sp1C + src->z * f0);
+ cos = Math_CosS(rotAngle);
+ sin = Math_SinS(rotAngle);
+ dst->x = translation->x + (src->x * cos + src->z * sin);
dst->y = translation->y + src->y;
- dst->z = translation->z + (src->z * sp1C - src->x * f0);
+ dst->z = translation->z + (src->z * cos - src->x * sin);
}
void Lib_LerpRGB(Color_RGB8* a, Color_RGB8* b, f32 t, Color_RGB8* dst) {
@@ -688,7 +688,7 @@ f32 Math_Vec3f_StepTo(Vec3f* start, Vec3f* target, f32 speed) {
start->z = start->z + f2 * diff.z;
} else {
Math_Vec3f_Copy(start, target);
- f0 = 0;
+ f0 = 0.0f;
}
return f0;
diff --git a/src/code/z_room.c b/src/code/z_room.c
index b8646a2d0..3507765a5 100644
--- a/src/code/z_room.c
+++ b/src/code/z_room.c
@@ -143,7 +143,7 @@ void func_8012EBF8(PlayState* play, RoomContext* roomCtx) {
roomCtx->prevRoom.segment = NULL;
func_800BA798(play, &play->actorCtx);
Actor_SpawnTransitionActors(play, &play->actorCtx);
- if (-1 < roomCtx->currRoom.num) {
+ if (roomCtx->currRoom.num > -1) {
Map_InitRoomData(play, roomCtx->currRoom.num);
Minimap_SavePlayerRoomInitInfo(play);
}
diff --git a/src/code/z_sub_s.c b/src/code/z_sub_s.c
index e7491a830..afc7f7168 100644
--- a/src/code/z_sub_s.c
+++ b/src/code/z_sub_s.c
@@ -830,43 +830,52 @@ s32 func_8013C964(Actor* actor, PlayState* play, f32 xzRange, f32 yRange, s32 it
xzRange = actor->xzDistToPlayer + 1.0f;
ret = Actor_PickUp(actor, play, itemId, xzRange, yRange);
break;
+
case 2:
if ((fabsf(actor->playerHeightRel) <= yRange) && (actor->xzDistToPlayer <= xzRange)) {
ret = func_800B8500(actor, play, xzRange, yRange, itemId);
}
break;
+
case 3:
//! @bug: Both x and y conditionals are always true, || should be an &&
if (((x >= 0) || (x < SCREEN_WIDTH)) && ((y >= 0) || (y < SCREEN_HEIGHT))) {
ret = func_800B8500(actor, play, xzRange, yRange, itemId);
}
break;
+
case 4:
yRange = fabsf(actor->playerHeightRel) + 1.0f;
xzRange = actor->xzDistToPlayer + 1.0f;
xzDistToPlayerTemp = actor->xzDistToPlayer;
actor->xzDistToPlayer = 0.0f;
- actor->flags |= 0x10000;
+ actor->flags |= ACTOR_FLAG_10000;
ret = func_800B8500(actor, play, xzRange, yRange, itemId);
actor->xzDistToPlayer = xzDistToPlayerTemp;
break;
+
case 5:
//! @bug: Both x and y conditionals are always true, || should be an &&
if (((x >= 0) || (x < SCREEN_WIDTH)) && ((y >= 0) || (y < SCREEN_HEIGHT)) &&
(fabsf(actor->playerHeightRel) <= yRange) && (actor->xzDistToPlayer <= xzRange) && actor->isTargeted) {
- actor->flags |= 0x10000;
+ actor->flags |= ACTOR_FLAG_10000;
ret = func_800B8500(actor, play, xzRange, yRange, itemId);
}
break;
+
case 6:
//! @bug: Both x and y conditionals are always true, || should be an &&
if (((x >= 0) || (x < SCREEN_WIDTH)) && ((y >= 0) || (y < SCREEN_HEIGHT)) &&
(fabsf(actor->playerHeightRel) <= yRange) && (actor->xzDistToPlayer <= xzRange)) {
- actor->flags |= 0x10000;
+ actor->flags |= ACTOR_FLAG_10000;
ret = func_800B8500(actor, play, xzRange, yRange, itemId);
}
break;
+
+ default:
+ break;
}
+
return ret;
}
diff --git a/src/overlays/actors/ovl_En_Bjt/z_en_bjt.c b/src/overlays/actors/ovl_En_Bjt/z_en_bjt.c
index 3400e5f52..b567450ce 100644
--- a/src/overlays/actors/ovl_En_Bjt/z_en_bjt.c
+++ b/src/overlays/actors/ovl_En_Bjt/z_en_bjt.c
@@ -15,10 +15,37 @@ void EnBjt_Destroy(Actor* thisx, PlayState* play);
void EnBjt_Update(Actor* thisx, PlayState* play);
void EnBjt_Draw(Actor* thisx, PlayState* play);
-void func_80BFDA48(EnBjt* this, PlayState* play);
-void func_80BFDAE8(EnBjt* this, PlayState* play);
+void EnBjt_Talk(EnBjt* this, PlayState* play);
+void EnBjt_FollowSchedule(EnBjt* this, PlayState* play);
+
+#define TOILET_HAND_STATE_TALKING (1 << 3) // Actually talking to Player
+#define TOILET_HAND_STATE_TEXTBOX (1 << 4) // Whenever a textbox is on screen
+#define TOILET_HAND_STATE_APPEARING (1 << 7) // Appearing
+#define TOILET_HAND_STATE_VANISHING (1 << 8) // Vanishing
+#define TOILET_HAND_STATE_VISIBLE (1 << 9) // Out
+
+typedef enum {
+ /* 0 */ TOILET_HAND_SCH_NONE,
+ /* 1 */ TOILET_HAND_SCH_AVAILABLE
+} ToiletHandScheduleResult;
+
+static u8 sScheduleScript[] = {
+ /* 0x00 */ SCHEDULE_CMD_CHECK_NOT_IN_SCENE_S(SCENE_YADOYA, 0x11 - 0x04),
+ /* 0x04 */ SCHEDULE_CMD_CHECK_TIME_RANGE_S(0, 0, 6, 0, 0x0B - 0x0A),
+ /* 0x0A */ SCHEDULE_CMD_RET_NONE(),
+ /* 0x0B */ SCHEDULE_CMD_RET_TIME(0, 0, 6, 0, TOILET_HAND_SCH_AVAILABLE),
+ /* 0x11 */ SCHEDULE_CMD_RET_NONE(),
+};
+
+static u8 sMsgEventScript[] = {
+ 0x0E, 0x29, 0x48, 0x0C, 0x0E, 0x00, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x52, 0x00, 0x5F, 0x2C, 0x29, 0x4A, 0x0C, 0x2F,
+ 0x00, 0x00, 0x0C, 0x15, 0x09, 0x00, 0x00, 0x0E, 0x29, 0x4B, 0x0C, 0x15, 0x09, 0x00, 0x00, 0x0E, 0x29, 0x4C, 0x0C,
+ 0x12, 0x00, 0x49, 0x08, 0x00, 0x1D, 0x09, 0x00, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x00, 0x13, 0x00, 0x0C, 0x2F, 0x00,
+ 0x00, 0x2E, 0x2D, 0x00, 0x28, 0x2D, 0x00, 0x0D, 0x0C, 0x11, 0x49, 0x08, 0x11, 0x5A, 0x80, 0x10, 0x09, 0x00, 0x00,
+ 0x06, 0x00, 0x02, 0x00, 0x00, 0x13, 0x00, 0x02, 0x2F, 0x00, 0x00, 0x2E, 0x2D, 0x00, 0x0D, 0x0C, 0x11, 0x5A, 0x80,
+ 0x10, 0x2C, 0x29, 0x49, 0x0C, 0x2F, 0x00, 0x00, 0x0C, 0x2D, 0x00, 0x0D, 0x12, 0x10, 0x2D, 0x00, 0x0D, 0x12, 0x10,
+};
-#if 0
const ActorInit En_Bjt_InitVars = {
ACTOR_EN_BJT,
ACTORCAT_NPC,
@@ -31,49 +58,407 @@ const ActorInit En_Bjt_InitVars = {
(ActorFunc)EnBjt_Draw,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80BFDF48 = {
- { COLTYPE_HIT1, AT_NONE, AC_NONE, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_ON, },
+static ColliderCylinderInit sCylinderInit = {
+ {
+ COLTYPE_HIT1,
+ AT_NONE,
+ AC_NONE,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK1,
+ { 0x00000000, 0x00, 0x00 },
+ { 0x00000000, 0x00, 0x00 },
+ TOUCH_NONE | TOUCH_SFX_NORMAL,
+ BUMP_NONE,
+ OCELEM_ON,
+ },
{ 10, 68, 0, { 0, 0, 0 } },
};
-// sColChkInfoInit
-static CollisionCheckInfoInit2 D_80BFDF74 = { 0, 0, 0, 0, MASS_IMMOVABLE };
+static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE };
+
+typedef enum {
+ /* -1 */ TOILET_HAND_ANIM_NONE = -1,
+ /* 0 */ TOILET_HAND_ANIM_WAITING,
+ /* 1 */ TOILET_HAND_ANIM_WAITING_MORPH, // Same as TOILET_HAND_ANIM_WAITING, but with morph frames
+ /* 2 */ TOILET_HAND_ANIM_WAGGING_FINGER, // Wrong
+ /* 3 */ TOILET_HAND_ANIM_THUMBS_UP, // Right
+ /* 4 */ TOILET_HAND_ANIM_OPEN_HAND,
+ /* 5 */ TOILET_HAND_ANIM_FIST // i.e. holding the reward
+} ToiletHandAnimations;
+
+static AnimationInfoS sAnimationInfos[] = {
+ /* 0 */ { &gToiletHandWaitingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 },
+ /* 1 */ { &gToiletHandWaitingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
+ /* 2 */ { &gToiletHandWaggingFingerAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
+ /* 3 */ { &gToiletHandThumbsUpAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
+ /* 4 */ { &gToiletHandOpenHandAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
+ /* 5 */ { &gToiletHandFistAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
+};
+
+void EnBjt_UpdateSkelAnime(EnBjt* this) {
+ this->skelAnime.playSpeed = this->animPlaySpeed;
+ SkelAnime_Update(&this->skelAnime);
+}
+
+s32 EnBjt_ChangeAnimation(EnBjt* this, s32 animIndex) {
+ s32 changeAnim = false;
+ s32 changed = false;
+
+ if ((animIndex == TOILET_HAND_ANIM_WAITING) || (animIndex == TOILET_HAND_ANIM_WAITING_MORPH)) {
+ if (!((this->curAnimIndex == TOILET_HAND_ANIM_WAITING) ||
+ (this->curAnimIndex == TOILET_HAND_ANIM_WAITING_MORPH))) {
+ changeAnim = true;
+ }
+ } else if (this->curAnimIndex != animIndex) {
+ changeAnim = true;
+ }
+
+ if (changeAnim) {
+ this->curAnimIndex = animIndex;
+ changed = SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfos, animIndex);
+ this->animPlaySpeed = this->skelAnime.playSpeed;
+ }
+
+ return changed;
+}
+
+void EnBjt_UpdateCollision(EnBjt* this, PlayState* play) {
+ static Vec3f sColliderBasePos = { 0.0f, 8.0f, 10.0f };
+ s32 pad;
+ Vec3f pos;
+ f32 height;
+
+ if (this->stateFlags & (TOILET_HAND_STATE_APPEARING | TOILET_HAND_STATE_VISIBLE)) {
+ Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &sColliderBasePos, &pos);
+ Math_Vec3f_ToVec3s(&this->collider.dim.pos, &pos);
+ height = this->actor.focus.pos.y - this->actor.world.pos.y;
+ this->collider.dim.height = height;
+ this->collider.dim.radius = 32;
+ CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
+ }
+}
+
+s32 EnBjt_TakeItem(s32 exchangeItem) {
+ switch (exchangeItem) {
+ case EXCH_ITEM_LETTER_TO_KAFEI:
+ Inventory_DeleteItem(ITEM_LETTER_TO_KAFEI, SLOT(ITEM_LETTER_TO_KAFEI));
+ break;
+
+ case EXCH_ITEM_DEED_SWAMP:
+ Inventory_DeleteItem(ITEM_DEED_SWAMP, SLOT(ITEM_DEED_SWAMP));
+ break;
+
+ case EXCH_ITEM_DEED_MOUNTAIN:
+ Inventory_DeleteItem(ITEM_DEED_MOUNTAIN, SLOT(ITEM_DEED_MOUNTAIN));
+ break;
+
+ case EXCH_ITEM_DEED_OCEAN:
+ Inventory_DeleteItem(ITEM_DEED_OCEAN, SLOT(ITEM_DEED_OCEAN));
+ break;
+
+ case EXCH_ITEM_DEED_LAND:
+ Inventory_DeleteItem(ITEM_DEED_LAND, SLOT(ITEM_DEED_LAND));
+ break;
+
+ case EXCH_ITEM_LETTER_MAMA:
+ Inventory_DeleteItem(ITEM_LETTER_MAMA, SLOT(ITEM_LETTER_MAMA));
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+#define FULLY_GROWN_SCALE 0.017f
+
+/**
+ * @return boolean true if scale is set to final value
+ */
+s32 EnBjt_Appear(EnBjt* this) {
+ s32 finished = false;
+
+ if (!this->playedSfx) {
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_TOILET_HAND_APPEAR);
+ this->playedSfx = true;
+ }
+
+ Math_ApproachF(&this->actor.scale.x, FULLY_GROWN_SCALE, 0.21f, 0.3f);
+ if ((FULLY_GROWN_SCALE - this->actor.scale.x) < FULLY_GROWN_SCALE / 100.0f) {
+ this->actor.scale.x = FULLY_GROWN_SCALE;
+ this->stateFlags |= TOILET_HAND_STATE_VISIBLE;
+ this->stateFlags &= ~TOILET_HAND_STATE_APPEARING;
+ finished = true;
+ }
+ this->heightOffset = (this->actor.scale.x / FULLY_GROWN_SCALE) * 4.0f;
+ this->actor.world.pos.y = this->actor.home.pos.y + this->heightOffset;
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+
+ return finished;
+}
+
+/**
+ * @return boolean true if scale is set to final value
+ */
+s32 EnBjt_Vanish(EnBjt* this) {
+ s32 finished = false;
+
+ if (!this->playedSfx) {
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_TOILET_HAND_VANISH);
+ this->playedSfx = true;
+ }
+
+ Math_ApproachF(&this->actor.scale.x, 0.0f, 0.21f, 0.3f);
+ if (this->actor.scale.x < FULLY_GROWN_SCALE / 100.0f) {
+ this->actor.scale.x = 0.0f;
+ this->stateFlags &= ~TOILET_HAND_STATE_VANISHING;
+ finished = true;
+ }
+ this->heightOffset = (this->actor.scale.x / FULLY_GROWN_SCALE) * 4.0f;
+ this->actor.world.pos.y = this->actor.home.pos.y + this->heightOffset;
+ Actor_SetScale(&this->actor, this->actor.scale.x);
+
+ return finished;
+}
+
+typedef enum {
+ /* 0 */ TOILET_HAND_BEHAVIOUR_WAIT_FOR_ITEM, // and check if item is suitable
+ /* 1 */ TOILET_HAND_BEHAVIOUR_TAKE_ITEM, // take paper and disappear to use it
+ /* 2 */ TOILET_HAND_BEHAVIOUR_USE_ITEM, // using paper, flushing
+ /* 3 */ TOILET_HAND_BEHAVIOUR_REAPPEAR, // reappear with reward
+ /* 4 */ TOILET_HAND_BEHAVIOUR_REWARD_GIVEN,
+} ToiletHandBehaviour;
+
+// msgevent callback/communication. Follow and choose parts of script to run
+s32 EnBjt_ChooseBehaviour(Actor* thisx, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ EnBjt* this = THIS;
+ s32 itemAP;
+ s32 scriptBranch = 0;
+
+ switch (this->behaviour) {
+ case TOILET_HAND_BEHAVIOUR_WAIT_FOR_ITEM:
+ switch (Message_GetState(&play->msgCtx)) {
+ case 4:
+ case 5:
+ if (!Message_ShouldAdvance(play)) {
+ break;
+ }
+ // Fallthrough
+ case 16:
+ itemAP = func_80123810(play);
+ if ((itemAP == EXCH_ITEM_DEED_LAND) || (itemAP == EXCH_ITEM_LETTER_TO_KAFEI) ||
+ (itemAP == EXCH_ITEM_DEED_SWAMP) || (itemAP == EXCH_ITEM_DEED_MOUNTAIN) ||
+ (itemAP == EXCH_ITEM_DEED_OCEAN) || (itemAP == EXCH_ITEM_LETTER_MAMA)) {
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_WAITING_MORPH);
+ this->playedSfx = false;
+ this->behaviour++;
+ scriptBranch = 1; // Right item
+ } else if (itemAP < 0) {
+ this->playedSfx = false;
+ this->behaviour++;
+ scriptBranch = 3; // Not showing item
+ } else if (itemAP != 0) {
+ this->playedSfx = false;
+ this->behaviour++;
+ scriptBranch = 2; // Wrong item
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case TOILET_HAND_BEHAVIOUR_TAKE_ITEM:
+ if (player->exchangeItemId != EXCH_ITEM_NONE) {
+ EnBjt_TakeItem(player->exchangeItemId);
+ player->exchangeItemId = EXCH_ITEM_NONE;
+ }
+ if (EnBjt_Vanish(this)) {
+ this->timer = 60;
+ this->behaviour++;
+ scriptBranch = 1; // Right item
+ }
+ break;
+
+ case TOILET_HAND_BEHAVIOUR_USE_ITEM:
+ if (DECR(this->timer) == 0) {
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_FIST); // change while not visible
+ this->playedSfx = false;
+ this->behaviour++;
+ } else if (this->timer == 10) {
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_TOILET_WATER);
+ }
+ break;
+
+ case TOILET_HAND_BEHAVIOUR_REAPPEAR:
+ if (EnBjt_Appear(this)) {
+ this->behaviour++;
+ scriptBranch = 1; // Right item
+ }
+ break;
+
+ case TOILET_HAND_BEHAVIOUR_REWARD_GIVEN:
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_OPEN_HAND);
+ this->behaviour++;
+ scriptBranch = 1; // Right item
+ break;
+
+ default:
+ break;
+ }
+
+ return scriptBranch;
+}
+
+s32 EnBjt_CheckTalk(EnBjt* this, PlayState* play) {
+ s32 ret = false;
+
+ if ((this->stateFlags & 7) && Actor_ProcessTalkRequest(&this->actor, &play->state)) {
+ this->stateFlags |= TOILET_HAND_STATE_TALKING;
+ SubS_UpdateFlags(&this->stateFlags, 0, 7);
+ this->msgEventCallback = EnBjt_ChooseBehaviour;
+ this->behaviour = 0;
+ this->actionFunc = EnBjt_Talk;
+ ret = true;
+ }
+ return ret;
+}
+
+s32 EnBjt_ChooseAnimation(EnBjt* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ u16 curTextId = play->msgCtx.currentTextId;
-#endif
+ if (player->stateFlags1 & (PLAYER_STATE1_40 | PLAYER_STATE1_400)) { // Talking, show item?
+ this->stateFlags |= TOILET_HAND_STATE_TEXTBOX;
+ if (this->textId != curTextId) {
+ switch (curTextId) {
+ case 0x2949: // Wrong item
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_WAGGING_FINGER);
+ break;
-extern ColliderCylinderInit D_80BFDF48;
-extern CollisionCheckInfoInit2 D_80BFDF74;
+ case 0x294A: // Right item
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_THUMBS_UP);
+ break;
-extern UNK_TYPE D_06002390;
+ default:
+ break;
+ }
+ }
+ this->textId = curTextId;
+ } else if (this->stateFlags & TOILET_HAND_STATE_TEXTBOX) {
+ this->stateFlags &= ~TOILET_HAND_STATE_TEXTBOX;
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_WAITING);
+ }
+ return 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD2E0.s")
+// Action function, based on msgEvent
+void EnBjt_Talk(EnBjt* this, PlayState* play) {
+ s16 yaw = this->actor.yawTowardsPlayer;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD30C.s")
+ // TODO: Casting to remove warning for now
+ if (func_8010BF58(&this->actor, play, (s32)sMsgEventScript, this->msgEventCallback, &this->msgEventArg4)) {
+ this->actor.flags &= ~ACTOR_FLAG_100;
+ SubS_UpdateFlags(&this->stateFlags, 3, 7);
+ this->stateFlags &= ~TOILET_HAND_STATE_TALKING;
+ this->msgEventArg4 = 0;
+ this->actionFunc = EnBjt_FollowSchedule;
+ } else {
+ Math_ApproachS(&this->actor.shape.rot.y, yaw, 4, 0x2AA8);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD3A4.s")
+// Change state based on schedule and stateFlags
+void EnBjt_FollowSchedule(EnBjt* this, PlayState* play) {
+ ScheduleOutput scheduleOutput;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD434.s")
+ if (!Schedule_RunScript(play, sScheduleScript, &scheduleOutput)) {
+ scheduleOutput.result = TOILET_HAND_SCH_NONE;
+ }
+ if (scheduleOutput.result == TOILET_HAND_SCH_AVAILABLE) {
+ if (this->stateFlags & TOILET_HAND_STATE_APPEARING) {
+ if (EnBjt_Appear(this)) {
+ SubS_UpdateFlags(&this->stateFlags, 3, 7);
+ }
+ } else if (this->stateFlags & TOILET_HAND_STATE_VANISHING) {
+ EnBjt_Vanish(this);
+ } else if (this->stateFlags & TOILET_HAND_STATE_VISIBLE) {
+ // Vanish if player goes too far away or heart piece given
+ if ((fabsf(this->actor.playerHeightRel) > 70.0f) || (this->actor.xzDistToPlayer > 140.0f) ||
+ (gSaveContext.save.weekEventReg[90] & 0x80)) {
+ SubS_UpdateFlags(&this->stateFlags, 0, 7);
+ this->playedSfx = false;
+ this->stateFlags &= ~TOILET_HAND_STATE_VISIBLE;
+ this->stateFlags |= TOILET_HAND_STATE_VANISHING;
+ }
+ } else {
+ // Appear if player approaches and heart piece not given
+ if ((fabsf(this->actor.playerHeightRel) < 20.0f) && (this->actor.xzDistToPlayer < 70.0f) &&
+ !(gSaveContext.save.weekEventReg[90] & 0x80)) {
+ this->stateFlags |= TOILET_HAND_STATE_APPEARING;
+ this->playedSfx = false;
+ }
+ }
+ this->scheduleResult = scheduleOutput.result;
+ } else {
+ this->actor.flags |= ACTOR_FLAG_8000000;
+ Actor_SetScale(&this->actor, 0.0f);
+ this->stateFlags = 0;
+ this->msgEventCallback = NULL;
+ this->scheduleResult = TOILET_HAND_SCH_NONE;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD4FC.s")
+void EnBjt_Init(Actor* thisx, PlayState* play) {
+ EnBjt* this = THIS;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD5E4.s")
+ ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
+ SkelAnime_InitFlex(play, &this->skelAnime, &gToiletHandSkel, NULL, this->jointTable, this->morphTable,
+ TOILET_HAND_LIMB_MAX);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD6BC.s")
+ this->curAnimIndex = TOILET_HAND_ANIM_NONE;
+ EnBjt_ChangeAnimation(this, TOILET_HAND_ANIM_WAITING);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD8F0.s")
+ Collider_InitAndSetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
+ CollisionCheck_SetInfo2(&this->actor.colChkInfo, DamageTable_Get(0x16), &sColChkInfoInit);
+ this->actor.flags |= ACTOR_FLAG_8000000;
+ Actor_SetScale(&this->actor, 0.0f);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFD984.s")
+ this->scheduleResult = TOILET_HAND_SCH_NONE;
+ this->stateFlags = 0;
+ this->actionFunc = EnBjt_FollowSchedule;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFDA48.s")
+void EnBjt_Destroy(Actor* thisx, PlayState* play) {
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/func_80BFDAE8.s")
+void EnBjt_Update(Actor* thisx, PlayState* play) {
+ EnBjt* this = THIS;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/EnBjt_Init.s")
+ EnBjt_CheckTalk(this, play);
+ this->actionFunc(this, play);
+ EnBjt_ChooseAnimation(this, play);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/EnBjt_Destroy.s")
+ if (this->scheduleResult != TOILET_HAND_SCH_NONE) {
+ EnBjt_UpdateSkelAnime(this);
+ func_8013C964(&this->actor, play, 60.0f, 10.0f, EXCH_ITEM_NONE, this->stateFlags & 7);
+ Actor_SetFocus(&this->actor, 26.0f);
+ EnBjt_UpdateCollision(this, play);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/EnBjt_Update.s")
+void EnBjt_Draw(Actor* thisx, PlayState* play) {
+ EnBjt* this = THIS;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Bjt/EnBjt_Draw.s")
+ if (this->scheduleResult != TOILET_HAND_SCH_NONE) {
+ func_8012C28C(play->state.gfxCtx);
+ SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
+ NULL, NULL, &this->actor);
+ }
+}
diff --git a/src/overlays/actors/ovl_En_Bjt/z_en_bjt.h b/src/overlays/actors/ovl_En_Bjt/z_en_bjt.h
index 33bc33bad..d1aabb999 100644
--- a/src/overlays/actors/ovl_En_Bjt/z_en_bjt.h
+++ b/src/overlays/actors/ovl_En_Bjt/z_en_bjt.h
@@ -2,18 +2,36 @@
#define Z_EN_BJT_H
#include "global.h"
+#include "objects/object_bjt/object_bjt.h"
struct EnBjt;
typedef void (*EnBjtActionFunc)(struct EnBjt*, PlayState*);
+typedef s32 (*MsgEventFunc)(Actor*, PlayState*);
typedef struct EnBjt {
/* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0x44];
+ /* 0x144 */ SkelAnime skelAnime;
/* 0x188 */ EnBjtActionFunc actionFunc;
- /* 0x18C */ char unk_18C[0xD0];
+ /* 0x18C */ ColliderCylinder collider;
+ /* 0x1D8 */ u8 scheduleResult;
+ /* 0x1DC */ s32 msgEventArg4;
+ /* 0x1E0 */ Vec3s jointTable[TOILET_HAND_LIMB_MAX];
+ /* 0x20A */ Vec3s morphTable[TOILET_HAND_LIMB_MAX];
+ /* 0x234 */ u16 stateFlags;
+ /* 0x236 */ u16 textId;
+ /* 0x238 */ f32 animPlaySpeed;
+ /* 0x23C */ f32 heightOffset;
+ /* 0x240 */ s16 behaviour;
+ /* 0x242 */ s16 timer;
+ /* 0x244 */ UNK_TYPE1 unk_244[4];
+ /* 0x248 */ s32 playedSfx; // to only play once
+ /* 0x24C */ MsgEventFunc msgEventCallback;
+ /* 0x250 */ s32 curAnimIndex;
+ /* 0x254 */ UNK_TYPE1 pad_254[8];
} EnBjt; // size = 0x25C
+
extern const ActorInit En_Bjt_InitVars;
#endif // Z_EN_BJT_H
diff --git a/src/overlays/actors/ovl_En_Sellnuts/z_en_sellnuts.c b/src/overlays/actors/ovl_En_Sellnuts/z_en_sellnuts.c
index 3faeedd7e..a6b90f58a 100644
--- a/src/overlays/actors/ovl_En_Sellnuts/z_en_sellnuts.c
+++ b/src/overlays/actors/ovl_En_Sellnuts/z_en_sellnuts.c
@@ -341,7 +341,7 @@ void func_80ADB544(EnSellnuts* this, PlayState* play) {
Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 3, 0x7D0, 0);
this->actor.world.rot.y = this->actor.shape.rot.y;
if (Actor_ProcessTalkRequest(&this->actor, &play->state)) {
- if (Player_GetExchangeItemId(play) == EXCH_ITEM_2A) {
+ if (Player_GetExchangeItemId(play) == EXCH_ITEM_MOON_TEAR) {
player->actor.textId = D_80ADD928[this->unk_33A];
this->unk_340 = player->actor.textId;
this->actionFunc = func_80ADBAB8;
@@ -382,7 +382,7 @@ void func_80ADB544(EnSellnuts* this, PlayState* play) {
} else if (((this->actor.xzDistToPlayer < 80.0f) &&
(((this->actor.playerHeightRel < 50.0f) && (this->actor.playerHeightRel > -50.0f)) ? true : false)) ||
this->actor.isTargeted) {
- func_800B85E0(&this->actor, play, 80.0f, EXCH_ITEM_2A);
+ func_800B85E0(&this->actor, play, 80.0f, EXCH_ITEM_MOON_TEAR);
if (player->transformation == PLAYER_FORM_DEKU) {
if (gSaveContext.save.day == 3) {
this->unk_33A = 2;
@@ -422,7 +422,7 @@ void func_80ADB924(EnSellnuts* this, PlayState* play) {
if (msgState == 0x10) {
item = func_80123810(play);
if (item > EXCH_ITEM_NONE) {
- if (item == EXCH_ITEM_2A) {
+ if (item == EXCH_ITEM_MOON_TEAR) {
player->actor.textId = D_80ADD928[this->unk_33A];
this->unk_340 = player->actor.textId;
player->exchangeItemId = item;
diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt
index 96b94580a..e5826c464 100644
--- a/tools/disasm/functions.txt
+++ b/tools/disasm/functions.txt
@@ -16436,17 +16436,17 @@
0x80BFD148:("EnScopecoin_Destroy",),
0x80BFD158:("EnScopecoin_Update",),
0x80BFD17C:("EnScopecoin_Draw",),
- 0x80BFD2E0:("func_80BFD2E0",),
- 0x80BFD30C:("func_80BFD30C",),
- 0x80BFD3A4:("func_80BFD3A4",),
- 0x80BFD434:("func_80BFD434",),
- 0x80BFD4FC:("func_80BFD4FC",),
- 0x80BFD5E4:("func_80BFD5E4",),
- 0x80BFD6BC:("func_80BFD6BC",),
- 0x80BFD8F0:("func_80BFD8F0",),
- 0x80BFD984:("func_80BFD984",),
- 0x80BFDA48:("func_80BFDA48",),
- 0x80BFDAE8:("func_80BFDAE8",),
+ 0x80BFD2E0:("EnBjt_UpdateSkelAnime",),
+ 0x80BFD30C:("EnBjt_ChangeAnimation",),
+ 0x80BFD3A4:("EnBjt_UpdateCollision",),
+ 0x80BFD434:("EnBjt_TakeItem",),
+ 0x80BFD4FC:("EnBjt_Appear",),
+ 0x80BFD5E4:("EnBjt_Vanish",),
+ 0x80BFD6BC:("EnBjt_ChooseBehaviour",),
+ 0x80BFD8F0:("EnBjt_CheckTalk",),
+ 0x80BFD984:("EnBjt_ChooseAnimation",),
+ 0x80BFDA48:("EnBjt_Talk",),
+ 0x80BFDAE8:("EnBjt_FollowSchedule",),
0x80BFDC98:("EnBjt_Init",),
0x80BFDD80:("EnBjt_Destroy",),
0x80BFDD90:("EnBjt_Update",),
diff --git a/undefined_syms.txt b/undefined_syms.txt
index 9a78d3105..c01caf4a0 100644
--- a/undefined_syms.txt
+++ b/undefined_syms.txt
@@ -944,10 +944,6 @@ D_06004210 = 0x06004210;
D_06007C70 = 0x06007C70;
D_0600823C = 0x0600823C;
-// ovl_En_Bjt
-
-D_06002390 = 0x06002390;
-
// ovl_En_Bombal
D_06000A00 = 0x06000A00;