From d5b1fe6863fa433ad9fa815a38fa5b8f8046088a Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Sun, 23 Mar 2025 16:07:48 -0400 Subject: [PATCH] Implement & link ac_ev_yomise --- configure.py | 2 +- include/ac_ev_yomise.h | 26 +- src/actor/npc/event/ac_ev_yomise.c | 114 +++++++ src/actor/npc/event/ac_ev_yomise_move.c_inc | 339 ++++++++++++++++++++ 4 files changed, 479 insertions(+), 2 deletions(-) create mode 100644 src/actor/npc/event/ac_ev_yomise.c create mode 100644 src/actor/npc/event/ac_ev_yomise_move.c_inc diff --git a/configure.py b/configure.py index 71ac4004..9ad11cea 100644 --- a/configure.py +++ b/configure.py @@ -1180,7 +1180,7 @@ config.libs = [ Object(Matching, "actor/npc/event/ac_ev_soncho2.c"), Object(Matching, "actor/npc/event/ac_ev_speech_soncho.c"), Object(Matching, "actor/npc/event/ac_ev_turkey.c"), - Object(NonMatching, "actor/npc/event/ac_ev_yomise.c"), + Object(Matching, "actor/npc/event/ac_ev_yomise.c"), ], ), Rel( diff --git a/include/ac_ev_yomise.h b/include/ac_ev_yomise.h index 42e1c137..b6a7889c 100644 --- a/include/ac_ev_yomise.h +++ b/include/ac_ev_yomise.h @@ -3,11 +3,36 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +#define aEYMS_GOODS_COUNT 8 + +typedef struct { + mActor_name_t goods[aEYMS_GOODS_COUNT]; + s16 cnt; + s16 kind; +} aEv_yomise_save_c; + +typedef struct ev_yomise_actor_s EV_YOMISE_ACTOR; + +typedef void (*aEYMS_TALK_PROC)(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play); + +struct ev_yomise_actor_s { + NPC_ACTOR npc_class; + aEYMS_TALK_PROC talk_proc; + int talk_action; + int next_talk_action; + mActor_name_t item; + s16 cur_choice_start; + s16 next_choice_start; + u32 price; + s16 dst_pos[2]; +}; + extern ACTOR_PROFILE Ev_Yomise_Profile; #ifdef __cplusplus @@ -15,4 +40,3 @@ extern ACTOR_PROFILE Ev_Yomise_Profile; #endif #endif - diff --git a/src/actor/npc/event/ac_ev_yomise.c b/src/actor/npc/event/ac_ev_yomise.c new file mode 100644 index 00000000..574ff075 --- /dev/null +++ b/src/actor/npc/event/ac_ev_yomise.c @@ -0,0 +1,114 @@ +#include "ac_ev_yomise.h" +#include "m_common_data.h" +#include "m_player_lib.h" +#include "m_string.h" +#include "m_msg.h" +#include "m_font.h" +#include "libultra/libultra.h" + +enum { + aEYMS_TALK_ADD_ACTION, + aEYMS_TALK_SELECT, + aEYMS_TALK_SELECT2, + aEYMS_TALK_FRUIT, + aEYMS_TALK_END, + aEYMS_TALK_GIVE, + + aEYMS_TALK_NUM +}; + +static void aEYMS_actor_ct(ACTOR* actorx, GAME* game); +static void aEYMS_actor_dt(ACTOR* actorx, GAME* game); +static void aEYMS_actor_move(ACTOR* actorx, GAME* game); +static void aEYMS_actor_draw(ACTOR* actorx, GAME* game); +static void aEYMS_actor_init(ACTOR* actorx, GAME* game); +static void aEYMS_actor_save(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Ev_Yomise_Profile = { + // clang-format off + mAc_PROFILE_EV_YOMISE, + ACTOR_PART_NPC, + ACTOR_STATE_NONE, + SP_NPC_EV_YOMISE, + ACTOR_OBJ_BANK_KEEP, + sizeof(EV_YOMISE_ACTOR), + aEYMS_actor_ct, + aEYMS_actor_dt, + aEYMS_actor_init, + mActor_NONE_PROC1, + aEYMS_actor_save, + // clang-format on +}; + +static void aEYMS_talk_request(ACTOR* actorx, GAME* game); +static int aEYMS_talk_init(ACTOR* actorx, GAME* game); +static int aEYMS_talk_end_chk(ACTOR* actorx, GAME* game); + +static void aEYMS_setupAction(EV_YOMISE_ACTOR* yomise, int action); + +static void yomise_save_area_ct(void); + +static void aEYMS_actor_ct(ACTOR* actorx, GAME* game) { + static aNPC_ct_data_c ct_data = { + // clang-format off + aEYMS_actor_move, + aEYMS_actor_draw, + aNPC_CT_SCHED_TYPE_STAND, + aEYMS_talk_request, + aEYMS_talk_init, + aEYMS_talk_end_chk, + 0 + // clang-format on + }; + + EV_YOMISE_ACTOR* yomise = (EV_YOMISE_ACTOR*)actorx; + + if (NPC_CLIP->birth_check_proc(actorx, game) == TRUE) { + + NPC_CLIP->ct_proc(actorx, game, &ct_data); + yomise->npc_class.draw.main_animation.keyframe.morph_counter = 0.0f; + yomise->npc_class.condition_info.hide_flg = FALSE; + yomise->npc_class.palActorIgnoreTimer = -1; + actorx->status_data.weight = MASSTYPE_IMMOVABLE; + + mEv_check_status(mEv_EVENT_FIREWORKS_SHOW, mEv_STATUS_SHOW); // @cleanup - not needed + yomise->npc_class.collision.check_kind = aNPC_BG_CHECK_TYPE_NONE; + actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f); + actorx->position_speed.y = 0.0f; + actorx->gravity = 0.0f; + actorx->max_velocity_y = 0.0f; + yomise_save_area_ct(); + aEYMS_setupAction(yomise, aEYMS_TALK_END); + yomise->dst_pos[1] = actorx->world.position.z + 50.0f; + + if (actorx->npc_id == SP_NPC_EV_YOMISE) { + yomise->dst_pos[0] = actorx->world.position.x + 50.0f; + } else { + yomise->dst_pos[0] = actorx->world.position.x - 50.0f; + } + + NPC_CLIP->set_dst_pos_proc((NPC_ACTOR*)yomise, yomise->dst_pos[0], yomise->dst_pos[1]); + } +} + +static void aEYMS_actor_save(ACTOR* actorx, GAME* game) { + NPC_CLIP->save_proc(actorx, game); +} + +static void aEYMS_actor_dt(ACTOR* actorx, GAME* game) { + if (mEv_check_status(mEv_EVENT_FIREWORKS_SHOW, mEv_STATUS_SHOW)) { + mEv_actor_dying_message(mEv_EVENT_FIREWORKS_SHOW, actorx); + } + + NPC_CLIP->dt_proc(actorx, game); +} + +static void aEYMS_actor_init(ACTOR* actorx, GAME* game) { + NPC_CLIP->init_proc(actorx, game); +} + +static void aEYMS_actor_draw(ACTOR* actorx, GAME* game) { + NPC_CLIP->draw_proc(actorx, game); +} + +#include "../src/actor/npc/event/ac_ev_yomise_move.c_inc" diff --git a/src/actor/npc/event/ac_ev_yomise_move.c_inc b/src/actor/npc/event/ac_ev_yomise_move.c_inc new file mode 100644 index 00000000..e0a0684d --- /dev/null +++ b/src/actor/npc/event/ac_ev_yomise_move.c_inc @@ -0,0 +1,339 @@ +static aEv_yomise_save_c* get_yomise_save_area(void) { + aEv_yomise_save_c* save_p = (aEv_yomise_save_c*)mEv_get_save_area(mEv_EVENT_FIREWORKS_SHOW, 0); + + return save_p; +} + +static int aYMS_check_goods_cnt(int start_idx) { + int i; + int cnt; + aEv_yomise_save_c* save_p; + + save_p = get_yomise_save_area(); + cnt = 0; + + for (i = start_idx; i < aEYMS_GOODS_COUNT; i++) { + if (save_p->goods[i] != EMPTY_NO) { + cnt++; + } + } + + return cnt; +} + +static void setUp_yomise_goods(void) { + aEv_yomise_save_c* save_p; + int i; + int j; + static mActor_name_t sell_table[] = { ITM_BLUEBELL_FAN, ITM_YELLOW_PINWHEEL, ITM_RED_BALLOON }; + + save_p = get_yomise_save_area(); + + for (i = 0; i < aEYMS_GOODS_COUNT; i++) { + save_p->goods[i] = EMPTY_NO; + } + + save_p->cnt = aEYMS_GOODS_COUNT; + save_p->kind = RANDOM(ARRAY_COUNT(sell_table)); + + for (j = 0; j < aEYMS_GOODS_COUNT; j++) { + save_p->goods[j] = sell_table[save_p->kind] + j; + } +} + +static void yomise_save_area_ct(void) { + aEv_yomise_save_c* save_p; + + save_p = get_yomise_save_area(); + if (save_p == NULL) { + mEv_reserve_save_area(mEv_EVENT_FIREWORKS_SHOW, 0); + get_yomise_save_area(); // @cleanup - unused + setUp_yomise_goods(); + } +} + +static int aEYMS_set_choise_data(int start_idx, int max) { + aEv_yomise_save_c* save_p = get_yomise_save_area(); + mChoice_c* choice_p = mChoice_Get_base_window_p(); + u8 buf[mChoice_CHOICE_STRING_LEN * mChoice_CHOICE_NUM]; + u8* str_p[mChoice_CHOICE_NUM]; + int i; + int j; + static u8 new_player_str[mChoice_CHOICE_STRING_LEN] = "I'm not buying! "; + static u8 new_player_str2[mChoice_CHOICE_STRING_LEN] = "I don't want it!"; + + mem_clear(buf, sizeof(buf), CHAR_SPACE); + for (i = 0; i < mChoice_CHOICE_NUM; i++) { + str_p[i] = NULL; + } + + i = 0; + for (j = start_idx; i < max && j < aEYMS_GOODS_COUNT; j++) { + if (save_p->goods[j] != EMPTY_NO) { + str_p[i] = &buf[i * mChoice_CHOICE_STRING_LEN]; + mIN_copy_name_str(str_p[i], save_p->goods[j]); + i++; + } + } + + if (max == 3) { + for (i = 0; i < mChoice_CHOICE_NUM; i++) { + if (str_p[i] == NULL) { + if (j == aEYMS_GOODS_COUNT) { + mem_copy(&buf[i * mChoice_CHOICE_STRING_LEN], new_player_str, mChoice_CHOICE_STRING_LEN); + } else { + mem_copy(&buf[i * mChoice_CHOICE_STRING_LEN], new_player_str2, mChoice_CHOICE_STRING_LEN); + } + + str_p[i] = &buf[i * mChoice_CHOICE_STRING_LEN]; + i = mChoice_CHOICE_NUM; + } + } + } + + mChoice_Set_choice_data(choice_p, + str_p[0], mChoice_CHOICE_STRING_LEN, + str_p[1], mChoice_CHOICE_STRING_LEN, + str_p[2], mChoice_CHOICE_STRING_LEN, + str_p[3], mChoice_CHOICE_STRING_LEN, + NULL, mChoice_CHOICE_STRING_LEN, + NULL, mChoice_CHOICE_STRING_LEN + ); + + return j; +} + +static void aNSM_set_item_value_str(u32 price, int str_no) { + u8 str[6]; + + mFont_UnintToString(str, 6, price, 5, TRUE, FALSE, TRUE); + mMsg_SET_FREE_STR(str_no, str, sizeof(str)); +} + +static void aYMS_make_utiwa(ACTOR* actorx, GAME* game) { + EV_YOMISE_ACTOR* yomise = (EV_YOMISE_ACTOR*)actorx; + + if (yomise->npc_class.right_hand.item_actor_p == NULL) { + ACTOR* utiwa_p = CLIP(tools_clip)->aTOL_birth_proc(TOOL_UTIWA, aTOL_ACTION_S_TAKEOUT, actorx, game, -1, NULL); + + if (utiwa_p != NULL) { + yomise->npc_class.right_hand.item_actor_p = utiwa_p; + } + } +} + +static void aEYMS_to_talk_buy(EV_YOMISE_ACTOR* yomise) { + int cnt = aYMS_check_goods_cnt(yomise->cur_choice_start); + + yomise->next_choice_start = aEYMS_set_choise_data(yomise->cur_choice_start, 3); + + if (cnt < 4) { + mMsg_SET_CONTINUE_MSG_NUM(0x1761); + } else { + mMsg_SET_CONTINUE_MSG_NUM(0x1762); + } +} + +static int get_now_select_goods_idx(EV_YOMISE_ACTOR* yomise, int buy_idx) { + aEv_yomise_save_c* save_p = get_yomise_save_area(); + int i; + + if (buy_idx == 3) { + return -1; + } + + for (i = yomise->cur_choice_start; i < aEYMS_GOODS_COUNT; i++) { + if (save_p->goods[i] != EMPTY_NO) { + if (buy_idx == 0) { + return i; + } + + buy_idx--; + } + } + + return -1; +} + +static void aEYMS_talk_give(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 2) { + aNPC_DEMO_GIVE_ITEM(yomise->item, aHOI_REQUEST_PUTAWAY, FALSE); + aEYMS_setupAction(yomise, yomise->next_talk_action); + + switch (yomise->next_talk_action) { + case aEYMS_TALK_END: + mMsg_SET_CONTINUE_MSG_NUM(0x1765); + break; + case aEYMS_TALK_ADD_ACTION: + mMsg_SET_CONTINUE_MSG_NUM(0x1766); + break; + } + } +} + +static void aEYMS_talk_add_action(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play) { + if (mMsg_CHECK_MAINNORMALCONTINUE()) { + aEYMS_setupAction(yomise, yomise->talk_action + 1); + } +} + +static void aEYMS_talk_fruit(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play) { + int buy_idx; + int idx; + mActor_name_t item; + int price; + aEv_yomise_save_c* save_p = get_yomise_save_area(); + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + + if (order == 1) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + buy_idx = mChoice_GET_CHOSENUM(); + aEYMS_setupAction(yomise, aEYMS_TALK_END); + idx = get_now_select_goods_idx(yomise, buy_idx); + if (idx == -1) { + if (aYMS_check_goods_cnt(yomise->cur_choice_start) < 4) { + mMsg_SET_CONTINUE_MSG_NUM(0x1763); + aEYMS_setupAction(yomise, aEYMS_TALK_END); + } else { + mMsg_SET_CONTINUE_MSG_NUM(0x1767); + yomise->cur_choice_start = yomise->next_choice_start; + aEYMS_setupAction(yomise, aEYMS_TALK_SELECT); + } + } else { + item = save_p->goods[idx]; + price = yomise->price; + + if (mPr_GetPossessionItemSum(Now_Private, EMPTY_NO) == 0) { + mMsg_SET_CONTINUE_MSG_NUM(0x175D); + } else if (mSP_money_check(price) == FALSE) { + mMsg_SET_CONTINUE_MSG_NUM(0x175E); + } else { + mPr_SetFreePossessionItem(Now_Private, item, mPr_ITEM_COND_NORMAL); + yomise->item = item; + mSP_get_sell_price(price); + aEYMS_setupAction(yomise, aEYMS_TALK_GIVE); + save_p->goods[idx] = EMPTY_NO; + yomise->cur_choice_start = 0; + if (aYMS_check_goods_cnt(0) == 0) { + yomise->next_talk_action = aEYMS_TALK_END; + } else { + yomise->next_talk_action = aEYMS_TALK_ADD_ACTION; + } + + mMsg_SET_CONTINUE_MSG_NUM(0x1764); + } + } + } +} + +static void aEYMS_talk_select2(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + + if (order == 1) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + + switch (mChoice_GET_CHOSENUM()) { + case mChoice_CHOICE0: + mMsg_SET_CONTINUE_MSG_NUM(0x175C); + aEYMS_setupAction(yomise, aEYMS_TALK_FRUIT); + aEYMS_set_choise_data(0, 4); + break; + case mChoice_CHOICE1: + aEYMS_setupAction(yomise, aEYMS_TALK_END); + break; + } + } +} + +static void aEYMS_talk_select(EV_YOMISE_ACTOR* yomise, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + + if (order == 1) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + + switch (mChoice_GET_CHOSENUM()) { + case mChoice_CHOICE0: + aNSM_set_item_value_str(yomise->price, mMsg_FREE_STR0); + aEYMS_to_talk_buy(yomise); + aEYMS_setupAction(yomise, aEYMS_TALK_FRUIT); + break; + case mChoice_CHOICE1: + aEYMS_setupAction(yomise, aEYMS_TALK_END); + break; + } + } +} + +static void aEYMS_set_talk_info(ACTOR* actorx) { + int sel_msg_no; + static s16 msg_no[] = { 0x1758, 0x1759, 0x175A }; + aEv_yomise_save_c* save_p = get_yomise_save_area(); + EV_YOMISE_ACTOR* yomise = (EV_YOMISE_ACTOR*)actorx; + static u16 price[] = { 780, 680, 480 }; + + if (aYMS_check_goods_cnt(0) == 0) { + sel_msg_no = 0x1757; + yomise->next_talk_action = aEYMS_TALK_END; + } else { + sel_msg_no = msg_no[save_p->kind]; + yomise->next_talk_action = aEYMS_TALK_SELECT; + yomise->price = price[save_p->kind]; + yomise->cur_choice_start = 0; + } + + mDemo_Set_msg_num(sel_msg_no); + mDemo_Set_camera(CAMERA2_PROCESS_CUST_TALK); +} + +static void aEYMS_talk_request(ACTOR* actorx, GAME* game) { + if (Actor_player_look_direction_check(actorx, DEG2SHORT_ANGLE2(45.0f), (GAME_PLAY*)game)) { + if (ABS((s16)(actorx->player_angle_y - actorx->shape_info.rotation.y)) < DEG2SHORT_ANGLE2(45.0f)) { + mDemo_Request(mDemo_TYPE_TALK, actorx, aEYMS_set_talk_info); + } + } +} + +static int aEYMS_talk_init(ACTOR* actorx, GAME* game) { + EV_YOMISE_ACTOR* yomise = (EV_YOMISE_ACTOR*)actorx; + + aEYMS_setupAction(yomise, yomise->next_talk_action); + mDemo_Set_ListenAble(); + return TRUE; +} + +static int aEYMS_talk_end_chk(ACTOR* actorx, GAME* game) { + EV_YOMISE_ACTOR* yomise = (EV_YOMISE_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + int ret = FALSE; + + (*yomise->talk_proc)(yomise, play); + if (!mDemo_Check(mDemo_TYPE_TALK, actorx)) { + ret = TRUE; + NPC_CLIP->set_dst_pos_proc((NPC_ACTOR*)actorx, yomise->dst_pos[0], yomise->dst_pos[1]); + } + + return ret; +} + +static void aEYMS_actor_move(ACTOR* actorx, GAME* game) { + aYMS_make_utiwa(actorx, game); + NPC_CLIP->move_proc(actorx, game); +} + +static void aEYMS_setupAction(EV_YOMISE_ACTOR* yomise, int action) { + static aEYMS_TALK_PROC process[] = { + // clang-format off + aEYMS_talk_add_action, + aEYMS_talk_select, + aEYMS_talk_select2, + aEYMS_talk_fruit, + (aEYMS_TALK_PROC)none_proc1, + aEYMS_talk_give, + // clang-format on + }; + + yomise->talk_action = action; + yomise->talk_proc = process[action]; +}