Files
ac-decomp/src/ac_set_manager.c
T
2023-12-09 13:34:31 +01:00

282 lines
8.1 KiB
C

#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, sizeof(aSetMgr_keep_c));
}
/**
* @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 = {
mAc_PROFILE_SET_MANAGER,
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_KEEP,
sizeof(SET_MANAGER),
aSetMgr_ct,
aSetMgr_dt,
aSetMgr_move,
mActor_NONE_PROC1,
NULL
};