diff --git a/include/audio.h b/include/audio.h index a5837c3f..d818fe9d 100644 --- a/include/audio.h +++ b/include/audio.h @@ -7,6 +7,12 @@ extern "C" { #endif +/* sizeof(TempoBeat_c) == 2 */ +typedef struct audio_tempo_beat_s { + /* 0x00 */ u8 tempo; + /* 0x01 */ s8 beat; +} TempoBeat_c; + extern void sAdo_GameFrame(); extern void sAdo_SoftReset(); diff --git a/include/game.h b/include/game.h index 20973f5e..a1a7c626 100644 --- a/include/game.h +++ b/include/game.h @@ -54,10 +54,14 @@ do { \ extern void game_get_controller(GAME* game); -extern GAME* game_class_p; - extern GAME* gamePT; +extern GAME* game_class_p; +extern u8 game_GameFrame; +extern float game_GameFrameF; +extern float game_GameFrame_2F; +extern float game_GameFrame__1F; + #ifdef __cplusplus }; #endif diff --git a/include/libultra/ultratypes.h b/include/libultra/ultratypes.h index cb22866b..ccb05f87 100644 --- a/include/libultra/ultratypes.h +++ b/include/libultra/ultratypes.h @@ -1,5 +1,5 @@ -#ifndef U64TYPES_H -#define U64TYPES_H +#ifndef ULTRATYPES_H +#define ULTRATYPES_H #include "types.h" diff --git a/include/m_actor.h b/include/m_actor.h new file mode 100644 index 00000000..0d39b13d --- /dev/null +++ b/include/m_actor.h @@ -0,0 +1,19 @@ +#ifndef M_ACTOR_H +#define M_ACTOR_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct actor_s { + /* TODO ... */ + u8 _tmp; +} ACTOR; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_common_data.h b/include/m_common_data.h index adcbacab..d88d44e8 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -6,6 +6,10 @@ #include "m_land_h.h" #include "lb_rtc.h" #include "m_flashrom.h" +#include "m_home.h" +#include "m_private.h" +#include "m_npc.h" +#include "m_field_make.h" #ifdef __cplusplus extern "C" { @@ -30,17 +34,32 @@ typedef struct time_s { } Time_c; typedef struct Save_s { - /* 0x000000 */ mFRm_chk_t save_check; - /* 0x000014 */ int scene_no; - u8 _tmp0[0x9108]; - /* 0x009120 */ mLd_land_info_c land_info; - u8 _tmp1[0x17DE8]; - /* 0x020F14 */ lbRTC_ymd_t renew_time; - u8 _tmp2[0x476]; - /* 0x02138E */ u8 saved_rom_debug; - u8 _tmp3[0x1199]; - /* 0x022528 */ OSTime time_delta; - u8 _tmp4[0x3AD0]; + /* 0x000000 */ mFRm_chk_t save_check; /* save information */ + /* 0x000014 */ int scene_no; /* current 'scene' id */ + /* 0x000018 */ u8 now_npc_max; /* current number of villagers living in town (see mNpc_(Add/Sub)NowNpcMax) */ + /* 0x000019 */ u8 remove_animal_idx; /* index of the villager which is scheduled to leave town, 0xFF when none selected */ + /* 0x00001A */ u16 copy_protect; /* 'unique' value between [1, 65520] used for copy protection (see mCD_get_land_copyProtect) */ + /* 0x00001C */ u8 _tmp0[0x9104]; /* Private_c struct [4] goes here starting at 0x20 */ + /* 0x009120 */ mLd_land_info_c land_info; /* town name & id */ + /* 0x00912C */ u8 _tmp1[0xBBC]; /* notice board info goes here */ + /* 0x009CE8 */ mHm_hs_c homes[PLAYER_NUM]; /* player house data */ + /* 0x0137A8 */ mFM_fg_c fg[FG_BLOCK_Z_NUM][FG_BLOCK_X_NUM]; /* fg items (fg = foreground?) */ + /* 0x0173A8 */ mFM_combination_c combi_table[BLOCK_Z_NUM][BLOCK_X_NUM]; /* acre 'combination' data */ + /* 0x017438 */ Animal_c animals[ANIMAL_NUM_MAX]; /* villagers in town */ + /* 0x020330 */ AnmPersonalID_c last_removed_animal_id; /* ID of last villager who left town */ + /* 0x02033E */ u8 _tmp3[0xBD6]; + /* 0x020F14 */ lbRTC_ymd_t renew_time; /* next renew date */ + /* 0x020F18 */ u8 station_type; /* train station type */ + /* 0x020F19 */ u8 weather; /* upper nibble is intensity, lower nibble is type */ + /* 0x020F1A */ u8 save_exist; /* unsure, set in mCD_SaveHome_bg_set_data (1) & mCD_SaveHome_bg (bss) */ + /* 0x020F1B */ u8 npc_force_go_home; /* when set to 1, forces the 'm_go_home' code to activate */ + /* 0x020F1C */ u16 deposit[FG_BLOCK_X_NUM * FG_BLOCK_Z_NUM][UT_Z_NUM]; /* flags for which items are buried around town */ + /* 0x0212DC */ lbRTC_time_c last_grow_time; /* last time that a new villager moved into town */ + /* 0x0212E4 */ u8 _tmp4[0xAA]; + /* 0x02138E */ u8 saved_rom_debug; /* flag to set save to 'debug rom' mode */ + /* 0x02138F */ u8 _tmp5[0x1199]; + /* 0x022528 */ OSTime time_delta; /* time delta against GC RTC */ + /* 0x022530 */ u8 _tmp6[0x3AD0]; } Save_t; typedef union save_u { @@ -50,7 +69,7 @@ typedef union save_u { typedef struct common_data_s { /* 0x000000 */ Save save; - /* 0x026000 */ u8 game_1_patu; + /* 0x026000 */ u8 game_started; /* 0x026001 */ u8 field_type; /* 0x026002 */ u8 field_draw_type; /* 0x026003 */ u8 player_no; diff --git a/include/m_field_make.h b/include/m_field_make.h new file mode 100644 index 00000000..a7124f69 --- /dev/null +++ b/include/m_field_make.h @@ -0,0 +1,35 @@ +#ifndef M_FIELD_MAKE_H +#define M_FIELD_MAKE_H + +#include "types.h" +#include "m_actor_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLOCK_X_NUM 7 +#define BLOCK_Z_NUM 10 + +#define FG_BLOCK_X_NUM (BLOCK_X_NUM - 2) /* 5 */ +#define FG_BLOCK_Z_NUM (BLOCK_Z_NUM - 4) /* 6 */ + +#define UT_X_NUM 16 /* Spaces per block (acre) in x direction */ +#define UT_Z_NUM 16 /* Spaces per block (acre) in z direction */ + +/* sizeof(mFM_combination_c) == 2 */ +typedef struct block_combination_s { + /* 0x00 */ u16 combination_type:14; /* acre type index */ + /* 0x00 */ u16 height:2; /* 0, 1, 2, or 3 (unused) */ +} mFM_combination_c; + +/* sizeof(mFM_fg_c) == 0x200 */ +typedef struct fg_items_s { + /* 0x000 */ mActor_name_t items[UT_Z_NUM][UT_X_NUM]; +} mFM_fg_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_flashrom.h b/include/m_flashrom.h index dfc0a89d..80ba2ee4 100644 --- a/include/m_flashrom.h +++ b/include/m_flashrom.h @@ -30,8 +30,8 @@ typedef int (save_check_proc)(void); extern void mFRm_set_msg_idx(int idx); extern int mFRm_get_msg_idx(); -extern u16 mFRm_ReturnCheckSum(u16* data, s32 size); -extern u16 mFRm_GetFlatCheckSum(u16* data, s32 size, s16 now_checksum); +extern u16 mFRm_ReturnCheckSum(u16* data, int size); +extern u16 mFRm_GetFlatCheckSum(u16* data, int size, u16 now_checksum); extern int mFRm_CheckSaveData_ID(mFRm_chk_t* save_check); extern int mFRm_CheckSaveData_common(mFRm_chk_t* save_check, u16 land_id); extern int mFRm_CheckSaveData(); diff --git a/include/m_home.h b/include/m_home.h index 13e1a058..fcde6133 100644 --- a/include/m_home.h +++ b/include/m_home.h @@ -2,11 +2,119 @@ #define M_HOME_H #include "types.h" +#include "m_field_make.h" +#include "m_actor_type.h" +#include "m_personal_id.h" +#include "audio.h" +#include "lb_rtc.h" +#include "m_mail.h" #ifdef __cplusplus extern "C" { #endif +#define HOME_MAILBOX_SIZE 10 +#define HANIWA_ITEM_HOLD_NUM 4 +#define HANIWA_MESSAGE_LEN 128 + +/* sizeof(mHm_rmsz_c) == 6 */ +typedef struct home_size_info_s { + /* 0x00 */ struct { + /* 0x00 */ u8 day; + /* 0x01 */ u8 month; + /* 0x02 */ u16 year; + } upgrade_order_date; /* date you ordered an upgrade, seems to be a struct */ + + /* 0x04 */ u8 size:3; /* current house size */ + /* 0x04 */ u8 next_size:3; /* next house size when upgrade is ordered */ + /* 0x04 */ u8 statue_rank:2; /* statue ranking, 0 = gold, 1 = silver, 2 = bronze, 3 = jade */ + /* 0x05 */ u8 renew:1; /* refresh house size & 'outlook' palette */ + /* 0x05 */ u8 statue_ordered:1; /* set when statue is ordered from Nook */ + /* 0x05 */ u8 basement_ordered:1; /* set when basement has been ordered */ + /* 0x05 */ u8 pad:5; /* unused? */ +} mHm_rmsz_c; + +/* sizeof(Haniwa_Item_c) == 8 */ +typedef struct home_haniwa_item_s { + /* 0x00 */ mActor_name_t item; /* held item */ + /* 0x02 */ s16 exchange_type; /* type of exchange (sale, free, trade) */ + /* 0x04 */ u32 extra_data; /* trade related data */ +} Haniwa_Item_c; + +/* sizeof(Haniwa_c) == 0xA4 */ +typedef struct home_haniwa_s { + /* 0x00 */ Haniwa_Item_c items[HANIWA_ITEM_HOLD_NUM]; /* held items */ + /* 0x20 */ u8 message[HANIWA_MESSAGE_LEN]; /* message for visitors */ + /* 0xA0 */ u32 bells; /* held bells from selling items */ +} Haniwa_c; + +/* sizeof(mHm_wf_c) == 2 */ +typedef struct home_wall_floor_s { + /* 0x00 */ u8 flooring_idx; + /* 0x01 */ u8 wallpaper_idx; +} mHm_wf_c; + +/* sizeof(mHm_goki_c) == 0xA */ +typedef struct home_goki_s { + /* 0x00 */ lbRTC_time_c time; /* last time updated */ + /* 0x08 */ u8 num; /* number of cockroaches in the house */ +} mHm_goki_c; + +/* sizeof(mHm_lyr_c) == 0x228 */ +typedef struct home_layer_s { + /* 0x000 */ mActor_name_t items[UT_Z_NUM][UT_X_NUM]; /* Furniture item actors */ + /* 0x200 */ u64 ftr_switch; /* Bitfield for controlling which furniture items are active, max of 64 */ + /* 0x208 */ u32 unk_208[8]; /* Only referenced in mISL_gc_to_agb_layer */ +} mHm_lyr_c; + +/* sizeof(mHm_flr_c) == 0x8A8 */ +typedef struct home_floor_s { + /* 0x000 */ mHm_lyr_c layer_main; + /* 0x228 */ mHm_lyr_c layer_secondary; /* Also storage layer 0 */ + /* 0x450 */ mHm_lyr_c layer_storage1; + /* 0x678 */ mHm_lyr_c layer_storage2; + /* 0x8A0 */ mHm_wf_c wall_floor; + /* 0x8A2 */ TempoBeat_c tempo_beat; + /* 0x8A4 */ struct { + u8 wall_original:1; /* is wallpaper a pattern (original)? */ + u8 floor_original:1; /* is flooring a pattern (original)? */ + u8 bit_2_7:6; /* unused? */ + } fllot_bit; /* Name exposed? by mISL_gc_to_agb_fllot_bit */ +} mHm_flr_c; + +/* sizeof(mHm_hs_c) == 0x26B0 */ +typedef struct home_s { + /* 0x0000 */ PersonalID_c ownerID; /* owner player's ID */ + /* 0x0014 */ u8 unk_14[6]; + /* 0x001A */ TempoBeat_c haniwa_tempo; /* unsure about this */ + /* 0x001C */ lbRTC_ymd_t hra_mark_time; /* last HRA judge date */ + /* 0x0020 */ u32 hra_mark_info; /* bitfield of HRA info pulled when HRA mails letter */ + /* 0x0024 */ struct { + u8 house_updated:1; /* signals HRA to re-score house */ + u8 has_saved:1; /* whether or not the player has saved at this house before */ + u8 hra_member:1; /* whether or not the house has been setup for HRA membership */ + u8 has_basement:1; /* set when the basement is built */ + u8 bit_4:1; /* unused */ + u8 bit_5:1; /* unused */ + u8 bit_6:1; /* unused */ + u8 bit_7:1; /* unused */ + } flags; + /* 0x0026 */ mHm_rmsz_c size_info; /* home size info */ + /* 0x002C */ u8 outlook_pal; /* current house palette */ + /* 0x002D */ u8 ordered_outlook_pal; /* house palette ordered at Nook's via upgrade */ + /* 0x002E */ u8 next_outlook_pal; /* next house palette set via all other means (villager, Wisp, paint @ Nook's, ...) */ + /* 0x002F */ u8 door_original; /* player design shown on door, apparently called 'original', maybe 'original design'? */ + /* 0x0030 */ u8 unk_30[8]; /* unused? */ + /* 0x0038 */ mHm_flr_c main_floor; /* main floor */ + /* 0x08E0 */ mHm_flr_c upper_floor; /* second floor */ + /* 0x1188 */ mHm_flr_c basement; /* basement floor */ + /* 0x1A30 */ Mail_c mailbox[HOME_MAILBOX_SIZE]; /* mailbox */ + /* 0x25D4 */ Haniwa_c haniwa; /* gyroid info */ + /* 0x2678 */ mHm_goki_c goki; /* cockroach info */ + /* 0x2684 */ u32 music_box[2]; /* bitfield of inserted music */ + /* 0x268C */ u8 unk_286C[36]; /* unused? */ +} mHm_hs_c; + extern void mHm_ClearAllHomeInfo(); #ifdef __cplusplus diff --git a/include/m_land_h.h b/include/m_land_h.h index 1330a653..563d29fd 100644 --- a/include/m_land_h.h +++ b/include/m_land_h.h @@ -11,10 +11,11 @@ extern "C" { #define LAND_NAME_SIZE 8 #define LAND_NAME_MURA_SIZE (LAND_NAME_SIZE + 2) +/* sizeof(mLd_land_info_c) == 0x0C */ typedef struct land_info_s { - u8 name[LAND_NAME_SIZE]; - s8 exists; - u16 id; + /* 0x00 */ u8 name[LAND_NAME_SIZE]; + /* 0x08 */ s8 exists; + /* 0x0A */ u16 id; } mLd_land_info_c; #ifdef __cplusplus diff --git a/include/m_lib.h b/include/m_lib.h index 7fc4d46f..87134171 100644 --- a/include/m_lib.h +++ b/include/m_lib.h @@ -2,11 +2,19 @@ #define M_LIB_H #include "types.h" +#include "m_play.h" +#include "m_actor.h" -#define ABS(x) ((x) >= 0) ? (x) : -(x) +#ifdef __cplusplus +extern "C" { +#endif + +#define SHT_MAX 32767.0f +#define SHT_MINV (1.0f / SHT_MAX) +#define ABS(x) (((x) >= 0) ? (x) : -(x)) #define SQ(x) ((x)*(x)) -typedef struct xy_s { +typedef struct xy_s { f32 x, y; } xy_t; @@ -22,49 +30,54 @@ typedef struct rgba_t { //can be put in other place u8 r, g, b, a; } rgba_t; -extern void mem_copy(u8*, u8*, u32); -extern void mem_clear(u8*, u32, u8); -extern s32 mem_cmp(u8*, u8*, u32); +extern void mem_copy(u8* dst, u8* src, size_t size); +extern void mem_clear(u8* dst, size_t size, u8 val); +extern int mem_cmp(u8* p1, u8* p2, size_t size); -extern f32 sin_s(s16); -extern f32 cos_s(s16); +extern f32 cos_s(s16 angle); +extern f32 sin_s(s16 angle); -extern s32 chase_angle(s16*, s16, s16); -extern s32 chase_s(s16*, s16, s16); -extern s32 chase_f(f32*, f32, f32); -extern f32 chase_xyz_t(xyz_t*, xyz_t*, f32); -extern s32 chase_angle2(s16*, s16, s16); +extern int chase_angle(s16* const pValue, const s16 target, s16 step); +extern int chase_s(s16* const pValue, const s16 target, s16 step); +extern int chase_f(f32* const pValue, const f32 target, f32 step); +extern f32 chase_xyz_t(xyz_t* const pValue, const xyz_t* const target, const f32 fraction); +extern int chase_angle2(s16* const pValue, const s16 limit, const s16 step); -extern void inter_float(f32*, f32, s32); -extern s16 get_random_timer(s16, s16); +extern void inter_float(f32* const pValue, const f32 arg1, const int step); +extern s16 get_random_timer(const s16 base, const s16 range); -extern void xyz_t_move(xyz_t*, xyz_t*); -extern void xyz_t_move_s_xyz(xyz_t*, s_xyz*); -extern void xyz_t_add(xyz_t*, xyz_t*, xyz_t*); -extern void xyz_t_sub(xyz_t*, xyz_t*, xyz_t*); -extern void xyz_t_mult_v(xyz_t*, f32); +extern void xyz_t_move(xyz_t* const dest, const xyz_t* const src); +extern void xyz_t_move_s_xyz(xyz_t* const dest, const s_xyz* const src); +extern void xyz_t_add(const xyz_t* const augend, const xyz_t* const addend, xyz_t* const total); +extern void xyz_t_sub(const xyz_t* const minuend, const xyz_t* const subtrahend, xyz_t* const diff); +extern void xyz_t_mult_v(xyz_t* const multiplicand, const f32 multiplier); -extern f32 search_position_distance(xyz_t*, xyz_t*); -extern f32 search_position_distanceXZ(xyz_t*, xyz_t*); -extern s16 search_position_angleY(xyz_t*, xyz_t*); -extern s16 search_position_angleX(xyz_t*, xyz_t*); +extern f32 search_position_distance(const xyz_t* const pos, const xyz_t* const target); +extern f32 search_position_distanceXZ(const xyz_t* const pos, const xyz_t* const target); +extern s16 search_position_angleY(const xyz_t* const pos, const xyz_t* const target); +extern s16 search_position_angleX(const xyz_t* const pos, const xyz_t* const target); -extern void add_calc2(f32*, f32, f32, f32); -extern void add_calc0(f32*, f32, f32); +extern f32 add_calc(f32* pValue, f32 target, f32 fraction, f32 maxStep, f32 minStep); +extern void add_calc2(f32* pValue, f32 target, f32 fraction, f32 maxStep); +extern void add_calc0(f32* pValue, f32 fraction, f32 maxStep); -extern s16 add_calc_short_angle2(s16*, s16, f32, s16, s16); -extern s16 add_calc_short_angle3(s16*, s16, f32, s16, s16); +extern s16 add_calc_short_angle2(s16* pValue, s16 target, f32 fraction, s16 maxStep, s16 minStep); +extern s16 add_calc_short_angle3(s16* pValue, s16 target, f32 fraction, s16 maxStep, s16 minStep); -extern void rgba_t_move(rgba_t*, rgba_t*); +extern void rgba_t_move(rgba_t* dest, const rgba_t* const src); -extern u32 none_proc1(void); -extern void none_proc2(void); +extern int none_proc1(); +extern void none_proc2(ACTOR* actor, GAME* game); -extern void _Game_play_isPause(u32); //IDK +extern int _Game_play_isPause(GAME_PLAY* play); +extern f32 check_percent_abs(f32 x, f32 min, f32 max, f32 scale, int shift_by_min); +extern f32 get_percent_forAccelBrake(const f32 now, const f32 start, const f32 end, const f32 accelerateDist, const f32 brakeDist); +extern void Game_play_Projection_Trans(GAME_PLAY* const play, xyz_t* wpos, xyz_t* screen_pos); + +extern f32 get_percent(const int max, const int min, const int x); + +#ifdef __cplusplus +} +#endif -//Unsure -//?? check_percent_abs(); -//?? get_percent_forAccelBrake(); -//void Game_play_Projection_Trans(game_play*, Vec3f*, Vec3f); -extern f32 get_percent(s32, s32, s32); #endif \ No newline at end of file diff --git a/include/m_mail.h b/include/m_mail.h new file mode 100644 index 00000000..e9dd4c73 --- /dev/null +++ b/include/m_mail.h @@ -0,0 +1,66 @@ +#ifndef M_MAIL_H +#define M_MAIL_H + +#include "types.h" +#include "m_personal_id.h" +#include "m_actor_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAIL_HEADER_LEN (32 - PLAYER_NAME_LEN) +#define MAIL_FOOTER_LEN 32 +#define MAIL_BODY_LEN 192 + +enum { + mMl_NAME_TYPE_PLAYER, + mMl_NAME_TYPE_NPC, + mMl_NAME_TYPE_MUSEUM, + + mMl_TYPE_CLEAR = 0xFF +}; + +/* sizeof(Mail_nm_c) == 0x16 */ +typedef struct mail_nm_s { + /* 0x00 */ PersonalID_c personalID; + /* 0x14 */ u8 type; +} Mail_nm_c; + +/* sizeof(mail_header_save_s) == 0x3A */ +typedef struct mail_header_save_s { + /* 0x00 */ s8 header_back_start; + /* 0x01 */ u8 unknown; + /* 0x02 */ u8 header[MAIL_HEADER_LEN]; + /* 0x1A */ u8 footer[MAIL_FOOTER_LEN]; +} Mail_hs_c; + +/* sizeof(Mail_hdr_c) == 0x2C */ +typedef struct mail_header_s { + /* 0x00 */ Mail_nm_c recipient; + /* 0x16 */ Mail_nm_c sender; +} Mail_hdr_c; + +/* sizeof(Mail_ct_c) == 0xFC */ +typedef struct mail_content_s { + /* 0x00 */ u8 font; + /* 0x01 */ u8 header_back_start; + /* 0x02 */ u8 mail_type; + /* 0x03 */ u8 paper_type; + /* 0x04 */ u8 header[MAIL_HEADER_LEN]; + /* 0x1C */ u8 body[MAIL_BODY_LEN]; + /* 0xDC */ u8 footer[MAIL_FOOTER_LEN]; +} Mail_ct_c; + +/* sizeof(Mail_c) == 0x12A */ +typedef struct mail_s { + /* 0x000 */ Mail_hdr_c header; + /* 0x02C */ mActor_name_t present; + /* 0x02E */ Mail_ct_c content; +} Mail_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_npc.h b/include/m_npc.h index cb82d58a..b503b65c 100644 --- a/include/m_npc.h +++ b/include/m_npc.h @@ -3,11 +3,110 @@ #include "types.h" #include "libu64/gfxprint.h" +#include "m_actor_type.h" +#include "m_land_h.h" +#include "m_mail.h" +#include "lb_rtc.h" +#include "m_personal_id.h" +#include "m_quest.h" #ifdef __cplusplus extern "C" { #endif +#define mNpc_GET_IDX(npc_id) ((npc_id) & 0x0FFF) +#define mNpc_GET_TYPE(npc_id) ((npc_id) & 0xF000) +#define mNpc_IS_SPECIAL(npc_id) (mNpc_GET_TYPE(npc_id) == 0xD000) + +#define ANIMAL_NUM_MAX 15 /* Maximum number of villagers possible in town */ +#define ANIMAL_MEMORY_NUM 7 +#define ANIMAL_CATCHPHRASE_LEN 10 +#define ANIMAL_HP_MAIL_NUM 4 + +/* sizeof(AnmPersonalID_c) == 0xE */ +typedef struct animal_personal_id_s { + /* 0x00 */ mActor_name_t npc_id; /* id */ + /* 0x02 */ u16 land_id; /* town id */ + /* 0x04 */ u8 land_name[LAND_NAME_SIZE]; /* town name */ + /* 0x0C */ u8 name_id; /* lower byte of the id */ + /* 0x0D */ u8 looks; /* internal name for personality */ +} AnmPersonalID_c; + +/* sizeof(Anmplmail_c) == 0x104 */ +typedef struct animal_player_maiL_s { + /* 0x000 */ u8 font; /* 'font' to use for letter info */ + /* 0x001 */ u8 paper_type; + /* 0x002 */ mActor_name_t present; + /* 0x004 */ u8 header_back_start; /* position for name insertion in header */ + /* 0x005 */ u8 header[MAIL_HEADER_LEN]; + /* 0x01D */ u8 body[MAIL_BODY_LEN]; + /* 0x0DD */ u8 footer[MAIL_FOOTER_LEN]; + /* 0x0FD */ u8 pad0; /* likely pad */ + /* 0x0FE */ lbRTC_ymd_t date; /* sent date */ +} Anmplmail_c; + +/* sizeof(Anmhome_c) == 5 */ +typedef struct animal_home_s { + /* 0x00 */ u8 type_unused; /* Likely the house type, but seems to be unused outside of SChk_Anmhome_c_sub */ + /* 0x01 */ u8 block_x; /* acre x position */ + /* 0x02 */ u8 block_z; /* acre y position */ + /* 0x03 */ u8 ut_x; /* unit x position */ + /* 0x04 */ u8 ut_z; /* unit z position */ +} Anmhome_c; + +/* sizeof(Anmlet_c) == 1 */ +typedef struct animal_letter_info_s { + u8 exists:1; /* letter received by villager and exists */ + u8 password_letter:1; /* set when the letter contains a 'key' symbol and is considered a password letter */ + u8 send_reply:1; /* set when the villager should reply */ + u8 has_present_cloth:1; /* set when the villager's held present shirt is from this letter */ + u8 wearing_present_cloth:1; /* set when a villager is wearing the shirt sent with the saved letter */ + u8 bit5_7:3; /* seemingly unused */ +} Anmlet_c; + +/* sizeof(Anmmem_c) == 0x138 */ +typedef struct animal_memory_s { + /* 0x000 */ PersonalID_c memory_player_id; /* personal id of the player memory belongs to */ + /* 0x014 */ lbRTC_time_c last_speak_time; /* time the player last spoke to this villager */ + /* 0x01C */ u8 land_name[LAND_NAME_SIZE]; /* memory origin land name */ + /* 0x024 */ u16 land_id; /* memory origin land id */ + /* 0x028 */ u64 saved_town_tune; /* memory origin town tune */ + /* 0x030 */ s8 friendship; /* friendship with the player */ + /* 0x031 */ Anmlet_c letter_info; /* saved letter flags */ + /* 0x032 */ Anmplmail_c letter; /* saved letter */ +} Anmmem_c; + +/* sizeof(AnmHPMail_c) == 0x1C */ +typedef struct animal_password_mail_s { + /* 0x00 */ lbRTC_time_c receive_time; + /* 0x08 */ u8 password[20]; /* TODO: this should not be a hardcoded length */ +} AnmHPMail_c; + +/* sizeof(Animal_c) == 0x988 */ +typedef struct animal_s { + /* 0x000 */ AnmPersonalID_c id; /* this villager's ID */ + /* 0x010 */ Anmmem_c memories[ANIMAL_MEMORY_NUM]; /* memories of players who've spoken to this villager */ + /* 0x898 */ Anmhome_c home_info; /* home position info */ + /* 0x89D */ u8 catchphrase[ANIMAL_CATCHPHRASE_LEN]; /* may be called 'word_ending' */ + /* 0x8A8 */ mQst_contest_c contest_quest; /* current contest quest information */ + /* 0x8D0 */ u8 parent_name[PLAYER_NAME_LEN]; /* name of the player who 'spawned' the villager in, unsure why this is tracked */ + /* 0x8D8 */ u8 previous_land_name[LAND_NAME_SIZE]; /* name of the last town the villager lived in */ + /* 0x8E0 */ u16 previous_land_id; /* id of the previous town the villager lived in */ + /* 0x8E2 */ u8 mood; /* probably called 'feel' based on code */ + /* 0x8E3 */ u8 mood_time; /* probably called 'feel_tim' based on code */ + /* 0x8E4 */ mActor_name_t cloth; /* shirt the villager is wearing */ + /* 0x8E6 */ u16 remove_info; /* info about villager moving between towns? kinda stubbed */ + /* 0x8E8 */ u8 is_home; /* TRUE when the villager is home, otherwise FALSE */ + /* 0x8E9 */ u8 moved_in; /* TRUE when the villager moved in after town creation, FALSE if they started out in town */ + /* 0x8EA */ u8 removing; /* TRUE when the villager is leaving town, FALSE otherwise */ + /* 0x8EB */ s8 cloth_original_id; /* 0xFF when not wearing an Able Sister's pattern, otherwise 0-3 indicating which pattern */ + /* 0x8EC */ s8 umbrella_id; /* 0xFF when no umbrella, 0-31 when a standard umbrella, 32-35 when using an Able Sister's pattern */ + /* 0x8EE */ mActor_name_t present_cloth; /* The most recently received shirt from a letter which the villager may change into */ + /* 0x8F0 */ u8 animal_relations[ANIMAL_NUM_MAX]; /* relationships between all villagers in town, starts at 128 which is neutral */ + /* 0x900 */ AnmHPMail_c hp_mail[ANIMAL_HP_MAIL_NUM]; /* mail password info storage */ + /* 0x000 */ u8 unused[24]; /* unknown usage/unused */ +} Animal_c; + extern void mNpc_PrintRemoveInfo(gfxprint_t* gfxprint); extern void mNpc_PrintFriendship_fdebug(gfxprint_t* gfxprint); diff --git a/include/m_personal_id.h b/include/m_personal_id.h new file mode 100644 index 00000000..0eafd880 --- /dev/null +++ b/include/m_personal_id.h @@ -0,0 +1,27 @@ +#ifndef M_PERSONAL_ID_H +#define M_PERSONAL_ID_H + +#include "types.h" + +#include "m_land_h.h" +#include "m_actor_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PLAYER_NAME_LEN 8 + +/* sizeof(PersonalID_c) == 0x14 */ +typedef struct personal_id_s { + /* 0x00 */ u8 player_name[PLAYER_NAME_LEN]; + /* 0x08 */ u8 land_name[LAND_NAME_SIZE]; + /* 0x10 */ u16 player_id; + /* 0x12 */ u16 land_id; +} PersonalID_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_play.h b/include/m_play.h index 4d446105..fae5580c 100644 --- a/include/m_play.h +++ b/include/m_play.h @@ -3,6 +3,7 @@ #include "types.h" #include "game.h" +#include "libultra/ultratypes.h" #ifdef __cplusplus extern "C" { @@ -12,7 +13,10 @@ extern "C" { typedef struct game_play_s { /* 0x0000 */ GAME game; // TODO: finish - /* 0x00E0 */ u8 _temp[0x2520]; + /* 0x00E0 */ u8 d[0x1CC0]; + /* 0x1DA0*/ int isPause; + /* 0x1DA4*/ u8 _temp[0x268]; + /* 0x200C*/ MtxF matrix; } GAME_PLAY; extern void play_init(GAME_PLAY* play); diff --git a/include/m_quest.h b/include/m_quest.h index 6a2878e9..c6d66e49 100644 --- a/include/m_quest.h +++ b/include/m_quest.h @@ -3,11 +3,66 @@ #include "types.h" #include "libu64/gfxprint.h" +#include "lb_rtc.h" +#include "m_actor_type.h" +#include "m_personal_id.h" #ifdef __cplusplus extern "C" { #endif +enum { + mQst_QUEST_TYPE_DELIVERY, /* Deliver item quest */ + mQst_QUEST_TYPE_ERRAND, /* Villager 'can I help' quests */ + mQst_QUEST_TYPE_CONTEST, /* Villager send letter, plant flowers, bring ball, etc */ + mQst_QUEST_TYPE_NONE +}; + +enum { + mQst_CONTEST_KIND_FRUIT, /* get fruit for villager */ + mQst_CONTEST_KIND_SOCCER, /* get ball for villager */ + mQst_CONTEST_KIND_SNOWMAN, /* build snowman for villager */ + mQst_CONTEST_KIND_FLOWER, /* plant flowers for villager */ + mQst_CONTEST_KIND_FISH, /* get fish for villager */ + mQst_CONTEST_KIND_INSECT, /* get insect for villager */ + mQst_CONTEST_KIND_LETTER /* send letter to villager */ +}; + +/* TODO: delivery & errand quests, along with chore quests (first job) */ + +/* sizeof(mQst_base_c) == 0xC */ +typedef struct quest_base_s { + /* 0x00 */ u32 quest_type:2; /* type, 0 = delivery, 1 = errand, 2 = contest, 3 = none */ + /* 0x00 */ u32 quest_kind:6; /* kind, differs by type */ + /* 0x01 */ u32 time_limit_enabled:1; /* when set, the time limit will be utilized */ + /* 0x01 */ u32 progress:4; /* progress towards quest goal */ + /* 0x01 */ u32 give_reward:1; /* set to true when player cannot take the item, and will skip quest completion checks */ + /* 0x01 */ u32 unused:2; + + /* 0x02 */ lbRTC_time_c time_limit; +} mQst_base_c; + +/* sizeof(mQst_contest_info_u) == 4 */ +typedef union quest_contest_info_s { + struct { + /* 0x00 */ u8 flowers_requested; /* number of flowers village requests be planted in acre */ + } flower_data; + + struct { + /* 0x00 */ u8 score; /* score rank of letter */ + /* 0x02 */ mActor_name_t present; /* present sent with letter */ + } letter_data; +} mQst_contest_info_u; + +/* sizeof(mQst_contest_c) == 0x28 */ +typedef struct quest_contest_s { + /* 0x00 */ mQst_base_c base; /* quest base struct */ + /* 0x0C */ mActor_name_t requested_item; /* item (if any) requested by the villager */ + /* 0x0E */ PersonalID_c player_id; /* personal id of the player */ + /* 0x22 */ s8 type; /* type of quest, seems to be repeat of data in quest base */ + /* 0x24 */ mQst_contest_info_u info; /* contest info for flower & letter quests */ +} mQst_contest_c; + extern void mQst_PrintQuestInfo(gfxprint_t* gfxprint); #ifdef __cplusplus diff --git a/include/main.h b/include/main.h index cd0e7b5a..1a00b99f 100644 --- a/include/main.h +++ b/include/main.h @@ -10,6 +10,9 @@ extern "C" { #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 +#define SCREEN_WIDTH_F ((f32)SCREEN_WIDTH) +#define SCREEN_HEIGHT_F ((f32)SCREEN_HEIGHT) + extern int ScreenWidth; extern int ScreenHeight; diff --git a/rel/m_debug_mode.c b/rel/m_debug_mode.c index 96671632..4ac4fbf2 100644 --- a/rel/m_debug_mode.c +++ b/rel/m_debug_mode.c @@ -26,6 +26,7 @@ #include "dolphin/dvd.h" #include "libjsys/jsyswrapper.h" #include "boot.h" +#include "m_common_data.h" #define DEBUG_MODE_PRINT_BUF_COUNT 6 #define DEBUG_MODE_PRINT_OUTPUT_X 26 @@ -589,8 +590,38 @@ static void Debug_mode_zelda_malloc_info_output(gfxprint_t* gfxprint) { } #pragma pool_data reset +/* sizeof(haniwa_tempo_data) == 6 */ +typedef struct { + /* 0x00 */ TempoBeat_c Gt; + /* 0x02 */ TempoBeat_c BS; + /* 0x04 */ TempoBeat_c AS; +} haniwa_tempo_data; + +static haniwa_tempo_data tempo_data[PLAYER_NUM] = { + { {0, 0}, {0, 0}, {0, 0} }, /* House 0 */ + { {0, 0}, {0, 0}, {0, 0} }, /* House 1 */ + { {0, 0}, {0, 0}, {0, 0} }, /* House 2 */ + { {0, 0}, {0, 0}, {0, 0} } /* House 3 */ +}; + static void DebugHaniwaTempo(gfxprint_t* gfxprint) { - /* TODO: this requires implementing m_home & m_house */ + int i; + for (i = 0; i < PLAYER_NUM; i++) { + gfxprint_color(gfxprint, 250, 200, 200, 255); + gfxprint_locate8x8(gfxprint, 3, 23 + i); + gfxprint_printf( + gfxprint, + "S%d,%dGt%d,%dBS%d,%dAS%d,%d", + Save_Get(homes[i].haniwa_tempo.tempo), + Save_Get(homes[i].haniwa_tempo.beat), + tempo_data[i].Gt.tempo, + tempo_data[i].Gt.beat, + tempo_data[i].BS.tempo, + tempo_data[i].BS.beat, + tempo_data[i].AS.tempo, + tempo_data[i].AS.beat + ); + } } #define GFXLIST_RESERVED_SIZE (int)(512 * sizeof(Gfx)) /* requires 0x1000 bytes, or 512 free Gfx */ diff --git a/rel/m_lib.c b/rel/m_lib.c index 3ef2056d..bc605aa1 100644 --- a/rel/m_lib.c +++ b/rel/m_lib.c @@ -1,371 +1,818 @@ +/** + * @file m_lib.c + * @brief Utility functions for various mathematical and memory operations. + * + * This file contains a collection of utility functions used for various mathematical + * and memory operations. These functions include: + * + * - mem_copy(): Copy memory from one location to another. + * - mem_clear(): Clear (set) a memory area to a given value. + * - mem_cmp(): Compare two memory areas. + * - cos_s(): Calculate the cosine of a short angle. + * - sin_s(): Calculate the sine of a short angle. + * - chase_angle(): Chase an angle with a given step value. + * - chase_s(): Chase a short integer value with a given step value. + * - chase_f(): Chase a float value with a given step value. + * - chase_xyz_t(): Chase an xyz_t structure value with a given fraction value. + * - chase_angle2(): Chase an angle with a given step value and limit. + * - inter_float(): Interpolate between two float values with a given step value. + * - get_random_timer(): Get a random timer value with a base and range. + * - xyz_t_move(): Move an xyz_t value from a source to a destination. + * - xyz_t_move_s_xyz(): Move an xyz_t value from an s_xyz source to a destination. + * - xyz_t_add(): Add two xyz_t values. + * - xyz_t_sub(): Subtract two xyz_t values. + * - xyz_t_mult_v(): Multiply an xyz_t value by a scalar. + * - search_position_distance(): Calculate the distance between two 3D positions. + * - search_position_distanceXZ(): Calculate the horizontal distance between two 3D positions. + * - search_position_angleY(): Calculate the Y angle between two 3D positions. + * - search_position_angleX(): Calculate the X angle between two 3D positions. + * - add_calc(): Update a float value towards a target with a given fraction, max step, and min step. + * - add_calc2(): Update a float value towards a target with a given fraction and max step. + * - add_calc0(): Update a float value with a given fraction and max step. + * - add_calc_short_angle2(): Update a short angle value towards a target with given fraction, max step, and min step. + * - add_calc_short_angle3(): Update a short angle value towards a target with given fraction, max step, and min step. + * - rgba_t_move(): Move an rgba_t value from a source to a destination. + * - none_proc1(): A general no-op function that returns 0. + * - none_proc2(): A no-op function meant for ACTORs which does nothing. + * - _Game_play_isPause(): Check if the game is paused. + * - check_percent_abs(): Calculate a percentage value with scaling and optional shifting. + * - get_percent_forAccelBrake(): Calculate a percentage value for acceleration and braking. + * - Game_play_Projection_Trans(): Transform a world position into screen space. + * - get_percent(): Calculate a percentage value given a min and max range. + */ + #include "m_lib.h" +#include "game.h" +#include "m_actor.h" +#include "m_play.h" +#include "main.h" +/** + * @brief Copy memory from the source buffer to the destination buffer. + * + * @param dst Pointer to the destination buffer. + * @param src Pointer to the source buffer. + * @param size Number of bytes to copy. + */ +extern void mem_copy(u8* dst, u8* src, size_t size) { + for (size; size != 0; size--) { + *dst = *src; + src++; + dst++; + } +} -void mem_copy(u8* arg0, u8* arg1, u32 arg2) { - while (arg2 != 0) { - *arg0 = *arg1; - arg1++; - arg0++; - arg2--; +/** + * @brief Clear memory in the destination buffer by setting it to the specified value. + * + * @param dst Pointer to the destination buffer. + * @param size Number of bytes to clear. + * @param val Value to set each byte in the destination buffer. + */ +extern void mem_clear(u8* dst, size_t size, u8 val) { + u32 i; + + for (i = 0; i < size; i++) { + *dst++ = val; + } +} + +/** + * @brief Compare two memory buffers for equality. + * + * @param p1 Pointer to the first memory buffer. + * @param p2 Pointer to the second memory buffer. + * @param size Number of bytes to compare. + * @return TRUE if the memory buffers are equal, FALSE otherwise. + */ +extern int mem_cmp(u8* p1, u8* p2, size_t size) { + for (size; size != 0; size--) { + if (*p1 != *p2) { + return FALSE; } + p1++; + p2++; + } + return TRUE; } -void mem_clear(u8* arg0, u32 arg1, u8 arg2) { - u32 i; +/** + * @brief Calculate the cosine of the given s16 angle. + * + * @param angle Angle in s16 format. + * @return Cosine of the angle as a floating-point value. + */ +extern f32 cos_s(s16 angle) { return coss(angle) * SHT_MINV; } - for (i = 0; i < arg1; i++) {*arg0++ = arg2;} -} +/** + * @brief Calculate the sine of the given s16 angle. + * + * @param angle Angle in s16 format. + * @return Sine of the angle as a floating-point value. + */ +extern f32 sin_s(s16 angle) { return sins(angle) * SHT_MINV; } -s32 mem_cmp(u8* arg0, u8* arg1, u32 arg2) { - while (arg2 != 0) { - if (*arg0 != *arg1) { - return 0; - } - arg0++; - arg1++; - arg2--; - } - return 1; -} +/** + * @brief Chase an angle value towards a target angle, with a specified step. + * + * This function updates the angle value, moving it towards the target angle + * by a specified step. The angle will not overshoot the target. The function + * returns TRUE if the angle reaches the target, and FALSE otherwise. + * + * @param pValue Pointer to the angle value to be updated. + * @param target Target angle to chase. + * @param step Step value to be added or subtracted from the current angle. + * @return TRUE if the angle reaches the target, FALSE otherwise. + */ +extern int chase_angle(s16* const pValue, const s16 target, s16 step) { + if (step) { + f32 updateScale = game_GameFrame_2F; - -f32 sin_s(s16 arg0) { - f32 ret = 3.051850945e-05f * sins(arg0); //something something get this from data - return ret; -} - -f32 cos_s(s16 arg0) { - f32 ret = 3.051850945e-05f * coss(arg0); //something something get this from data - return ret; -} - -s32 chase_angle(s16* pValue, s16 target, s16 step) { - if (step) { - f32 updateScale = game_GameFrame_2F; - - if ((s16)(*pValue - target) > 0) { - step = -step; - } - - *pValue += (s16)(step * updateScale); - - if (((s16)(*pValue - target) * step) >= 0) { - *pValue = target; - return 1; - } - } else if (*pValue == target) { - return 1; + if ((s16)(*pValue - target) > 0) { + step = -step; } - return 0; -} + *pValue += (s16)(step * updateScale); - -s32 chase_s(s16* pValue, s16 target, s16 step) { - if (step) { - if (*pValue > target) { - step = -step; - } - - *pValue += step; - - if ((step * (*pValue - target)) >= 0) { - *pValue = target; - return 1; - } - } else { - if (*pValue == target) { - return 1; - } + if (((s16)(*pValue - target) * step) >= 0) { + *pValue = target; + return TRUE; } - return 0; + } else if (*pValue == target) { + return TRUE; + } + + return FALSE; } -s32 chase_f(f32* pValue, f32 target, f32 step) { - if (step) { - if (*pValue > target) { - step = -step; - } - - *pValue += step; - - if ((step * (*pValue - target)) >= 0.0f) { - *pValue = target; - return 1; - } - } else { - if (*pValue == target) { - return 1; - } +/** + * @brief Chase a signed 16-bit value towards a target value, with a specified step. + * + * This function updates the value, moving it towards the target value + * by a specified step. The value will not overshoot the target. The function + * returns TRUE if the value reaches the target, and FALSE otherwise. + * + * @param pValue Pointer to the value to be updated. + * @param target Target value to chase. + * @param step Step value to be added or subtracted from the current value. + * @return TRUE if the value reaches the target, FALSE otherwise. + */ +extern int chase_s(s16* const pValue, const s16 target, s16 step) { + if (step) { + if (*pValue > target) { + step = -step; } - return 0; -} - -f32 chase_xyz_t(xyz_t* pValue, xyz_t* target, f32 fraction) { - xyz_t diff; - f32 dist; - f32 stepSize; - - xyz_t_sub(target, pValue, &diff); - - dist = Math3DVecLength(&diff); - if (dist > fraction) { - stepSize = fraction / dist; - pValue->x += stepSize * diff.x; - pValue->y += stepSize * diff.y; - pValue->z += stepSize * diff.z; - - return dist - fraction; - } else { - xyz_t_move(pValue, target); - - return 0.0f; - } -} - - -s32 chase_angle2(s16* pValue, s16 limit, s16 step) { - s16 prev = *pValue; *pValue += step; - if (((s16)(*pValue - limit) * (s16)(prev - limit)) <= 0) { - s32 absDiff = ABS((s16)(*pValue - limit)); - if (absDiff < 0x4000) { - *pValue = limit; - return 1; - } + if ((step * (*pValue - target)) >= 0) { + *pValue = target; + return TRUE; } - - return 0; + } else { + if (*pValue == target) { + return TRUE; + } + } + return FALSE; } -void inter_float(f32* pValue, f32 arg1, s32 arg2) { - if (arg2 <= 0) { - *pValue = arg1; +/** + * @brief Chase a floating-point value towards a target value, with a specified step. + * + * This function updates the value, moving it towards the target value + * by a specified step. The value will not overshoot the target. The function + * returns TRUE if the value reaches the target, and FALSE otherwise. + * + * @param pValue Pointer to the value to be updated. + * @param target Target value to chase. + * @param step Step value to be added or subtracted from the current value. + * @return TRUE if the value reaches the target, FALSE otherwise. + */ +extern int chase_f(f32* const pValue, const f32 target, f32 step) { + if (step) { + if (*pValue > target) { + step = -step; + } + + *pValue += step; + + if ((step * (*pValue - target)) >= 0.0f) { + *pValue = target; + return TRUE; + } + } else { + if (*pValue == target) { + return TRUE; + } + } + return FALSE; +} + +/** + * @brief Chase an xyz_t value towards a target xyz_t value, with a specified fraction. + * + * This function updates the xyz_t value, moving it towards the target xyz_t value + * by a specified fraction of the distance between the current value and the target. + * The function returns the remaining distance after the chase. + * + * @param pValue Pointer to the xyz_t value to be updated. + * @param target Pointer to the target xyz_t value to chase. + * @param fraction Fraction of the distance to move towards the target. + * @return Remaining distance after the chase. + */ +extern f32 chase_xyz_t(xyz_t* const pValue, const xyz_t* const target, + const f32 fraction) { + xyz_t diff; + f32 dist; + f32 stepSize; + + xyz_t_sub(target, pValue, &diff); + + dist = Math3DVecLength(&diff); + if (dist > fraction) { + stepSize = fraction / dist; + pValue->x += stepSize * diff.x; + pValue->y += stepSize * diff.y; + pValue->z += stepSize * diff.z; + + return dist - fraction; + } else { + xyz_t_move(pValue, target); + + return 0.0f; + } +} + +/** + * @brief Chase an angle value towards a limit angle with a specified step, considering wrap-around. + * + * This function updates the angle value, moving it towards the limit angle by a specified step, + * taking into account the angle wrap-around (0 to 65535). The function returns TRUE if the value + * reaches the limit, and FALSE otherwise. + * + * @param pValue Pointer to the angle value to be updated. + * @param limit Limit angle to chase. + * @param step Step value to be added to the current angle. + * @return TRUE if the angle reaches the limit, FALSE otherwise. + */ +extern int chase_angle2(s16* const pValue, const s16 limit, const s16 step) { + s16 prev = *pValue; + + *pValue += step; + if (((s16)(*pValue - limit) * (s16)(prev - limit)) <= 0) { + s32 absDiff = ABS((s16)(*pValue - limit)); + + if (absDiff < 16384) { + *pValue = limit; + return TRUE; + } + } + + return FALSE; +} + +/** + * @brief Interpolate between a float and a target using a step. + * + * @param pValue Pointer to the float to be updated. + * @param arg1 Target value for interpolation. + * @param step Step value for interpolation speed. + */ +extern void inter_float(f32* const pValue, const f32 arg1, const int step) { + if (step <= 0) { + *pValue = arg1; + } else { + f32 diff = arg1 - *pValue; + + *pValue += diff / step; + } +} + +/** + * @brief Generate a random timer value based on a base value and a range. + * + * This function generates a random timer value by adding a fraction of the specified range + * to the base value. The random fraction is generated using fqrand(). + * Range will be [base, base + range). + * + * @param base Base value for the timer. + * @param range Range value used to generate the random fraction. + * @return Random timer value. + */ +extern s16 get_random_timer(const s16 base, const s16 range) { + return base + (s16)(range * fqrand()); +} + +/** + * @brief Copy an xyz_t to another xyz_t. + * + * @param dest Destination xyz_t structure. + * @param src Source xyz_t structure. + */ +extern void xyz_t_move(xyz_t* const dest, const xyz_t* const src) { + dest->x = src->x; + dest->y = src->y; + dest->z = src->z; +} + +/** + * @brief Move the content of an s_xyz structure to an xyz_t structure. + * + * @param dest Pointer to the destination xyz_t structure. + * @param src Pointer to the source s_xyz structure. + */ +extern void xyz_t_move_s_xyz(xyz_t* const dest, const s_xyz* const src) { + dest->x = src->x; + dest->y = src->y; + dest->z = src->z; +} + +/** + * @brief Add two xyz_t structures element-wise. + * + * @param augend First input xyz_t structure. + * @param addend Second input xyz_t structure. + * @param total Output xyz_t structure for the result. + */ + +extern void xyz_t_add(const xyz_t* const augend, const xyz_t* const addend, + xyz_t* const total) { + total->x = augend->x + addend->x; + total->y = augend->y + addend->y; + total->z = augend->z + addend->z; +} + +/** + * @brief Subtract two xyz_t structures element-wise. + * + * @param minuend First input xyz_t structure. + * @param subtrahend Second input xyz_t structure. + * @param diff Output xyz_t structure for the result. + */ +extern void xyz_t_sub(const xyz_t* const minuend, const xyz_t* const subtrahend, + xyz_t* const diff) { + diff->x = minuend->x - subtrahend->x; + diff->y = minuend->y - subtrahend->y; + diff->z = minuend->z - subtrahend->z; +} + +/** + * @brief Multiply an xyz_t by a scalar. + * + * @param multiplicand Input xyz_t structure. + * @param multiplier Scalar value. + */ +extern void xyz_t_mult_v(xyz_t* const multiplicand, const f32 multiplier) { + multiplicand->x *= multiplier; + multiplicand->y *= multiplier; + multiplicand->z *= multiplier; +} + +/** + * @brief Calculate the Euclidean distance between two xyz_t structures. + * + * @param pos Pointer to the first xyz_t structure representing the position. + * @param target Pointer to the second xyz_t structure representing the target position. + * @return The Euclidean distance between the two xyz_t structures. + */ +extern f32 search_position_distance(const xyz_t* const pos, + const xyz_t* const target) { + f32 diffX = target->x - pos->x; + f32 diffY = target->y - pos->y; + f32 diffZ = target->z - pos->z; + + return sqrtf((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)); +} + +/** + * @brief Calculate the Euclidean distance between two xyz_t structures in the XZ plane. + * + * @param pos Pointer to the first xyz_t structure representing the position. + * @param target Pointer to the second xyz_t structure representing the target position. + * @return The Euclidean distance between the two xyz_t structures in the XZ plane. + */ +extern f32 search_position_distanceXZ(const xyz_t* const pos, + const xyz_t* const target) { + f32 diffX = target->x - pos->x; + f32 diffZ = target->z - pos->z; + + return sqrtf((diffX * diffX) + (diffZ * diffZ)); +} + +/** + * @brief Calculate the angle in the Y axis (yaw) between two xyz_t positions. + * + * @param pos Pointer to the first xyz_t structure representing the current position. + * @param target Pointer to the second xyz_t structure representing the target position. + * @return The angle in the Y axis (yaw) between the two xyz_t positions. + */ +extern s16 search_position_angleY(const xyz_t* const pos, + const xyz_t* const target) { + f32 diffX = target->x - pos->x; + f32 diffZ = target->z - pos->z; + + return atans_table(diffZ, diffX); +} + +/** + * @brief Calculate the angle in the X axis (pitch) between two xyz_t positions. + * + * @param pos Pointer to the first xyz_t structure representing the current position. + * @param target Pointer to the second xyz_t structure representing the target position. + * @return The angle in the X axis (pitch) between the two xyz_t structures. + */ +extern s16 search_position_angleX(const xyz_t* const pos, + const xyz_t* const target) { + f32 diffXZ = search_position_distanceXZ(pos, target); + f32 diffY = pos->y - target->y; + + return atans_table(diffXZ, diffY); +} + +/** + * @brief Add a calculated value to a variable to approach a target value with minimum and maximum step limits. + * + * This function adds a calculated step size to the input variable to approach the target value. + * The step size is calculated based on the fraction and is limited by the minimum and maximum step values. + * + * @param pValue Pointer to the input variable. + * @param target Target value to approach. + * @param fraction Fraction to use in the step size calculation. + * @param maxStep Maximum allowed step size. + * @param minStep Minimum allowed step size. + * @return The difference between the updated input variable value and the target value. + */ +extern f32 add_calc(f32* pValue, f32 target, f32 fraction, f32 maxStep, + f32 minStep) { + f32 negMinStep; + f32 stepSize; + + if (*pValue != target) { + stepSize = fraction * (target - *pValue); + negMinStep = -minStep; + + if ((stepSize <= negMinStep) || (minStep <= stepSize)) { + if (stepSize > maxStep) { + stepSize = maxStep; + } else if (stepSize < -maxStep) { + stepSize = -maxStep; + } + + *pValue += stepSize; + + if (stepSize > 0.0f) { + if (*pValue > target) { + *pValue = target; + } + } else { + if (*pValue < target) { + *pValue = target; + } + } } else { - f32 diff = arg1 - *pValue; - - *pValue += diff / arg2; - } -} - -s16 get_random_timer(s16 base, s16 range) { - return base + (s16)(range * fqrand()); -} - -void xyz_t_move(xyz_t* dest, xyz_t* src) { - dest->x = src->x; - dest->y = src->y; - dest->z = src->z; -} - -void xyz_t_move_s_xyz(xyz_t* dest, s_xyz* src) { - dest->x = src->x; - dest->y = src->y; - dest->z = src->z; -} - -void xyz_t_add(xyz_t* augend, xyz_t* addend, xyz_t* total) { - total->x = augend->x + addend->x; - total->y = augend->y + addend->y; - total->z = augend->z + addend->z; -} - -void xyz_t_sub(xyz_t* minuend, xyz_t* subtrahend, xyz_t* diff) { - diff->x = minuend->x - subtrahend->x; - diff->y = minuend->y - subtrahend->y; - diff->z = minuend->z - subtrahend->z; -} - -void xyz_t_mult_v(xyz_t* multiplicand, f32 multiplier) { - multiplicand->x *= multiplier; - multiplicand->y *= multiplier; - multiplicand->z *= multiplier; -} - -f32 search_position_distance(xyz_t* subtrahend, xyz_t* minuend) { - f32 diffX = minuend->x - subtrahend->x; - f32 diffY = minuend->y - subtrahend->y; - f32 diffZ = minuend->z - subtrahend->z; - - return sqrtf(SQ(diffX) + SQ(diffY) + SQ(diffZ)); -} - -f32 search_position_distanceXZ(xyz_t* subtrahend, xyz_t* minuend) { - f32 diffX = minuend->x - subtrahend->x; - f32 diffZ = minuend->z - subtrahend->z; - - return sqrtf(SQ(diffX) + SQ(diffZ)); -} - -s16 search_position_angleY(xyz_t* subtrahend, xyz_t* minuend) { - f32 diffX = minuend->x - subtrahend->x; - f32 diffZ = minuend->z - subtrahend->z; - - return atans_table(diffZ, diffX); -} - -s16 search_position_angleX(xyz_t* subtrahend, xyz_t* minuend) { - f32 diffXZ = search_position_distanceXZ(subtrahend, minuend); - f32 diffY = subtrahend->y - minuend->y; - - return atans_table(diffXZ, diffY); -} - -void add_calc2(f32* pValue, f32 target, f32 fraction, f32 step) { - f32 stepSize; - - if (*pValue != target) { - stepSize = fraction * (target - *pValue); - - if (stepSize > step) { - stepSize = step; - } else if (stepSize < -step) { - stepSize = -step; + if (stepSize > 0.0f) { + *pValue += minStep; + if (*pValue > target) { + *pValue = target; } - - *pValue += stepSize; - } -} - -void add_calc0(f32* pValue, f32 fraction, f32 step) { - f32 stepSize = *pValue * fraction; - - if (stepSize > step) { - stepSize = step; - } else if (stepSize < -step) { - stepSize = -step; - } - - *pValue -= stepSize; -} - - -s16 add_calc_short_angle2(s16* pValue, s16 target, f32 fraction, s16 step, s16 minStep) { - s16 stepSize = 0; - s16 diff = target - *pValue; - - if (*pValue != target) { - stepSize = (s16)(diff * fraction); - - if ((stepSize > minStep) || (stepSize < -minStep)) { - if (stepSize > step) { - stepSize = step; - } else if (stepSize < -step) { - stepSize = -step; - } - - *pValue += stepSize; - - if (stepSize > 0) { - if ((s16)(target - *pValue) < 0) { - *pValue = target; - } - } else { - if ((s16)(target - *pValue) > 0) { - *pValue = target; - } - } - } else { - if (diff >= 0) { - *pValue += minStep; - if ((s16)(target - *pValue) < 0) { - *pValue = target; - } - } else { - *pValue -= minStep; - if ((s16)(target - *pValue) > 0) { - *pValue = target; - } - } - } - - } - return target - *pValue; -} - -s16 add_calc_short_angle3(s16* pValue, s16 target, f32 fraction, s16 maxStep, s16 minStep) { - f32 stepSize; - s32 uTarget; - s32 newValue; - s32 uValue; - - if (target != *pValue) { - uValue = (u16)*pValue; - uTarget = (u16)target; - - if (uValue > uTarget) { - uTarget += 0x10000; + } else { + *pValue += negMinStep; + if (*pValue < target) { + *pValue = target; } + } + } + } - stepSize = (uTarget - uValue) * fraction; + return target - *pValue; +} - if (stepSize > maxStep) { - stepSize = maxStep; - } else if (stepSize < minStep) { - stepSize = minStep; - } +/** + * @brief Add a calculated value to a variable to approach a target value with a maximum step limit. + * + * This function adds a calculated step size to the input variable to approach the target value. + * The step size is calculated based on the fraction and is limited by the maximum step value. + * + * @param pValue Pointer to the input variable. + * @param target Target value to approach. + * @param fraction Fraction to use in the step size calculation. + * @param maxStep Maximum allowed step size. + */ +extern void add_calc2(f32* pValue, f32 target, f32 fraction, f32 maxStep) { + f32 stepSize; - newValue = uValue + (s32) stepSize; - if (newValue > uTarget) { - newValue = uTarget; - } - *pValue = newValue; + if (*pValue != target) { + stepSize = fraction * (target - *pValue); + + if (stepSize > maxStep) { + stepSize = maxStep; + } else if (stepSize < -maxStep) { + stepSize = -maxStep; } - return target - *pValue; + *pValue += stepSize; + } } -void rgba_t_move(rgba_t* dest, rgba_t* src) { - dest->r = src->r; - dest->g = src->g; - dest->b = src->b; - dest->a = src->a; +/** + * @brief Step a variable towards 0 by a fixed fraction, with a specified maximum possible step. + * + * @param pValue Pointer to the input variable. + * @param fraction Fraction to use in the step size calculation. + * @param maxStep Maximum allowed step size. + */ +extern void add_calc0(f32* pValue, f32 fraction, f32 maxStep) { + f32 stepSize = *pValue * fraction; + + if (stepSize > maxStep) { + stepSize = maxStep; + } else if (stepSize < -maxStep) { + stepSize = -maxStep; + } + + *pValue -= stepSize; } -u32 none_proc1(void){ - return 0; - //stub -} +/** + * @brief Add a calculated value to a short integer variable to approach a target angle with minimum and maximum step limits. + * + * This function adds a calculated step size to the input short integer variable to approach the target angle. + * The step size is calculated based on the fraction and is limited by the minimum and maximum step values. + * + * @param pValue Pointer to the input short integer variable. + * @param target Target angle to approach. + * @param fraction Fraction to use in the step size calculation. + * @param maxStep Maximum allowed step size. + * @param minStep Minimum allowed step size. + * @return The difference between the updated input variable angle and the target angle. + */ +extern s16 add_calc_short_angle2(s16* pValue, s16 target, f32 fraction, + s16 maxStep, s16 minStep) { + s16 stepSize = 0; + s16 diff = target - *pValue; -void none_proc2(void){ - //stub -} + if (*pValue != target) { + stepSize = (s16)(diff * fraction); -// f32 check_percent_abs(s32 arg0, f32 arg8, f32 arg9, f32 argA, f32 argB) -// f32 get_percent_forAccelBrake(f32 arg8, f32 arg9, f32 argA, f32 argB, f32 argC) + if ((stepSize > minStep) || (stepSize < -minStep)) { + if (stepSize > maxStep) { + stepSize = maxStep; + } else if (stepSize < -maxStep) { + stepSize = -maxStep; + } + *pValue += stepSize; -void Game_play_Projection_Trans(game_play* play, Vec3f* src, Vec3f* dest) { - f32 w; - - Matrix_mult(&play->unk_200C, 0); - Matrix_Position(src, dest); - w = play->unk_200C.ww + ( - (play->unk_200C.wx * src->x) - + (play->unk_200C.wy * src->y) - + (play->unk_200C.wz * src->z)); - dest->x = 160.0f + ((dest->x / w) * 160.0f); - dest->y = 120.0f - ((dest->y / w) * 120.0f); -} - -f32 get_percent(s32 arg0, s32 arg1, s32 arg2) { - f32 temp_f0; - f32 var_f2; - - var_f2 = 1.0f; - if (arg2 < arg1) { - var_f2 = 0.0f; - } else if (arg2 < arg0) { - temp_f0 = (f32) (arg0 - arg1); - if (temp_f0 != 0.0f) { - var_f2 = (f32) (arg2 - arg1) / temp_f0; - if (var_f2 > 1.0f) { - var_f2 = 1.0f; - } + if (stepSize > 0) { + if ((s16)(target - *pValue) < 0) { + *pValue = target; } + } else { + if ((s16)(target - *pValue) > 0) { + *pValue = target; + } + } + } else { + if (diff >= 0) { + *pValue += minStep; + if ((s16)(target - *pValue) < 0) { + *pValue = target; + } + } else { + *pValue -= minStep; + if ((s16)(target - *pValue) > 0) { + *pValue = target; + } + } } - return var_f2; -} \ No newline at end of file + } + return target - *pValue; +} + +/** + * @brief Add a calculated value to a short integer angle variable to approach a target angle with minimum and maximum step limits. + * + * This function adds a calculated step size to the input short integer angle variable to approach the target angle. + * The step size is calculated based on the fraction and is limited by the minimum and maximum step values. + * Handles angle wrapping correctly. + * + * @param pValue Pointer to the input short integer angle variable. + * @param target Target angle to approach. + * @param fraction Fraction to use in the step size calculation. + * @param maxStep Maximum allowed step size. + * @param minStep Minimum allowed step size. + * @return The difference between the updated input variable angle and the target angle. + */ +extern s16 add_calc_short_angle3(s16* pValue, s16 target, f32 fraction, + s16 maxStep, s16 minStep) { + f32 stepSize; + s32 uTarget; + s32 newValue; + s32 uValue; + + if (target != *pValue) { + uValue = (u16)*pValue; + uTarget = (u16)target; + + if (uValue > uTarget) { + uTarget += 65536; /* Add 360 short degrees */ + } + + stepSize = (uTarget - uValue) * fraction; + + if (stepSize > maxStep) { + stepSize = maxStep; + } else if (stepSize < minStep) { + stepSize = minStep; + } + + newValue = uValue + (s32)stepSize; + if (newValue > uTarget) { + newValue = uTarget; + } + *pValue = newValue; + } + + return target - *pValue; +} + +/** + * @brief Copy RBGA color from one rgba_t to another. + * + * @param dest Pointer to the destination rgba_t variable. + * @param src Pointer to the source rgba_t variable. + */ +extern void rgba_t_move(rgba_t* dest, const rgba_t* const src) { + dest->r = src->r; + dest->g = src->g; + dest->b = src->b; + dest->a = src->a; +} + +/** + * @brief A general purpose no-op function. + * + * @return 0 + */ +extern int none_proc1() { return 0; } + +/** + * @brief No-op function meant for use in actor profiles. + * + * @param actor Pointer to an ACTOR structure. + * @param game Pointer to a GAME structure. + */ +extern void none_proc2(ACTOR* actor, GAME* game) {} + +/** + * @brief Check if the game is in pause state. + * + * @param play Pointer to a GAME_PLAY structure. + * @return TRUE if the game is in pause state, FALSE otherwise. + */ +extern int _Game_play_isPause(GAME_PLAY* play) { return (play->isPause != 0); } + +/** + * @brief Calculate a percentage with respect to minimum and maximum values, and apply scaling. + * + * - If `x` is closer to 0 than `min`, return 0 + * - If `x` is further from 0 than `max`, return the sign of `x` + * - Otherwise, scale `x` by `scale` and return it. + * If `shift_by_min`, move `x` by `min` towards 0 before scaling it. + * + * @param x Input value to check. + * @param min Minimum value for the range. + * @param max Maximum value for the range. + * @param scale Scaling factor to apply to the percentage. + * @param shift_by_min Flag to shift the percentage by the minimum value (1 to shift, 0 not to shift). + * @return Scaled percentage of the input value within the specified range. + */ +extern f32 check_percent_abs(f32 x, f32 min, f32 max, f32 scale, + int shift_by_min) { + if ((-min <= x) && (x <= min)) { + return 0.0f; + } + if (x >= max) { + return 1.0f; + } + if (x <= -max) { + return -1.0f; + } + if (shift_by_min) { + if (x > 0.0f) { + return (x - min) * scale; + } else { + return (x + min) * scale; + } + } else { + return x * scale; + } +} + +/** + * @brief Calculate the percentage of completion based on acceleration and braking values. + * + * This function calculates the percentage of completion using the current position, start and end positions, + * acceleration and braking distances using quadratic easing. + * + * @param now Current position value. + * @param start Start position value. + * @param end End position value. + * @param accelerateDist Acceleration distance. + * @param brakeDist Braking distance. + * @return Percentage of completion. + */ +extern f32 get_percent_forAccelBrake(const f32 now, const f32 start, const f32 end, + const f32 accelerateDist, const f32 brakeDist) { + f32 percent; + f32 total_delta; + f32 now_delta; + f32 step; + + if (now >= end) { + return 1.0f; + } + if (now <= start) { + return 0.0f; + } + total_delta = end - start; + now_delta = now - start; + if (total_delta < (accelerateDist + brakeDist)) { + return 0.0f; + } + + step = 1.0f / (((2.0f * total_delta) - accelerateDist) - brakeDist); + if (accelerateDist != 0.0f) { + if (now_delta <= accelerateDist) { + percent = (now_delta * (step * now_delta)); + percent /= accelerateDist; + return percent; + } + percent = step * accelerateDist; + } else { + percent = 0.0f; + } + if (now_delta <= (total_delta - brakeDist)) { + percent += (step * 2.0f) * (now_delta - accelerateDist); + return percent; + } + percent += (2.0f * step * ((total_delta - accelerateDist) - brakeDist)); + if (brakeDist != 0.0f) { + percent += step * brakeDist; + if (now_delta < total_delta) { + f32 diff = total_delta - now_delta; + percent -= step * diff * diff / brakeDist; + } + } + return percent; +} + +/** + * @brief Project a 3D world position onto a 2D screen position. + * + * @param play Pointer to a GAME_PLAY structure. + * @param wpos Pointer to the 3D world position (xyz_t). + * @param screen_pos Pointer to the resulting 2D screen position (xyz_t). + */ +extern void Game_play_Projection_Trans(GAME_PLAY* const play, xyz_t* wpos, + xyz_t* screen_pos) { + f32 w; + + Matrix_mult(&play->matrix, 0); + Matrix_Position(wpos, screen_pos); + w = play->matrix.ww + + ((play->matrix.wx * wpos->x) + + (play->matrix.wy * wpos->y) + + (play->matrix.wz * wpos->z)); + screen_pos->x = (SCREEN_WIDTH_F / 2.0f) + ((screen_pos->x / w) * (SCREEN_WIDTH_F / 2.0f)); + screen_pos->y = (SCREEN_HEIGHT_F / 2.0f) - ((screen_pos->y / w) * (SCREEN_HEIGHT_F / 2.0f)); +} + +/** + * @brief Calculate the percentage of the input value within the specified range. + * + * @param max Maximum value for the range. + * @param min Minimum value for the range. + * @param x Input value to check. + * @return Percentage of the input value within the specified range. + */ +extern f32 get_percent(const int max, const int min, const int x) { + f32 total_delta; + f32 percent; + + percent = 1.0f; + if (x < min) { + percent = 0.0f; + } else if (x < max) { + total_delta = max - min; + if (total_delta != 0.0f) { + percent = (f32)(x - min) / total_delta; + if (percent > 1.0f) { + percent = 1.0f; + } + } + } + return percent; +}