Files
ac-decomp/src/m_actor.c
T
2024-01-02 12:09:43 -05:00

1035 lines
29 KiB
C

#include "m_actor.h"
#include "m_play.h"
#include "m_player_lib.h"
#include "m_name_table.h"
#include "ac_npc.h"
#include "m_scene.h"
#include "m_lib.h"
#include "m_bg_item.h"
#include "m_lights.h"
#include "m_collision_obj.h"
#include "libforest/gbi_extensions.h"
#include "sys_matrix.h"
#include "libultra/libultra.h"
#include "m_field_info.h"
#include "m_event.h"
#include "m_skin_matrix.h"
#include "m_npc.h"
#include "m_malloc.h"
#include "m_common_data.h"
#ifdef MUST_MATCH
#include "ppcdis.h"
void _savefpr_29();
void _restfpr_29();
//#include "orderstrings/8064d600_8064d604.inc"
static char lbl_8064d600[] = "";
#endif
#ifdef MUST_MATCH
/* @unused | necessary for proper float ordering*/
extern void __declspec(section "forcestrip") projection_pos_set(GAME_PLAY* play, xyz_t* pos, xyz_t* proj_pos, f32* proj_w) {
Skin_Matrix_PrjMulVector(&play->projection_matrix, pos, proj_pos, proj_w);
*proj_w = *proj_w < 1.0f ? 1.0f : 1.0f / *proj_w;
}
#endif
extern void Actor_world_to_eye(ACTOR* actor, f32 eye_height) {
/* Update position */
actor->eye.position.x = actor->world.position.x;
actor->eye.position.y = actor->world.position.y + eye_height;
actor->eye.position.z = actor->world.position.z;
/* Update rotation */
actor->eye.angle.x = actor->world.angle.x;
actor->eye.angle.y = actor->world.angle.y;
actor->eye.angle.z = actor->world.angle.z;
}
extern void Actor_position_move(ACTOR* actor) {
(*((GAME_PLAY*)gamePT)->kankyo.nature.proc)(actor);
/* divide by 2 because of 30fps -> 60fps? */
actor->world.position.x += 0.5f * actor->position_speed.x + actor->status_data.collision_vec.x;
actor->world.position.y += 0.5f * actor->position_speed.y + actor->status_data.collision_vec.y;
actor->world.position.z += 0.5f * actor->position_speed.z + actor->status_data.collision_vec.z;
}
extern void Actor_position_speed_set(ACTOR* actor) {
actor->position_speed.x = actor->speed * sin_s(actor->world.angle.y);
actor->position_speed.z = actor->speed * cos_s(actor->world.angle.y);
/* divide by 2 because of 30fps -> 60fps? */
chase_f(&actor->position_speed.y, actor->max_velocity_y, 0.5f * actor->gravity);
}
extern void Actor_position_moveF(ACTOR* actor) {
Actor_position_speed_set(actor);
Actor_position_move(actor);
}
extern int Actor_player_look_direction_check(ACTOR* actor, s16 angle, GAME_PLAY* play) {
s16 player_rot_y = get_player_actor_withoutCheck(play)->actor_class.shape_info.rotation.y;
s16 inv_angle = actor->player_angle_y - -0x8000;
s16 diff = inv_angle - player_rot_y;
int delta = ABS(diff);
return delta < angle;
}
/* @unused ? Actor_display_position_set(... ?) */
static int Actor_data_bank_dma_end_check(ACTOR* actor, GAME_PLAY* play) {
switch (ITEM_NAME_GET_TYPE(actor->npc_id)) {
case NAME_TYPE_SPNPC:
case NAME_TYPE_NPC:
return TRUE;
}
return TRUE;
}
extern void Shape_Info_init(ACTOR* actor, f32 ofs_y, mActor_shadow_proc shadow_proc, f32 shadow_size_x, f32 shadow_size_z) {
actor->shape_info.ofs_y = ofs_y;
actor->shape_info.shadow_proc = shadow_proc;
actor->shape_info.shadow_size_x = shadow_size_x;
actor->shape_info.shadow_size_z = shadow_size_z;
actor->shape_info.draw_shadow = TRUE;
actor->shape_info.shadow_position = &actor->world.position;
actor->shape_info.unk_20 = 0;
actor->shape_info.shadow_size_change_rate = 1.0f;
actor->shape_info.shadow_alpha_change_rate = 1.0f;
actor->shape_info.force_shadow_position = FALSE;
#ifndef BUGFIXES
actor->shape_info.shadow_position = &actor->world.position; // ???
#endif
actor->shape_info.unk_28 = -1;
actor->shape_info.unk_2D = 0;
}
extern void Actor_delete(ACTOR* actor) {
if (actor == NULL) {
return;
}
actor->mv_proc = NULL;
actor->dw_proc = NULL;
}
static void Actor_ct(ACTOR* actor, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
Object_Exchange_c* exchange;
Object_Bank_c* bank;
exchange = &play->object_exchange;
bank = &exchange->banks[actor->data_bank_id];
bank->num_exist++;
if (actor->part == ACTOR_PART_NPC) {
NPC_ACTOR* npc_actor = (NPC_ACTOR*)actor;
aNPC_draw_data_c draw_data;
int tex_bank_id;
(*Common_Get(clip).npc_clip->dma_draw_data_proc)(&draw_data, actor->npc_id);
tex_bank_id = mSc_bank_regist_check(exchange, draw_data.texture_bank);
npc_actor->draw.texture_bank_idx = tex_bank_id;
bank = &exchange->banks[tex_bank_id];
bank->num_exist++;
}
/* Initialize world position & rotation to home position & rotation */
actor->world = actor->home;
actor->shape_info.rotation = actor->world.angle;
Actor_world_to_eye(actor, 0.0f);
xyz_t_move(&actor->last_world_position, &actor->world.position);
actor->scale.x = 0.01f;
actor->scale.y = 0.01f;
actor->scale.z = 0.01f;
actor->max_velocity_y = -20.0f;
actor->player_distance = 3.4028235E+38;
actor->cull_width = 350.0f;
actor->cull_height = 700.0f;
actor->cull_distance = 1000.0f;
actor->cull_radius = 350.0f;
actor->talk_distance = 55.0f;
actor->shape_info.shadow_size_change_rate = 1.0f;
actor->shape_info.shadow_alpha_change_rate = 1.0f;
CollisionCheck_Status_ct(&actor->status_data);
Shape_Info_init(actor, 0.0f, NULL, 0.0f, 0.0f);
if (Actor_data_bank_dma_end_check(actor, play) == TRUE) {
(*actor->ct_proc)(actor, game);
actor->ct_proc = NULL;
}
}
static void Actor_dt(ACTOR* actor, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
Object_Exchange_c* exchange;
ACTOR* t;
if (actor->sv_proc != NULL) {
(*actor->sv_proc)(actor, game);
actor->sv_proc = NULL;
}
if (actor->dt_proc != NULL) {
(*actor->dt_proc)(actor, game);
actor->dt_proc = NULL;
}
t = actor->child_actor;
if (t != NULL && t->parent_actor == actor) {
t->parent_actor = NULL;
}
t = actor->parent_actor;
if (t != NULL && t->child_actor == actor) {
t->child_actor = NULL;
}
exchange = &play->object_exchange;
if (ITEM_NAME_GET_TYPE(actor->npc_id) >= NAME_TYPE_PAD15 || ITEM_NAME_GET_TYPE(actor->npc_id) < NAME_TYPE_SPNPC) {
int bank_id = actor->data_bank_id;
if (bank_id >= exchange->exchange_id && exchange->banks[bank_id].num_exist > 0) {
actor->data_bank_id = -1;
exchange->banks[bank_id].num_exist--;
}
}
}
static void Actor_draw_ta_set(ACTOR* actor, GAME_PLAY* play) {
GRAPH* g;
if ((actor->state_bitfield & ACTOR_STATE_TA_SET) == 0) {
return;
}
g = play->game.graph;
OPEN_DISP(g);
gDPSetTextureAdjustMode(NOW_POLY_OPA_DISP++, G_TA_DOLPHIN);
gDPSetTextureAdjustMode(NOW_SHADOW_DISP++, G_TA_DOLPHIN);
gDPSetTextureAdjustMode(NOW_POLY_XLU_DISP++, G_TA_DOLPHIN);
gDPSetTexEdgeAlpha(NOW_POLY_OPA_DISP++, 127);
gDPSetTexEdgeAlpha(NOW_SHADOW_DISP++, 127);
gDPSetTexEdgeAlpha(NOW_POLY_XLU_DISP++, 127);
CLOSE_DISP(g);
}
static void Actor_draw_ta_clr(ACTOR* actor, GAME_PLAY* play) {
GRAPH* g;
if ((actor->state_bitfield & ACTOR_STATE_TA_SET) == 0) {
return;
}
g = play->game.graph;
OPEN_DISP(g);
gDPSetTextureAdjustMode(NOW_POLY_OPA_DISP++, G_TA_N64);
gDPSetTextureAdjustMode(NOW_SHADOW_DISP++, G_TA_N64);
gDPSetTextureAdjustMode(NOW_POLY_XLU_DISP++, G_TA_N64);
gDPSetTexEdgeAlpha(NOW_POLY_OPA_DISP++, 144);
gDPSetTexEdgeAlpha(NOW_SHADOW_DISP++, 144);
gDPSetTexEdgeAlpha(NOW_POLY_XLU_DISP++, 144);
CLOSE_DISP(g);
}
static void Actor_draw(GAME_PLAY* play, ACTOR* actor) {
LightsN* lights = Global_light_read(&play->global_light, play->game.graph);
/* Light actor */
LightsN_list_check(lights, play->global_light.list, (actor->state_bitfield & ACTOR_STATE_LIGHTING) ? NULL : &actor->world.position);
LightsN_disp(lights, play->game.graph);
LightsN_disp_BG(lights, play->game.graph);
/* Load actor position/scale matrix */
Matrix_softcv3_load(&actor->shape_info.rotation, actor->world.position.x, actor->world.position.y + actor->shape_info.ofs_y * actor->scale.y, actor->world.position.z);
Matrix_scale(actor->scale.x, actor->scale.y, actor->scale.z, 1);
/* Draw actor */
Actor_draw_ta_set(actor, play);
(*actor->dw_proc)(actor, &play->game);
Actor_draw_ta_clr(actor, play);
/* Draw shadow */
if (actor->shape_info.shadow_proc != NULL) {
(*actor->shape_info.shadow_proc)(actor, lights, play);
}
}
extern int Actor_draw_actor_no_culling_check(ACTOR* actor) {
return Actor_draw_actor_no_culling_check2(actor, &actor->camera_position, actor->camera_w);
}
extern int Actor_draw_actor_no_culling_check2(ACTOR* actor, xyz_t* camera_pos, f32 camera_w) {
int res = FALSE;
if (-actor->cull_radius < camera_pos->z && camera_pos->z < actor->cull_distance + actor->cull_radius) {
f32 m = camera_w < 1.0f ? 1.0f : 1.0f / camera_w;
if ((m * (fabsf(camera_pos->x) - actor->cull_width)) < 1.0f &&
(m * (camera_pos->y + actor->cull_height)) > -1.0f &&
(m * (camera_pos->y - actor->cull_radius) < 1.0f)
) {
res = TRUE;
}
}
return res;
}
static void Actor_cull_check(ACTOR* actor) {
if (Actor_draw_actor_no_culling_check(actor) == TRUE) {
actor->state_bitfield |= ACTOR_STATE_NO_CULL;
}
else {
actor->state_bitfield &= ~ACTOR_STATE_NO_CULL;
}
}
static void Actor_delete_check(ACTOR* actor, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
if ((actor->state_bitfield & (ACTOR_STATE_NO_MOVE_WHILE_CULLED | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_CULL)) == 0) {
if (actor->npc_id != EMPTY_NO) {
if (actor->block_x >= 0 && actor->block_z >= 0) {
if (actor->block_x != play->block_table.block_x || actor->block_z != play->block_table.block_z) {
Actor_delete(actor);
}
}
}
}
}
extern void Actor_info_ct(GAME* game, Actor_info* actor_info, Actor_data* player_data) {
GAME_PLAY* play = (GAME_PLAY*)game;
ACTOR* player_actor;
ACTOR_DLFTBL* dlftbl;
int i;
bzero(actor_info, sizeof(Actor_info));
actor_dlftbls_init();
Matrix_copy_MtxF(&play->billboard_matrix, &MtxF_clear);
Matrix_copy_MtxF(&play->projection_matrix, &MtxF_clear);
/* Reset the actor dlf table info */
dlftbl = actor_dlftbls;
for (i = 0; i < mAc_PROFILE_NUM; i++) {
dlftbl->alloc_buf = NULL;
dlftbl->num_actors = 0;
dlftbl++;
}
if (mEv_CheckFirstJob() == TRUE) {
Common_Set(demo_profiles[0], mAc_PROFILE_INTRO_DEMO); // force intro demo to spawn
}
/* Spawn any demo actors */
for (i = 0; i < 2; i++) {
s16 demo_profile = Common_Get(demo_profiles[i]);
if (demo_profile != mAc_PROFILE_NUM) {
Actor_info_make_actor(
actor_info,
game,
demo_profile,
0.0f, 0.0f, 0.0f,
0, 0, 0,
-1, -1,
-1,
EMPTY_NO,
-1,
-1,
-1
);
}
Common_Set(demo_profiles[i], mAc_PROFILE_NUM);
}
/* Try spawning the player actor */
player_actor = Actor_info_make_actor(
actor_info,
game,
player_data->profile,
player_data->position.x, player_data->position.y, player_data->position.z,
player_data->rotation.x, player_data->rotation.y, player_data->rotation.z,
-1, -1,
-1,
EMPTY_NO,
player_data->arg,
-1,
-1
);
if (player_actor != NULL) {
player_actor->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(player_actor->world.position, 0.0f);
mFI_SetBearActor(play, player_actor->world.position, FALSE);
}
/* Spawn the current bg item type actor */
if (Common_Get(bg_item_profile) != 0) {
Actor_info_make_actor(
actor_info,
game,
Common_Get(bg_item_profile),
0.0f, 0.0f, 0.0f,
0, 0, 0,
-1, -1,
-1,
EMPTY_NO,
-1,
-1,
-1
);
}
/* Spawn all pending control actors */
if (play->ctrl_actor_data_num != 0) {
s16* ctrl_actor_data = play->ctrl_actor_data;
for (i = 0; i < play->ctrl_actor_data_num; i++) {
Actor_info_make_actor(
&play->actor_info,
game,
*ctrl_actor_data,
0.0f, 0.0f, 0.0f,
0, 0, 0,
-1, -1,
-1,
EMPTY_NO,
-1,
-1,
-1
);
ctrl_actor_data++;
}
play->ctrl_actor_data_num = 0;
}
mSc_regist_initial_exchange_bank(play);
/* Spawn all pending actors */
if (play->actor_data_num != 0) {
Actor_data* actor_data = play->actor_data;
for (i = 0; i < play->actor_data_num; i++) {
Actor_info_make_actor(
&play->actor_info,
(GAME*)play,
actor_data->profile,
actor_data->position.x, actor_data->position.y, actor_data->position.z,
actor_data->rotation.x, actor_data->rotation.y, actor_data->rotation.z,
-1, -1,
-1,
EMPTY_NO,
actor_data->arg,
-1,
-1
);
actor_data++;
}
play->actor_data_num = 0;
}
}
extern void Actor_info_dt(Actor_info* actor_info, GAME_PLAY* play) {
int i;
for (i = 0; i < ACTOR_PART_NUM; i++) {
ACTOR* actor;
while (actor = actor_info->list[i].actor, actor != NULL) {
Actor_info_delete(actor_info, actor, (GAME*)play);
}
}
actor_dlftbls_cleanup();
}
extern void Actor_info_call_actor(GAME_PLAY* play, Actor_info* actor_info) {
//GAME* game = (GAME*)play;
PLAYER_ACTOR* player_actor = get_player_actor_withoutCheck(play);
ACTOR* actor;
int i;
mFI_FieldMove(player_actor->actor_class.world.position);
mBI_move(play);
for (i = 0; i < ACTOR_PART_NUM; i++) {
ACTOR* next;
actor = actor_info->list[i].actor;
while (actor != NULL) {
play->game.doing_point = actor->id;
play->game.doing_point_specific = 151;
if (actor->world.position.y < -25000.0f) {
actor->world.position.y = -25000.0f;
}
if (actor->ct_proc != NULL) {
if (Actor_data_bank_dma_end_check(actor, play) == TRUE) {
play->game.doing_point_specific = 152;
(*actor->ct_proc)(actor, (GAME*)play);
play->game.doing_point_specific = 153;
actor->ct_proc = NULL;
}
next = actor->next_actor;
}
else {
if (Actor_data_bank_dma_end_check(actor, play) == FALSE) {
play->game.doing_point_specific = 154;
Actor_delete(actor);
play->game.doing_point_specific = 155;
next = actor->next_actor;
}
else if (actor->mv_proc == NULL) {
if (actor->drawn == FALSE) {
play->game.doing_point_specific = 156;
next = Actor_info_delete(&play->actor_info, actor, (GAME*)play);
play->game.doing_point_specific = 157;
}
else {
play->game.doing_point_specific = 158;
Actor_dt(actor, (GAME*)play);
play->game.doing_point_specific = 159;
next = actor->next_actor;
}
}
else {
play->game.doing_point_specific = 160;
xyz_t_move(&actor->last_world_position, &actor->world.position);
actor->player_distance_xz = search_position_distanceXZ(&actor->world.position, &player_actor->actor_class.world.position);
actor->player_distance_y = player_actor->actor_class.world.position.y - actor->world.position.y;
actor->player_distance = actor->player_distance_xz * actor->player_distance_xz + actor->player_distance_y * actor->player_distance_y;
actor->player_angle_y = search_position_angleY(&actor->world.position, &player_actor->actor_class.world.position);
actor->state_bitfield &= ~ACTOR_STATE_24;
if ((actor->state_bitfield & (ACTOR_STATE_NO_MOVE_WHILE_CULLED | ACTOR_STATE_NO_CULL)) || actor->part == ACTOR_PART_NPC) {
play->game.doing_point_specific = 161;
(*actor->mv_proc)(actor, (GAME*)play);
play->game.doing_point_specific = 162;
}
CollisionCheck_Status_Clear(&actor->status_data);
next = actor->next_actor;
}
}
actor = next;
}
}
play->game.doing_point_specific = 163;
}
extern void Actor_info_draw_actor(GAME_PLAY* play, Actor_info* actor_info) {
Actor_list* list;
ACTOR* actor;
int i;
DRAW_CHK_PROC draw_chk_proc = play->draw_chk_proc;
list = actor_info->list;
for (i = 0; i < ACTOR_PART_NUM; i++) {
int do_not_draw;
for (actor = list->actor; actor != NULL; actor = actor->next_actor) {
/* Apply projection matrix to actor position */
Skin_Matrix_PrjMulVector(&play->projection_matrix, &actor->world.position, &actor->camera_position, &actor->camera_w);
Actor_cull_check(actor);
do_not_draw = (*draw_chk_proc)(actor, play);
actor->drawn = FALSE;
if (do_not_draw == FALSE && actor->ct_proc == NULL && actor->dw_proc != NULL) {
if ((actor->state_bitfield & (ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_CULL))) {
if ((actor->state_bitfield & ACTOR_STATE_INVISIBLE) == 0 && actor->cull_while_talking == FALSE && actor->skip_drawing == FALSE) {
Actor_draw(play, actor);
actor->drawn = TRUE;
}
}
else {
Actor_delete_check(actor, (GAME*)play);
}
}
}
list++;
}
Light_list_point_draw(play);
}
static void Actor_info_part_new(Actor_info* actor_info, ACTOR* actor, u8 part) {
ACTOR* next;
actor->part = part;
actor_info->total_num++;
actor_info->list[part].num_actors++;
next = actor_info->list[part].actor;
if (next != NULL) {
next->prev_actor = actor;
}
actor_info->list[part].actor = actor;
actor->next_actor = next;
}
static ACTOR* Actor_info_part_delete(Actor_info* actor_info, ACTOR* actor) {
ACTOR* next;
actor_info->total_num--;
actor_info->list[actor->part].num_actors--;
if (actor->prev_actor != NULL) {
actor->prev_actor->next_actor = actor->next_actor;
}
else {
actor_info->list[actor->part].actor = actor->next_actor;
}
next = actor->next_actor;
if (next != NULL) {
next->prev_actor = actor->prev_actor;
}
actor->prev_actor = NULL;
actor->next_actor = NULL;
return next;
}
extern void Actor_free_overlay_area(ACTOR_DLFTBL* dlftbl) {
if ((dlftbl->flags & 2) == 0) {
if ((dlftbl->flags & 1)) {
dlftbl->alloc_buf = NULL;
}
else {
zelda_free(dlftbl->alloc_buf);
dlftbl->alloc_buf = NULL;
}
}
}
static void actor_free_check(ACTOR_DLFTBL* dlftbl, mActor_name_t id) {
if (dlftbl->num_actors == 0 && dlftbl->alloc_buf != NULL) {
switch (ITEM_NAME_GET_TYPE(id)) {
case NAME_TYPE_SPNPC:
case NAME_TYPE_NPC:
(*Common_Get(clip).npc_clip->free_overlay_area_proc)(dlftbl);
break;
case NAME_TYPE_STRUCT:
(*Common_Get(clip).structure_clip->free_overlay_area_proc)(dlftbl);
break;
default:
Actor_free_overlay_area(dlftbl);
break;
}
}
}
extern void Actor_get_overlay_area(ACTOR_DLFTBL* dlftbl, int unused, size_t alloc_size) {
if ((dlftbl->flags & 2)) {
dlftbl->alloc_buf = (u8*)zelda_malloc_r(alloc_size);
}
else {
dlftbl->alloc_buf = (u8*)zelda_malloc(alloc_size);
}
}
static int Actor_data_bank_regist_check_npc(int* bank_id, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, GAME* game, mActor_name_t name_id) {
return TRUE;
}
static int Actor_data_bank_regist_check(int* bank_id, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, GAME* game, mActor_name_t name_id) {
int res = TRUE;
if (*bank_id == -1) {
if (profile->part == ACTOR_PART_NPC) {
res = Actor_data_bank_regist_check_npc(bank_id, profile, dlftbl, game, name_id);
}
else {
// in DnM, this was another func call
res = TRUE;
}
}
return res;
}
static int Actor_malloc_actor_class(ACTOR** actor_pp, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, const char* unk, mActor_name_t id) {
aNPC_draw_data_c draw_data;
switch (ITEM_NAME_GET_TYPE(id)) {
case NAME_TYPE_SPNPC:
case NAME_TYPE_NPC:
{
*actor_pp = (*Common_Get(clip).npc_clip->get_actor_area_proc)(profile->class_size, unk, 1);
(*Common_Get(clip).npc_clip->dma_draw_data_proc)(&draw_data, id); // leftover?
break;
}
case NAME_TYPE_STRUCT:
{
*actor_pp = (ACTOR*)((*Common_Get(clip).structure_clip->get_actor_area_proc)());
break;
}
default:
{
*actor_pp = (ACTOR*)zelda_malloc(profile->class_size);
break;
}
}
if (*actor_pp == NULL) {
actor_free_check(dlftbl, id);
return FALSE;
}
return TRUE;
}
extern void Actor_init_actor_class(ACTOR* actor, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, GAME_PLAY* play, int bank_idx, f32 x, f32 y, f32 z, s16 rot_x, s16 rot_y, s16 rot_z, s8 block_x, s8 block_z, s16 move_actor_list_idx, mActor_name_t name_id, s16 arg) {
mem_clear((u8*)actor, profile->class_size, 0);
actor->dlftbl = dlftbl;
actor->id = profile->id;
actor->state_bitfield = profile->initial_flags_state;
actor->data_bank_id = bank_idx;
actor->ct_proc = profile->ct_proc;
actor->dt_proc = profile->dt_proc;
actor->mv_proc = profile->mv_proc;
actor->dw_proc = profile->dw_proc;
actor->sv_proc = profile->sv_proc;
actor->actor_specific = arg;
actor->scene_id = play->scene_id;
actor->home.position.x = x;
actor->home.position.y = y;
actor->home.position.z = z;
actor->home.angle.x = rot_x;
actor->home.angle.y = rot_y;
actor->home.angle.z = rot_z;
actor->block_x = block_x;
actor->block_z = block_z;
actor->move_actor_list_idx = move_actor_list_idx;
actor->npc_id = name_id;
}
#ifndef MUST_MATCH
/* @nonmatching */
extern ACTOR* Actor_info_make_actor(Actor_info* actor_info, GAME* game, s16 profile_no, f32 x, f32 y, f32 z, s16 rot_x, s16 rot_y, s16 rot_z, s8 block_x, s8 block_z, s16 move_actor_list_idx, mActor_name_t name_id, s16 arg, s8 npc_info_idx, int data_bank_idx) {
const char* test = "";
GAME_PLAY* play = (GAME_PLAY*)game;
ACTOR* actor;
ACTOR_PROFILE* profile;
ACTOR_DLFTBL* dlftbl;
test = ""; // removing this line helps a bit...
dlftbl = &actor_dlftbls[profile_no];
if (actor_info->total_num > mAc_MAX_ACTORS) {
return NULL;
}
profile = dlftbl->profile;
if (Actor_data_bank_regist_check(&data_bank_idx, profile, dlftbl, game, name_id) == FALSE) {
return NULL;
}
if (Actor_malloc_actor_class(&actor, profile, dlftbl, test, name_id) == FALSE) {
return NULL;
}
dlftbl->num_actors++;
Actor_init_actor_class(actor, profile, dlftbl, play, data_bank_idx, x, y, z, rot_x, rot_y, rot_z, block_x, block_z, move_actor_list_idx, name_id, arg);
Actor_info_part_new(actor_info, actor, profile->part);
mNpc_SetNpcinfo(actor, npc_info_idx);
Actor_ct(actor, (GAME*)play);
return actor;
}
#else
extern asm ACTOR* Actor_info_make_actor(Actor_info* actor_info, GAME* game, s16 profile_no, f32 x, f32 y, f32 z, s16 rot_x, s16 rot_y, s16 rot_z, s8 block_x, s8 block_z, s16 move_actor_list_idx, mActor_name_t name_id, s16 arg, s8 npc_info_idx, int data_bank_idx) {
#include "asm/80375830.s"
}
#endif
extern ACTOR* Actor_info_make_child_actor(Actor_info* actor_info, ACTOR* parent_actor, GAME* game, s16 profile, f32 x, f32 y, f32 z, s16 rot_x, s16 rot_y, s16 rot_z, s16 move_actor_list_idx, mActor_name_t name_id, s16 arg, int data_bank_idx) {
ACTOR* actor = Actor_info_make_actor(actor_info, game, profile, x, y, z, rot_x, rot_y, rot_z, -1, -1, move_actor_list_idx, name_id, arg, -1, data_bank_idx);
if (actor != NULL) {
parent_actor->child_actor = actor;
actor->parent_actor = parent_actor;
}
return actor;
}
static void restore_fgdata(ACTOR* actor, GAME_PLAY* play) {
mActor_name_t name = actor->npc_id;
if (name != EMPTY_NO && actor->move_actor_list_idx == -1 && actor->block_x >= 0 && actor->block_z >= 0) {
if (ITEM_NAME_GET_TYPE(name) == NAME_TYPE_ITEM2) {
xyz_t pos;
xyz_t_move(&pos, &actor->home.position);
if (mFI_search_unit_around(&pos, EMPTY_NO) == TRUE) {
/* pos now holds the position of the empty unit */
mFI_SetFG_common(actor->npc_id, pos, FALSE); /* This causes the airplane duplication "bug" */
}
}
else {
mFI_SetFG_common(name, actor->home.position, FALSE);
}
}
}
static int restore_flag[ACTOR_PART_NUM] = {
TRUE, /* FG */
TRUE, /* ITEM */
FALSE, /* PLAYER */
FALSE, /* 3 */
FALSE, /* NPC */
FALSE, /* BG */
FALSE, /* EFFECT */
FALSE /* CONTROL */
};
static void restore_fgdata_one(ACTOR* actor, GAME_PLAY* play) {
if (restore_flag[actor->part] == TRUE) {
restore_fgdata(actor, play);
}
else if (actor->restore_fg == TRUE) {
restore_fgdata(actor, play);
}
}
extern void restore_fgdata_all(GAME_PLAY* play) {
Actor_info* info;
ACTOR* actor;
int i;
info = &play->actor_info;
for (i = 0; i < ACTOR_PART_NUM; i++) {
if (restore_flag[i] == TRUE) {
for (actor = info->list[i].actor; actor != NULL; actor = actor->next_actor) {
restore_fgdata(actor, play);
}
}
else {
for (actor = info->list[i].actor; actor != NULL; actor = actor->next_actor) {
if (actor->restore_fg == TRUE) {
restore_fgdata(actor, play);
}
}
}
}
}
extern void Actor_info_save_actor(GAME_PLAY* play) {
Actor_info* info;
ACTOR* actor;
int i;
info = &play->actor_info;
for (i = 0; i < ACTOR_PART_NUM; i++) {
for (actor = info->list[i].actor; actor != NULL; actor = actor->next_actor) {
if (actor->sv_proc != NULL) {
(*actor->sv_proc)(actor, (GAME*)play);
actor->sv_proc = NULL;
}
}
}
restore_fgdata_all(play);
}
extern ACTOR* Actor_info_delete(Actor_info* actor_info, ACTOR* actor, GAME* game) {
mActor_name_t name_id = actor->npc_id;
ACTOR_DLFTBL* dlftbl = actor->dlftbl;
ACTOR* next_actor;
restore_fgdata_one(actor, (GAME_PLAY*)game);
Actor_dt(actor, game);
next_actor = Actor_info_part_delete(actor_info, actor);
switch (ITEM_NAME_GET_TYPE(name_id)) {
case NAME_TYPE_SPNPC:
case NAME_TYPE_NPC:
{
(*Common_Get(clip).npc_clip->free_actor_area_proc)(actor);
break;
}
case NAME_TYPE_STRUCT:
{
(*Common_Get(clip).structure_clip->free_actor_area_proc)((STRUCTURE_ACTOR*)actor);
break;
}
default:
{
zelda_free(actor);
break;
}
}
if (dlftbl->ram_start == NULL) {
dlftbl->num_actors--;
}
else {
dlftbl->num_actors--;
actor_free_check(dlftbl, actor->npc_id);
}
return next_actor;
}
extern ACTOR* Actor_info_name_search_sub(ACTOR* actor, s16 name) {
while (actor != NULL) {
if (actor->id == name) {
return actor;
}
actor = actor->next_actor;
}
return actor;
}
extern ACTOR* Actor_info_name_search(Actor_info* actor_info, s16 name, int part) {
ACTOR* actor = actor_info->list[part].actor;
if (actor != NULL) {
return Actor_info_name_search_sub(actor, name);
}
return NULL;
}
extern ACTOR* Actor_info_fgName_search_sub(ACTOR* actor, mActor_name_t fgName) {
while (actor != NULL) {
if (actor->npc_id == fgName) {
return actor;
}
actor = actor->next_actor;
}
return actor;
}
extern ACTOR* Actor_info_fgName_search(Actor_info* actor_info, mActor_name_t fgName, int part) {
ACTOR* actor = actor_info->list[part].actor;
if (actor != NULL) {
return Actor_info_fgName_search_sub(actor, fgName);
}
return NULL;
}
extern Gfx* HiliteReflect_new(xyz_t* pos, xyz_t* eye, xyz_t* light_direction, GRAPH* graph, Gfx* gfx, Hilite** hilite) {
static Mtx work_view_matrix;
LookAt* lookat = GRAPH_ALLOC_TYPE(graph, LookAt, 1);
int pos_eye_equal = FALSE;
f32 eye_x = eye->x;
if (eye_x == pos->x && eye->z == pos->z) {
pos_eye_equal = TRUE;
}
if (pos_eye_equal) {
eye_x = 0.001f + eye_x;
}
*hilite = GRAPH_ALLOC_TYPE(graph, Hilite, 1);
guLookAtHilite(
&work_view_matrix,
lookat,
*hilite,
eye_x, eye->y, eye->z,
pos->x, pos->y, pos->z,
0.0f, 1.0f, 0.0f,
light_direction->x, light_direction->y, light_direction->z,
light_direction->x, light_direction->y, light_direction->z,
16, 16
);
gSPLookAt(gfx++, lookat);
gDPPipeSync(gfx++);
gDPSetTileSize(gfx++, 1, (*hilite)->h.x1, (*hilite)->h.y1, (*hilite)->h.x1 + 60, (*hilite)->h.y1 + 60);
return gfx;
}
extern Hilite* HiliteReflect_init(xyz_t* pos, xyz_t* eye, xyz_t* light_direction, GRAPH* graph) {
Hilite* hilite;
OPEN_DISP(graph);
SET_POLY_OPA_DISP(HiliteReflect_new(pos, eye, light_direction, graph, NOW_POLY_OPA_DISP, &hilite));
CLOSE_DISP(graph);
return hilite;
}
extern Hilite* HiliteReflect_xlu_init(xyz_t* pos, xyz_t* eye, xyz_t* light_direction, GRAPH* graph) {
Hilite* hilite;
OPEN_DISP(graph);
SET_POLY_XLU_DISP(HiliteReflect_new(pos, eye, light_direction, graph, NOW_POLY_XLU_DISP, &hilite));
CLOSE_DISP(graph);
return hilite;
}
extern void Setpos_HiliteReflect_init(xyz_t* pos, GAME_PLAY* play) {
Kankyo* kankyo = &play->kankyo;
xyz_t sun_pos;
sun_pos.x = (int)kankyo->sun_light.lights.diffuse.x;
sun_pos.y = (int)kankyo->sun_light.lights.diffuse.y;
sun_pos.z = (int)kankyo->sun_light.lights.diffuse.z;
HiliteReflect_init(pos, &play->view.eye, &sun_pos, play->game.graph);
}
extern void Setpos_HiliteReflect_xlu_init(xyz_t* pos, GAME_PLAY* play) {
Kankyo* kankyo = &play->kankyo;
xyz_t sun_pos;
sun_pos.x = (int)kankyo->sun_light.lights.diffuse.x;
sun_pos.y = (int)kankyo->sun_light.lights.diffuse.y;
sun_pos.z = (int)kankyo->sun_light.lights.diffuse.z;
HiliteReflect_xlu_init(pos, &play->view.eye, &sun_pos, play->game.graph);
}