385 lines
12 KiB
C
385 lines
12 KiB
C
/**
|
|
* File z_eff_dust.c
|
|
* Overlay: ovl_Eff_Dust
|
|
* Description: Dust effects
|
|
*/
|
|
|
|
#include "z_eff_dust.h"
|
|
#include "objects/gameplay_keep/gameplay_keep.h"
|
|
#include "soh/frame_interpolation.h"
|
|
|
|
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5)
|
|
|
|
void EffDust_Init(Actor* thisx, GlobalContext* globalCtx);
|
|
void EffDust_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
|
void EffDust_Update(Actor* thisx, GlobalContext* globalCtx);
|
|
void EffDust_Draw(Actor* thisx, GlobalContext* globalCtx);
|
|
|
|
void EffDust_InitPosAndDistance(EffDust* this);
|
|
|
|
void EffDust_UpdateFunc_8099DB28(EffDust* this, GlobalContext* globalCtx);
|
|
void EffDust_UpdateFunc_8099DD74(EffDust* this, GlobalContext* globalCtx);
|
|
void EffDust_UpdateFunc_8099DFC0(EffDust* this, GlobalContext* globalCtx);
|
|
void EffDust_DrawFunc_8099E4F4(Actor* thisx, GlobalContext* globalCtx);
|
|
void EffDust_DrawFunc_8099E784(Actor* thisx, GlobalContext* globalCtx);
|
|
|
|
const ActorInit Eff_Dust_InitVars = {
|
|
ACTOR_EFF_DUST,
|
|
ACTORCAT_NPC,
|
|
FLAGS,
|
|
OBJECT_GAMEPLAY_KEEP,
|
|
sizeof(EffDust),
|
|
(ActorFunc)EffDust_Init,
|
|
(ActorFunc)EffDust_Destroy,
|
|
(ActorFunc)EffDust_Update,
|
|
(ActorFunc)EffDust_Draw,
|
|
NULL,
|
|
};
|
|
|
|
static Gfx sEmptyDL[] = {
|
|
gsSPEndDisplayList(),
|
|
};
|
|
|
|
void EffDust_SetupAction(EffDust* this, EffDustActionFunc actionFunc) {
|
|
this->actionFunc = actionFunc;
|
|
}
|
|
|
|
void EffDust_SetupDraw(EffDust* this, EffDustDrawFunc drawFunc) {
|
|
this->drawFunc = drawFunc;
|
|
}
|
|
|
|
void EffDust_InitPosAndDistance(EffDust* this) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
this->initialPositions[i].z = 0.0f;
|
|
this->initialPositions[i].y = 0.0f;
|
|
this->initialPositions[i].x = 0.0f;
|
|
|
|
this->distanceTraveled[i] = 1.0f;
|
|
}
|
|
this->index = 0;
|
|
}
|
|
|
|
void EffDust_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|
EffDust* this = (EffDust*)thisx;
|
|
EffDustType dustEffect = this->actor.params;
|
|
|
|
EffDust_InitPosAndDistance(this);
|
|
|
|
switch (dustEffect) {
|
|
case EFF_DUST_TYPE_0:
|
|
EffDust_SetupAction(this, EffDust_UpdateFunc_8099DB28);
|
|
EffDust_SetupDraw(this, EffDust_DrawFunc_8099E4F4);
|
|
this->dy = 0.8f;
|
|
this->dz = 0.8f;
|
|
this->dx = 1.0f;
|
|
this->scalingFactor = 0.1f;
|
|
break;
|
|
case EFF_DUST_TYPE_1:
|
|
EffDust_SetupAction(this, EffDust_UpdateFunc_8099DD74);
|
|
EffDust_SetupDraw(this, EffDust_DrawFunc_8099E4F4);
|
|
this->dx = 0.8f;
|
|
this->dz = 0.8f;
|
|
this->dy = 1.0f;
|
|
this->scalingFactor = 0.5f;
|
|
break;
|
|
case EFF_DUST_TYPE_2:
|
|
EffDust_SetupAction(this, EffDust_UpdateFunc_8099DFC0);
|
|
EffDust_SetupDraw(this, EffDust_DrawFunc_8099E784);
|
|
this->dx = 0.5f;
|
|
this->scalingFactor = 15.0f;
|
|
break;
|
|
case EFF_DUST_TYPE_3:
|
|
EffDust_SetupAction(this, EffDust_UpdateFunc_8099DFC0);
|
|
EffDust_SetupDraw(this, EffDust_DrawFunc_8099E784);
|
|
this->dx = 0.5f;
|
|
this->scalingFactor = 10.0f;
|
|
break;
|
|
case EFF_DUST_TYPE_4:
|
|
EffDust_SetupAction(this, EffDust_UpdateFunc_8099DFC0);
|
|
EffDust_SetupDraw(this, EffDust_DrawFunc_8099E784);
|
|
this->actor.room = -1;
|
|
this->dx = 0.5f;
|
|
this->scalingFactor = 20.0f;
|
|
break;
|
|
default:
|
|
SYSTEM_ARENA_FREE_DEBUG(this);
|
|
break;
|
|
}
|
|
|
|
this->life = 10;
|
|
}
|
|
|
|
void EffDust_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
|
}
|
|
|
|
void EffDust_UpdateFunc_8099DB28(EffDust* this, GlobalContext* globalCtx) {
|
|
s16 theta;
|
|
s16 fi;
|
|
f32* distanceTraveled = this->distanceTraveled;
|
|
s32 i;
|
|
s32 j;
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
if ((*distanceTraveled) < 1.0f) {
|
|
*distanceTraveled += 0.05f;
|
|
}
|
|
distanceTraveled++;
|
|
}
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
i = this->index & 0x3F;
|
|
if (this->distanceTraveled[i] >= 1.0f) {
|
|
// Spherical coordinate system.
|
|
fi = Rand_CenteredFloat(8192.0f);
|
|
theta = Rand_CenteredFloat(4096.0f);
|
|
this->initialPositions[i].x = -800.0f * Math_CosS(fi) * Math_CosS(theta);
|
|
this->initialPositions[i].y = -800.0f * Math_SinS(theta);
|
|
this->initialPositions[i].z = -800.0f * Math_SinS(fi) * Math_CosS(theta);
|
|
this->distanceTraveled[i] = 0.0f;
|
|
this->index += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EffDust_UpdateFunc_8099DD74(EffDust* this, GlobalContext* globalCtx) {
|
|
s16 theta;
|
|
s16 fi;
|
|
f32* distanceTraveled = this->distanceTraveled;
|
|
s32 i;
|
|
s32 j;
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
if ((*distanceTraveled) < 1.0f) {
|
|
*distanceTraveled += 0.03f;
|
|
}
|
|
distanceTraveled++;
|
|
}
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
i = this->index & 0x3F;
|
|
if (this->distanceTraveled[i] >= 1.0f) {
|
|
// Spherical coordinate system.
|
|
fi = Rand_CenteredFloat(65536.0f);
|
|
theta = Rand_ZeroFloat(8192.0f);
|
|
this->initialPositions[i].x = 400.0f * Math_CosS(fi) * Math_CosS(theta);
|
|
this->initialPositions[i].y = 400.0f * Math_SinS(theta);
|
|
this->initialPositions[i].z = 400.0f * Math_SinS(fi) * Math_CosS(theta);
|
|
this->distanceTraveled[i] = 0.0f;
|
|
this->index += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EffDust_UpdateFunc_8099DFC0(EffDust* this, GlobalContext* globalCtx) {
|
|
s16 theta;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
Actor* parent = this->actor.parent;
|
|
f32* distanceTraveled = this->distanceTraveled;
|
|
s32 i;
|
|
s32 j;
|
|
|
|
if (parent == NULL || parent->update == NULL || !(player->stateFlags1 & 0x1000)) {
|
|
if (this->life != 0) {
|
|
this->life -= 1;
|
|
} else {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
if ((*distanceTraveled) < 1.0f) {
|
|
*distanceTraveled += 0.2f;
|
|
}
|
|
distanceTraveled++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
if ((*distanceTraveled) < 1.0f) {
|
|
*distanceTraveled += 0.1f;
|
|
}
|
|
distanceTraveled++;
|
|
}
|
|
|
|
this->actor.world.pos = parent->world.pos;
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
i = this->index & 0x3F;
|
|
if (this->distanceTraveled[i] >= 1.0f) {
|
|
|
|
theta = Rand_CenteredFloat(65536.0f);
|
|
switch (this->actor.params) {
|
|
case EFF_DUST_TYPE_2:
|
|
this->initialPositions[i].x = (Rand_ZeroOne() * 4500.0f) + 700.0f;
|
|
if (this->initialPositions[i].x > 3000.0f) {
|
|
this->initialPositions[i].y = (3000.0f * Rand_ZeroOne()) * Math_SinS(theta);
|
|
this->initialPositions[i].z = (3000.0f * Rand_ZeroOne()) * Math_CosS(theta);
|
|
} else {
|
|
this->initialPositions[i].y = 3000.0f * Math_SinS(theta);
|
|
this->initialPositions[i].z = 3000.0f * Math_CosS(theta);
|
|
}
|
|
break;
|
|
|
|
case EFF_DUST_TYPE_3:
|
|
this->initialPositions[i].x = (Rand_ZeroOne() * 2500.0f) + 700.0f;
|
|
if (this->initialPositions[i].x > 2000.0f) {
|
|
this->initialPositions[i].y = (2000.0f * Rand_ZeroOne()) * Math_SinS(theta);
|
|
this->initialPositions[i].z = (2000.0f * Rand_ZeroOne()) * Math_CosS(theta);
|
|
} else {
|
|
this->initialPositions[i].y = 2000.0f * Math_SinS(theta);
|
|
this->initialPositions[i].z = 2000.0f * Math_CosS(theta);
|
|
}
|
|
break;
|
|
|
|
case EFF_DUST_TYPE_4:
|
|
this->initialPositions[i].x = (Rand_ZeroOne() * 8500.0f) + 1700.0f;
|
|
if (this->initialPositions[i].x > 5000.0f) {
|
|
this->initialPositions[i].y = (4000.0f * Rand_ZeroOne()) * Math_SinS(theta);
|
|
this->initialPositions[i].z = (4000.0f * Rand_ZeroOne()) * Math_CosS(theta);
|
|
} else {
|
|
this->initialPositions[i].y = 4000.0f * Math_SinS(theta);
|
|
this->initialPositions[i].z = 4000.0f * Math_CosS(theta);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
this->distanceTraveled[i] = 0.0f;
|
|
this->index += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EffDust_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|
EffDust* this = (EffDust*)thisx;
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
}
|
|
|
|
void EffDust_DrawFunc_8099E4F4(Actor* thisx, GlobalContext* globalCtx2) {
|
|
EffDust* this = (EffDust*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
Vec3f* initialPositions;
|
|
f32* distanceTraveled;
|
|
s32 i;
|
|
f32 aux;
|
|
static u32 epoch = 0;
|
|
epoch++;
|
|
|
|
OPEN_DISPS(gfxCtx);
|
|
|
|
func_80093D18(gfxCtx);
|
|
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 128, 128, 128, 255);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 128, 128, 128, 0);
|
|
|
|
initialPositions = this->initialPositions;
|
|
distanceTraveled = this->distanceTraveled;
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 0x08, sEmptyDL);
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
FrameInterpolation_RecordOpenChild("Dust 8099E4F4", epoch + i * 25);
|
|
|
|
if (*distanceTraveled < 1.0f) {
|
|
aux = 1.0f - (*distanceTraveled * *distanceTraveled);
|
|
Matrix_Translate(this->actor.world.pos.x + (initialPositions->x * ((this->dx * aux) + (1.0f - this->dx))),
|
|
this->actor.world.pos.y + (initialPositions->y * ((this->dy * aux) + (1.0f - this->dy))),
|
|
this->actor.world.pos.z + (initialPositions->z * ((this->dz * aux) + (1.0f - this->dz))),
|
|
MTXMODE_NEW);
|
|
|
|
Matrix_Scale(this->scalingFactor, this->scalingFactor, this->scalingFactor, MTXMODE_APPLY);
|
|
Matrix_Mult(&globalCtx->billboardMtxF, MTXMODE_APPLY);
|
|
|
|
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gEffSparklesDL));
|
|
}
|
|
|
|
FrameInterpolation_RecordCloseChild();
|
|
|
|
initialPositions++;
|
|
distanceTraveled++;
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx);
|
|
}
|
|
|
|
void EffDust_DrawFunc_8099E784(Actor* thisx, GlobalContext* globalCtx2) {
|
|
EffDust* this = (EffDust*)thisx;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
f32* distanceTraveled;
|
|
Vec3f* initialPositions;
|
|
s32 i;
|
|
f32 aux;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
static u32 epoch = 0;
|
|
epoch++;
|
|
|
|
OPEN_DISPS(gfxCtx);
|
|
|
|
func_80093D18(gfxCtx);
|
|
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
if (player->unk_858 >= 0.85f) {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0);
|
|
} else {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 255, 0);
|
|
}
|
|
|
|
initialPositions = this->initialPositions;
|
|
distanceTraveled = this->distanceTraveled;
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 0x08, sEmptyDL);
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
FrameInterpolation_RecordOpenChild("Dust 8099E784", epoch + i * 25);
|
|
|
|
if (*distanceTraveled < 1.0f) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, *distanceTraveled * 255);
|
|
|
|
// Needed to match.
|
|
if (!this) {}
|
|
|
|
aux = 1.0f - (*distanceTraveled * *distanceTraveled);
|
|
|
|
Matrix_Mult(&player->mf_9E0, MTXMODE_NEW);
|
|
|
|
Matrix_Translate(initialPositions->x * ((this->dx * aux) + (1.0f - this->dx)),
|
|
initialPositions->y * (1.0f - *distanceTraveled) + 320.0f,
|
|
initialPositions->z * (1.0f - *distanceTraveled) + -20.0f, MTXMODE_APPLY);
|
|
|
|
Matrix_Scale(*distanceTraveled * this->scalingFactor, *distanceTraveled * this->scalingFactor,
|
|
*distanceTraveled * this->scalingFactor, MTXMODE_APPLY);
|
|
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
|
|
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(gfxCtx),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gEffSparklesDL));
|
|
}
|
|
|
|
FrameInterpolation_RecordCloseChild();
|
|
|
|
initialPositions++;
|
|
distanceTraveled++;
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx);
|
|
}
|
|
|
|
void EffDust_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
|
EffDust* this = (EffDust*)thisx;
|
|
|
|
this->drawFunc(thisx, globalCtx);
|
|
}
|