Files
ac-decomp/src/ef_effect_control.c
T
2024-03-13 04:13:41 -04:00

445 lines
14 KiB
C

#include "ef_effect_control.h"
#include "m_common_data.h"
#include "sys_matrix.h"
#include "m_rcp.h"
#include "m_player_lib.h"
#include "m_debug.h"
static eEC_PROFILE_c* profile_tbl[] = {
&iam_ef_shock,
&iam_ef_dust,
&iam_ef_muka,
&iam_ef_warau,
&iam_ef_ha,
&iam_ef_sibuki,
&iam_ef_gimonhu,
&iam_ef_kantanhu,
&iam_ef_ase,
&iam_ef_ase_ch,
&iam_ef_kangaeru,
&iam_ef_otikomi,
&iam_ef_buruburu,
&iam_ef_siawase_hikari,
&iam_ef_siawase_hana,
&iam_ef_siawase_hana_ch,
&iam_ef_takurami,
&iam_ef_takurami_kira,
&iam_ef_kaze,
&iam_ef_kaze_happa,
&iam_ef_lovelove,
&iam_ef_lovelove_heart,
&iam_ef_pun,
&iam_ef_pun_yuge,
&iam_ef_pun_sekimen,
&iam_ef_naku,
&iam_ef_namida,
&iam_ef_hirameki_den,
&iam_ef_hirameki_hikari,
&iam_ef_situren,
&iam_ef_ase2,
&iam_ef_dash_asimoto,
&iam_ef_konpu,
&iam_ef_lovelove2,
&iam_ef_kpun,
&iam_ef_kisha_kemuri,
&iam_ef_neboke,
&iam_ef_neboke_awa,
&iam_ef_hanabi_yanagi,
&iam_ef_hanabi_botan1,
&iam_ef_hanabi_botan2,
&iam_ef_hanabi_hoshi,
&iam_ef_hanabi_set,
&iam_ef_hanabi_switch,
&iam_ef_footprint,
&iam_ef_turn_footprint,
&iam_ef_bubu,
&iam_ef_turn_asimoto,
&iam_ef_string,
&iam_ef_yukihane,
&iam_ef_anahikari,
&iam_ef_bush_happa,
&iam_ef_bush_yuki,
&iam_ef_tumble,
&iam_ef_tumble_bodyprint,
&iam_ef_slip,
&iam_ef_tumble_dust,
&iam_ef_swing_net,
&iam_ef_ami_mizu,
&iam_ef_mizutama,
&iam_ef_yukidama,
&iam_ef_kikuzu,
&iam_ef_swing_axe,
&iam_ef_steam,
&iam_ef_night15_moon,
&iam_ef_night13_moon,
&iam_ef_neboke_akubi,
&iam_ef_slip_footprint,
&iam_ef_walk_asimoto,
&iam_ef_turi_hamon,
&iam_ef_turi_mizu,
&iam_ef_turi_hane0,
&iam_ef_turi_hane1,
&iam_ef_turi_suiteki,
&iam_ef_ongen,
&iam_ef_impact_star,
&iam_ef_sandsplash,
&iam_ef_young_tree,
&iam_ef_swing_rod,
&iam_ef_doyon,
&iam_ef_kagu_happa,
&iam_ef_hanabi_dummy,
&iam_ef_dig_hole,
&iam_ef_dig_scoop,
&iam_ef_dig_mud,
&iam_ef_kigae,
&iam_ef_kigae_light,
&iam_ef_tape,
&iam_ef_clacker,
&iam_ef_kamifubuki,
&iam_ef_car_blight,
&iam_ef_tamaire,
&iam_ef_car_light,
&iam_ef_reset_hole,
&iam_ef_goki,
&iam_ef_hanabira,
&iam_ef_wait_asimoto,
&iam_ef_otosiana,
&iam_ef_ikigire,
&iam_ef_yukidaruma,
&iam_ef_kyousou_onpu,
&iam_ef_douzou_light,
&iam_ef_halloween_smoke,
&iam_ef_halloween,
&iam_ef_motiyuge,
&iam_ef_taberu,
&iam_ef_kasamizu,
&iam_ef_kasamizutama,
&iam_ef_hanatiri,
&iam_ef_uranai,
&iam_ef_suisou_awa,
&iam_ef_break_axe,
&iam_ef_yajirushi,
&iam_ef_soba_yuge,
&iam_ef_furo_yuge,
&iam_ef_shooting,
&iam_ef_shooting_set,
&iam_ef_shooting_kira,
&iam_ef_coin,
&iam_ef_tent_lamp,
&iam_ef_flash,
&iam_ef_flashC,
&iam_ef_killer,
&iam_ef_make_hem,
&iam_ef_make_hem_kira,
&iam_ef_make_hem_light,
};
static u8 eEC_effect_feature[] = {
FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE,
TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,
FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE,
};
static void eEC_actor_ct(ACTOR* actorx, GAME* game);
static void eEC_actor_dt(ACTOR* actorx, GAME* game);
static void eEC_actor_move(ACTOR* actorx, GAME* game);
static void eEC_actor_draw(ACTOR* actorx, GAME* game);
ACTOR_PROFILE Effect_Control_Profile = {
mAc_PROFILE_EFFECT_CONTROL,
ACTOR_PART_CONTROL,
ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED,
EMPTY_NO,
ACTOR_OBJ_BANK_KEEP,
sizeof(EFFECT_CONTROL_ACTOR),
&eEC_actor_ct,
&eEC_actor_dt,
&eEC_actor_move,
&eEC_actor_draw,
NULL,
};
static eEC_work_c eEC_ctrl_work;
#include "../src/ef_effect_lib.c"
static void eEC_Name2EffectMake(int effect_id, xyz_t pos, int prio, s16 angle, GAME* game, u16 item_name, s16 arg0,
s16 arg1) {
if (effect_id >= 0 && effect_id < eEC_EFFECT_NUM) {
if (eEC_effect_feature[effect_id] == FALSE) {
profile_tbl[effect_id]->init_proc(pos, prio, angle, game, item_name, arg0, arg1);
} else if (eEC_effect_feature[effect_id] == TRUE) {
int i;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
eEC_Effect_c* effect = eEC_ctrl_work.effects;
/* Check if any of the spawned effects are an exact match to this one */
for (i = 0; i < eEC_EFFECT_ACTIVE_MAX; i++, active_flags++, effect++) {
if (*active_flags && effect->name == effect_id && effect->item_name == item_name) {
return;
}
}
/* No exact matches, so create effect */
profile_tbl[effect_id]->init_proc(pos, prio, angle, game, item_name, arg0, arg1);
}
}
}
static void eEC_Name2EffectKill(int effect_id, u16 item_name) {
int i;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
eEC_Effect_c* effect = eEC_ctrl_work.effects;
for (i = 0; i < eEC_EFFECT_ACTIVE_MAX; i++, active_flags++, effect++) {
if (*active_flags && effect->name == effect_id && effect->item_name == item_name && effect->prog_idx != -1) {
if (profile_tbl[effect_id]->n_frames == eEC_IMMEDIATE_DEATH) {
*active_flags = 0;
if (profile_tbl[effect_id]->child_effect_id != eEC_NO_CHILD_ID) {
eEC_Name2EffectKill(profile_tbl[effect_id]->child_effect_id, item_name);
}
} else if (profile_tbl[effect_id]->n_frames != eEC_IGNORE_DEATH) {
effect->timer = profile_tbl[effect_id]->n_frames;
effect->state = eEC_STATE_FINISHED;
if (profile_tbl[effect_id]->child_effect_id != eEC_NO_CHILD_ID) {
eEC_Name2EffectKill(profile_tbl[effect_id]->child_effect_id, item_name);
}
}
}
}
}
static void eEC_Name2EffectKillAll(u16 item_name) {
int i;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
eEC_Effect_c* effect = eEC_ctrl_work.effects;
for (i = 0; i < eEC_EFFECT_ACTIVE_MAX; i++, active_flags++, effect++) {
if (*active_flags && effect->item_name == item_name && effect->prog_idx != -1) {
if (profile_tbl[effect->name]->n_frames == eEC_IMMEDIATE_DEATH) {
*active_flags = FALSE;
} else if (eEC_ctrl_work.program_info[effect->prog_idx].end_frame != eEC_IGNORE_DEATH) {
effect->timer = eEC_ctrl_work.program_info[effect->prog_idx].end_frame;
effect->state = eEC_STATE_FINISHED;
}
}
}
}
static void eEC_InitEffectControlWork(void) {
eEL_InitUnchar(eEC_ctrl_work.effect_active_flags, eEC_EFFECT_ACTIVE_MAX, 0);
eEC_ctrl_work.active_effect_num = 0;
}
static eEC_Effect_c* eEC_MakeEffect(s16 effect_id, xyz_t pos, xyz_t* ofs, GAME* game, void* ct_arg, u16 item_name,
int prio, s16 arg0, s16 arg1);
static void eEC_EffectLib2Clip(ACTOR* actorx) {
EFFECT_CONTROL_ACTOR* effect_ctrl = (EFFECT_CONTROL_ACTOR*)actorx;
effect_ctrl->clip.effect_make_proc = &eEC_Name2EffectMake;
effect_ctrl->clip.effect_kill_proc = &eEC_Name2EffectKill;
effect_ctrl->clip.effect_kill_all_proc = &eEC_Name2EffectKillAll;
effect_ctrl->clip.vector_rotate_y_proc = &eEL_VectorRoteteY;
effect_ctrl->clip.random_first_speed_proc = &eEL_RandomFirstSpeed;
effect_ctrl->clip.set_continious_env_proc = &eEL_SetContiniousEnv;
effect_ctrl->clip.calc_adjust_proc = &eEL_CalcAdjust;
effect_ctrl->clip.auto_matrix_xlu_proc = &eEL_AutoMatrixXlu;
effect_ctrl->clip.auto_matrix_xlu_offset_proc = &eEL_AutoMatrixXlu_Offset;
effect_ctrl->clip._20 = NULL;
effect_ctrl->clip._24 = NULL;
effect_ctrl->clip.make_effect_proc = &eEC_MakeEffect;
effect_ctrl->clip.morph_combine_proc = &eEC_MorphCombine;
effect_ctrl->clip.regist_effect_light = &eEL_RegistEffectLight;
effect_ctrl->clip.decide_light_power_proc = &eEL_DecideLightPower;
effect_ctrl->clip.check_lookat_block_proc = &mEL_CheckLookAtBlock;
effect_ctrl->clip.effect_light_status = &eEL_EffectLightStatus;
effect_ctrl->clip.special_block_center_pos_proc = &eEL_SpecialBlockCenterPos;
eEC_CLIP = &effect_ctrl->clip;
}
static void eEC_MakeEffectLight(GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
Light_diffuse_ct(&eEC_ctrl_work.light_info, 0, 127, 0, 0, 0, 0);
eEC_ctrl_work.light_list = Global_light_list_new(game, &play->global_light, &eEC_ctrl_work.light_info);
}
static void eEC_DeleteEffectLight(GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
Global_light_list_delete(&play->global_light, eEC_ctrl_work.light_list);
}
int eMH_special_point_light_num = 0;
static void eEC_actor_ct(ACTOR* actorx, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
eEC_EffectLib2Clip(actorx);
eEC_InitEffectControlWork();
eEC_MakeEffectLight(game);
eEL_InitEffectLight();
if (Save_Get(scene_no) == SCENE_TENT) {
eEC_CLIP->effect_make_proc(eEC_EFFECT_TENT_LAMP, actorx->world.position, 3, 0, game, RSV_NO, 0, 0);
}
eMH_special_point_light_num = -1;
}
static void eEC_actor_dt(ACTOR* actorx, GAME* game) {
eEC_CLIP = NULL;
eEC_DeleteEffectLight(game);
}
static void eEC_actor_draw(ACTOR* actorx, GAME* game) {
int i;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
eEC_Effect_c* effect = eEC_ctrl_work.effects;
_texture_z_light_fog_prim(game->graph);
_texture_z_light_fog_prim_xlu(game->graph);
for (i = 0; i < eEC_EFFECT_ACTIVE_MAX; i++, active_flags++, effect++) {
if (*active_flags) {
profile_tbl[effect->name]->draw_proc(effect, game);
}
}
}
static int eEC_DistDeath(eEC_Effect_c* effect, GAME* game, s16 prog_idx) {
GAME_PLAY* play = (GAME_PLAY*)game;
int res = FALSE; // in range
if (prog_idx != -1) {
f32 max_dist = profile_tbl[effect->name]->max_dist;
if (max_dist != eEC_IGNORE_DEATH_DIST) {
PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play);
if (ABS(player->actor_class.world.position.x - effect->position.x) > max_dist ||
ABS(player->actor_class.world.position.z - effect->position.z) > max_dist ||
ABS(player->actor_class.world.position.y - effect->position.y) > max_dist) {
res = TRUE; // out of range
}
}
}
return res;
}
static void eEC_AllEffectMove(GAME* game) {
int i;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
eEC_Effect_c* effect = eEC_ctrl_work.effects;
for (i = 0; i < eEC_EFFECT_ACTIVE_MAX; i++, active_flags++, effect++) {
if (*active_flags) {
s16 prog_idx = effect->prog_idx;
profile_tbl[effect->name]->move_proc(effect, game);
effect->timer--;
if (effect->timer <= 0 || eEC_DistDeath(effect, game, prog_idx) == TRUE) {
*active_flags = 0;
effect->timer = 0;
effect->_0A = 0;
}
}
}
}
static void eEC_actor_move(ACTOR* actorx, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play);
eEL_CalcEffectLight_Set(game);
eEC_AllEffectMove(game);
actorx->world.position = player->actor_class.world.position;
}
static int eEC_GetEffectBuff(int prio) {
int now_idx = eEC_ctrl_work.active_effect_num;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
int i;
for (i = now_idx; i < eEC_EFFECT_ACTIVE_MAX; i++) {
if (active_flags[i] == 0) {
return i;
}
}
for (i = 0; i < now_idx - 1; i++) {
if (active_flags[i] == 0) {
return i;
}
}
for (i = now_idx; i < eEC_EFFECT_ACTIVE_MAX; i++) {
if (active_flags[i] < prio) {
return i;
}
}
for (i = 0; i < now_idx - 1; i++) {
if (active_flags[i] != 2) {
return i;
}
}
return -1;
}
static void eEC_SetFirstOffset(eEC_Effect_c* effect, xyz_t* ofs) {
static xyz_t default_offset = { 0.0f, 0.0f, 0.0f };
effect->offset = default_offset;
if (ofs != NULL) {
effect->offset = *ofs;
}
}
static eEC_Effect_c* eEC_MakeEffect(s16 effect_id, xyz_t pos, xyz_t* ofs, GAME* game, void* ct_arg, u16 item_name,
int prio, s16 arg0, s16 arg1) {
static xyz_t defaultX = { 0.0f, 0.0f, 0.0f };
static xyz_t scale_default = { 0.01f, 0.01f, 0.01f };
int* active_effect_num = &eEC_ctrl_work.active_effect_num;
eEC_Effect_c* effect = NULL;
eEC_Effect_c* effects = eEC_ctrl_work.effects;
u8* active_flags = eEC_ctrl_work.effect_active_flags;
int use_idx;
use_idx = eEC_GetEffectBuff(prio);
if (use_idx != -1) {
active_flags[use_idx] = prio;
effects[use_idx].name = effect_id;
effects[use_idx].position = pos;
effects[use_idx].item_name = item_name;
effects[use_idx].prio = prio;
effects[use_idx].state = eEC_STATE_NORMAL;
eEC_SetFirstOffset(&effects[use_idx], ofs);
effects[use_idx].timer = 10;
effects[use_idx].velocity = defaultX;
effects[use_idx].acceleration = defaultX;
effects[use_idx].scale = scale_default;
effects[use_idx].arg0 = arg0;
effects[use_idx].arg1 = arg1;
profile_tbl[effect_id]->ct_proc(&effects[use_idx], game, ct_arg);
*active_effect_num = use_idx + 1;
effect = &effects[use_idx];
}
return effect;
}