mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-23 22:45:09 -04:00
1b0b96665a
Co-authored-by: NWPlayer123 <NWPlayer123@users.noreply.github.com>
445 lines
14 KiB
C
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/effect/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;
|
|
}
|