mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-09-10 19:06:54 -04:00
437 lines
14 KiB
Plaintext
437 lines
14 KiB
Plaintext
static void aNPC_make_accessory(ACTOR* actorx, GAME* game, s16 type, s16 joint) {
|
|
NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx;
|
|
|
|
if (CLIP(tools_clip) != NULL) {
|
|
ACTOR* acc_actor = CLIP(tools_clip)->aTOL_birth_proc(type, aTOL_ACTION_S_TAKEOUT, actorx, game, -1, NULL);
|
|
|
|
if (acc_actor != NULL) {
|
|
nactorx->accessory.type = type;
|
|
nactorx->accessory.pos_joint_idx = joint;
|
|
nactorx->accessory.accessory = acc_actor;
|
|
xyz_t_move(&acc_actor->world.position, &actorx->world.position);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int aNPC_setP_friendship(NPC_ACTOR* nactorx) {
|
|
Animal_c* animal = aNPC_GET_ANM(nactorx);
|
|
int mem_idx;
|
|
s8* friendship_p = NULL;
|
|
int ret = FALSE;
|
|
|
|
mem_idx = mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, animal->memories, ANIMAL_MEMORY_NUM);
|
|
if (mem_idx != -1) {
|
|
friendship_p = &animal->memories[mem_idx].friendship;
|
|
ret = TRUE;
|
|
}
|
|
|
|
nactorx->condition_info.friendship = friendship_p;
|
|
return ret;
|
|
}
|
|
|
|
#ifndef aNPC_NPC2
|
|
static void aNPC_check_force_use_umbrella(NPC_ACTOR* nactorx) {
|
|
u8 req = FALSE;
|
|
|
|
if (aNPC_GET_ANM(nactorx)->is_home == FALSE && Common_Get(weather) == mEnv_WEATHER_RAIN) {
|
|
req = TRUE;
|
|
}
|
|
|
|
nactorx->request.umb_flag = req;
|
|
}
|
|
|
|
static void aNPC_set_start_pos(ACTOR* actorx) {
|
|
NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx;
|
|
Animal_c* animal = aNPC_GET_ANM(nactorx);
|
|
|
|
mNpcW_GetAppearStatusWay(&nactorx->condition_info.appear_flag, &nactorx->condition_info.appear_rotation, animal);
|
|
}
|
|
|
|
#else
|
|
|
|
static int aNPC_set_start_pos_sub(ACTOR* actorx, int uz) {
|
|
int ux;
|
|
int* unit_info_p;
|
|
int unit_flag;
|
|
int i;
|
|
int ret;
|
|
|
|
unit_info_p = (int*)((NPC_CONTROL_ACTOR*)aNPC_ctrlActor)->unit_info;
|
|
unit_flag = 0;
|
|
i = 0;
|
|
ret = TRUE;
|
|
unit_info_p += uz * aNPC2_UNIT_X_NUM;
|
|
for (i; i < aNPC2_UNIT_X_NUM; i++) {
|
|
while (TRUE) {
|
|
ux = RANDOM(aNPC2_UNIT_X_NUM);
|
|
if (((unit_flag >> ux) & 1) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*(unit_info_p + ux) != 0) {
|
|
goto exit;
|
|
}
|
|
|
|
unit_flag |= (1 << ux);
|
|
}
|
|
|
|
ret = FALSE;
|
|
exit:
|
|
actorx->world.position.x = (ux + 1.5f) * mFI_UT_WORLDSIZE_X_F;
|
|
actorx->world.position.z = (uz + 1.5f) * mFI_UT_WORLDSIZE_Z_F;
|
|
return ret;
|
|
}
|
|
|
|
static void aNPC_set_start_pos(ACTOR* actorx) {
|
|
static int uz_def_tbl[3][2] = {
|
|
{ 1, 2 },
|
|
{ 0, 3 },
|
|
{ 4, 5 },
|
|
};
|
|
|
|
static f32 chk_val000[3] = {
|
|
0.4f,
|
|
0.1f,
|
|
0.0f,
|
|
};
|
|
|
|
static f32 chk_val001[3] = {
|
|
1.0f,
|
|
0.25f,
|
|
0.0f,
|
|
};
|
|
|
|
static f32 chk_val010[3] = {
|
|
0.14f,
|
|
1.0f,
|
|
0.0f,
|
|
};
|
|
|
|
static f32 chk_val011[3] = {
|
|
1.0f,
|
|
1.0f,
|
|
0.0f,
|
|
};
|
|
|
|
static f32 chk_val100[3] = {
|
|
0.3f,
|
|
0.0f,
|
|
1.0f,
|
|
};
|
|
|
|
static f32 chk_val101[3] = {
|
|
1.0f,
|
|
0.0f,
|
|
1.0f,
|
|
};
|
|
|
|
static f32 chk_val110[3] = {
|
|
0.0f,
|
|
1.0f,
|
|
1.0f,
|
|
};
|
|
|
|
static f32* chk_val_tbl[8] = {
|
|
chk_val000, chk_val001, chk_val010, chk_val011, chk_val100, chk_val101, chk_val110, NULL,
|
|
};
|
|
|
|
static s16 angl_tbl[] = {
|
|
DEG2SHORT_ANGLE2(0.0f),
|
|
DEG2SHORT_ANGLE2(90.0f),
|
|
DEG2SHORT_ANGLE2(180.0f),
|
|
DEG2SHORT_ANGLE2(270.0f),
|
|
};
|
|
|
|
f32 rnd;
|
|
int uz;
|
|
int j;
|
|
int idx;
|
|
int uz_tbl[3][2];
|
|
f32* check_p;
|
|
int i;
|
|
s16 angle;
|
|
|
|
i = 0;
|
|
mem_copy((u8*)uz_tbl, (u8*)uz_def_tbl, sizeof(uz_tbl));
|
|
uz = 0;
|
|
idx = 0;
|
|
|
|
while (TRUE) {
|
|
check_p = chk_val_tbl[i];
|
|
rnd = RANDOM_F(1.0f);
|
|
for (j = 0; j < 3; j++) {
|
|
if (rnd >= check_p[j]) {
|
|
idx = RANDOM(2);
|
|
uz = uz_tbl[j][idx];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (aNPC_set_start_pos_sub(actorx, uz) != TRUE) {
|
|
if (uz_tbl[j][0] == uz_tbl[j][1]) {
|
|
i |= 1 << j;
|
|
} else {
|
|
uz_tbl[j][idx] = uz_tbl[j][idx ^ 1];
|
|
}
|
|
} else {
|
|
angle = angl_tbl[RANDOM(ARRAY_COUNT(angl_tbl))];
|
|
|
|
actorx->shape_info.rotation.y = angle;
|
|
actorx->world.angle.y = angle;
|
|
((NPC_ACTOR*)actorx)->movement.mv_angl = angle;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static void aNPC_actor_schedule(NPC_ACTOR* nactorx, int type) {
|
|
mNPS_schedule_c* sched_p = &nactorx->schedule.schedule;
|
|
|
|
switch (type) {
|
|
case aNPC_CT_SCHED_TYPE_NORMAL:
|
|
aNPC_first_set_schedule(nactorx);
|
|
break;
|
|
case aNPC_CT_SCHED_TYPE_STAND:
|
|
sched_p->current_type = mNPS_SCHED_STAND;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_STAND;
|
|
break;
|
|
case aNPC_CT_SCHED_TYPE_WANDER:
|
|
#ifndef aNPC_NPC2
|
|
sched_p->current_type = mNPS_SCHED_WANDER;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_WANDER;
|
|
#else
|
|
sched_p->current_type = aNPC_SCHEDULE_TYPE_IN_HOUSE;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_IN_HOUSE;
|
|
#endif
|
|
break;
|
|
case aNPC_CT_SCHED_TYPE_WALK_WANDER:
|
|
#ifndef aNPC_NPC2
|
|
sched_p->current_type = mNPS_SCHED_WALK_WANDER;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_WALK_WANDER;
|
|
#else
|
|
sched_p->current_type = aNPC_SCHEDULE_TYPE_IN_HOUSE;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_IN_HOUSE;
|
|
#endif
|
|
break;
|
|
case aNPC_CT_SCHED_TYPE_SPECIAL:
|
|
sched_p->current_type = mNPS_SCHED_SPECIAL;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_SPECIAL;
|
|
break;
|
|
default:
|
|
sched_p->current_type = mNPS_SCHED_STAND;
|
|
nactorx->npc_info.schedule = sched_p;
|
|
nactorx->schedule.type = aNPC_SCHEDULE_TYPE_STAND;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void aNPC_actor_ct(ACTOR* actorx, GAME* game, aNPC_ct_data_c* ct_data) {
|
|
int name_type;
|
|
mActor_name_t org_name = actorx->npc_id;
|
|
mActor_name_t npc_name = org_name;
|
|
aNPC_draw_data_c draw_data;
|
|
|
|
name_type = ITEM_NAME_GET_TYPE(actorx->npc_id);
|
|
if (name_type != NAME_TYPE_NPC && name_type != NAME_TYPE_SPNPC) {
|
|
Actor_delete(actorx);
|
|
actorx->sv_proc = NULL;
|
|
actorx->dt_proc = NULL;
|
|
mNpc_RenewalSetNpc(actorx);
|
|
} else {
|
|
NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx;
|
|
cKF_Skeleton_R_c* skeleton;
|
|
f32 scale;
|
|
f32 eye_y;
|
|
|
|
aNPC_dma_draw_data_proc(&draw_data, org_name);
|
|
mem_copy((u8*)&nactorx->draw.draw_tex_data, (u8*)&draw_data.tex_data, sizeof(draw_data.tex_data));
|
|
nactorx->draw.shape_bank = draw_data.model_bank;
|
|
nactorx->draw.tex_bank = draw_data.texture_bank;
|
|
nactorx->talk_info.type = draw_data.talk_type;
|
|
nactorx->draw.draw_type = draw_data.species_sub_idx;
|
|
|
|
if (aNPC_GET_ANM(nactorx) != NULL) {
|
|
nactorx->right_hand.umbrella_type = aNPC_GET_ANM(nactorx)->umbrella_id;
|
|
} else {
|
|
nactorx->right_hand.umbrella_type = draw_data.umbrella_type;
|
|
}
|
|
|
|
if (draw_data.accessory_type != -1) {
|
|
aNPC_make_accessory(actorx, game, draw_data.accessory_type, draw_data.accessory_joint);
|
|
}
|
|
|
|
skeleton = draw_data.model_skeleton;
|
|
eye_y = (f32)draw_data.eye_height;
|
|
scale = draw_data.scale;
|
|
|
|
cKF_SkeletonInfo_R_ct(&nactorx->draw.main_animation.keyframe, skeleton, NULL, nactorx->draw.main_animation.work,
|
|
nactorx->draw.main_animation.morph);
|
|
cKF_SkeletonInfo_R_ct(&nactorx->draw.sub_animation0.keyframe, skeleton, NULL, nactorx->draw.sub_animation0.work,
|
|
nactorx->draw.sub_animation0.morph);
|
|
cKF_SkeletonInfo_R_ct(&nactorx->draw.sub_animation1.keyframe, skeleton, NULL, nactorx->draw.sub_animation1.work,
|
|
nactorx->draw.sub_animation1.morph);
|
|
Shape_Info_init(actorx, 0.0f, &mAc_ActorShadowEllipse, 9.0f, 17.0f);
|
|
actorx->shape_info.ofs_y = 2.0f;
|
|
|
|
{
|
|
ClObjPipe_c* pipe_p = &nactorx->collision.pipe;
|
|
|
|
ClObjPipe_ct(game, pipe_p);
|
|
ClObjPipe_set5(game, pipe_p, actorx, &aNPC_CoInfoData);
|
|
CollisionCheck_Status_set3(&actorx->status_data, &aNPC_StatusData);
|
|
pipe_p->attribute.pipe.radius = draw_data.col_radius;
|
|
pipe_p->attribute.pipe.height = draw_data.col_height;
|
|
}
|
|
|
|
nactorx->move_proc = ct_data->move_proc;
|
|
nactorx->draw_proc = ct_data->draw_proc;
|
|
|
|
nactorx->draw.animation_id = aNPC_ANIM_NUM;
|
|
nactorx->draw.effect_pattern = 0xFF;
|
|
nactorx->draw.effect_type = -1;
|
|
nactorx->draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_LOCKED;
|
|
|
|
nactorx->collision.BGcheck_radius = 18.0f;
|
|
nactorx->collision.check_kind = aNPC_BG_CHECK_TYPE_RANGE;
|
|
|
|
nactorx->eye_y = eye_y;
|
|
nactorx->action.idx = aNPC_ACT_NONE;
|
|
|
|
nactorx->left_hand.after_mode = aHOI_REQUEST_PUTAWAY;
|
|
nactorx->draw.main_animation.animation_id = -1;
|
|
nactorx->draw.sub_animation0.animation_id = -1;
|
|
nactorx->draw.sub_animation1.animation_id = -1;
|
|
nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_NONE;
|
|
|
|
nactorx->talk_info.talk_request_proc = ct_data->talk_request_proc;
|
|
nactorx->talk_info.talk_init_proc = ct_data->talk_init_proc;
|
|
nactorx->talk_info.talk_end_check_proc = ct_data->talk_end_check_proc;
|
|
nactorx->talk_info.default_animation = -1;
|
|
nactorx->talk_info.default_turn_animation = -1;
|
|
nactorx->talk_info.default_act = aNPC_ACT_TALK;
|
|
nactorx->talk_info.turn = aNPC_TALK_TURN_NORMAL;
|
|
|
|
nactorx->schedule.type = aNPC_SCHEDULE_NONE;
|
|
|
|
nactorx->movement.range_center_x = (((int)actorx->block_x + 0.5f) * mFI_BK_WORLDSIZE_X_F);
|
|
nactorx->movement.range_center_z = (((int)actorx->block_z + 0.5f) * mFI_BK_WORLDSIZE_Z_F);
|
|
nactorx->movement.range_radius = 280.0f;
|
|
nactorx->movement.movement_ut_x = -1;
|
|
nactorx->movement.movement_ut_z = -1;
|
|
|
|
// @duplicate, already set above
|
|
nactorx->action.idx = aNPC_ACT_NONE;
|
|
nactorx->action.act_obj = aNPC_ACT_OBJ_DEFAULT;
|
|
|
|
nactorx->think.force_call_msg_no = -1;
|
|
nactorx->think.force_call_camera_type = CAMERA2_PROCESS_NORMAL;
|
|
|
|
nactorx->talk_info.feel = 0xFF;
|
|
nactorx->talk_info.memory = TRUE;
|
|
|
|
nactorx->head.angle_add_x = 0x200;
|
|
nactorx->head.angle_add_y = 0x400;
|
|
|
|
nactorx->draw.frame_sub_speed = 1.0f;
|
|
|
|
if (mEv_CheckTitleDemo() > 0) {
|
|
actorx->status_data.weight = 0;
|
|
}
|
|
|
|
xyz_t_move(&nactorx->feet[aNPC_FOOT_LEFT], &actorx->world.position);
|
|
xyz_t_move(&nactorx->feet[aNPC_FOOT_RIGHT], &actorx->world.position);
|
|
aNPC_set_hide_flg(nactorx, TRUE);
|
|
|
|
if (name_type == NAME_TYPE_NPC) {
|
|
Animal_c* animal = aNPC_GET_ANM(nactorx);
|
|
mActor_name_t cloth = animal->cloth;
|
|
u8 org_idx;
|
|
|
|
if (animal->cloth == RSV_CLOTH) {
|
|
org_idx = animal->cloth_original_id;
|
|
} else {
|
|
org_idx = 0xFF;
|
|
}
|
|
|
|
aNPC_setup_next_cloth(nactorx, cloth, org_idx);
|
|
aNPC_setup_chg_cloth(nactorx, cloth, org_idx);
|
|
|
|
nactorx->condition_info.feel_tim = animal->mood_time * FRAMES_PER_MINUTE;
|
|
nactorx->talk_info.talk_end_check_proc = &aNPC_talk_end_check;
|
|
aNPC_set_start_pos(actorx);
|
|
aNPC_setP_friendship(nactorx);
|
|
#ifndef aNPC_NPC2
|
|
aNPC_check_force_use_umbrella(nactorx);
|
|
#endif
|
|
nactorx->talk_info.melody_inst = draw_data.voice_type;
|
|
nactorx->talk_info.npc_voice_id = draw_data.voice_type;
|
|
} else {
|
|
mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(org_name);
|
|
|
|
if (event_npc != NULL) {
|
|
mActor_name_t texture_name = event_npc->texture_id;
|
|
|
|
npc_name = event_npc->npc_id; // r29
|
|
nactorx->npc_info.event = event_npc;
|
|
event_npc->exists = TRUE;
|
|
if (ITEM_NAME_GET_TYPE(texture_name) == NAME_TYPE_NPC) {
|
|
aNPC_dma_draw_data_proc(&draw_data, texture_name);
|
|
}
|
|
} else {
|
|
mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(org_name);
|
|
|
|
if (mask_npc != NULL) {
|
|
mActor_name_t mask_id = mask_npc->npc_id;
|
|
|
|
npc_name = mask_id; // r29
|
|
nactorx->npc_info.mask = mask_npc;
|
|
mask_npc->exists = TRUE;
|
|
|
|
if (ITEM_NAME_GET_TYPE(npc_name) == NAME_TYPE_NPC) {
|
|
aNPC_dma_draw_data_proc(&draw_data, mask_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
nactorx->talk_info.melody_inst = draw_data.voice_type;
|
|
nactorx->talk_info.npc_voice_id = draw_data.voice_type;
|
|
nactorx->right_hand.umbrella_disabled_flag = TRUE;
|
|
}
|
|
|
|
nactorx->npc_info.npc_name = npc_name;
|
|
#ifndef aNPC_NPC2
|
|
actorx->max_velocity_y = -20.0f;
|
|
actorx->gravity = -1.0f;
|
|
|
|
{
|
|
mActor_name_t* fg_p = mFI_GetUnitFG(actorx->world.position);
|
|
|
|
if (fg_p != NULL && (ITEM_IS_HOLE(*fg_p) || *fg_p == HOLE_SHINE)) {
|
|
mFI_SetFG_common(EMPTY_NO, actorx->world.position, TRUE);
|
|
}
|
|
}
|
|
#else
|
|
actorx->max_velocity_y = 0.0f;
|
|
actorx->gravity = 0.0f;
|
|
#endif
|
|
|
|
actorx->scale.x = scale;
|
|
actorx->scale.y = scale;
|
|
actorx->scale.z = scale;
|
|
actorx->unknown_b4 = TRUE;
|
|
|
|
if (ct_data->sched_type != aNPC_CT_SCHED_TYPE_NONE) {
|
|
aNPC_actor_schedule(nactorx, ct_data->sched_type);
|
|
}
|
|
}
|
|
}
|