mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-07-28 15:07:07 -04:00
1023 lines
33 KiB
C
1023 lines
33 KiB
C
#include "ac_sign.h"
|
|
|
|
#include "m_common_data.h"
|
|
#include "m_debug.h"
|
|
#include "m_skin_matrix.h"
|
|
#include "libultra/libultra.h"
|
|
#include "m_player_lib.h"
|
|
#include "m_msg.h"
|
|
#include "m_choice.h"
|
|
#include "m_needlework_ovl.h"
|
|
#include "sys_matrix.h"
|
|
#include "m_rcp.h"
|
|
|
|
enum {
|
|
aSIGN_ACTION_WAIT,
|
|
aSIGN_ACTION_TALK,
|
|
aSIGN_ACTION_TALK_END,
|
|
aSIGN_ACTION_MENU_OPEN_WAIT,
|
|
aSIGN_ACTION_MENU_END_WAIT,
|
|
aSIGN_ACTION_SINGLE_BIRTH,
|
|
aSIGN_ACTION_SINGLE_ERASE,
|
|
|
|
aSIGN_ACTION_NUM
|
|
};
|
|
|
|
extern Vtx obj_kanban_shadow_v[];
|
|
extern Gfx obj_kanban_shadowT_model[];
|
|
|
|
static u8 aSIGN_shadow_vtx_fix_flg_table[] = { TRUE, FALSE, FALSE, TRUE };
|
|
static bIT_ShadowData_c aSIGN_shadow_data = {
|
|
ARRAY_COUNT(aSIGN_shadow_vtx_fix_flg_table),
|
|
aSIGN_shadow_vtx_fix_flg_table,
|
|
50.0f,
|
|
obj_kanban_shadow_v,
|
|
obj_kanban_shadowT_model,
|
|
};
|
|
|
|
static void aSIGN_actor_ct(ACTOR* actorx, GAME* game);
|
|
static void aSIGN_actor_dt(ACTOR* actorx, GAME* game);
|
|
static void aSIGN_actor_move(ACTOR* actorx, GAME* game);
|
|
static void aSIGN_actor_draw(ACTOR* actorx, GAME* game);
|
|
|
|
// clang-format off
|
|
ACTOR_PROFILE Ac_Sign_Profile = {
|
|
mAc_PROFILE_AC_SIGN,
|
|
ACTOR_PART_ITEM,
|
|
ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED,
|
|
EMPTY_NO,
|
|
ACTOR_OBJ_BANK_AC_SIGN,
|
|
sizeof(SIGN_ACTOR),
|
|
&aSIGN_actor_ct,
|
|
&aSIGN_actor_dt,
|
|
&aSIGN_actor_move,
|
|
&aSIGN_actor_draw,
|
|
NULL,
|
|
};
|
|
// clang-format on
|
|
|
|
static void aSIGN_setup_action(SIGN_ACTOR* sign, int action);
|
|
static void aSIGN_change_my_original(SIGN_ACTOR* sign, GAME* game, u16 design_no);
|
|
static void aSIGN_single_birth(SIGN_ACTOR* sign, GAME* game);
|
|
static void aSIGN_single_erase(SIGN_ACTOR* sign, GAME* game);
|
|
|
|
static void aSIGN_actor_ct(ACTOR* actorx, GAME* game) {
|
|
SIGN_ACTOR* sign = (SIGN_ACTOR*)actorx;
|
|
|
|
Common_Get(clip).sign_control_actor = sign;
|
|
sign->is_winter = Common_Get(time.season) == mTM_SEASON_WINTER;
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
}
|
|
|
|
static void aSIGN_actor_dt(ACTOR* actorx, GAME* game) {
|
|
Common_Get(clip).sign_control_actor = NULL;
|
|
}
|
|
|
|
static int aSIGN_no_cull_check(GAME_PLAY* play, int bz, int bx, int ut_z, int ut_x) {
|
|
xyz_t center_pos;
|
|
xyz_t clip_pos;
|
|
f32 w;
|
|
f32 max_dist = aSIGN_CULL_MAX_DIST;
|
|
|
|
if (GETREG(NMREG, 5)) {
|
|
max_dist = GETREG(NMREG, 5);
|
|
}
|
|
|
|
/* Get the world space of the unit */
|
|
mFI_BkandUtNum2CenterWpos(¢er_pos, bx, bz, ut_x, ut_z);
|
|
center_pos.y = mFI_UNIT_BASE_SIZE_F + mCoBG_GetBgY_OnlyCenter_FromWpos2(center_pos, 0.0f);
|
|
|
|
/* Transform world space to clip space */
|
|
Skin_Matrix_PrjMulVector(&play->projection_matrix, ¢er_pos, &clip_pos, &w);
|
|
|
|
/* Test that the clip space is within the camera bounds */
|
|
if (clip_pos.z > -max_dist) {
|
|
f32 inv_w = (w < 1.0f) ? 1.0f : (1.0f / w);
|
|
|
|
if (inv_w * (fabsf(clip_pos.x) - max_dist) < 1.0f && inv_w * (fabsf(clip_pos.y) - max_dist) < 1.0f) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int aSIGN_no_cull_talk_area(GAME_PLAY* play, int bz, int bx, int ut_z, int ut_x) {
|
|
xyz_t center_pos;
|
|
|
|
mFI_BkandUtNum2CenterWpos(¢er_pos, bx, bz, ut_x, ut_z);
|
|
if (Camera2_CheckEnterCullingArea(center_pos.x, center_pos.z, 65.0f) == FALSE) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int aSIGN_draw_anime_check(SIGN_ACTOR* sign, int ut_z, int ut_x) {
|
|
int i;
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
if (sign->single[i].exist_flag && sign->single[i].unit.z == ut_z && sign->single[i].unit.x == ut_x) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void aSIGN_draw_set(SIGN_ACTOR* sign, aSIGN_draw_c* draw, GAME_PLAY* play, int bz, int bx, int base_ut_z,
|
|
int base_ut_x) {
|
|
mActor_name_t* fg_p = mFI_BkNumtoUtFGTop(bx, bz);
|
|
int ut_z;
|
|
int ut_x;
|
|
int ut_z_max = 5;
|
|
int ut_x_max = 7;
|
|
|
|
if (GETREG(NMREG, 2)) {
|
|
ut_z_max = GETREG(NMREG, 2);
|
|
}
|
|
|
|
if (GETREG(NMREG, 3)) {
|
|
ut_x_max = GETREG(NMREG, 3);
|
|
}
|
|
|
|
draw->block.z = bz;
|
|
draw->block.x = bx;
|
|
|
|
if (fg_p != NULL) {
|
|
|
|
for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) {
|
|
u16 ut_x_bitfield = 0;
|
|
u16 x_bit = 1;
|
|
|
|
for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) {
|
|
int ut_z_local = base_ut_z - ut_z;
|
|
int ut_x_local = base_ut_x - ut_x;
|
|
|
|
ut_z_local = ABS(ut_z_local);
|
|
ut_x_local = ABS(ut_x_local);
|
|
|
|
if (ITEM_NAME_GET_TYPE(*fg_p) == NAME_TYPE_ITEM0 && ITEM_NAME_GET_CAT(*fg_p) == ITEM0_CAT_SIGN) {
|
|
if (aSIGN_draw_anime_check(sign, ut_z, ut_x) == FALSE) {
|
|
if ((ut_z_local <= ut_z_max && ut_x_local <= ut_z_max) ||
|
|
(ut_z_local <= ut_x_max && ut_x_local <= ut_x_max &&
|
|
aSIGN_no_cull_check(play, bz, bx, ut_z, ut_x))) {
|
|
if (Camera2_CheckCullingMode()) {
|
|
if (aSIGN_no_cull_talk_area(play, bz, bx, ut_z, ut_x)) {
|
|
ut_x_bitfield |= x_bit;
|
|
}
|
|
} else {
|
|
ut_x_bitfield |= x_bit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
x_bit <<= 1;
|
|
fg_p++;
|
|
}
|
|
|
|
draw->exist_bitfield[ut_z] = ut_x_bitfield;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_actor_set_draw(SIGN_ACTOR* sign, GAME* game) {
|
|
xyz_t* camera_center_pos_p = Camera2_getCenterPos_p();
|
|
int bz_max = mFI_GetBlockZMax();
|
|
int bx_max = mFI_GetBlockXMax();
|
|
int bz0;
|
|
int bx0;
|
|
xyz_t pos;
|
|
int ut_z;
|
|
int ut_x;
|
|
int t_bz;
|
|
int t_bx;
|
|
int bz;
|
|
int bx;
|
|
int base_ut_z;
|
|
int base_ut_x;
|
|
int t_base_ut_z;
|
|
int t_base_ut_x;
|
|
int i;
|
|
int j;
|
|
aSIGN_draw_c* draw_p;
|
|
|
|
for (i = 0, draw_p = sign->draw; i < 2; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
bzero(draw_p->exist_bitfield, sizeof(draw_p->exist_bitfield));
|
|
draw_p++;
|
|
}
|
|
}
|
|
|
|
pos = *camera_center_pos_p;
|
|
if (mPlib_get_player_actor_main_index(game) == mPlayer_INDEX_DOOR) {
|
|
pos.z -= mFI_UT_WORLDSIZE_Z_F;
|
|
}
|
|
|
|
if (GETREG(NMREG, 4)) {
|
|
pos.z -= (f32)GETREG(NMREG, 4);
|
|
} else {
|
|
pos.z -= 2 * mFI_UT_WORLDSIZE_Z_F;
|
|
}
|
|
|
|
if (mFI_Wpos2BkandUtNuminBlock(&bx0, &bz0, &ut_x, &ut_z, pos)) {
|
|
if (ut_z < (UT_Z_NUM / 2)) {
|
|
t_bz = bz0 - 1;
|
|
t_base_ut_z = ut_z + UT_Z_NUM;
|
|
} else {
|
|
t_bz = bz0;
|
|
t_base_ut_z = ut_z;
|
|
}
|
|
|
|
if (ut_x < (UT_X_NUM / 2)) {
|
|
t_bx = bx0 - 1;
|
|
t_base_ut_x = ut_x + UT_X_NUM;
|
|
} else {
|
|
t_bx = bx0;
|
|
t_base_ut_x = ut_x;
|
|
}
|
|
|
|
bz = t_bz;
|
|
base_ut_z = t_base_ut_z;
|
|
for (i = 0, draw_p = sign->draw; i < 2; i++) {
|
|
bx = t_bx;
|
|
base_ut_x = t_base_ut_x;
|
|
for (j = 0; j < 2; j++) {
|
|
if (bz >= 0 && bz < bz_max && bx >= 0 && bx < bx_max) {
|
|
aSIGN_draw_set(sign, draw_p, (GAME_PLAY*)game, bz, bx, base_ut_z, base_ut_x);
|
|
}
|
|
|
|
bx++;
|
|
base_ut_x -= UT_X_NUM;
|
|
draw_p++;
|
|
}
|
|
|
|
bz++;
|
|
base_ut_z -= UT_Z_NUM;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int aSIGN_actor_BkandUtNum_formal(int* bz_p, int* bx_p, int* ut_z_p, int* ut_x_p) {
|
|
int bz_max = mFI_GetBlockZMax();
|
|
int bx_max = mFI_GetBlockXMax();
|
|
|
|
if (*ut_z_p < 0) {
|
|
(*ut_z_p) += UT_Z_NUM;
|
|
(*bz_p)--;
|
|
} else if (*ut_z_p >= UT_Z_NUM) {
|
|
(*ut_z_p) -= UT_Z_NUM;
|
|
(*bz_p)++;
|
|
}
|
|
|
|
if (*ut_x_p < 0) {
|
|
(*ut_x_p) += UT_X_NUM;
|
|
(*bx_p)--;
|
|
} else if (*ut_x_p >= UT_X_NUM) {
|
|
(*ut_x_p) -= UT_X_NUM;
|
|
(*bx_p)++;
|
|
}
|
|
|
|
return *bz_p >= 0 && *bz_p < bz_max && *bx_p >= 0 && *bx_p < bx_max;
|
|
}
|
|
|
|
static int aSIGN_actor_set_target(SIGN_ACTOR* sign, GAME* game) {
|
|
xyz_t sign_pos;
|
|
int base_bz;
|
|
int base_bx;
|
|
int base_ut_z;
|
|
int base_ut_x;
|
|
int bz;
|
|
int bx;
|
|
int ut_z;
|
|
int ut_x;
|
|
ACTOR* player_actor = GET_PLAYER_ACTOR_GAME_ACTOR(game);
|
|
f32 min_dist = FLT_MAX;
|
|
int z;
|
|
int x;
|
|
int i;
|
|
int j;
|
|
aSIGN_draw_c* draw_p;
|
|
int res = FALSE;
|
|
|
|
if (mFI_Wpos2BkandUtNuminBlock(&base_bx, &base_bz, &base_ut_x, &base_ut_z, player_actor->world.position)) {
|
|
|
|
for (z = -1; z < 1; z++) {
|
|
|
|
for (x = -1; x < 2; x++) {
|
|
bz = base_bz;
|
|
bx = base_bx;
|
|
ut_x = base_ut_x + x;
|
|
ut_z = base_ut_z + z;
|
|
|
|
if (aSIGN_actor_BkandUtNum_formal(&bz, &bx, &ut_z, &ut_x)) {
|
|
for (i = 0, draw_p = sign->draw; i < 2; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
if (draw_p->block.z == bz && draw_p->block.x == bx &&
|
|
(draw_p->exist_bitfield[ut_z] & (1 << ut_x)) != 0) {
|
|
mFI_BkandUtNum2CenterWpos(&sign_pos, bx, bz, ut_x, ut_z);
|
|
sign_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(sign_pos, 0.0f);
|
|
if (player_actor->world.position.z > sign_pos.z) {
|
|
s16 angle_y = search_position_angleY(&sign_pos, &player_actor->world.position);
|
|
int abs_angle_y = ABS(angle_y);
|
|
|
|
if (abs_angle_y < DEG2SHORT_ANGLE2(45.0f)) {
|
|
s16 d_angle_y =
|
|
(angle_y + DEG2SHORT_ANGLE2(180.0f)) - player_actor->shape_info.rotation.y;
|
|
s16 diff_angle_y = ABS(d_angle_y);
|
|
|
|
if (diff_angle_y <= DEG2SHORT_ANGLE2(68.83483f)) {
|
|
f32 dist_sq = Math3DLengthSquare(&player_actor->world.position, &sign_pos);
|
|
|
|
if (dist_sq < SQ(55.0f) && dist_sq < min_dist) {
|
|
res = TRUE;
|
|
min_dist = dist_sq;
|
|
sign->sign_pos.x = sign_pos.x;
|
|
sign->sign_pos.y = sign_pos.y;
|
|
sign->sign_pos.z = sign_pos.z;
|
|
sign->target_block.z = bz;
|
|
sign->target_block.x = bx;
|
|
sign->target_unit.z = ut_z;
|
|
sign->target_unit.x = ut_x;
|
|
xyz_t_move(&sign->target_pos, &sign_pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
draw_p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static ACTOR* aSIGN_search_exist_npc_inCircle_forSign(GAME* game, const xyz_t* pos_p, f32 max_dist) {
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
Actor_info* actor_info_p = &play->actor_info;
|
|
ACTOR* actor = actor_info_p->list[ACTOR_PART_NPC].actor;
|
|
f32 x = pos_p->x;
|
|
f32 z = pos_p->z;
|
|
|
|
for (actor; actor != NULL; actor = actor->next_actor) {
|
|
f32 dist = Math3DVecLengthSquare2D(actor->world.position.x - x, actor->world.position.z - z);
|
|
|
|
if (dist < max_dist) {
|
|
NPC_ACTOR* npc_actor = (NPC_ACTOR*)actor;
|
|
|
|
if (npc_actor->condition_info.hide_flg == FALSE) {
|
|
return actor;
|
|
}
|
|
}
|
|
}
|
|
|
|
actor = actor_info_p->list[ACTOR_PART_BG].actor;
|
|
for (actor; actor != NULL; actor = actor->next_actor) {
|
|
if (actor->id == mAc_PROFILE_PSNOWMAN) {
|
|
f32 dist = Math3DVecLengthSquare2D(actor->world.position.x - x, actor->world.position.z - z);
|
|
|
|
if (dist < max_dist) {
|
|
return actor;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int aSIGN_single_anime_check(aSIGN_single_c* single_p, xyz_t pos) {
|
|
int bz;
|
|
int bx;
|
|
int ut_z;
|
|
int ut_x;
|
|
|
|
mFI_Wpos2BkandUtNuminBlock(&bx, &bz, &ut_x, &ut_z, pos);
|
|
if (single_p->block.x == bx && single_p->block.z == bz && single_p->unit.x == ut_x && single_p->unit.z == ut_z) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
extern int aSIGN_set_white_sign(GAME* game, xyz_t* pos_p) {
|
|
SIGN_ACTOR* sign = Common_Get(clip).sign_control_actor;
|
|
int no_free_single = TRUE;
|
|
ACTOR* actor_in_circle;
|
|
int i;
|
|
|
|
if (sign == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
actor_in_circle = aSIGN_search_exist_npc_inCircle_forSign(game, pos_p, 20.0f);
|
|
if (actor_in_circle != NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
if (sign->single[i].exist_flag == FALSE) {
|
|
no_free_single = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (no_free_single) {
|
|
return FALSE;
|
|
}
|
|
|
|
sign->sign_birth_pos = *pos_p;
|
|
sAdo_OngenTrgStart(NA_SE_ITEM_HORIDASHI, &sign->sign_birth_pos);
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_SINGLE_BIRTH);
|
|
return TRUE;
|
|
}
|
|
|
|
extern int aSIGN_erase_white_sign(GAME* game, xyz_t* pos_p) {
|
|
SIGN_ACTOR* sign = Common_Get(clip).sign_control_actor;
|
|
int i;
|
|
|
|
if (sign == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
aSIGN_single_c* single = &sign->single[i];
|
|
|
|
if (single->exist_flag != 0) {
|
|
/* Check if a sign is already being erected here */
|
|
if (aSIGN_single_anime_check(single, *pos_p) != FALSE) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
mActor_name_t* fg_p = mFI_GetUnitFG(*pos_p);
|
|
|
|
single->scale.x = 0.0099f;
|
|
single->scale.y = 0.0099f;
|
|
single->scale.z = 0.0099f;
|
|
|
|
mFI_Wpos2BkandUtNuminBlock(&single->block.x, &single->block.z, &single->unit.x, &single->unit.z, *pos_p);
|
|
single->exist_flag = 2;
|
|
single->item = *fg_p;
|
|
}
|
|
}
|
|
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
return TRUE;
|
|
}
|
|
|
|
static void aSIGN_set_talk_info(ACTOR* actorx) {
|
|
int player_no = Common_Get(player_no);
|
|
rgba_t window_color;
|
|
|
|
if (player_no < PLAYER_NUM) {
|
|
if (GETREG(NMREG, 90)) {
|
|
mDemo_Set_msg_num(0x3065);
|
|
} else {
|
|
mDemo_Set_msg_num(0x3064);
|
|
}
|
|
} else {
|
|
mDemo_Set_msg_num(0x3065);
|
|
}
|
|
|
|
mDemo_Set_talk_display_name(FALSE);
|
|
mDemo_Set_ListenAble();
|
|
window_color.r = 185;
|
|
window_color.g = 60;
|
|
window_color.b = 40;
|
|
window_color.a = 255;
|
|
mDemo_Set_talk_window_color(&window_color);
|
|
mDemo_Set_camera(CAMERA2_PROCESS_NORMAL);
|
|
mDemo_Set_use_zoom_sound(TRUE);
|
|
}
|
|
|
|
static void aSIGN_talk(SIGN_ACTOR* sign, GAME* game) {
|
|
mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
|
|
|
|
if (mDemo_Check(mDemo_TYPE_SPEAK, &sign->actor_class)) {
|
|
ACTOR* player_actor = GET_PLAYER_ACTOR_GAME_ACTOR(game);
|
|
s_xyz player_angle = player_actor->shape_info.rotation;
|
|
s16 target_y = search_position_angleY(&player_actor->world.position, &sign->target_pos);
|
|
|
|
add_calc_short_angle2(&player_angle.y, target_y, 0.3f, DEG2SHORT_ANGLE2(22.5f), DEG2SHORT_ANGLE2(1.40625f));
|
|
GET_PLAYER_ACTOR_NOW()->Set_force_position_angle_proc(gamePT, NULL, &player_angle,
|
|
mPlayer_FORCE_POSITION_ANGLE_ROTY);
|
|
|
|
if (mMsg_Check_MainNormalContinue(msg_p) == TRUE) {
|
|
switch (mChoice_GET_CHOSENUM()) {
|
|
case mChoice_CHOICE0:
|
|
mMsg_REQUEST_MAIN_DISAPPEAR_WAIT_TYPE1();
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_MENU_OPEN_WAIT);
|
|
break;
|
|
case mChoice_CHOICE1:
|
|
default:
|
|
mMsg_REQUEST_MAIN_DISAPPEAR_WAIT_TYPE1();
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_TALK_END);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
}
|
|
}
|
|
|
|
static void aSIGN_talk_end(SIGN_ACTOR* sign, GAME* game) {
|
|
if (mMsg_CHECK_MAIN_WAIT()) {
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
mMsg_request_main_forceoff();
|
|
}
|
|
}
|
|
|
|
static void aSIGN_wait(SIGN_ACTOR* sign, GAME* game) {
|
|
if (mDemo_Get_talk_actor() == NULL && aSIGN_actor_set_target(sign, game) && chkTrigger(BUTTON_A) &&
|
|
mDemo_Get_talk_actor() == NULL) {
|
|
mDemo_Request(mDemo_TYPE_SPEAK, &sign->actor_class, &aSIGN_set_talk_info);
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_TALK);
|
|
}
|
|
}
|
|
|
|
static void aSIGN_menu_open_wait(SIGN_ACTOR* sign, GAME* game) {
|
|
u32 player_no = Common_Get(player_no);
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
Submenu* submenu_p = &play->submenu;
|
|
|
|
if (mMsg_CHECK_MAIN_WAIT()) {
|
|
|
|
mSM_open_submenu(submenu_p, mSM_OVL_NEEDLEWORK, 0, player_no);
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_MENU_END_WAIT);
|
|
mMsg_request_main_forceoff();
|
|
}
|
|
}
|
|
|
|
static void aSIGN_menu_end_wait(SIGN_ACTOR* sign, GAME* game) {
|
|
u32 player_no = Common_Get(player_no);
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
Submenu* submenu_p = &play->submenu;
|
|
|
|
if (submenu_p->open_flag == FALSE && mMsg_CHECK_NOT_SERIES_MAIN_WAIT() == TRUE) {
|
|
Submenu_Item_c* sm_item_p = submenu_p->item_p;
|
|
|
|
if (sm_item_p->item == RSV_NO) {
|
|
int img_no = mNW_get_image_no(submenu_p, sm_item_p->slot_no);
|
|
img_no += player_no * mPr_ORIGINAL_DESIGN_COUNT;
|
|
|
|
aSIGN_change_my_original(sign, game, img_no);
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
} else {
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_setup_action(SIGN_ACTOR* sign, int action) {
|
|
// clang-format off
|
|
static aSIGN_ACTION_PROC process[] = {
|
|
&aSIGN_wait,
|
|
&aSIGN_talk,
|
|
&aSIGN_talk_end,
|
|
&aSIGN_menu_open_wait,
|
|
&aSIGN_menu_end_wait,
|
|
&aSIGN_single_birth,
|
|
&aSIGN_single_erase,
|
|
};
|
|
// clang-format on
|
|
|
|
sign->action_proc = process[action];
|
|
}
|
|
|
|
static void aSIGN_change_my_original(SIGN_ACTOR* sign, GAME* game, u16 design_no) {
|
|
mActor_name_t* fg_p = mFI_GetUnitFG(sign->sign_pos);
|
|
|
|
if (ITEM_IS_SIGNBOARD(*fg_p)) {
|
|
mFI_SetFG_common(SIGNBOARD_START + design_no, sign->sign_pos, TRUE);
|
|
sAdo_OngenTrgStart(NA_SE_461, &sign->sign_pos);
|
|
}
|
|
}
|
|
|
|
static void aSIGN_single_birth(SIGN_ACTOR* sign, GAME* game) {
|
|
ACTOR* player_actor = GET_PLAYER_ACTOR_GAME_ACTOR(game); // unused
|
|
xyz_t sign_birth_pos = sign->sign_birth_pos;
|
|
int i;
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
if (sign->single[i].exist_flag != 0) {
|
|
if (aSIGN_single_anime_check(&sign->single[i], sign_birth_pos)) {
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
return;
|
|
}
|
|
} else {
|
|
mActor_name_t* fg_p = mFI_GetUnitFG(sign_birth_pos); // unused
|
|
|
|
sign->single[i].item = SIGNBOARD;
|
|
sign->single[i].scale.x = 0.0001f;
|
|
sign->single[i].scale.y = 0.0001f;
|
|
sign->single[i].scale.z = 0.0001f;
|
|
mFI_Wpos2BkandUtNuminBlock(&sign->single[i].block.x, &sign->single[i].block.z, &sign->single[i].unit.x,
|
|
&sign->single[i].unit.z, sign_birth_pos);
|
|
sign->single[i].exist_flag = 1;
|
|
sign->single[i]._24 = 0;
|
|
sign->single[i]._20 = 0.005f;
|
|
sign->single[i]._26 = 6000;
|
|
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
mFI_BkandUtNum2CenterWpos(&sign_birth_pos, sign->single[i].block.x, sign->single[i].block.z,
|
|
sign->single[i].unit.x, sign->single[i].unit.z);
|
|
mFI_SetFG_common(RSV_SIGNBOARD, sign_birth_pos, TRUE);
|
|
mCoBG_RegistDecalCircle(&sign_birth_pos, 16.0f, 19.0f, 36);
|
|
return;
|
|
}
|
|
}
|
|
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
}
|
|
|
|
static void aSIGN_single_erase(SIGN_ACTOR* sign, GAME* game) {
|
|
ACTOR* player_actor = GET_PLAYER_ACTOR_GAME_ACTOR(game); // unused
|
|
xyz_t sign_birth_pos = sign->sign_birth_pos;
|
|
int i;
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
aSIGN_single_c* single = &sign->single[i];
|
|
|
|
if (single->exist_flag != 0) {
|
|
if (aSIGN_single_anime_check(single, sign_birth_pos)) {
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
return;
|
|
}
|
|
} else {
|
|
mActor_name_t* fg_p = mFI_GetUnitFG(sign_birth_pos);
|
|
|
|
single->scale.x = 0.0099f;
|
|
single->scale.y = 0.0099f;
|
|
single->scale.z = 0.0099f;
|
|
mFI_Wpos2BkandUtNuminBlock(&single->block.x, &single->block.z, &single->unit.x, &single->unit.z,
|
|
sign_birth_pos);
|
|
single->exist_flag = 2;
|
|
single->item = *fg_p;
|
|
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
return;
|
|
}
|
|
}
|
|
|
|
aSIGN_setup_action(sign, aSIGN_ACTION_WAIT);
|
|
}
|
|
|
|
static void aSIGN_single_all_check(SIGN_ACTOR* sign) {
|
|
s16 prev_angle;
|
|
s16 now_angle;
|
|
xyz_t* scale_p;
|
|
int i;
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
if (sign->single[i].exist_flag != 0) {
|
|
f32 wobble;
|
|
|
|
if (sign->single[i].exist_flag == 1) {
|
|
|
|
prev_angle = sign->single[i]._24;
|
|
sign->single[i]._24 = prev_angle + sign->single[i]._26;
|
|
now_angle = sign->single[i]._24;
|
|
sign->single[i].scale.y = sign->single[i]._20 * sinf_table((f32)now_angle * 0.0000958738f);
|
|
sign->single[i].scale.x = 0.01f - sign->single[i].scale.y;
|
|
sign->single[i].scale.y += 0.01f;
|
|
sign->single[i].scale.z = sign->single[i].scale.x;
|
|
|
|
if ((prev_angle < 0 && now_angle >= 0) || (prev_angle < -0x8000 && now_angle >= -0x8000)) {
|
|
sign->single[i]._20 *= 0.4f;
|
|
sign->single[i]._26 += 750;
|
|
}
|
|
}
|
|
|
|
if (sign->single[i].exist_flag == 2) {
|
|
scale_p = &sign->single[i].scale;
|
|
add_calc(&scale_p->x, 0.0f, 0.5f, 0.0006f, 0.001f);
|
|
add_calc(&scale_p->y, 0.0f, 0.5f, 0.0006f, 0.001f);
|
|
add_calc(&scale_p->z, 0.0f, 0.5f, 0.0006f, 0.001f);
|
|
}
|
|
|
|
// wobble = ABS(sign->single[i]._20);
|
|
if (ABS(sign->single[i]._20) < 0.0002f && sign->single[i].exist_flag == 1) {
|
|
xyz_t center_pos;
|
|
|
|
mFI_BkandUtNum2CenterWpos(¢er_pos, sign->single[i].block.x, sign->single[i].block.z,
|
|
sign->single[i].unit.x, sign->single[i].unit.z);
|
|
mFI_SetFG_common(SIGNBOARD_END, center_pos, TRUE);
|
|
sign->single[i].exist_flag = 0;
|
|
}
|
|
|
|
if (sign->single[i].scale.x <= 0.0f && sign->single[i].exist_flag == 2) {
|
|
xyz_t center_pos;
|
|
|
|
mFI_BkandUtNum2CenterWpos(¢er_pos, sign->single[i].block.x, sign->single[i].block.z,
|
|
sign->single[i].unit.x, sign->single[i].unit.z);
|
|
center_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(center_pos, 0.0f); // unused??
|
|
sign->single[i].exist_flag = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_random_set(void);
|
|
static void aSIGN_all_clear(void);
|
|
|
|
static void aSIGN_actor_move(ACTOR* actorx, GAME* game) {
|
|
SIGN_ACTOR* sign = (SIGN_ACTOR*)actorx;
|
|
|
|
(*sign->action_proc)(sign, game);
|
|
aSIGN_single_all_check(sign);
|
|
aSIGN_actor_set_draw(sign, game);
|
|
|
|
if (GETREG(NMREG, 1)) {
|
|
int type = GETREG(NMREG, 0);
|
|
|
|
if (type == 1000 || type == 100) {
|
|
aSIGN_random_set();
|
|
SETREG(NMREG, 0, 0);
|
|
}
|
|
|
|
if (GETREG(NMREG, 0) == 10) {
|
|
aSIGN_all_clear();
|
|
SETREG(NMREG, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_random_set(void) {
|
|
mActor_name_t* fg_p;
|
|
int ut_z;
|
|
int ut_x;
|
|
int bz;
|
|
int bx;
|
|
int bx_max = mFI_GetBlockXMax();
|
|
int bz_max = mFI_GetBlockZMax();
|
|
|
|
for (bz = 0; bz < bz_max; bz++) {
|
|
|
|
for (bx = 0; bx < bx_max; bx++) {
|
|
fg_p = mFI_BkNumtoUtFGTop(bx, bz);
|
|
for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) {
|
|
for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) {
|
|
if (*fg_p == TREE && GETREG(NMREG, 0) == 1000) {
|
|
mFI_UtNumtoFGSet_common(SIGNBOARD_START + (qrand() >> 27), bx * UT_X_NUM + ut_x,
|
|
bz * UT_Z_NUM + ut_z, TRUE);
|
|
} else if (*fg_p == EMPTY_NO && GETREG(NMREG, 0) == 100) {
|
|
if ((ut_z & 1) != 0 && (ut_x & 1) != 0) {
|
|
mFI_UtNumtoFGSet_common(SIGNBOARD_START + (u16)(qrand() >> 27), bx * UT_X_NUM + ut_x,
|
|
bz * UT_Z_NUM + ut_z, TRUE);
|
|
}
|
|
}
|
|
|
|
fg_p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_all_clear(void) {
|
|
mActor_name_t* fg_p;
|
|
int ut_z;
|
|
int ut_x;
|
|
int bz;
|
|
int bx;
|
|
int bx_max = mFI_GetBlockXMax();
|
|
int bz_max = mFI_GetBlockZMax();
|
|
|
|
for (bz = 0; bz < bz_max; bz++) {
|
|
for (bx = 0; bx < bx_max; bx++) {
|
|
fg_p = mFI_BkNumtoUtFGTop(bx, bz);
|
|
for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) {
|
|
for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) {
|
|
if (*fg_p >= SIGNBOARD_START && *fg_p < (SIGNBOARD_END + 1)) {
|
|
mFI_UtNumtoFGSet_common(EMPTY_NO, bx * UT_X_NUM + ut_x, bz * UT_Z_NUM + ut_z, TRUE);
|
|
}
|
|
|
|
fg_p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void aSIGN_draw_shadow(GAME* game, bIT_ShadowData_c* shadow_data);
|
|
|
|
extern u8 hakushi_tex[];
|
|
extern u16 hakushi_pal[];
|
|
extern Gfx write_model[];
|
|
extern Gfx obj_sign_s_model[];
|
|
extern Gfx obj_sign_w_model[];
|
|
|
|
static void aSIGN_single_all_draw(SIGN_ACTOR* sign, GAME* game) {
|
|
static Gfx* mdl[] = { obj_sign_s_model, obj_sign_w_model };
|
|
|
|
GRAPH* graph = game->graph;
|
|
int i;
|
|
|
|
_texture_z_light_fog_prim_npc(graph);
|
|
|
|
OPEN_DISP(graph);
|
|
gDPSetTextureAdjustMode(NEXT_POLY_OPA_DISP, G_TA_DOLPHIN);
|
|
CLOSE_DISP(graph);
|
|
|
|
for (i = 0; i < aSIGN_SINGLE_NUM; i++) {
|
|
if (sign->single[i].exist_flag != 0) {
|
|
xyz_t sign_pos;
|
|
u32 player_no;
|
|
int my_original_idx;
|
|
u16* pal_p;
|
|
u8* tex_p;
|
|
|
|
Matrix_push();
|
|
mFI_BkandUtNum2CenterWpos(&sign_pos, sign->single[i].block.x, sign->single[i].block.z,
|
|
sign->single[i].unit.x, sign->single[i].unit.z);
|
|
sign_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(sign_pos, 0.0f);
|
|
player_no = (sign->single[i].item >> 3) & 3;
|
|
my_original_idx = sign->single[i].item & 7;
|
|
|
|
Matrix_translate(sign_pos.x, sign_pos.y, sign_pos.z - 1.0f, 0);
|
|
Matrix_scale(sign->single[i].scale.x, sign->single[i].scale.y, sign->single[i].scale.z, 1);
|
|
|
|
OPEN_POLY_OPA_DISP(graph);
|
|
|
|
if ((sign->single[i].item >> 5) & 1) {
|
|
pal_p = hakushi_pal;
|
|
tex_p = hakushi_tex;
|
|
} else {
|
|
pal_p = mNW_PaletteIdx2Palette(Save_Get(private_data[player_no]).my_org[my_original_idx].palette);
|
|
tex_p = Save_Get(private_data[player_no]).my_org[my_original_idx].design.data;
|
|
}
|
|
|
|
gSPSegment(POLY_OPA_DISP++, ANIME_1_TXT_SEG, pal_p);
|
|
gSPSegment(POLY_OPA_DISP++, ANIME_2_TXT_SEG, tex_p);
|
|
gSPMatrix(POLY_OPA_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, write_model);
|
|
gSPDisplayList(POLY_OPA_DISP++, mdl[sign->is_winter]);
|
|
|
|
CLOSE_POLY_OPA_DISP(graph);
|
|
|
|
aSIGN_draw_shadow(game, &aSIGN_shadow_data);
|
|
Matrix_pull();
|
|
}
|
|
}
|
|
|
|
OPEN_DISP(graph);
|
|
gDPSetTextureAdjustMode(NEXT_POLY_OPA_DISP, G_TA_N64);
|
|
CLOSE_DISP(graph);
|
|
}
|
|
|
|
static void aSIGN_actor_draw(ACTOR* actorx, GAME* game) {
|
|
static Gfx* mdl[] = { obj_sign_s_model, obj_sign_w_model };
|
|
|
|
GRAPH* graph = game->graph;
|
|
SIGN_ACTOR* sign = (SIGN_ACTOR*)actorx;
|
|
MtxF* mtxf = get_Matrix_now();
|
|
mActor_name_t* fg_p;
|
|
int ut_z;
|
|
int ut_x;
|
|
int i;
|
|
int j;
|
|
aSIGN_draw_c* draw_p;
|
|
u16 exist_bitfield;
|
|
u16 ut_bit;
|
|
|
|
aSIGN_single_all_draw(sign, game);
|
|
_texture_z_light_fog_prim_npc(graph);
|
|
|
|
draw_p = sign->draw;
|
|
|
|
OPEN_DISP(graph);
|
|
gDPSetTextureAdjustMode(NEXT_POLY_OPA_DISP, G_TA_DOLPHIN);
|
|
CLOSE_DISP(graph);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
fg_p = mFI_BkNumtoUtFGTop(draw_p->block.x, draw_p->block.z);
|
|
for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) {
|
|
exist_bitfield = draw_p->exist_bitfield[ut_z];
|
|
|
|
if (exist_bitfield == 0) {
|
|
fg_p += UT_X_NUM;
|
|
} else {
|
|
for (ut_x = 0, ut_bit = 1; ut_x < UT_X_NUM; ut_x++) {
|
|
if ((exist_bitfield & ut_bit) != 0) {
|
|
mActor_name_t item = *fg_p;
|
|
|
|
if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM0 &&
|
|
ITEM_NAME_GET_CAT(item) == ITEM0_CAT_SIGN) {
|
|
xyz_t sign_pos;
|
|
u32 player_no;
|
|
int my_original_idx;
|
|
u16* pal_p;
|
|
u8* tex_p;
|
|
|
|
mFI_BkandUtNum2CenterWpos(&sign_pos, draw_p->block.x, draw_p->block.z, ut_x, ut_z);
|
|
sign_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(sign_pos, 0.0f);
|
|
|
|
player_no = (item >> 3) & 3;
|
|
my_original_idx = item & 7;
|
|
|
|
OPEN_POLY_OPA_DISP(graph);
|
|
|
|
/* Copy sign position to world matrix translation */
|
|
mtxf->mf[3][0] = sign_pos.x;
|
|
mtxf->mf[3][1] = sign_pos.y;
|
|
mtxf->mf[3][2] = sign_pos.z;
|
|
|
|
if ((item >> 5) & 1) {
|
|
pal_p = hakushi_pal;
|
|
tex_p = hakushi_tex;
|
|
} else {
|
|
pal_p = mNW_PaletteIdx2Palette(
|
|
Save_Get(private_data[player_no]).my_org[my_original_idx].palette);
|
|
tex_p = Save_Get(private_data[player_no]).my_org[my_original_idx].design.data;
|
|
}
|
|
|
|
gSPSegment(POLY_OPA_DISP++, ANIME_1_TXT_SEG, pal_p);
|
|
gSPSegment(POLY_OPA_DISP++, ANIME_2_TXT_SEG, tex_p);
|
|
gSPMatrix(POLY_OPA_DISP++, _Matrix_to_Mtx_new(graph),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_OPA_DISP++, write_model);
|
|
gSPDisplayList(POLY_OPA_DISP++, mdl[sign->is_winter]);
|
|
|
|
CLOSE_POLY_OPA_DISP(graph);
|
|
|
|
/* Draw shadow behind the sign */
|
|
mtxf->mf[3][0] = sign_pos.x;
|
|
mtxf->mf[3][1] = sign_pos.y;
|
|
mtxf->mf[3][2] = sign_pos.z - 1.0f;
|
|
aSIGN_draw_shadow(game, &aSIGN_shadow_data);
|
|
}
|
|
}
|
|
|
|
ut_bit <<= 1;
|
|
fg_p++;
|
|
}
|
|
}
|
|
}
|
|
|
|
draw_p++;
|
|
}
|
|
}
|
|
|
|
OPEN_DISP(graph);
|
|
gDPSetTextureAdjustMode(NEXT_POLY_OPA_DISP, G_TA_N64);
|
|
CLOSE_DISP(graph);
|
|
}
|
|
|
|
static void aSIGN_copy_vtx(Vtx* dst, Vtx* src, u32 n_vtx, u8* vtx_fix_flg_table, int fix_ofs) {
|
|
int i;
|
|
|
|
for (i = 0; i != n_vtx; i++) {
|
|
*dst = *src;
|
|
|
|
if (*vtx_fix_flg_table == TRUE) {
|
|
dst->v.ob[0] = src->v.ob[0] + fix_ofs;
|
|
} else {
|
|
dst->v.ob[0] = src->v.ob[0];
|
|
}
|
|
|
|
src++;
|
|
dst++;
|
|
vtx_fix_flg_table++;
|
|
}
|
|
}
|
|
|
|
static void aSIGN_draw_shadow(GAME* game, bIT_ShadowData_c* shadow_data) {
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
GRAPH* graph = game->graph;
|
|
Vtx* vtx = (Vtx*)GRAPH_ALLOC_TYPE(graph, Vtx, shadow_data->vtx_num);
|
|
rgba_t color;
|
|
u8 l;
|
|
u8 r;
|
|
u8 g;
|
|
u8 b;
|
|
u8 a;
|
|
|
|
if (vtx != NULL) {
|
|
aSIGN_copy_vtx(vtx, shadow_data->vtx, shadow_data->vtx_num, shadow_data->vtx_fix_flags,
|
|
play->kankyo.shadow_pos * shadow_data->size);
|
|
} else {
|
|
vtx = shadow_data->vtx;
|
|
}
|
|
|
|
OPEN_SHADOW_DISP(graph);
|
|
|
|
gDPPipeSync(SHADOW_DISP++);
|
|
gSPMatrix(SHADOW_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPSegment(SHADOW_DISP++, ANIME_3_TXT_SEG, vtx);
|
|
l = play->kankyo.shadow_alpha;
|
|
r = play->kankyo.base_light.shadow_color[0];
|
|
g = play->kankyo.base_light.shadow_color[1];
|
|
b = play->kankyo.base_light.shadow_color[2];
|
|
a = play->kankyo.shadow_alpha;
|
|
gDPSetPrimColor(SHADOW_DISP++, 0, l, r, g, b, a);
|
|
gSPDisplayList(SHADOW_DISP++, shadow_data->gfx);
|
|
|
|
CLOSE_SHADOW_DISP(graph);
|
|
}
|