Shipwright/soh/src/overlays/actors/ovl_En_G_Switch/z_en_g_switch.c

611 lines
24 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* File: z_en_g_switch.c
* Overlay: ovl_En_G_Switch
* Description: Silver rupees, shooting gallery targets, and horseback archery pots
*/
#include "z_en_g_switch.h"
#include "vt.h"
#include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h"
#include "overlays/effects/ovl_Effect_Ss_Kakera/z_eff_ss_kakera.h"
#include "overlays/effects/ovl_Effect_Ss_HitMark/z_eff_ss_hitmark.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_tsubo/object_tsubo.h"
#include "objects/object_gi_rupy/object_gi_rupy.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
/* 0 */ MOVE_TARGET,
/* 1 */ MOVE_HOME
} GSwitchMoveState;
void EnGSwitch_Init(Actor* thisx, GlobalContext* globalCtx);
void EnGSwitch_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnGSwitch_Update(Actor* thisx, GlobalContext* globalCtx);
void EnGSwitch_DrawRupee(Actor* thisx, GlobalContext* globalCtx);
void EnGSwitch_DrawPot(Actor* thisx, GlobalContext* globalCtx);
void EnGSwitch_SilverRupeeTracker(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_SilverRupeeIdle(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_WaitForObject(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_SilverRupeeCollected(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_GalleryRupee(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_ArcheryPot(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_Kill(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_SpawnEffects(EnGSwitch* this, Vec3f* pos, s16 scale, s16 colorIdx);
void EnGSwitch_UpdateEffects(EnGSwitch* this, GlobalContext* globalCtx);
void EnGSwitch_DrawEffects(EnGSwitch* this, GlobalContext* globalCtx);
static s16 sCollectedCount = 0;
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK2,
{ 0x00000000, 0x00, 0x00 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ 13, 40, 0, { 0, 0, 0 } },
};
// Unused, but probably intended to be this
static s16 sRupeeTypes[] = {
ITEM00_RUPEE_GREEN, ITEM00_RUPEE_BLUE, ITEM00_RUPEE_RED, ITEM00_RUPEE_ORANGE, ITEM00_RUPEE_PURPLE,
};
const ActorInit En_G_Switch_InitVars = {
ACTOR_EN_G_SWITCH,
ACTORCAT_PROP,
FLAGS,
OBJECT_GAMEPLAY_KEEP,
sizeof(EnGSwitch),
(ActorFunc)EnGSwitch_Init,
(ActorFunc)EnGSwitch_Destroy,
(ActorFunc)EnGSwitch_Update,
NULL,
NULL,
};
void EnGSwitch_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnGSwitch* this = (EnGSwitch*)thisx;
this->type = (this->actor.params >> 0xC) & 0xF;
this->switchFlag = this->actor.params & 0x3F;
this->numEffects = ARRAY_COUNT(this->effects);
// "index"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ インデックス ☆☆☆☆☆ %x\n" VT_RST, this->type);
// "save"
osSyncPrintf(VT_FGCOL(YELLOW) "☆☆☆☆☆ セーブ\t ☆☆☆☆☆ %x\n" VT_RST, this->switchFlag);
switch (this->type) {
case ENGSWITCH_SILVER_TRACKER:
osSyncPrintf("\n\n");
// "parent switch spawn"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 親スイッチ発生 ☆☆☆☆☆ %x\n" VT_RST, this->actor.params);
sCollectedCount = 0;
this->silverCount = this->actor.params >> 6;
this->silverCount &= 0x3F;
// "maximum number of checks"
osSyncPrintf(VT_FGCOL(PURPLE) "☆☆☆☆☆ 最大チェック数 ☆☆☆☆☆ %d\n" VT_RST, this->silverCount);
osSyncPrintf("\n\n");
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
// This is a reference to Hokuto no Ken
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ ☆☆☆☆☆ %d\n" VT_RST, this->switchFlag);
Actor_Kill(&this->actor);
} else {
this->actionFunc = EnGSwitch_SilverRupeeTracker;
}
break;
case ENGSWITCH_SILVER_RUPEE:
osSyncPrintf("\n\n");
// "child switch spawn"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 子スイッチ発生 ☆☆☆☆☆ %x\n" VT_RST, this->actor.params);
this->colorIdx = 5;
this->numEffects = 20;
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
this->actor.draw = EnGSwitch_DrawRupee;
this->actor.shape.yOffset = 700.0f;
if (CVar_GetS32("gNewDrops", 0) !=0) {
this->actor.shape.yOffset = 35.0f;
} else {
this->actor.shape.yOffset = 700.0f;
}
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ ☆☆☆☆☆ %d\n" VT_RST, this->switchFlag);
Actor_Kill(&this->actor);
} else {
if (CVar_GetS32("gNewDrops", 0) !=0) {
Actor_SetScale(&this->actor, 0.6f);
} else {
Actor_SetScale(&this->actor, 0.03f);
}
this->actionFunc = EnGSwitch_SilverRupeeIdle;
}
break;
case ENGSWITCH_ARCHERY_POT:
osSyncPrintf("\n\n");
// "Horseback archery destructible pot"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ やぶさめぶち抜き壷 ☆☆☆☆☆ \n" VT_RST);
this->actor.gravity = -3.0f;
this->colorIdx = Rand_ZeroFloat(2.99f);
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
this->actor.scale.x = 0.25f;
this->actor.scale.y = 0.45f;
this->actor.scale.z = 0.25f;
this->collider.info.bumper.dmgFlags = 0x1F820;
this->objId = OBJECT_TSUBO;
this->objIndex = Object_GetIndex(&globalCtx->objectCtx, this->objId);
if (this->objIndex < 0) {
Actor_Kill(&this->actor);
// "what?"
osSyncPrintf(VT_FGCOL(PURPLE) " なにみの? %d\n" VT_RST "\n", this->objIndex);
// "bank is funny"
osSyncPrintf(VT_FGCOL(CYAN) " バンクおかしいしぞ!%d\n" VT_RST "\n", this->actor.params);
}
this->collider.dim.radius = 24;
this->collider.dim.height = 74;
this->collider.dim.yShift = 0;
this->actionFunc = EnGSwitch_WaitForObject;
break;
case ENGSWITCH_TARGET_RUPEE:
if (CVar_GetS32("gNewDrops", 0) !=0) {
this->actor.shape.yOffset = 35.0f;
Actor_SetScale(&this->actor, 0.9f);
} else {
this->actor.shape.yOffset = 700.0f;
Actor_SetScale(&this->actor, 0.05f);
}
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
this->actor.draw = EnGSwitch_DrawRupee;
this->collider.dim.radius = 20;
this->collider.dim.height = 60;
this->collider.dim.yShift = 5;
this->actionFunc = EnGSwitch_GalleryRupee;
break;
}
}
void EnGSwitch_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnGSwitch* this = (EnGSwitch*)thisx;
Collider_DestroyCylinder(globalCtx, &this->collider);
}
void EnGSwitch_Break(EnGSwitch* this, GlobalContext* globalCtx) {
Vec3f randPos;
Vec3f hitPos;
Vec3f accel = { 0.0f, 0.0f, 0.0f };
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
s32 i;
randPos.x = this->actor.world.pos.x + Rand_CenteredFloat(40.0f);
randPos.y = this->actor.world.pos.y + 30.0f + Rand_CenteredFloat(35.0f);
randPos.z = this->actor.world.pos.z + Rand_CenteredFloat(40.0f);
hitPos.x = this->collider.info.bumper.hitPos.x;
hitPos.y = this->collider.info.bumper.hitPos.y;
hitPos.z = this->collider.info.bumper.hitPos.z;
EffectSsHitMark_SpawnCustomScale(globalCtx, EFFECT_HITMARK_WHITE, 700, &hitPos);
if (this->type == ENGSWITCH_ARCHERY_POT) {
velocity.y = 15.0f;
EffectSsExtra_Spawn(globalCtx, &hitPos, &velocity, &accel, 5, 2);
}
if (this->type == ENGSWITCH_TARGET_RUPEE) {
for (i = 0; i < this->numEffects; i++) {
EnGSwitch_SpawnEffects(this, &randPos, 100, this->colorIdx);
}
}
}
void EnGSwitch_WaitForObject(EnGSwitch* this, GlobalContext* globalCtx) {
if (Object_IsLoaded(&globalCtx->objectCtx, this->objIndex)) {
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->objIndex].segment);
this->actor.objBankIndex = this->objIndex;
this->actor.draw = EnGSwitch_DrawPot;
this->actionFunc = EnGSwitch_ArcheryPot;
}
}
void EnGSwitch_SilverRupeeTracker(EnGSwitch* this, GlobalContext* globalCtx) {
static s8 majorScale[] = { 0, 2, 4, 5, 7 };
if (this->noteIndex < sCollectedCount) {
if (sCollectedCount < 5) {
// "sound?"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 音? ☆☆☆☆☆ %d\n" VT_RST, this->noteIndex);
Audio_PlaySoundTransposed(&D_801333D4, NA_SE_EV_FIVE_COUNT_LUPY, majorScale[this->noteIndex]);
this->noteIndex = sCollectedCount;
}
}
if (sCollectedCount >= this->silverCount) {
// "It is now the end of the century."
// This another reference to Hokuto no Ken.
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 時はまさに世紀末〜 ☆☆☆☆☆ %d\n" VT_RST, this->switchFlag);
// "Last!"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ らすとぉ! ☆☆☆☆☆ \n" VT_RST);
if ((globalCtx->sceneNum == SCENE_MEN) && (this->actor.room == 2)) {
Flags_SetTempClear(globalCtx, this->actor.room);
} else {
func_80078884(NA_SE_SY_CORRECT_CHIME);
Flags_SetSwitch(globalCtx, this->switchFlag);
}
func_80078884(NA_SE_SY_GET_RUPY);
Actor_Kill(&this->actor);
}
}
void EnGSwitch_SilverRupeeIdle(EnGSwitch* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
this->actor.shape.rot.y += 0x800;
if (this->actor.xyzDistToPlayerSq < 900.0f) {
Rupees_ChangeBy(5);
sCollectedCount++;
func_80078884(NA_SE_SY_GET_RUPY);
this->actor.world.pos = player->actor.world.pos;
this->actor.world.pos.y += 40.0f;
if (LINK_IS_ADULT) {
this->actor.world.pos.y += 20.0f;
}
this->actor.gravity = 0.0f;
this->killTimer = 15;
this->actionFunc = EnGSwitch_SilverRupeeCollected;
}
}
void EnGSwitch_SilverRupeeCollected(EnGSwitch* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
this->actor.shape.rot.y += 0x3C0;
if (this->killTimer == 0) {
Actor_Kill(&this->actor);
return;
}
this->actor.world.pos = player->actor.world.pos;
this->actor.world.pos.y =
player->actor.world.pos.y + 40.0f + (this->killTimer * 0.3f) * Math_SinS(this->killTimer * 0x3A98);
if (LINK_IS_ADULT) {
this->actor.world.pos.y += 20.0f;
}
}
void EnGSwitch_GalleryRupee(EnGSwitch* this, GlobalContext* globalCtx) {
EnSyatekiItm* gallery;
this->actor.shape.rot.y += 0x3C0;
if (this->delayTimer == 0) {
switch (this->moveMode) {
case GSWITCH_THROW:
Actor_MoveForward(&this->actor);
if ((this->actor.velocity.y < 0.0f) && (this->actor.world.pos.y < (this->actor.home.pos.y - 50.0f))) {
gallery = ((EnSyatekiItm*)this->actor.parent);
this->actor.velocity.y = 0.0f;
this->actor.gravity = 0.0f;
if (gallery->actor.update != NULL) {
gallery->targetState[this->index] = ENSYATEKIHIT_MISS;
}
Actor_Kill(&this->actor);
}
break;
case GSWITCH_LEFT:
func_8002D7EC(&this->actor);
if ((this->actor.velocity.x < 0.0f) && (this->actor.world.pos.x < this->targetPos.x)) {
gallery = ((EnSyatekiItm*)this->actor.parent);
if (gallery->actor.update != NULL) {
gallery->targetState[this->index] = ENSYATEKIHIT_MISS;
}
Actor_Kill(&this->actor);
}
break;
case GSWITCH_RIGHT:
func_8002D7EC(&this->actor);
if (this->actor.world.pos.x > this->targetPos.x) {
gallery = ((EnSyatekiItm*)this->actor.parent);
if (gallery->actor.update != NULL) {
gallery->targetState[this->index] = ENSYATEKIHIT_MISS;
}
Actor_Kill(&this->actor);
}
break;
default:
switch (this->moveState) {
case MOVE_TARGET:
if ((fabsf(this->actor.world.pos.x - this->targetPos.x) > 5.0f) ||
(fabsf(this->actor.world.pos.y - this->targetPos.y) > 5.0f)) {
Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.3f, 30.0f);
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.3f, 30.0f);
} else {
this->moveState = MOVE_HOME;
this->waitTimer = 60;
}
break;
case MOVE_HOME:
if (this->waitTimer == 0) {
if ((fabsf(this->actor.world.pos.x - this->actor.home.pos.x) > 5.0f) ||
(fabsf(this->actor.world.pos.y - this->actor.home.pos.y) > 5.0f)) {
Math_ApproachF(&this->actor.world.pos.x, this->actor.home.pos.x, 0.3f, 30.0f);
Math_ApproachF(&this->actor.world.pos.y, this->actor.home.pos.y, 0.3f, 30.0f);
} else {
gallery = ((EnSyatekiItm*)this->actor.parent);
if (gallery->actor.update != NULL) {
gallery->targetState[this->index] = ENSYATEKIHIT_MISS;
}
Actor_Kill(&this->actor);
}
}
break;
}
break;
}
if ((this->collider.base.acFlags & AC_HIT) || BREG(8)) {
gallery = ((EnSyatekiItm*)this->actor.parent);
this->collider.base.acFlags &= ~AC_HIT;
if (gallery->actor.update != NULL) {
gallery->hitCount++;
gallery->targetState[this->index] = ENSYATEKIHIT_HIT;
func_80078884(NA_SE_EV_HIT_SOUND);
func_80078884(NA_SE_SY_GET_RUPY);
// "Yeah !"
osSyncPrintf(VT_FGCOL(YELLOW) "☆☆☆☆☆ いぇぇーす!HIT!! ☆☆☆☆☆ %d\n" VT_RST, gallery->hitCount);
EnGSwitch_Break(this, globalCtx);
this->killTimer = 50;
this->broken = true;
this->actionFunc = EnGSwitch_Kill;
}
}
}
}
void EnGSwitch_ArcheryPot(EnGSwitch* this, GlobalContext* globalCtx) {
s32 i;
s16 angle;
Vec3f* thisPos = &this->actor.world.pos;
this->actor.shape.rot.y += 0x3C0;
if (this->collider.base.acFlags & AC_HIT) {
this->collider.base.acFlags &= ~AC_HIT;
for (i = 0, angle = 0; i < 30; i++, angle += 0x4E20) {
Vec3f pos;
Vec3f vel;
f32 sn = Math_SinS(angle);
f32 cs = Math_CosS(angle);
f32 rand;
s32 phi_s0;
s32 scale;
s32 pad;
pos.x = sn * 8.0f;
pos.y = 10.0f + Rand_CenteredFloat(5.0f);
pos.z = cs * 8.0f;
vel.x = pos.x / 2.0f;
vel.y = 10.0f + Rand_ZeroOne() * 15.0f;
vel.z = pos.z / 2.0f;
pos.x += thisPos->x;
pos.y += thisPos->y;
pos.z += thisPos->z;
rand = Rand_ZeroOne();
if (rand < 0.2f) {
phi_s0 = 0x60;
} else if (rand < 0.6f) {
phi_s0 = 0x40;
} else {
phi_s0 = 0x20;
}
scale = 30.0f + Rand_ZeroOne() * 130.0f;
EffectSsKakera_Spawn(globalCtx, &pos, &vel, thisPos, -240, phi_s0, 10, 10, 0, scale, 0, 0x20, 60,
KAKERA_COLOR_NONE, OBJECT_TSUBO, object_tsubo_DL_001960);
}
func_80033480(globalCtx, thisPos, 30.0f, 4, 20, 50, 0);
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, thisPos, 40, NA_SE_EV_POT_BROKEN);
EnGSwitch_Break(this, globalCtx);
this->killTimer = 50;
this->broken = true;
this->actionFunc = EnGSwitch_Kill;
}
}
void EnGSwitch_Kill(EnGSwitch* this, GlobalContext* globalCtx) {
if (this->killTimer == 0) {
Actor_Kill(&this->actor);
}
}
void EnGSwitch_Update(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnGSwitch* this = (EnGSwitch*)thisx;
this->actionFunc(this, globalCtx);
if (this->killTimer != 0) {
this->killTimer--;
}
if (this->waitTimer != 0) {
this->waitTimer--;
}
if (this->delayTimer != 0) {
this->delayTimer--;
}
if ((this->type != ENGSWITCH_SILVER_TRACKER) && (this->type != ENGSWITCH_SILVER_RUPEE) &&
(this->type != ENGSWITCH_TARGET_RUPEE)) {
Actor_MoveForward(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 0x1C);
}
if (this->actor.draw != NULL) {
if (this->type == ENGSWITCH_TARGET_RUPEE) {
EnGSwitch_UpdateEffects(this, globalCtx);
}
if ((this->actionFunc != EnGSwitch_Kill) && (this->actionFunc != EnGSwitch_SilverRupeeIdle)) {
Collider_UpdateCylinder(&this->actor, &this->collider);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
}
if (BREG(0) && (this->type == ENGSWITCH_SILVER_TRACKER)) {
DebugDisplay_AddObject(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f, 1.0f,
1.0f, 255, 0, 0, 255, 4, globalCtx->state.gfxCtx);
}
}
void EnGSwitch_DrawPot(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnGSwitch* this = (EnGSwitch*)thisx;
if (!this->broken) {
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, object_tsubo_DL_0017C0);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
}
static void* sRupeeTextures[] = {
gRupeeGreenTex, gRupeeBlueTex, gRupeeRedTex, gRupeePinkTex, gRupeeOrangeTex, gRupeeSilverTex,
};
static void* sRupeeTexturesNew[] = {
GID_RUPEE_GREEN, GID_RUPEE_BLUE, GID_RUPEE_RED, GID_RUPEE_PURPLE, GID_RUPEE_GOLD,
};
void EnGSwitch_DrawRupee(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnGSwitch* this = (EnGSwitch*)thisx;
if (!this->broken) {
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
func_8002EBCC(&this->actor, globalCtx, 0);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (CVar_GetS32("gNewDrops", 0) !=0) {
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD);
if (this->type == ENGSWITCH_TARGET_RUPEE) {
GetItem_Draw(globalCtx, sRupeeTexturesNew[this->colorIdx]);
} else {
gsDPSetGrayscaleColor(POLY_OPA_DISP++, 255, 255, 255, 255);
gsSPGrayscale(POLY_OPA_DISP++, true);
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gGiRupeeInnerDL);
gSPDisplayList(POLY_OPA_DISP++, gGiGoldRupeeInnerColorDL);
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gGiRupeeOuterDL);
gSPDisplayList(POLY_OPA_DISP++, gGiGoldRupeeOuterColorDL);
gsSPGrayscale(POLY_OPA_DISP++, false);
}
} else {
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sRupeeTextures[this->colorIdx]));
gSPDisplayList(POLY_OPA_DISP++, gRupeeDL);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
if (this->type == ENGSWITCH_TARGET_RUPEE) {
EnGSwitch_DrawEffects(this, globalCtx);
}
}
void EnGSwitch_SpawnEffects(EnGSwitch* this, Vec3f* pos, s16 scale, s16 colorIdx) {
EnGSwitchEffect* effect = this->effects;
s16 i;
for (i = 0; i < this->numEffects; i++, effect++) {
if (!effect->flag) {
Vec3f baseVel;
f32 pitch;
f32 yaw;
effect->epoch++;
effect->pos = *pos;
effect->scale = scale;
effect->colorIdx = colorIdx;
effect->timer = 30;
effect->rot.x = effect->rot.y = effect->rot.z = 0.0f;
pitch = Rand_CenteredFloat(1000.0f) - 13000.0f;
yaw = Rand_CenteredFloat(65535.0f);
Matrix_RotateY(yaw, MTXMODE_NEW);
Matrix_RotateX(pitch, MTXMODE_APPLY);
baseVel.x = baseVel.y = 0.0f;
baseVel.z = 20.0f;
Matrix_MultVec3f(&baseVel, &effect->velocity);
effect->flag = true;
return;
}
}
}
void EnGSwitch_UpdateEffects(EnGSwitch* this, GlobalContext* globalCtx) {
Vec3f temp;
s16 i;
EnGSwitchEffect* effect = this->effects;
for (i = 0; i < this->numEffects; i++, effect++) {
if (effect->flag) {
effect->rot.x += Rand_ZeroOne() * 10.0f + 15.0f;
effect->rot.y += Rand_ZeroOne() * 10.0f + 15.0f;
effect->rot.z += Rand_ZeroOne() * 10.0f + 15.0f;
temp.x = effect->pos.x + effect->velocity.x;
temp.y = effect->pos.y + effect->velocity.y;
temp.z = effect->pos.z + effect->velocity.z;
Math_ApproachF(&effect->pos.x, temp.x, 0.3f, 30.0f);
Math_ApproachF(&effect->pos.y, temp.y, 0.8f, 250.0f);
Math_ApproachF(&effect->pos.z, temp.z, 0.3f, 30.0f);
Math_ApproachF(&effect->velocity.y, -20.0f, 0.9f, 1.0f);
if (effect->timer != 0) {
effect->timer--;
} else if (effect->scale < 10) {
effect->flag = false;
} else {
effect->scale -= 2;
}
}
}
}
void EnGSwitch_DrawEffects(EnGSwitch* this, GlobalContext* globalCtx) {
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
EnGSwitchEffect* effect = this->effects;
s16 i;
f32 scale;
s32 pad;
OPEN_DISPS(gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
for (i = 0; i < this->numEffects; i++, effect++) {
if (effect->flag) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
scale = effect->scale / 10000.0f;
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
Matrix_RotateX(effect->rot.x, MTXMODE_APPLY);
Matrix_RotateY(effect->rot.y, MTXMODE_APPLY);
Matrix_RotateZ(effect->rot.z, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sRupeeTextures[effect->colorIdx]));
gSPDisplayList(POLY_OPA_DISP++, gRupeeDL);
FrameInterpolation_RecordCloseChild();
}
}
CLOSE_DISPS(gfxCtx);
}