diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 2f491205..3ef70122 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -171,6 +171,10 @@ m_trademark.c: .text: [0x8062B848, 0x8062C048] .rodata: [0x8064D1C0, 0x8064D1C8] .data: [0x806D4958, 0x806D4B18] +player_select.c: + .text: [0x8062C048, 0x8062CA5C] + .rodata: [0x8064D1C8, 0x8064D1F8] + .data: [0x806D4B18, 0x806D4B80] save_menu.c: .text: [0x8062CA5C, 0x8062D39C] .rodata: [0x8064D1F8, 0x8064D318] diff --git a/include/m_field_info.h b/include/m_field_info.h index 44c03624..c5a306c1 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -137,6 +137,7 @@ extern u8 mFI_GetBlockZMax(); extern u8 mFI_BkNum2BlockType(); extern mFI_sound_source_info_c* mFI_GetSoundSourcePBlockNum(int block_x,int block_z); extern int mFI_Wpos2UtNum(int* ut_x, int* ut_z, xyz_t wpos); +extern void mFI_ClearFieldData(); extern void mFI_PrintNowBGNum(gfxprint_t* gfxprint); extern void mFI_PrintFgAttr(gfxprint_t* gfxprint); diff --git a/include/m_private.h b/include/m_private.h index e74d4252..0e66f697 100644 --- a/include/m_private.h +++ b/include/m_private.h @@ -182,6 +182,7 @@ typedef struct private_s { extern s16 mPr_GetGoodsPower(); extern s16 mPr_GetMoneyPower(); +extern int mPr_CheckPrivate(Private_c* private_p); extern void mPr_PrintMapInfo_debug(gfxprint_t* gfxprint); extern int mPr_NullCheckPersonalID(PersonalID_c* pid); extern int mPr_CheckCmpPersonalID(PersonalID_c* pid_a, PersonalID_c* pid_b); @@ -191,6 +192,7 @@ extern void mPr_ClearPrivateInfo(Private_c* private_data); extern int mPr_CheckCmpPlayerName(u8* str0, u8* str1); extern void mPr_RandomSetPlayerData_title_demo(); extern int mPr_GetPossessionItemSumWithCond(Private_c* priv, mActor_name_t item_no, u32 cond); +extern void mPr_CopyPlayerName(u8* dst, Private_c* private_p); #ifdef __cplusplus } diff --git a/include/m_start_data_init.h b/include/m_start_data_init.h new file mode 100644 index 00000000..e06b302a --- /dev/null +++ b/include/m_start_data_init.h @@ -0,0 +1,35 @@ +#ifndef M_START_DATA_INIT_H +#define M_START_DATA_INIT_H + +#include "types.h" +#include "game_h.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + mSDI_INIT_MODE_NEW, + mSDI_INIT_MODE_NEW_PLAYER, + mSDI_INIT_MODE_FROM, + mSDI_INIT_MODE_PAK, + mSDI_INIT_MODE_ERR, + + mSDI_INIT_MODE_NUM +}; + +enum { + mSDI_MALLOC_FLAG_GAME, + mSDI_MALLOC_FLAG_ZELDA, + + mSDI_MALLOC_FLAG_NUM +}; + +extern void mSDI_StartInitAfter(GAME* game, int renewal_reserve_flag, int malloc_flag); +extern int mSDI_StartInitBefore(GAME* game, int player_no, int init_mode, int malloc_flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/player_select.h b/include/player_select.h index 992387d4..4e36e00b 100644 --- a/include/player_select.h +++ b/include/player_select.h @@ -4,21 +4,64 @@ #include "types.h" #include "game.h" #include "m_view.h" +#include "m_private.h" +#include "m_land.h" #ifdef __cplusplus extern "C" { #endif +typedef struct game_player_select_s GAME_PLAYER_SELECT; +typedef void (*PLAYER_SELECT_INIT_PROC)(GAME_PLAYER_SELECT*); + +#define SELECT_PLAYER_NUM TOTAL_PLAYER_NUM +#define SELECT_PLAYER_NAME_EXTRA 10 +#define SELECT_NAME_LEN PLAYER_NAME_LEN + SELECT_PLAYER_NAME_EXTRA + /* sizeof(struct game_player_select_s) == 0x0288 */ -typedef struct game_player_select_s { +struct game_player_select_s { /* 0x0000 */ GAME game; /* 0x00E0 */ View view; - // TODO: finish this - /* 0x0200 */ u8 _temp[0x88]; -} GAME_PLAYER_SELECT; + /* 0x0200 */ PLAYER_SELECT_INIT_PROC init_procs[SELECT_PLAYER_NUM]; + /* 0x0214 */ int player_no; + /* 0x0218 */ int err_no; + /* 0x021C */ int mode; + /* 0x0220 */ u8 player_names[SELECT_PLAYER_NUM][SELECT_NAME_LEN]; + /* 0x027A */ u8 player_types[SELECT_PLAYER_NUM]; + /* 0x027F */ u8 land_name[LAND_NAME_SIZE]; + /* 0x0287 */ u8 land_exist; +}; -extern void player_select_init(GAME_PLAYER_SELECT* player_select); -extern void player_select_cleanup(GAME_PLAYER_SELECT* player_select); +enum { + PLAYER_SELECT_MODE_SELECTION, + PLAYER_SELECT_MODE_PLAY, + + PLAYER_SELECT_MODE_NUM +}; + +enum { + PLAYER_SELECT_PLAYER_MODE_NO_SAVE, + PLAYER_SELECT_PLAYER_MODE_UNREGISTERED, + PLAYER_SELECT_PLAYER_MODE_HOME, + PLAYER_SELECT_PLAYER_MODE_OUT, + + PLAYER_SELECT_PLAYER_MODE_NUM +}; + +enum { + PLAYER_SELECT_INIT_ERR_NONE, + PLAYER_SELECT_INIT_ERR_SUCCESS, + PLAYER_SELECT_INIT_ERR_2, + PLAYER_SELECT_INIT_ERR_3, + PLAYER_SELECT_INIT_ERR_SAVE, + PLAYER_SELECT_INIT_ERR_5, + PLAYER_SELECT_INIT_ERR_PAK, + + PLAYER_SELECT_INIT_ERR_NUM +}; + +extern void player_select_init(GAME* game); +extern void player_select_cleanup(GAME* game); #ifdef __cplusplus } diff --git a/rel/player_select.c b/rel/player_select.c new file mode 100644 index 00000000..1fd5ed95 --- /dev/null +++ b/rel/player_select.c @@ -0,0 +1,336 @@ +#include "player_select.h" + +#include "m_field_info.h" +#include "m_start_data_init.h" +#include "m_controller.h" +#include "m_select.h" +#include "m_font.h" +#include "m_lib.h" +#include "m_rcp.h" +#include "sys_matrix.h" +#include "m_flashrom.h" +#include "m_common_data.h" + +/* ' みとうろく' (Unregisterd) */ +static u8 mitouroku_str[6] = { 0x20, 0x1F, 0x13, 0x02, 0xC0, 0x07 }; + +/* '<がいしゅつちゅう>' () */ +static u8 l_gaishutu_str[10] = { 0x3C, 0xE7, 0x01, 0x0B, 0xCA, 0x11, 0x10, 0xCA, 0x02, 0x3E }; + +/* '<ざいたくちゅう>' () */ +static u8 l_zaitaku_str[9] = { 0x3C, 0xEC, 0x01, 0x0F, 0x07, 0x10, 0xCA, 0x02, 0x3E }; + +/* 'よそからあそびにきた' (Came from another place) */ +static u8 l_yosokara_str[10] = { 0x60, 0x0E, 0x05, 0x7B, 0x00, 0x0E, 0xF7, 0x15, 0x06, 0x0F }; + +static void player_select_game_data_init(GAME_PLAYER_SELECT* player_select) { + int player_no = player_select->player_no; + mFI_ClearFieldData(); + if (mSDI_StartInitBefore((GAME*)player_select, player_no, mSDI_INIT_MODE_NEW, mSDI_MALLOC_FLAG_GAME) == TRUE) { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SUCCESS; + } +} + +static void player_select_game_data_init_save(GAME_PLAYER_SELECT* player_select) { + if (mSDI_StartInitBefore((GAME*)player_select, player_select->player_no, mSDI_INIT_MODE_FROM, mSDI_MALLOC_FLAG_GAME) == TRUE) { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SUCCESS; + } + else { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SAVE; + } +} + +static void player_select_game_data_init_new_player(GAME_PLAYER_SELECT* player_select) { + if (mSDI_StartInitBefore((GAME*)player_select, player_select->player_no, mSDI_INIT_MODE_NEW_PLAYER, mSDI_MALLOC_FLAG_GAME) == TRUE) { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SUCCESS; + } + else { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SAVE; + } +} + +static void player_select_game_data_init_pak(GAME_PLAYER_SELECT* player_select) { + if (mSDI_StartInitBefore((GAME*)player_select, player_select->player_no, mSDI_INIT_MODE_PAK, mSDI_MALLOC_FLAG_GAME) == TRUE) { + player_select->err_no = PLAYER_SELECT_INIT_ERR_SUCCESS; + } + else { + player_select->err_no = PLAYER_SELECT_INIT_ERR_PAK; + } +} + +static void player_select_game_data_init_err(GAME_PLAYER_SELECT* player_select) { + player_select->mode = PLAYER_SELECT_MODE_SELECTION; +} + +static PLAYER_SELECT_INIT_PROC l_init_proc[mSDI_INIT_MODE_NUM] = { + &player_select_game_data_init, + &player_select_game_data_init_new_player, + &player_select_game_data_init_save, + &player_select_game_data_init_pak, + &player_select_game_data_init_err +}; + +static void player_select_init_after(GAME_PLAYER_SELECT* player_select) { + mSDI_StartInitAfter((GAME*)player_select, FALSE, mSDI_MALLOC_FLAG_GAME); +} + +static void player_select_next_mode(int* mode, int max) { + (*mode)++; + if (*mode >= max) { + *mode = 0; + } +} + +static void player_select_back_mode(int* mode, int max) { + (*mode)--; + if (*mode < 0) { + *mode = max - 1; + } +} + +static void player_select_move_main(GAME_PLAYER_SELECT* player_select) { + int mode = player_select->mode; + + if (player_select->err_no == PLAYER_SELECT_INIT_ERR_NONE) { + if (chkTrigger(BUTTON_A)) { + int player_no = player_select->player_no; + if (mode == PLAYER_SELECT_MODE_SELECTION) { + player_select->mode = PLAYER_SELECT_MODE_PLAY; + } + + if (player_select->mode == PLAYER_SELECT_MODE_PLAY) { + (*player_select->init_procs[player_no])(player_select); + } + } + + if (chkTrigger(BUTTON_DDOWN) && player_select->mode == PLAYER_SELECT_MODE_SELECTION) { + if (player_select->land_exist == TRUE) { + player_select_next_mode(&player_select->player_no, SELECT_PLAYER_NUM); + } + else { + player_select_next_mode(&player_select->player_no, PLAYER_NUM); + } + } + + if (chkTrigger(BUTTON_DUP) && player_select->mode == PLAYER_SELECT_MODE_SELECTION) { + if (player_select->land_exist == TRUE) { + player_select_back_mode(&player_select->player_no, SELECT_PLAYER_NUM); + } + else { + player_select_back_mode(&player_select->player_no, PLAYER_NUM); + } + } + } + else if (player_select->err_no == PLAYER_SELECT_INIT_ERR_SUCCESS) { + player_select_init_after(player_select); + GAME_GOTO_NEXT((GAME*)player_select, select, SELECT); + } + else { + Common_Set(scene_from_title_demo, -1); + player_select->err_no = PLAYER_SELECT_INIT_ERR_NONE; + player_select->mode = PLAYER_SELECT_MODE_SELECTION; + } +} + +static void str_add_word(u8* dst, const u8* word0, const u8* word1, int word0_len, int word1_len) { + for (word0_len; word0_len != 0; word0_len--) { + *dst++ = *word0++; + } + + for (word1_len; word1_len != 0; word1_len--) { + *dst++ = *word1++; + } +} + +static int l_ps_white_color[3] = { 250, 220, 100 }; +static int l_ps_select_color[3] = { 200, 55, 55 }; + +/* not translated, プレーヤー せんたく, player selection */ +static u8 _debug_player_select[10] = { 0xE4, 0xBA, 0x90, 0xB4, 0x90, 0x20, 0x0D, 0xC3, 0x0F, 0x07 }; + +static void player_select_draw_title(GAME_PLAYER_SELECT* player_select) { + mFont_SetMatrix(player_select->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace( + (GAME*)player_select, + _debug_player_select, ARRAY_SIZE(_debug_player_select, u8), + 85.0f, 15.0f, + 200, 200, 200, 255, + FALSE, TRUE, 0, + 1.2f, 1.2f, + mFont_MODE_FONT + ); + mFont_UnSetMatrix(player_select->game.graph, mFont_MODE_FONT); +} + +static void player_select_draw_player_no(GAME_PLAYER_SELECT* player_select) { + u8 name_buf[8 + SELECT_NAME_LEN]; + u8 pre_str[8] = { 0xED, 0xCA, 0x02, 0x15, 0xC3, 0x20, 0x20, 0x20 }; + int player_no = player_select->player_no; + int i; + + for (i = 0; i < PLAYER_NUM; i++) { + int* color; + + /* create text */ + mem_clear(name_buf, ARRAY_SIZE(name_buf, u8), CHAR_SPACE); + str_add_word(name_buf, pre_str, player_select->player_names[i], 8, SELECT_NAME_LEN); + + /* set player no */ + name_buf[6] = (u8)i | CHAR_ZERO; + + color = (player_no == i) ? l_ps_select_color : l_ps_white_color; + + mFont_SetMatrix(player_select->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace( + (GAME*)player_select, + name_buf, ARRAY_SIZE(name_buf, u8), + 70.0f, 65.0f + 15.0f * i, + color[0], color[1], color[2], 255, + FALSE, TRUE, 0, + 0.8f, 0.8f, + mFont_MODE_FONT + ); + mFont_UnSetMatrix(player_select->game.graph, mFont_MODE_FONT); + } +} + +static void player_select_draw_yosokara(GAME_PLAYER_SELECT* player_select) { + u8* name = player_select->player_names[PLAYER_NUM]; + int* color = (player_select->player_no == PLAYER_NUM) ? l_ps_select_color : l_ps_white_color; + + mFont_SetMatrix(player_select->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace( + (GAME*)player_select, + name, SELECT_NAME_LEN, + 70.0f, 65.0f + 15.0f * PLAYER_NUM, + color[0], color[1], color[2], 255, + FALSE, TRUE, 0, + 0.8f, 0.8f, + mFont_MODE_FONT + ); + mFont_UnSetMatrix(player_select->game.graph, mFont_MODE_FONT); +} + +static void player_select_draw_main(GAME_PLAYER_SELECT* player_select) { + GRAPH* g = player_select->game.graph; + + OPEN_DISP(g); + + gSPSegment(NOW_POLY_OPA_DISP++, G_MWO_SEGMENT_0, 0); + gSPSegment(NOW_FONT_DISP++, G_MWO_SEGMENT_0, 0); + + DisplayList_initialize(g, 0, 0, 0, NULL); + + gDPPipeSync(NOW_POLY_OPA_DISP++); + + CLOSE_DISP(g); + + showView(&player_select->view, VIEW_UPDATE_ALL); + player_select_draw_title(player_select); + player_select_draw_player_no(player_select); + player_select_draw_yosokara(player_select); +} + +static void player_select_main(GAME* game) { + GAME_PLAYER_SELECT* player_select = (GAME_PLAYER_SELECT*)game; + + player_select_move_main(player_select); + player_select_draw_main(player_select); + + { + GRAPH* g = game->graph; + game_debug_draw_last(game, g); + game_draw_last(g); + } +} + +extern void player_select_cleanup(GAME* game) { } + +#pragma pool_data on +extern void player_select_init(GAME* game) { + GAME_PLAYER_SELECT* player_select = (GAME_PLAYER_SELECT*)game; + GRAPH* g = game->graph; + int i; + + game->exec = &player_select_main; + game->cleanup = &player_select_cleanup; + + { + View* view = &player_select->view; + initView(view, g); + view->flag = VIEW_UPDATE_ORTHOGRAPHIC; + } + + new_Matrix(game); + SetGameFrame(1); + + player_select->player_no = 0; + player_select->err_no = PLAYER_SELECT_INIT_ERR_NONE; + player_select->mode = PLAYER_SELECT_MODE_SELECTION; + + for (i = 0; i < SELECT_PLAYER_NUM; i++) { + int j; + + for (j = 0; j < 6; j++) { + player_select->player_names[i][j] = mitouroku_str[j]; + } + + for (j = 6; j < SELECT_NAME_LEN; j++) { + player_select->player_names[i][j] = CHAR_SPACE; + } + + player_select->player_types[i] = PLAYER_SELECT_PLAYER_MODE_NO_SAVE; + } + + for (i = 0; i < LAND_NAME_SIZE; i++) { + player_select->land_name[i] = CHAR_SPACE; + } + player_select->land_exist = FALSE; + + if (mFRm_CheckSaveData() == TRUE) { + Private_c* private_p = Save_Get(private); + for (i = 0; i < PLAYER_NUM; i++) { + u8* name = player_select->player_names[i]; + + if (mPr_CheckPrivate(private_p) == TRUE) { + mPr_CopyPlayerName(name, private_p); + + if (private_p->exists == FALSE) { + mem_copy(name + PLAYER_NAME_LEN, l_gaishutu_str, 10); + player_select->player_types[i] = PLAYER_SELECT_PLAYER_MODE_OUT; + } + else { + mem_copy(name + PLAYER_NAME_LEN, l_zaitaku_str, 9); + player_select->player_types[i] = PLAYER_SELECT_PLAYER_MODE_HOME; + } + } + else { + player_select->player_types[i] = PLAYER_SELECT_PLAYER_MODE_UNREGISTERED; + } + + private_p++; + } + + mLd_CopyLandName(player_select->land_name, Save_Get(land_info.name)); + player_select->land_exist = TRUE; + } + + for (i = 0; i < SELECT_PLAYER_NAME_EXTRA; i++) { + player_select->player_names[PLAYER_NUM][i] = l_yosokara_str[i]; + } + + for (i = SELECT_PLAYER_NAME_EXTRA; i < SELECT_NAME_LEN; i++) { + player_select->player_names[PLAYER_NUM][i] = CHAR_SPACE; + } + + player_select->player_types[PLAYER_NUM] = PLAYER_SELECT_PLAYER_MODE_OUT; + + for (i = 0; i < SELECT_PLAYER_NUM; i++) { + player_select->init_procs[i] = l_init_proc[player_select->player_types[i]]; + } + + Common_Set(player_no, 0); + Common_Set(player_data_mode, 0); + Common_Set(scene_from_title_demo, -1); +} +#pragma pool_data reset