From 2af13706e7a24ad59a5c5016e44dcabf2dea7ef4 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Tue, 16 May 2023 21:13:49 -0400 Subject: [PATCH] Implement & link ac_set_manager --- config/rel_slices.yml | 4 + include/ac_set_manager.h | 75 ++++++++++ include/ac_set_ovl_gyoei.h | 17 +++ include/ac_set_ovl_insect.h | 16 ++ include/m_actor.h | 22 +++ include/m_field_info.h | 11 +- include/m_player.h | 27 ++++ include/m_player_lib.h | 17 +++ rel/ac_set_manager.c | 281 ++++++++++++++++++++++++++++++++++++ 9 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 include/ac_set_manager.h create mode 100644 include/ac_set_ovl_gyoei.h create mode 100644 include/ac_set_ovl_insect.h create mode 100644 include/m_player.h create mode 100644 include/m_player_lib.h create mode 100644 rel/ac_set_manager.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index db32c24b..214fac36 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -96,6 +96,10 @@ zurumode.c: sys_ucode.c: .text: [0x8040F008, 0x8040F048] .data: [0x8065FA30, 0x8065FA40] +ac_set_manager.c: + .text: [0x80496AB8, 0x80496F50] + .rodata: [0x80644DB8, 0x80644DC8] + .data: [0x8068BBE0, 0x8068BC18] m_huusui_room_ovl.c: .text: [0x804D1BBC, 0x804D2164] .rodata: [0x80646558, 0x806465C8] diff --git a/include/ac_set_manager.h b/include/ac_set_manager.h new file mode 100644 index 00000000..a657c568 --- /dev/null +++ b/include/ac_set_manager.h @@ -0,0 +1,75 @@ +#ifndef AC_SET_MANAGER_H +#define AC_SET_MANAGER_H + +#include "types.h" +#include "m_actor.h" +#include "m_play.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct actor_set_manager_s SET_MANAGER; + +#define aSetMgr_SET_OVERLAY_BUF_SIZE 0x4000 +#define aSetMgr_KEEP_SIZE 0x354 + +#define aSetMgr_WAIT_TIME 5 // wait time between aSetMgr_move_check_wait -> aSetMgr_move_set + +typedef void (*aSetMgr_ovl_proc)(SET_MANAGER*, GAME_PLAY*); + +enum set_overlay_type { + aSetMgr_OVERLAY_BEGIN = 0, + + aSetMgr_OVERLAY_INSECT = aSetMgr_OVERLAY_BEGIN, + aSetMgr_OVERLAY_GYOEI, + + aSetMgr_OVERLAY_NUM +}; + +enum set_manager_move_proc_type { + aSetMgr_MOVE_move_check_set, + aSetMgr_MOVE_move_check_wait, + aSetMgr_MOVE_move_set, + + aSetMgr_MOVE_PROC_NUM +}; + +/* sizeof(aSetMgr_keep_c) == 0x354 */ +typedef struct actor_set_manager_keep_s { + /* 0x000 */ u8 unk[aSetMgr_KEEP_SIZE]; +} aSetMgr_keep_c; + +/* sizeof(aSetMgr_set_ovl_c) == 0x4004 */ +typedef struct actor_set_manager_ovl_s { + /* 0x0000 */ u8 buf[aSetMgr_SET_OVERLAY_BUF_SIZE]; + /* 0x4000 */ aSetMgr_ovl_proc ovl_proc; +} aSetMgr_set_ovl_c; + +/* sizeof(aSetMgr_player_pos) == 0x18 */ +typedef struct actor_set_manager_player_pos_s { + /* 0x00 */ int next_bx, next_bz; + /* 0x08 */ int now_bx, now_bz; + /* 0x10 */ int last_bx, last_bz; +} aSetMgr_player_pos_c; + +/* sizeof(SET_MANAGER) == 0x44F0 */ +struct actor_set_manager_s { + /* 0x0000 */ ACTOR actor_class; + /* 0x0174 */ u8 move_proc; + /* 0x0175 */ u8 next_move_proc; + /* 0x0176 */ u8 set_ovl_type; + /* 0x0178 */ aSetMgr_set_ovl_c set_overlay; + /* 0x417C */ int unk_417C; + /* 0x4180 */ aSetMgr_player_pos_c player_pos; + /* 0x4198 */ aSetMgr_keep_c keep; + /* 0x44EC */ s16 wait_timer; +}; + +extern ACTOR_PROFILE Set_Manager_Profile; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ac_set_ovl_gyoei.h b/include/ac_set_ovl_gyoei.h new file mode 100644 index 00000000..5766238b --- /dev/null +++ b/include/ac_set_ovl_gyoei.h @@ -0,0 +1,17 @@ +#ifndef AC_SET_OVL_GYOEI_H +#define AC_SET_OVL_GYOEI_H + +#include "types.h" +#include "ac_set_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void aSOG_gyoei_set(SET_MANAGER* set_manager, GAME_PLAY* play); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ac_set_ovl_insect.h b/include/ac_set_ovl_insect.h new file mode 100644 index 00000000..d37144ad --- /dev/null +++ b/include/ac_set_ovl_insect.h @@ -0,0 +1,16 @@ +#ifndef AC_SET_OVL_INSECT_H +#define AC_SET_OVL_INSECT_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void aSOI_insect_set(SET_MANAGER* set_manager, GAME_PLAY* play); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_actor.h b/include/m_actor.h index 7d59b1c1..3a8c742e 100644 --- a/include/m_actor.h +++ b/include/m_actor.h @@ -12,6 +12,26 @@ extern "C" { typedef void (*mActor_proc)(ACTOR*, GAME*); +#define ACTOR_STATE_NO_MOVE_WHILE_CULLED (1 << 4) +#define ACTOR_STATE_NO_DRAW_WHILE_CULLED (1 << 5) +#define ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES (1 << 29) + +#define ACTOR_OBJ_BANK_NONE 0 +#define ACTOR_OBJ_BANK_3 3 /* TODO: rename, also likely an enum */ + +enum actor_part { + ACTOR_PART_FG, + ACTOR_PART_ITEM, + ACTOR_PART_PLAYER, + ACTOR_PART_NPC, + ACTOR_PART_4, /* TODO: figure this one out */ + ACTOR_PART_BG, + ACTOR_PART_EFFECT, + ACTOR_PART_CONTROL, + + ACTOR_PART_NUM +}; + /* sizeof(ACTOR_PROFILE) == 0x24 */ typedef struct actor_profile_s { /* 0x00 */ s16 id; /* unique actor type ID */ @@ -105,6 +125,8 @@ struct actor_s { /* 0x170 */ void* dlftbl; /* display list function table */ }; +#define mActor_NONE_PROC1 ((mActor_proc)none_proc1) + #ifdef __cplusplus } #endif diff --git a/include/m_field_info.h b/include/m_field_info.h index 356f51fb..697e71dc 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -45,6 +45,14 @@ enum field_room { ((field_id) == mFI_FIELD_PLAYER0_ROOM || (field_id) == mFI_FIELD_PLAYER1_ROOM || \ (field_id) == mFI_FIELD_PLAYER2_ROOM || (field_id) == mFI_FIELD_PLAYER3_ROOM) +/* "wade" between acres (acre transition) */ +enum player_wade_state { + mFI_WADE_NONE, + mFI_WADE_START, + mFI_WADE_INPROGRESS, + mFI_WADE_END +}; + /* Not sure about these other than the island one */ enum { mFI_CLIMATE_0, @@ -75,7 +83,8 @@ extern void mFI_GetSpecialBlockNum(int* block_pos_tbl, u32* kind_list, int kind_ extern int mFI_SetTreasure(int* block_x, int* block_z, mActor_name_t item_no); extern void mFI_SetFGUpData(); extern int mFI_ClearBlockItemRandom_common(mActor_name_t item_no, int count, mActor_name_t* fg_items, u16* deposit, int include_deposited); -extern void mFI_Wpos2BlockNum(int* block_x, int* block_z, xyz_t world_pos); +extern int mFI_Wpos2BlockNum(int* block_x, int* block_z, xyz_t world_pos); +extern int mFI_CheckPlayerWade(int wade_state); extern void mFI_PrintNowBGNum(gfxprint_t* gfxprint); extern void mFI_PrintFgAttr(gfxprint_t* gfxprint); diff --git a/include/m_player.h b/include/m_player.h new file mode 100644 index 00000000..cb5247e5 --- /dev/null +++ b/include/m_player.h @@ -0,0 +1,27 @@ +#ifndef M_PLAYER_H +#define M_PLAYER_H + +#include "types.h" +#include "m_actor.h" +#include "m_lib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct player_actor_s PLAYER_ACTOR; + +/* sizeof(struct player_actor_s) == 0x13A8 */ +struct player_actor_s { + /* 0x0000 */ ACTOR actor_class; + /* 0x0174 */ u8 tmp0174[0x1318 - 0x0174]; + /* 0x1318 */ int (*Get_WadeEndPos_proc)(GAME*, xyz_t*); + /* 0x131C */ u8 tmp131C[0x13A8 - 0x131C]; + /* TODO: finish */ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_player_lib.h b/include/m_player_lib.h new file mode 100644 index 00000000..e8da4979 --- /dev/null +++ b/include/m_player_lib.h @@ -0,0 +1,17 @@ +#ifndef M_PLAYER_LIB_H +#define M_PLAYER_LIB_H + +#include "types.h" +#include "m_player.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern PLAYER_ACTOR* get_player_actor_withoutCheck(GAME_PLAY* play); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/ac_set_manager.c b/rel/ac_set_manager.c new file mode 100644 index 00000000..11f92c72 --- /dev/null +++ b/rel/ac_set_manager.c @@ -0,0 +1,281 @@ +#include "ac_set_manager.h" +#include "m_name_table.h" +#include "m_lib.h" +#include "m_field_info.h" +#include "m_player_lib.h" +#include "libultra/libultra.h" +#include "ac_set_ovl_insect.h" +#include "ac_set_ovl_gyoei.h" + +/** + * @brief Gets the X & Z acre the player is currently in. + * + * @param bx Out player X-acre + * @param bz Out player Z-acre + * @return TRUE/FALSE successfully updated the acre + **/ +static int aSetMgr_get_player_block(int* bx, int* bz, GAME_PLAY* play) { + int res = FALSE; + PLAYER_ACTOR* player_actor = get_player_actor_withoutCheck(play); + + if (player_actor != NULL) { + res = mFI_Wpos2BlockNum(bx, bz, player_actor->actor_class.world_position); + } + + return res; +} + +/** + * @brief Gets the next X & Z acre which the player is currently transitioning into. + * + * @param next_bx Out next player X-acre + * @param next_bz Out next player Z-acre + * @return TRUE/FALSE successfully updated next acre + **/ +static int aSetMgr_renewal_player_next_pos(int* next_bx, int* next_bz) { + int wade_end_pos_res; + int wpos_2_blocknum_res; + xyz_t endpos = { 0.0f, 0.0f, 0.0f }; + GAME_PLAY* play = (GAME_PLAY*)gamePT; + + wade_end_pos_res = get_player_actor_withoutCheck(play)->Get_WadeEndPos_proc((GAME*)play, &endpos); // maybe make this a macro like GET_PLAYER_ACTOR() ? + wpos_2_blocknum_res = mFI_Wpos2BlockNum(next_bx, next_bz, endpos); + return wpos_2_blocknum_res | wade_end_pos_res; +} + +/** + * @brief Updates the set manager's internal player acre and updates the previous player acre. + * + * @param play GAME_PLAY pointer + * @param player_pos Pointer to SET_MANAGER internal player position structure + **/ +static void aSetMgr_renewal_player_pos(GAME_PLAY* play, aSetMgr_player_pos_c* player_pos) { + int bx, bz; + + player_pos->last_bx = player_pos->now_bx; + player_pos->last_bz = player_pos->now_bz; + + if (aSetMgr_get_player_block(&bx, &bz, play) == TRUE) { + player_pos->now_bx = bx; + player_pos->now_bz = bz; + } +} + +/** + * @brief Checks if the player's wade state is 'starting'. + * + * @return TRUE when the player is beginning an acre transition, FALSE otherwise + **/ +static int aSetMgr_check_player_wade_start() { + return mFI_CheckPlayerWade(mFI_WADE_START); +} + +/** + * @brief Checks if the player's wade state is 'ending'. + * + * @return TRUE when the player is finishing an acre transition, FALSE otherwise + **/ +static int aSetMgr_check_player_wade_end() { + return mFI_CheckPlayerWade(mFI_WADE_END); +} + +/** + * @brief Clears the set overlay buffer. + * + * @param set_ovl Pointer to SET_MANAGER's internal aSetMgr_set_ovl_c overlay structure + **/ +static void aSetMgr_clear_set_ovl(aSetMgr_set_ovl_c* set_ovl) { + bzero(set_ovl->buf, aSetMgr_SET_OVERLAY_BUF_SIZE); + set_ovl->ovl_proc = NULL; +} + +/** + * @brief Updates the SET_MANAGER's current set overlay process. + * + * @param set_ovl Pointer to SET_MANAGER's internal aSetMgr_set_ovl_c overlay structure + * @param type The aSetMgr_OVERLAY_* type which will be executed + * @return TRUE + **/ +static int aSetMgr_ovl(aSetMgr_set_ovl_c* set_ovl, int type) { + static aSetMgr_ovl_proc proc_table[aSetMgr_OVERLAY_NUM] = { &aSOI_insect_set, &aSOG_gyoei_set }; + + if (type < aSetMgr_OVERLAY_BEGIN || type >= aSetMgr_OVERLAY_NUM) { + type = aSetMgr_OVERLAY_BEGIN; + } + + set_ovl->ovl_proc = proc_table[type]; + return TRUE; +} + +/** + * @brief Clears the SET_MANAGER's "kept" data buffer. + * + * @param keep Pointer to the SET_MANAGER's internal aSetMgr_keep_c structure + **/ +static void aSetMgr_clear_keep(aSetMgr_keep_c* keep) { + bzero(keep, aSetMgr_KEEP_SIZE); +} + +/** + * @brief Check if the 'move' func state should be updated to 'check_wait'. + * + * This check is succeeded by the player entering an acre transition state. + * + * @param play GAME_PLAY pointer + * @param set_manager SET_MANAGER pointer + * @return TRUE when updated, FALSE otherwise + **/ +static int aSetMgr_move_check_set(GAME_PLAY* play, SET_MANAGER* set_manager) { + int wading = FALSE; + aSetMgr_renewal_player_pos(play, &set_manager->player_pos); + + /* update the next acre position if player is starting acre transition state */ + if (aSetMgr_check_player_wade_start() == TRUE) { + aSetMgr_renewal_player_next_pos(&set_manager->player_pos.next_bx, &set_manager->player_pos.next_bz); + set_manager->next_move_proc = aSetMgr_MOVE_move_check_wait; + wading = TRUE; + } + + return wading; +} + +typedef int (*aSetMgr_move_proc)(GAME_PLAY*, SET_MANAGER*); + +/** + * @brief Checks whether or not to update the move proc to 'set'. + * + * The SET_MANAGER's internal wait timer must be zero to pass this check. + * + * @param play GAME_PLAY pointer + * @param set_manager SET_MANAGER pointer + * @return TRUE when updated, FALSE otherwise + **/ +static int aSetMgr_move_check_wait(GAME_PLAY* play, SET_MANAGER* set_manager) { + int wait_timer; + int res = FALSE; + + if (set_manager->next_move_proc == aSetMgr_MOVE_move_check_wait) { + if (set_manager->wait_timer == 0) { + wait_timer = 0; + } + else { + wait_timer = --set_manager->wait_timer; + } + + if (wait_timer == 0) { + set_manager->next_move_proc = aSetMgr_MOVE_move_set; + set_manager->wait_timer = aSetMgr_WAIT_TIME; + res = TRUE; + } + } + return res; +} + +/** + * @brief Processes SET_MANAGER's overlay actors & checks whether to update move func state. + * + * All SET_MANAGER overlay processes must have been executed OR the player must + * finish transitioning between acres for this check to pass. + * + * @param play GAME_PLAY pointer + * @param set_manager SET_MANAGER pointer + * @return TRUE when updated, FALSE otherwise + **/ +static int aSetMgr_move_set(GAME_PLAY* play, SET_MANAGER* set_manager) { + int res = FALSE; + + if (aSetMgr_ovl(&set_manager->set_overlay, set_manager->set_ovl_type) == TRUE && + set_manager->set_overlay.ovl_proc != NULL) { + set_manager->set_overlay.ovl_proc(set_manager, play); + set_manager->set_ovl_type++; + } + else { + set_manager->set_ovl_type++; + } + + if (set_manager->set_ovl_type >= aSetMgr_OVERLAY_NUM) { + set_manager->next_move_proc = aSetMgr_MOVE_move_check_set; + set_manager->set_ovl_type = aSetMgr_OVERLAY_BEGIN; + res = TRUE; + } + + if (aSetMgr_check_player_wade_end() == TRUE) { + set_manager->next_move_proc = aSetMgr_MOVE_move_check_set; + set_manager->set_ovl_type = aSetMgr_OVERLAY_BEGIN; + res = TRUE; + } + + return res; +} + +/** + * @brief SET_MANAGER move process. + * + * @param actor Pointer to the SET_MANAGER actor + * @param game GAME pointer + **/ +static void aSetMgr_move(ACTOR* actor, GAME* game) { + static aSetMgr_move_proc move[aSetMgr_MOVE_PROC_NUM] = { + &aSetMgr_move_check_set, + &aSetMgr_move_check_wait, + &aSetMgr_move_set + }; + + SET_MANAGER* set_manager = (SET_MANAGER*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + + if ((*move[set_manager->move_proc])(play, set_manager) == TRUE) { + set_manager->move_proc = set_manager->next_move_proc; + } +} + +/** + * @brief SET_MANAGER constructor. + * + * @param actor Pointer to the SET_MANAGER actor + * @param game GAME pointer + **/ +static void aSetMgr_ct(ACTOR* actor, GAME* game) { + SET_MANAGER* set_manager = (SET_MANAGER*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + + set_manager->move_proc = aSetMgr_MOVE_move_check_set; + set_manager->next_move_proc = aSetMgr_MOVE_move_check_set; + set_manager->set_ovl_type = aSetMgr_OVERLAY_BEGIN; + + aSetMgr_clear_set_ovl(&set_manager->set_overlay); + + set_manager->player_pos.next_bx = 0; + set_manager->player_pos.next_bz = 0; + set_manager->player_pos.now_bx = 0; + set_manager->player_pos.now_bz = 0; + set_manager->player_pos.last_bx = 0; + set_manager->player_pos.last_bz = 0; + + set_manager->wait_timer = aSetMgr_WAIT_TIME; + + aSetMgr_clear_keep(&set_manager->keep); +} + +/** + * @brief SET_MANAGER destructor. + * + * @param actor Pointer to the SET_MANAGER actor + * @param game GAME pointer + **/ +static void aSetMgr_dt(ACTOR* actor, GAME* game) { } + +/* actor profile for SET_MANAGER */ +ACTOR_PROFILE Set_Manager_Profile = { + 0x72, /* TODO: replace with enum */ + ACTOR_PART_CONTROL, /* control actor type */ + ACTOR_STATE_NO_MOVE_WHILE_CULLED | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES, + EMPTY_NO, + ACTOR_OBJ_BANK_3, + sizeof(SET_MANAGER), + aSetMgr_ct, + aSetMgr_dt, + aSetMgr_move, + mActor_NONE_PROC1, + NULL +};