Shipwright/soh/src/overlays/actors/ovl_Obj_Lightswitch/z_obj_lightswitch.c

586 lines
22 KiB
C
Raw Normal View History

/*
* File: z_obj_lightswitch.c
* Overlay: ovl_Obj_Lightswitch
* Description: Sun Emblem Trigger (Spirit Temple)
*/
#include "z_obj_lightswitch.h"
#include "vt.h"
#include "overlays/actors/ovl_Obj_Oshihiki/z_obj_oshihiki.h"
#include "objects/object_lightswitch/object_lightswitch.h"
#define FLAGS ACTOR_FLAG_4
typedef enum {
/* 0x00 */ FACE_EYES_CLOSED,
/* 0x01 */ FACE_EYES_OPEN,
/* 0x02 */ FACE_EYES_OPEN_SMILING
} FaceTextureIndex;
void ObjLightswitch_Init(Actor* thisx, GlobalContext* globalCtx);
void ObjLightswitch_Destroy(Actor* thisx, GlobalContext* globalCtx);
void ObjLightswitch_Update(Actor* thisx, GlobalContext* globalCtx);
void ObjLightswitch_Draw(Actor* thisx, GlobalContext* globalCtx);
void ObjLightswitch_SetupOff(ObjLightswitch* this);
void ObjLightswitch_Off(ObjLightswitch* this, GlobalContext* globalCtx);
void ObjLightswitch_SetupTurnOn(ObjLightswitch* this);
void ObjLightswitch_TurnOn(ObjLightswitch* this, GlobalContext* globalCtx);
void ObjLightswitch_SetupOn(ObjLightswitch* this);
void ObjLightswitch_On(ObjLightswitch* this, GlobalContext* globalCtx);
void ObjLightswitch_SetupTurnOff(ObjLightswitch* this);
void ObjLightswitch_TurnOff(ObjLightswitch* this, GlobalContext* globalCtx);
void ObjLightswitch_SetupDisappearDelay(ObjLightswitch* this);
void ObjLightswitch_DisappearDelay(ObjLightswitch* this, GlobalContext* globalCtx);
void ObjLightswitch_SetupDisappear(ObjLightswitch* this);
void ObjLightswitch_Disappear(ObjLightswitch* this, GlobalContext* globalCtx);
const ActorInit Obj_Lightswitch_InitVars = {
ACTOR_OBJ_LIGHTSWITCH,
ACTORCAT_SWITCH,
FLAGS,
OBJECT_LIGHTSWITCH,
sizeof(ObjLightswitch),
(ActorFunc)ObjLightswitch_Init,
(ActorFunc)ObjLightswitch_Destroy,
(ActorFunc)ObjLightswitch_Update,
(ActorFunc)ObjLightswitch_Draw,
NULL,
};
static ColliderJntSphElementInit sColliderJntSphElementInit[] = {
{
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x00200000, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_ON,
},
{ 0, { { 0, 0, 0 }, 19 }, 100 },
},
};
static ColliderJntSphInit sColliderJntSphInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_JNTSPH,
},
1,
sColliderJntSphElementInit,
};
// Collider info used for "Sunlight Arrows"
static ColliderJntSphElementInit sColliderLightArrowElementInit[] = {
{
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x00202000, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_ON,
},
{ 0, { { 0, 0, 0 }, 19 }, 100 },
},
};
// Sphere collider used for "Sunlight Arrows"
static ColliderJntSphInit sColliderLightArrowInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_JNTSPH,
},
1,
sColliderLightArrowElementInit,
};
bool sunSwitchActivatedByLightArrow = false;
bool sunLightArrowsEnabledOnSunSwitchLoad = false;
static CollisionCheckInfoInit sColChkInfoInit = { 0, 12, 60, MASS_IMMOVABLE };
static void* sFaceTextures[] = { object_lightswitch_Tex_000C20, object_lightswitch_Tex_000420,
object_lightswitch_Tex_001420 };
static Vec3f D_80B97F68 = { -1707.0f, 843.0f, -180.0f };
static Vec3f D_80B97F74 = { 0.0f, 0.0f, 0.0f };
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneScale, 500, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP),
};
void ObjLightswitch_InitCollider(ObjLightswitch* this, GlobalContext* globalCtx) {
s32 pad;
// Initialize this with the sun switch, so it can't be affected by toggling while the actor is loaded
sunLightArrowsEnabledOnSunSwitchLoad = (CVar_GetS32("gSunlightArrows", 0));
Collider_InitJntSph(globalCtx, &this->collider);
// If "Sunlight Arrows" is enabled, set up the collider to allow Light Arrow hits
if (sunLightArrowsEnabledOnSunSwitchLoad) {
Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sColliderLightArrowInit, this->colliderItems);
} else {
Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sColliderJntSphInit, this->colliderItems);
}
Matrix_SetTranslateRotateYXZ(this->actor.world.pos.x,
this->actor.world.pos.y + (this->actor.shape.yOffset * this->actor.scale.y),
this->actor.world.pos.z, &this->actor.shape.rot);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
Collider_UpdateSpheres(0, &this->collider);
}
void ObjLightswitch_SetSwitchFlag(ObjLightswitch* this, GlobalContext* globalCtx) {
Actor* thisx = &this->actor; // required
s32 type;
if (!Flags_GetSwitch(globalCtx, this->actor.params >> 8 & 0x3F)) {
type = this->actor.params >> 4 & 3;
Flags_SetSwitch(globalCtx, this->actor.params >> 8 & 0x3F);
if (type == OBJLIGHTSWITCH_TYPE_1) {
OnePointCutscene_AttentionSetSfx(globalCtx, thisx, NA_SE_SY_TRE_BOX_APPEAR);
} else if (type == OBJLIGHTSWITCH_TYPE_BURN) {
OnePointCutscene_AttentionSetSfx(globalCtx, thisx, NA_SE_SY_ERROR);
} else {
OnePointCutscene_AttentionSetSfx(globalCtx, thisx, NA_SE_SY_CORRECT_CHIME);
}
}
}
void ObjLightswitch_ClearSwitchFlag(ObjLightswitch* this, GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, this->actor.params >> 8 & 0x3F)) {
Flags_UnsetSwitch(globalCtx, this->actor.params >> 8 & 0x3F);
if ((this->actor.params >> 4 & 3) == OBJLIGHTSWITCH_TYPE_1) {
OnePointCutscene_AttentionSetSfx(globalCtx, &this->actor, NA_SE_SY_TRE_BOX_APPEAR);
}
}
}
void ObjLightswitch_SpawnDisappearEffects(ObjLightswitch* this, GlobalContext* globalCtx) {
Vec3f pos;
f32 s = Math_SinS(this->actor.shape.rot.y);
f32 c = Math_CosS(this->actor.shape.rot.y);
f32 x;
f32 y;
f32 z;
s32 pad;
if (this->alpha >= (100 << 6)) {
x = (CLAMP_MAX((1.0f - 1.0f / (255 << 6) * this->alpha) * 400.0f, 60.0f) - 30.0f + 30.0f) * Rand_ZeroOne();
y = x - 30.0f;
if (x > 30.0f) {
x = 30.0f;
} else {
x = 900.0f - (y * y);
if (x < 100.0f) {
x = 100.0f;
}
x = sqrtf(x);
}
x = 2.0f * (x * (Rand_ZeroOne() - 0.5f));
z = (30.0f - fabsf(x)) * 0.5f + 10.0f * Rand_ZeroOne();
pos.x = this->actor.world.pos.x + ((z * s) + (x * c));
pos.y = this->actor.world.pos.y + y + 10.0f;
pos.z = this->actor.world.pos.z + ((z * c) - (x * s));
EffectSsDeadDb_Spawn(globalCtx, &pos, &D_80B97F74, &D_80B97F74, 100, 0, 255, 255, 160, 160, 255, 0, 0, 1, 9,
true);
}
}
void ObjLightswitch_Init(Actor* thisx, GlobalContext* globalCtx) {
ObjLightswitch* this = (ObjLightswitch*)thisx;
s32 switchFlagSet = Flags_GetSwitch(globalCtx, this->actor.params >> 8 & 0x3F);
s32 removeSelf = false;
Actor_ProcessInitChain(&this->actor, sInitChain);
Actor_SetFocus(&this->actor, 0.0f);
if (switchFlagSet) {
if ((this->actor.params >> 4 & 3) == OBJLIGHTSWITCH_TYPE_BURN) {
removeSelf = true;
} else {
ObjLightswitch_SetupOn(this);
}
} else {
ObjLightswitch_SetupOff(this);
}
if ((this->actor.params & 1) == 1) {
if (switchFlagSet) {
Math_Vec3f_Copy(&this->actor.world.pos, &D_80B97F68);
Math_Vec3f_Copy(&this->actor.home.pos, &D_80B97F68);
}
this->actor.shape.rot.x = -0x4000;
this->actor.shape.rot.z = 0;
this->actor.world.rot.x = this->actor.home.rot.x = this->actor.shape.rot.x;
this->actor.world.rot.z = this->actor.home.rot.z = this->actor.shape.rot.z;
this->actor.flags |= ACTOR_FLAG_5;
if (Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_OBJ_OSHIHIKI,
this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, 0,
this->actor.home.rot.y, 0, (0xFF << 8) | PUSHBLOCK_SMALL_START_ON) == NULL) {
osSyncPrintf(VT_COL(RED, WHITE));
// "Push-pull block occurrence failure"
osSyncPrintf("押引ブロック発生失敗(%s %d)(arg_data 0x%04x)\n", __FILE__, __LINE__,
this->actor.params);
osSyncPrintf(VT_RST);
removeSelf = true;
}
}
ObjLightswitch_InitCollider(this, globalCtx);
CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
if (removeSelf) {
Actor_Kill(&this->actor);
}
// "Light switch"
osSyncPrintf("(光スイッチ)(arg_data 0x%04x)\n", this->actor.params);
}
void ObjLightswitch_Destroy(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
ObjLightswitch* this = (ObjLightswitch*)thisx;
// Unset the switch flag on room exit to prevent the rock in the wall from
// vanishing on its own after activating the sun switch by Light Arrow
// Also prevents the cobra mirror from rotating to face the sun on its own
// Makes sun switches temporary when activated by Light Arrows (will turn off on room exit)
if (sunSwitchActivatedByLightArrow) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
case OBJLIGHTSWITCH_TYPE_2:
case OBJLIGHTSWITCH_TYPE_1:
// Except for this one, because we want the chain platform to stay down for good
if (this->actor.room != 25) {
Flags_UnsetSwitch(globalCtx, this->actor.params >> 8 & 0x3F);
}
sunSwitchActivatedByLightArrow = false;
break;
case OBJLIGHTSWITCH_TYPE_BURN:
break;
}
}
Collider_DestroyJntSph(globalCtx, &this->collider);
}
void ObjLightswitch_SetupOff(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_Off;
this->faceTextureIndex = FACE_EYES_CLOSED;
this->color[0] = 155 << 6;
this->color[1] = 125 << 6;
this->color[2] = 255 << 6;
this->alpha = 255 << 6;
if (sunLightArrowsEnabledOnSunSwitchLoad) {
sunSwitchActivatedByLightArrow = false;
}
}
// A Sun Switch that is currently turned off
void ObjLightswitch_Off(ObjLightswitch* this, GlobalContext* globalCtx) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
case OBJLIGHTSWITCH_TYPE_2:
if (this->collider.base.acFlags & AC_HIT) {
ObjLightswitch_SetupTurnOn(this);
ObjLightswitch_SetSwitchFlag(this, globalCtx);
// Remember if we've been activated by a Light Arrow, so we can
// prevent the switch from immediately turning back off
if (sunLightArrowsEnabledOnSunSwitchLoad) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id == ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = true;
}
}
}
break;
case OBJLIGHTSWITCH_TYPE_1:
if ((this->collider.base.acFlags & AC_HIT) && !(this->prevFrameACflags & AC_HIT)) {
ObjLightswitch_SetupTurnOn(this);
ObjLightswitch_SetSwitchFlag(this, globalCtx);
}
break;
case OBJLIGHTSWITCH_TYPE_BURN:
if (this->collider.base.acFlags & AC_HIT) {
ObjLightswitch_SetupDisappearDelay(this);
ObjLightswitch_SetSwitchFlag(this, globalCtx);
}
break;
}
}
void ObjLightswitch_SetupTurnOn(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_TurnOn;
this->toggleDelay = 100;
this->timer = 0;
this->faceTextureIndex = FACE_EYES_CLOSED;
}
void ObjLightswitch_TurnOn(ObjLightswitch* this, GlobalContext* globalCtx) {
if (func_8005B198() == this->actor.category || this->toggleDelay <= 0) {
if (this->timer == 0) {
Audio_PlayActorSound2(&this->actor, NA_SE_EV_TRIFORCE_FLASH);
}
this->timer++;
Math_StepToS(&this->flameRingRotSpeed, -0xAA, 0xA);
this->flameRingRot += this->flameRingRotSpeed;
this->color[0] = this->timer * (((255 - 155) << 6) / 20) + (155 << 6);
this->color[1] = this->timer * (((255 - 125) << 6) / 20) + (125 << 6);
if (this->timer >= 20) {
ObjLightswitch_SetupOn(this);
} else if (this->timer == 15) {
this->faceTextureIndex = FACE_EYES_OPEN;
Audio_PlayActorSound2(&this->actor, NA_SE_EV_FOOT_SWITCH);
}
}
}
void ObjLightswitch_SetupOn(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_On;
this->faceTextureIndex = FACE_EYES_OPEN_SMILING;
this->color[0] = 255 << 6;
this->color[1] = 255 << 6;
this->color[2] = 255 << 6;
this->alpha = 255 << 6;
this->flameRingRotSpeed = -0xAA;
this->timer = 0;
}
// A Sun Switch that is currently turned on
void ObjLightswitch_On(ObjLightswitch* this, GlobalContext* globalCtx) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
if (!Flags_GetSwitch(globalCtx, this->actor.params >> 8 & 0x3F)) {
ObjLightswitch_SetupTurnOff(this);
}
// If hit by sunlight after already being turned on, then behave as if originally activated by sunlight
if (sunLightArrowsEnabledOnSunSwitchLoad && (this->collider.base.acFlags & AC_HIT)) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id != ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = false;
}
}
break;
case OBJLIGHTSWITCH_TYPE_1:
if (this->collider.base.acFlags & AC_HIT && !(this->prevFrameACflags & AC_HIT)) {
ObjLightswitch_SetupTurnOff(this);
ObjLightswitch_ClearSwitchFlag(this, globalCtx);
}
break;
case OBJLIGHTSWITCH_TYPE_2:
// If hit by sunlight after already being turned on, then behave as if originally activated by sunlight
if (sunLightArrowsEnabledOnSunSwitchLoad && (this->collider.base.acFlags & AC_HIT)) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id != ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = false;
}
}
if (!(this->collider.base.acFlags & AC_HIT)) {
if (this->timer >= 7) {
// If we aren't using Enhanced Light Arrows, let the switch turn off normally
if (!sunSwitchActivatedByLightArrow) {
ObjLightswitch_SetupTurnOff(this);
ObjLightswitch_ClearSwitchFlag(this, globalCtx);
}
} else {
this->timer++;
}
} else {
this->timer = 0;
}
break;
}
this->flameRingRot += this->flameRingRotSpeed;
}
void ObjLightswitch_SetupTurnOff(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_TurnOff;
this->toggleDelay = 100;
this->timer = 20;
this->faceTextureIndex = FACE_EYES_OPEN;
}
void ObjLightswitch_TurnOff(ObjLightswitch* this, GlobalContext* globalCtx) {
if ((this->actor.params >> 4 & 3) != OBJLIGHTSWITCH_TYPE_1 || func_8005B198() == this->actor.category ||
this->toggleDelay <= 0) {
this->timer--;
Math_StepToS(&this->flameRingRotSpeed, 0, 0xA);
this->flameRingRot += this->flameRingRotSpeed;
this->color[0] = this->timer * (((255 - 155) << 6) / 20) + (155 << 6);
this->color[1] = this->timer * (((255 - 125) << 6) / 20) + (125 << 6);
if (this->timer <= 0) {
ObjLightswitch_SetupOff(this);
} else if (this->timer == 15) {
this->faceTextureIndex = FACE_EYES_CLOSED;
Audio_PlayActorSound2(&this->actor, NA_SE_EV_FOOT_SWITCH);
}
}
}
void ObjLightswitch_SetupDisappearDelay(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_DisappearDelay;
this->toggleDelay = 100;
}
void ObjLightswitch_DisappearDelay(ObjLightswitch* this, GlobalContext* globalCtx) {
if (func_8005B198() == this->actor.category || this->toggleDelay <= 0) {
ObjLightswitch_SetupDisappear(this);
}
}
void ObjLightswitch_SetupDisappear(ObjLightswitch* this) {
this->actionFunc = ObjLightswitch_Disappear;
this->alpha = 255 << 6;
}
void ObjLightswitch_Disappear(ObjLightswitch* this, GlobalContext* globalCtx) {
this->alpha -= 200;
ObjLightswitch_SpawnDisappearEffects(this, globalCtx);
if (this->alpha < 0) {
Actor_Kill(&this->actor);
}
}
void ObjLightswitch_Update(Actor* thisx, GlobalContext* globalCtx2) {
ObjLightswitch* this = (ObjLightswitch*)thisx;
GlobalContext* globalCtx = globalCtx2;
if (this->toggleDelay > 0) {
this->toggleDelay--;
}
this->actionFunc(this, globalCtx);
if (this->actor.update != NULL) {
if ((this->actor.params & 1) == 1) {
this->actor.world.pos.x = this->actor.child->world.pos.x;
this->actor.world.pos.y = this->actor.child->world.pos.y + 60.0f;
this->actor.world.pos.z = this->actor.child->world.pos.z;
Actor_SetFocus(&this->actor, 0.0f);
}
this->prevFrameACflags = this->collider.base.acFlags;
this->collider.base.acFlags &= ~AC_HIT;
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
}
void ObjLightswitch_DrawOpa(ObjLightswitch* this, GlobalContext* globalCtx) {
Actor* child;
Vec3f pos;
Vec3s rot;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D18(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_OPA_DISP++, (u8)(this->color[0] >> 6), (u8)(this->color[1] >> 6), (u8)(this->color[2] >> 6),
(u8)(this->alpha >> 6));
gSPSegment(POLY_OPA_DISP++, 0x09, &D_80116280[2]);
if ((this->actor.params & 1) == 1) {
child = this->actor.child;
this->actor.world.pos.x = child->world.pos.x;
this->actor.world.pos.y = child->world.pos.y + 60.0f;
this->actor.world.pos.z = child->world.pos.z;
Math_Vec3f_Copy(&pos, &this->actor.world.pos);
Matrix_SetTranslateRotateYXZ(pos.x, pos.y, pos.z, &this->actor.shape.rot);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
} else {
pos.x = this->actor.world.pos.x;
pos.y = this->actor.world.pos.y + this->actor.shape.yOffset * this->actor.scale.y;
pos.z = this->actor.world.pos.z;
}
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(sFaceTextures[this->faceTextureIndex]));
gSPDisplayList(POLY_OPA_DISP++, object_lightswitch_DL_000260);
rot.x = this->actor.shape.rot.x;
rot.y = this->actor.shape.rot.y;
rot.z = this->actor.shape.rot.z + this->flameRingRot;
Matrix_SetTranslateRotateYXZ(pos.x, pos.y, pos.z, &rot);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, object_lightswitch_DL_000398);
rot.z = this->actor.shape.rot.z - this->flameRingRot;
Matrix_SetTranslateRotateYXZ(pos.x, pos.y, pos.z, &rot);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, object_lightswitch_DL_000408);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void ObjLightswitch_DrawXlu(ObjLightswitch* this, GlobalContext* globalCtx) {
s32 pad;
Vec3f sp68;
Vec3s sp60;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, (u8)(this->color[0] >> 6), (u8)(this->color[1] >> 6), (u8)(this->color[2] >> 6),
(u8)(this->alpha >> 6));
gSPSegment(POLY_XLU_DISP++, 0x09, D_80116280);
sp68.x = this->actor.world.pos.x;
sp68.y = this->actor.world.pos.y + (this->actor.shape.yOffset * this->actor.scale.y);
sp68.z = this->actor.world.pos.z;
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sFaceTextures[this->faceTextureIndex]));
gSPDisplayList(POLY_XLU_DISP++, object_lightswitch_DL_000260);
sp60.x = this->actor.shape.rot.x;
sp60.y = this->actor.shape.rot.y;
sp60.z = this->actor.shape.rot.z + this->flameRingRot;
Matrix_SetTranslateRotateYXZ(sp68.x, sp68.y, sp68.z, &sp60);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, object_lightswitch_DL_000398);
sp60.z = this->actor.shape.rot.z - this->flameRingRot;
Matrix_SetTranslateRotateYXZ(sp68.x, sp68.y, sp68.z, &sp60);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, object_lightswitch_DL_000408);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void ObjLightswitch_Draw(Actor* thisx, GlobalContext* globalCtx) {
ObjLightswitch* this = (ObjLightswitch*)thisx;
s32 alpha = this->alpha >> 6 & 0xFF;
if ((this->actor.params & 1) == 1) {
Collider_UpdateSpheres(0, &this->collider);
}
if ((this->actor.params >> 4 & 3) == OBJLIGHTSWITCH_TYPE_BURN && (alpha > 0 || alpha < 255)) {
ObjLightswitch_DrawXlu(this, globalCtx);
} else {
ObjLightswitch_DrawOpa(this, globalCtx);
}
}