Files
BanjoRecomp/patches/specific_actor_patches.c
2026-01-24 15:08:25 -03:00

276 lines
9.5 KiB
C

#include "patches.h"
#include "functions.h"
#include "transform_ids.h"
#include "bk_api.h"
#define IDS_PER_BEE 8
#define IDS_PER_PIECE 8
typedef struct {
f32 unk0[3];
f32 unkC[3];
f32 unk18[3];
f32 unk24[3];
}Struct_core2_47BD0_0;
typedef struct {
s32 unk0;
u8 unk4;
u8 unk5;
u8 unk6;
u8 unk7;
Struct_core2_47BD0_0 *unk8;
f32 unkC[3];
f32 unk18;
f32 unk1C;
BKModelBin *unk20;
s32 unk24;
}ActorLocal_core2_47BD0;
typedef struct struct_24_s {
s32 unk0;
BKModelBin* model_bin;
f32 unk8[3];
f32 unk14[3];
f32 unk20[3];
f32 unk2C;
f32 unk30[3];
ParticleEmitter* unk3C;
s32 unk40[4];
f32 unk50;
} Struct24s;
typedef struct struct_25_s {
Struct24s* begin;
Struct24s* current;
Struct24s* end;
Struct24s data[];
} Struct25s;
extern struct0* D_8037C200;
extern f32 func_8028E82C(void);
extern void func_8028E84C(f32 arg0[3]);
extern bool func_8028F070(void);
extern bool func_8028F150(void);
extern bool func_8028F2DC(void);
extern void func_802CA790(Actor* this);
extern s32 func_8033A170(void);
extern enum map_e map_get(void);
extern enum bswatergroup_e player_getWaterState(void);
extern u32 get_cutscene_counter(void);
// @recomp Patched to give the bees in the bee swarm individual IDs. The bees can show interpolation glitches otherwise, as they all share one matrix
// group and can get culled individually based on distance. This is easily reproduceable by walking into a beehive with bees from a far away distance.
RECOMP_PATCH Actor *chBeeSwarm_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) {
Actor *this;
ActorLocal_core2_47BD0 *local;
BKModelBin *phi_fp;
s32 phi_s2;
f32 sp8C[3];
f32 sp80[3];
Struct_core2_47BD0_0 *phi_s0;
this = marker_getActor(marker);
local = (ActorLocal_core2_47BD0 *)&this->local;
phi_fp = marker_loadModelBin(marker);
for (phi_s2 = 0, phi_s0 = local->unk8; phi_s2 < local->unk0; phi_s2++) {
sp80[0] = 0.0f;
sp80[1] = phi_s0->unk24[1] - 90.0f;
sp80[2] = 0.0f;
sp8C[0] = this->position[0] + phi_s0->unk0[0];
sp8C[1] = this->position[1] + phi_s0->unk0[1];
sp8C[2] = this->position[2] + phi_s0->unk0[2];
// @recomp Set the model transform ID.
s32 cur_drawn_marker_spawn_index = bkrecomp_get_marker_spawn_index(marker);
u32 transform_id = MARKER_TRANSFORM_ID_START + cur_drawn_marker_spawn_index * MARKER_TRANSFORM_ID_COUNT + phi_s2 * IDS_PER_BEE;
u32 prev_transform_id = cur_drawn_model_transform_id;
cur_drawn_model_transform_id = transform_id;
modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE);
modelRender_setAlpha(0xFF);
modelRender_draw(gfx, mtx, sp8C, sp80, 0.25f, NULL, phi_fp);
local->unk5 |= func_8033A170();
if (phi_s2 < 10) {
sp8C[1] = local->unk18 + 6.0f;
modelRender_setAlpha(0xC0);
modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE);
modelRender_draw(gfx, mtx, sp8C, sp80, 0.1f, NULL, local->unk20);
local->unk5 |= func_8033A170();
}
phi_s0++;
// @recomp Reset the model transform ID.
cur_drawn_model_transform_id = prev_transform_id;
}
return this;
}
// @recomp Patched to give the actors which spawn multiple pieces individual IDs for each piece. This function is primarily used by explosions of wood and others.
RECOMP_PATCH Actor* func_802C8484(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) {
Struct25s* temp_s1;
Struct24s* phi_s0;
f32 sp5C;
Actor* sp58;
u32 phi_v1;
s32 phi_s4;
sp58 = marker_getActorAndRotation(marker, &sp5C);
temp_s1 = (Struct25s*)(sp58->unk40);
phi_s4 = FALSE;
for (phi_s0 = temp_s1->begin; phi_s0 < temp_s1->current; phi_s0++) {
if ((phi_s0->unk0 != 0) && (phi_s0->model_bin != NULL)) {
// @recomp Set the model transform ID.
s32 cur_drawn_marker_spawn_index = bkrecomp_get_marker_spawn_index(marker);
u32 transform_id = MARKER_TRANSFORM_ID_START + cur_drawn_marker_spawn_index * MARKER_TRANSFORM_ID_COUNT + (phi_s0 - temp_s1->begin) * IDS_PER_PIECE;
u32 prev_transform_id = cur_drawn_model_transform_id;
cur_drawn_model_transform_id = transform_id;
modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL);
modelRender_draw(gfx, mtx, phi_s0->unk8, phi_s0->unk14, phi_s0->unk2C / 10.0f, NULL, phi_s0->model_bin);
phi_s4 = TRUE;
// @recomp Reset the model transform ID.
cur_drawn_model_transform_id = prev_transform_id;
}
}
if (phi_s4 == FALSE) {
marker_despawn(marker);
}
return sp58;
}
extern f32 D_8036E580[3];
extern void actor_postdrawMethod(ActorMarker *);
extern void actor_predrawMethod(Actor *);
extern BKModelBin *func_803257B4(ActorMarker *marker);
// @recomp Patch to skip interpolation on the Christmas tree while the lights
// turn on to prevent visual glitches.
RECOMP_PATCH Actor *actor_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) {
f32 sp3C[3];
Actor *this;
this = marker_getActorAndRotation(marker, sp3C);
// @recomp Check for the xmas tree model
if (marker->modelId == ASSET_488_MODEL_XMAS_TREE) {
// @recomp Check that the lights are currently turning on, flickering or turning off.
if (this->state == 2 || this->state == 3 || this->state == 5) {
// @recomp Skip interpolation
cur_drawn_model_skip_interpolation = TRUE;
}
}
// @recomp Check for the hut model.
else if (marker->modelId == ASSET_7D7_MODEL_MM_HUT) {
// @recomp Check if the hut is destroyed (HUT_STATE_2_DESTROYED).
if (this->state == 2) {
cur_drawn_model_skip_interpolation = TRUE;
}
}
modelRender_preDraw((GenFunction_1)actor_predrawMethod, (s32)this);
modelRender_postDraw((GenFunction_1)actor_postdrawMethod, (s32)marker);
modelRender_draw(gfx, mtx, this->position, sp3C, this->scale, (this->unk104 != NULL) ? D_8036E580 : NULL, func_803257B4(marker));
// @recomp Re-enable interpolation
cur_drawn_model_skip_interpolation = FALSE;
return this;
}
extern void func_802E0710(Actor *this);
// @recomp Make sure the model being skipped are the bulls during the intro cutscene, and only during the
// first few seconds of the cutscene while the camera is panning.
bool skip_drawing_intro_bulls(u32 model_id) {
return
(map_get() == MAP_1E_CS_START_NINTENDO) &&
(model_id == ASSET_353_MODEL_BIGBUTT || model_id == ASSET_354_MODEL_BULL_INTRO) &&
get_cutscene_counter() < 180;
}
// @recomp Patched to skip drawing the bull actors on the intro cutscene's start.
RECOMP_PATCH Actor *func_802E0738(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) {
f32 sp34[3];
Actor *this;
this = marker_getActorAndRotation(marker, &sp34);
// @recomp Check the condition for not drawing this actor if it's one of the bulls during the intro.
if (skip_drawing_intro_bulls(marker->modelId)) {
return this;
}
modelRender_preDraw((GenFunction_1)func_802E0710, (s32)this);
modelRender_postDraw((GenFunction_1)actor_postdrawMethod, (s32)marker);
modelRender_draw(gfx, mtx, this->position, sp34, this->scale, NULL, marker_loadModelBin(marker));
return this;
}
// @recomp Patched to skip interpolating the player shadow on large surface changes.
RECOMP_PATCH Actor* func_802CA7BC(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) {
Actor* this;
f32 sp60;
f32 sp54[3];
f32 rotation[3];
f32 sp44;
f32 sp40;
f32 sp34[3];
sp60 = (player_getWaterState() == BSWATERGROUP_2_UNDERWATER) ? 8.0f : 4.0f;
this = marker_getActor(marker);
if (!func_8028F070()
|| !func_8028F150()
|| !func_8028F2DC()
) {
return this;
}
player_getPosition(sp54);
sp40 = func_8028E82C();
func_8028E84C(sp34);
this->position_x = sp54[0];
this->position_y = sp40 + sp60;
this->position_z = sp54[2];
func_80258108(sp34, &this->yaw, &this->pitch);
rotation[0] = this->pitch;
rotation[1] = this->yaw;
rotation[2] = this->roll;
sp44 = ml_map_f(sp54[1] - sp40, 0.0f, 300.0f, 0.43f, 0.28f);
// @recomp Check for the player shadow model.
if (marker->modelId == ASSET_3BF_MODEL_PLAYER_SHADOW) {
// @recomp Skip interpolation if the player's projected position on the floor has changed too quickly. Only do this check when the triangle has changed.
static f32 previousPosY = 0.0f;
static f32 previousNormY = 1.0f;
static s16 previousTri[3] = { 0, 0, 0 };
s16* currentTri = &D_8037C200->unk4.unk0[0];
if (currentTri[0] != previousTri[0] || currentTri[1] != previousTri[1] || currentTri[2] != previousTri[2]) {
f32 projectedHeightDistance = previousNormY * mlAbsF(this->position_y - previousPosY);
const f32 skipHeightThreshold = 20.0f;
cur_drawn_model_skip_interpolation = projectedHeightDistance >= skipHeightThreshold;
previousNormY = D_8037C200->normY;
previousTri[0] = currentTri[0];
previousTri[1] = currentTri[1];
previousTri[2] = currentTri[2];
}
previousPosY = this->position_y;
}
modelRender_preDraw((GenFunction_1)func_802CA790, (s32)this);
modelRender_draw(gfx, mtx, this->position, rotation, sp44, NULL, marker_loadModelBin(marker));
// @recomp Re-enable interpolation
cur_drawn_model_skip_interpolation = FALSE;
return this;
}