diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 6773b8c5..9e31ef49 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -601,6 +601,11 @@ m_map_ovl.c: .rodata: [0x8064B628, 0x8064B6B0] .data: [0x806CD9C0, 0x806CE008] .bss: [0x81340468, 0x81340488] +m_repay_ovl.c: + .text: [0x805EC550, 0x805ED0FC] + .rodata: [0x8064B830, 0x8064B870] + .data: [0x806CE4E0, 0x806CE550] + .bss: [0x813405A8, 0x813405C0] m_timeIn_ovl.c: .text: [0x805FF3C4, 0x80600370] .rodata: [0x8064BA00, 0x8064BA58] diff --git a/include/m_player_lib.h b/include/m_player_lib.h index 7ea3e724..e946c6d3 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -45,6 +45,7 @@ extern int mPlib_Check_able_force_speak_label(GAME* game, ACTOR* label); extern int mPlib_able_submenu_type1(GAME* game); extern void mPlib_request_main_demo_wait_from_submenu(ACTOR* force_speak_label); extern void mPlib_Load_PlayerTexAndPallet(void* tex_p, void* pal_p, int idx); +extern void mPlib_request_main_give_from_submenu(mActor_name_t disp_item, int submenu_ovl, int present_flag, int counter_flag); extern mPlayer_change_data_from_submenu_c* mPlib_Get_change_data_from_submenu_p(); diff --git a/include/m_repay_ovl.h b/include/m_repay_ovl.h new file mode 100644 index 00000000..5e413cb6 --- /dev/null +++ b/include/m_repay_ovl.h @@ -0,0 +1,37 @@ +#ifndef M_REPAY_OVL_H +#define M_REPAY_OVL_H + +#include "types.h" +#include "m_repay_ovl_h.h" +#include "m_submenu_ovl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + mRP_CURSOR_100000, + mRP_CURSOR_10000, + mRP_CURSOR_1000, + mRP_CURSOR_100, + mRP_CURSOR_10, + mRP_CURSOR_1, + mRP_CURSOR_OK, + + mRP_CURSOR_NUM +}; + +struct repay_ovl_s { + u32 money; + u32 loan; + u32 repay_amount; + u32 max_money; + u32 max_repay; + int cursor_idx; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_repay_ovl_h.h b/include/m_repay_ovl_h.h new file mode 100644 index 00000000..7f5d8dfe --- /dev/null +++ b/include/m_repay_ovl_h.h @@ -0,0 +1,16 @@ +#ifndef M_REPAY_OVL_H_H +#define M_REPAY_OVL_H_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct repay_ovl_s mRP_Ovl_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_submenu_ovl.h b/include/m_submenu_ovl.h index 4a0b37cc..bb247459 100644 --- a/include/m_submenu_ovl.h +++ b/include/m_submenu_ovl.h @@ -21,6 +21,7 @@ #include "m_editEndChk_h.h" #include "m_haniwaPortrait_ovl_h.h" #include "m_timeIn_ovl_h.h" +#include "m_repay_ovl_h.h" #ifdef __cplusplus extern "C" { @@ -133,7 +134,7 @@ struct submenu_overlay_s { /* 0x9A0 */ mTI_Ovl_c* timeIn_ovl; /* 0x9A4 */ mEE_Ovl_c* editEndChk_ovl; /* 0x9A8 */ mWR_Ovl_c* warning_ovl; - /* 0x9AC */ void* _9AC; + /* 0x9AC */ mRP_Ovl_c* repay_ovl; /* 0x9B0 */ void* _9B0; /* 0x9B4 */ mMP_Overlay_c* map_ovl; /* 0x9B8 */ u8 _9B8[0x9D0 - 0x9B8]; diff --git a/src/m_repay_ovl.c b/src/m_repay_ovl.c new file mode 100644 index 00000000..70dbdffc --- /dev/null +++ b/src/m_repay_ovl.c @@ -0,0 +1,369 @@ +#include "m_repay_ovl.h" + +#include "m_common_data.h" +#include "m_font.h" +#include "m_name_table.h" +#include "m_player_lib.h" +#include "sys_matrix.h" + +static mRP_Ovl_c rp_ovl_data; +static mActor_name_t mRP_money_name[MONEY_NUM] = { ITM_MONEY_100, ITM_MONEY_1000, ITM_MONEY_10000, ITM_MONEY_30000 }; +static u32 mRP_money_amount[MONEY_NUM] = { 100, 1000, 10000, 30000 }; + +static int mRP_money_repay(mRP_Ovl_c* repay_ovl) { + mActor_name_t* item_p; + mActor_name_t* money_name_p = mRP_money_name; + u32* money_amount_p = mRP_money_amount; + u32 total_money = Common_Get(now_private)->inventory.wallet; + int j; + int i; + u32 money_left = 0; + + if (total_money >= repay_ovl->repay_amount) { + money_left = total_money - repay_ovl->repay_amount; + } + else { + for (i = 0; i < MONEY_NUM; i++) { + item_p = Common_Get(now_private)->inventory.pockets; + for (j = 0; j < mPr_POCKETS_SLOT_COUNT; j++) { + if ( + mPr_GET_ITEM_COND(Common_Get(now_private)->inventory.item_conditions, j) == mPr_ITEM_COND_NORMAL && + *item_p == *money_name_p + ) { + total_money += *money_amount_p; + mPr_SetPossessionItem(Common_Get(now_private), j, EMPTY_NO, mPr_ITEM_COND_NORMAL); + + if (total_money >= repay_ovl->repay_amount) { + return total_money - repay_ovl->repay_amount; + } + } + + item_p++; + } + + money_name_p++; + money_amount_p++; + } + } + + return money_left; +} + +static void mRP_move_Move(Submenu* submenu, mSM_MenuInfo_c* menu_info) { + (*submenu->overlay->move_Move_proc)(submenu, menu_info); +} + +static void mRP_move_Play(Submenu* submenu, mSM_MenuInfo_c* menu_info) { + static u32 step_money[mRP_CURSOR_NUM] = { + 100000, + 10000, + 1000, + 100, + 10, + 1, + 0 + }; + + mRP_Ovl_c* repay_ovl = submenu->overlay->repay_ovl; + u32 trigger = submenu->overlay->menu_control.trigger; + + if ((trigger & BUTTON_B)) { + (*submenu->overlay->move_chg_base_proc)(menu_info, mSM_MOVE_OUT_TOP); + sAdo_SysTrgStart(2); + } + else if (repay_ovl->cursor_idx >= mRP_CURSOR_OK || (trigger & BUTTON_START)) { + if ((trigger & BUTTON_A) || (trigger & BUTTON_START)) { + if (repay_ovl->repay_amount != 0) { + mPlib_request_main_give_from_submenu(ITM_MONEY_10000, mSM_OVL_REPAY, FALSE, TRUE); + Common_Get(now_private)->inventory.loan = repay_ovl->loan; + Common_Get(now_private)->inventory.wallet = mRP_money_repay(repay_ovl); + } + + (*submenu->overlay->move_chg_base_proc)(menu_info, mSM_MOVE_OUT_TOP); + sAdo_SysTrgStart(2); + } + else if ((trigger & (BUTTON_CUP | BUTTON_CLEFT))) { + repay_ovl->cursor_idx--; + sAdo_SysTrgStart(1); + } + } + else if (repay_ovl->cursor_idx != 0 && (trigger & BUTTON_CLEFT)) { + repay_ovl->cursor_idx--; + sAdo_SysTrgStart(1); + } + else if ((trigger & BUTTON_CRIGHT)) { + repay_ovl->cursor_idx++; + sAdo_SysTrgStart(1); + } + else if ((trigger & (BUTTON_CDOWN | BUTTON_CUP))) { + u32 repay_amount = repay_ovl->repay_amount; + + if ((trigger & BUTTON_CDOWN)) { + if (repay_amount < step_money[repay_ovl->cursor_idx]) { + if (repay_amount == 0) { + sAdo_SysTrgStart(0x1003); + return; + } + + repay_amount = 0; + } + else { + repay_amount -= step_money[repay_ovl->cursor_idx]; + } + } + else { + if (repay_amount == repay_ovl->max_repay) { + sAdo_SysTrgStart(0x1003); + return; + } + + repay_amount += step_money[repay_ovl->cursor_idx]; + if (repay_amount > repay_ovl->max_repay) { + repay_amount = repay_ovl->max_repay; + } + } + + sAdo_SysTrgStart(0x426); + repay_ovl->money = repay_ovl->max_money - repay_amount; + repay_ovl->loan = Common_Get(now_private)->inventory.loan - repay_amount; + repay_ovl->repay_amount = repay_amount; + } +} + +static void mRP_move_End(Submenu* submenu, mSM_MenuInfo_c* menu_info) { + (*submenu->overlay->move_End_proc)(submenu, menu_info); +} + +typedef void (*mRP_MOVE_PROC)(Submenu*, mSM_MenuInfo_c*); + +static void mRP_repay_ovl_move(Submenu* submenu) { + static mRP_MOVE_PROC ovl_move_proc[mSM_OVL_PROC_NUM] = { + &mRP_move_Move, + &mRP_move_Play, + (mRP_MOVE_PROC)none_proc1, + (mRP_MOVE_PROC)none_proc1, + &mRP_move_End + }; + + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[mSM_OVL_REPAY]; + + (*menu_info->pre_move_func)(submenu); + (*ovl_move_proc[menu_info->proc_status])(submenu, menu_info); +} + +extern Gfx fkm_win_mode[]; +extern Gfx fkm_win_model[]; + +static void mRP_set_frame_dl(Submenu* submenu, GRAPH* graph, mSM_MenuInfo_c* menu_info, f32 x, f32 y) { + f32 tex_x; + f32 tex_y; + int s; + int t; + Gfx* gfx; + + Matrix_scale(16.0f, 16.0f, 1.0f, 0); + Matrix_translate(x, y, 140.0f, 1); + + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + + /* Setup RDP */ + gSPDisplayList(gfx++, fkm_win_mode); + + /* Setup matrix */ + gSPMatrix(gfx++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + /* Set background texture scroll position */ + tex_x = -submenu->overlay->menu_control.texture_pos[0] * 4.0f; + tex_y = -submenu->overlay->menu_control.texture_pos[1] * 4.0f; + s = (int)tex_x & 0xFF; + t = (int)tex_y & 0xFF; + gDPSetTileSize_Dolphin(gfx++, G_TX_RENDERTILE, s, t, 32, 32); + + /* Draw background frame */ + gSPDisplayList(gfx++, fkm_win_model); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); +} + +static void mRP_set_num_str(GAME* game, u32 num, rgba_t* str_col_p, f32 x, f32 y, f32 scale) { + u8 str[7]; + + mFont_UnintToString(str, sizeof(str), num, 6, FALSE, FALSE, TRUE); + x -= scale * mFont_GetStringWidth(str, sizeof(str), TRUE); + mFont_SetLineStrings( + game, + str, sizeof(str), + x, y, + str_col_p->r, str_col_p->g, str_col_p->b, 255, + FALSE, + TRUE, + scale, scale, + mFont_MODE_POLY + ); +} + +static void mRP_set_character_dl(Submenu* submenu, GAME* game, f32 x, f32 y) { + static u8 kingaku_str[9] = "Your Loan"; + static u8 kettei_str[2] = "OK"; + static rgba_t money_col = { 100, 40, 255, 255 }; + static rgba_t repay_col = { 70, 120, 245, 255 }; + static rgba_t select_col = { 215, 0, 0, 255 }; + static rgba_t kettei_col = { 70, 120, 245, 255 }; + static rgba_t loan_col = { 40, 185, 110, 255 }; + + mRP_Ovl_c* repay_ovl = submenu->overlay->repay_ovl; + rgba_t* color_p; + u8 repay_amount_str[7]; + int sel; + f32 char_y; + f32 char_x; + int i; + + (*submenu->overlay->set_char_matrix_proc)(game->graph); + mFont_SetLineStrings( + game, + kingaku_str, sizeof(kingaku_str), + x + 153.0f, -y + 64.0f, + 255, 255, 255, 255, + FALSE, + TRUE, + 0.875f, 0.875f, + mFont_MODE_POLY + ); + + mRP_set_num_str(game, repay_ovl->money, &money_col, x + 206.0f, -y + 91.0f, 0.875f); + sel = repay_ovl->cursor_idx; + if (sel >= mRP_CURSOR_100) { + sel++; // move past the comma + } + + mFont_UnintToString(repay_amount_str, sizeof(repay_amount_str), repay_ovl->repay_amount, 6, FALSE, TRUE, TRUE); + + /* Draw each individual character in the repayment amount string */ + char_x = x - mFont_GetStringWidth(repay_amount_str, 7, TRUE) + 206.0f; + char_y = -y + 112.0f; + for (i = 0; i < 7; i++) { + if (sel == i) { + color_p = &select_col; + } + else { + color_p = &repay_col; + } + + mFont_SetLineStrings( + game, + &repay_amount_str[i], 1, + char_x, char_y, + color_p->r, color_p->g, color_p->b, 255, + FALSE, + TRUE, + 1.0f, 1.0f, + mFont_MODE_POLY + ); + + char_x += mFont_GetStringWidth(&repay_amount_str[i], 1, TRUE); + } + + if (repay_ovl->cursor_idx < mRP_CURSOR_OK) { + color_p = &kettei_col; + } + else { + color_p = &select_col; + } + + mFont_SetLineStrings( + game, + kettei_str, sizeof(kettei_str), + x + 207.0f, -y + 128.0f, + color_p->r, color_p->g, color_p->b, 255, + FALSE, + TRUE, + 0.875f, 0.875f, + mFont_MODE_POLY + ); + + mRP_set_num_str(game, repay_ovl->loan, &loan_col, x + 209.0f, -y + 155.0f, 0.875f); +} + +static void mRP_set_dl(Submenu* submenu, GAME* game, mSM_MenuInfo_c* menu_info) { + GRAPH* graph = game->graph; + f32 x = menu_info->position[0]; + f32 y = menu_info->position[1]; + + mRP_set_frame_dl(submenu, graph, menu_info, x, y); + mRP_set_character_dl(submenu, game, x, y); +} + +static void mRP_repay_ovl_draw(Submenu* submenu, GAME* game) { + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[mSM_OVL_REPAY]; + + (*menu_info->pre_draw_func)(submenu, game); + mRP_set_dl(submenu, game, menu_info); +} + +extern void mRP_repay_ovl_set_proc(Submenu* submenu) { + mSM_Control_c* control = &submenu->overlay->menu_control; + + control->menu_move_func = &mRP_repay_ovl_move; + control->menu_draw_func = &mRP_repay_ovl_draw; +} + +static void mRP_repay_ovl_init(Submenu* submenu) { + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[mSM_OVL_REPAY]; + mRP_Ovl_c* repay_ovl = submenu->overlay->repay_ovl; + mActor_name_t* item_p = Common_Get(now_private)->inventory.pockets; + int i; + u32 max_repay; + + submenu->overlay->menu_control.animation_flag = FALSE; + menu_info->proc_status = mSM_OVL_PROC_MOVE; + menu_info->next_proc_status = mSM_OVL_PROC_PLAY; + menu_info->move_drt = mSM_MOVE_IN_TOP; + + repay_ovl->money = Common_Get(now_private)->inventory.wallet; + + for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++, item_p++) { + if (mPr_GET_ITEM_COND(Common_Get(now_private)->inventory.item_conditions, i) == mPr_ITEM_COND_NORMAL) { + int j; + + for (j = 0; j < MONEY_NUM; j++) { + if (*item_p == mRP_money_name[j]) { + repay_ovl->money += mRP_money_amount[j]; + break; + } + } + } + } + + repay_ovl->max_money = repay_ovl->money; + repay_ovl->loan = Common_Get(now_private)->inventory.loan; + repay_ovl->repay_amount = 0; + + if (repay_ovl->max_money > Common_Get(now_private)->inventory.loan) { + max_repay = Common_Get(now_private)->inventory.loan; + } + else { + max_repay = repay_ovl->max_money; + } + + repay_ovl->max_repay = max_repay; + repay_ovl->cursor_idx = mRP_CURSOR_100000; +} + +extern void mRP_repay_ovl_construct(Submenu* submenu) { + Submenu_Overlay_c* overlay = submenu->overlay; + + if (overlay->repay_ovl == NULL) { + mem_clear((u8*)&rp_ovl_data, sizeof(mRP_Ovl_c), 0); + overlay->repay_ovl = &rp_ovl_data; + } + + mRP_repay_ovl_init(submenu); + mRP_repay_ovl_set_proc(submenu); +} + +extern void mRP_repay_ovl_destruct(Submenu* submenu) { + submenu->overlay->repay_ovl = NULL; +}