Document object_obj_tokeidai and improve documentation on ovl_Obj_Tokeidai (#569)

* Document object_obj_tokeidai XML

* Change "outer ring" to "minute ring" to better describe what it is

* Rename "sun and moon disk" to "sun and moon panel"

* Preserve ordering

* Standardize on "staircase to rooftop"

* Standardize on calling it "Exterior Gear" to contrast with all the interior stuff

* Lots more documentation

* Make it more obvious that the macros refer to clock time, not regular time

* More documentation and spacing

* Better document counterweight draw

* Respond to Anghelo's and engineer's reviews

* Split tokeidai into separate files

* Revert "Split tokeidai into separate files"

This reverts commit eed1fe5ff6.
This commit is contained in:
Tom Overton 2022-01-30 12:41:21 -08:00 committed by GitHub
parent 5ebc7c0e35
commit 4543b5ade6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 270 additions and 202 deletions

View File

@ -1,59 +1,81 @@
<Root>
<!-- Contains objects related to the Clock Tower and various wall clocks. -->
<File Name="object_obj_tokeidai" Segment="6">
<Texture Name="object_obj_tokeidai_TLUT_000000" OutName="tlut_000000" Format="rgba16" Width="4" Height="4" Offset="0x0" />
<Texture Name="object_obj_tokeidai_TLUT_000020" OutName="tlut_000020" Format="rgba16" Width="4" Height="4" Offset="0x20" />
<Texture Name="object_obj_tokeidai_Tex_000040" OutName="tex_000040" Format="i8" Width="64" Height="64" Offset="0x40" />
<Texture Name="object_obj_tokeidai_Tex_001040" OutName="tex_001040" Format="rgba16" Width="32" Height="32" Offset="0x1040" />
<Texture Name="object_obj_tokeidai_Tex_001840" OutName="tex_001840" Format="rgba16" Width="32" Height="32" Offset="0x1840" />
<Texture Name="object_obj_tokeidai_Tex_002040" OutName="tex_002040" Format="rgba16" Width="32" Height="32" Offset="0x2040" />
<Texture Name="object_obj_tokeidai_Tex_002840" OutName="tex_002840" Format="rgba16" Width="32" Height="32" Offset="0x2840" />
<Texture Name="object_obj_tokeidai_Tex_003040" OutName="tex_003040" Format="rgba16" Width="16" Height="32" Offset="0x3040" />
<Texture Name="object_obj_tokeidai_Tex_003440" OutName="tex_003440" Format="rgba16" Width="8" Height="32" Offset="0x3440" />
<Texture Name="object_obj_tokeidai_Tex_003640" OutName="tex_003640" Format="rgba16" Width="16" Height="16" Offset="0x3640" />
<Texture Name="object_obj_tokeidai_Tex_003840" OutName="tex_003840" Format="rgba16" Width="16" Height="16" Offset="0x3840" />
<Texture Name="object_obj_tokeidai_Tex_003A40" OutName="tex_003A40" Format="rgba16" Width="16" Height="16" Offset="0x3A40" />
<Texture Name="object_obj_tokeidai_Tex_003C40" OutName="tex_003C40" Format="rgba16" Width="16" Height="32" Offset="0x3C40" />
<Texture Name="object_obj_tokeidai_Tex_004040" OutName="tex_004040" Format="rgba16" Width="16" Height="16" Offset="0x4040" />
<Texture Name="object_obj_tokeidai_Tex_004240" OutName="tex_004240" Format="rgba16" Width="32" Height="16" Offset="0x4240" />
<Texture Name="object_obj_tokeidai_Tex_004640" OutName="tex_004640" Format="rgba16" Width="32" Height="16" Offset="0x4640" />
<Texture Name="object_obj_tokeidai_Tex_004A40" OutName="tex_004A40" Format="rgba16" Width="32" Height="16" Offset="0x4A40" />
<Texture Name="object_obj_tokeidai_Tex_004E40" OutName="tex_004E40" Format="rgba16" Width="32" Height="16" Offset="0x4E40" />
<Texture Name="object_obj_tokeidai_Tex_005240" OutName="tex_005240" Format="ci4" Width="64" Height="64" Offset="0x5240" />
<Texture Name="object_obj_tokeidai_Tex_005A40" OutName="tex_005A40" Format="ci4" Width="64" Height="64" Offset="0x5A40" />
<Texture Name="object_obj_tokeidai_Tex_006240" OutName="tex_006240" Format="rgba16" Width="8" Height="8" Offset="0x6240" />
<!-- <Blob Name="object_obj_tokeidai_Blob_0062C0" Size="0x1000" Offset="0x62C0" /> -->
<Texture Name="object_obj_tokeidai_Tex_0072C0" OutName="tex_0072C0" Format="ia8" Width="32" Height="64" Offset="0x72C0" />
<Texture Name="object_obj_tokeidai_Tex_007AC0" OutName="tex_007AC0" Format="i8" Width="32" Height="32" Offset="0x7AC0" />
<Texture Name="object_obj_tokeidai_Tex_007EC0" OutName="tex_007EC0" Format="i4" Width="64" Height="64" Offset="0x7EC0" />
<Texture Name="object_obj_tokeidai_Tex_0086C0" OutName="tex_0086C0" Format="i4" Width="64" Height="64" Offset="0x86C0" />
<Texture Name="object_obj_tokeidai_Tex_008EC0" OutName="tex_008EC0" Format="i4" Width="64" Height="64" Offset="0x8EC0" />
<DList Name="object_obj_tokeidai_DL_009A00" Offset="0x9A00" />
<DList Name="object_obj_tokeidai_DL_009A08" Offset="0x9A08" />
<Texture Name="object_obj_tokeidai_Tex_009B48" OutName="tex_009B48" Format="rgba16" Width="32" Height="32" Offset="0x9B48" />
<Texture Name="object_obj_tokeidai_Tex_00A348" OutName="tex_00A348" Format="i4" Width="64" Height="64" Offset="0xA348" />
<DList Name="object_obj_tokeidai_DL_00B0C0" Offset="0xB0C0" />
<DList Name="object_obj_tokeidai_DL_00B208" Offset="0xB208" />
<TextureAnimation Name="object_obj_tokeidai_Matanimheader_00B4E4" Offset="0xB4E4" />
<DList Name="object_obj_tokeidai_DL_00BA70" Offset="0xBA70" />
<DList Name="object_obj_tokeidai_DL_00BA78" Offset="0xBA78" />
<DList Name="object_obj_tokeidai_DL_00BEE0" Offset="0xBEE0" />
<DList Name="object_obj_tokeidai_DL_00BEE8" Offset="0xBEE8" />
<DList Name="object_obj_tokeidai_DL_00C360" Offset="0xC360" />
<DList Name="object_obj_tokeidai_DL_00C368" Offset="0xC368" />
<DList Name="object_obj_tokeidai_DL_00CF20" Offset="0xCF20" />
<DList Name="object_obj_tokeidai_DL_00CF28" Offset="0xCF28" />
<DList Name="object_obj_tokeidai_DL_00D380" Offset="0xD380" />
<DList Name="object_obj_tokeidai_DL_00D388" Offset="0xD388" />
<DList Name="object_obj_tokeidai_DL_00D8E0" Offset="0xD8E0" />
<DList Name="object_obj_tokeidai_DL_00D8E8" Offset="0xD8E8" />
<Texture Name="object_obj_tokeidai_Tex_00DAC0" OutName="tex_00DAC0" Format="rgba16" Width="16" Height="32" Offset="0xDAC0" />
<DList Name="object_obj_tokeidai_DL_00E810" Offset="0xE810" />
<DList Name="object_obj_tokeidai_DL_00E818" Offset="0xE818" />
<DList Name="object_obj_tokeidai_DL_00F510" Offset="0xF510" />
<DList Name="object_obj_tokeidai_DL_00F518" Offset="0xF518" />
<Texture Name="object_obj_tokeidai_Tex_00F7F8" OutName="tex_00F7F8" Format="rgba16" Width="16" Height="32" Offset="0xF7F8" />
<Texture Name="object_obj_tokeidai_Tex_00FBF8" OutName="tex_00FBF8" Format="rgba16" Width="64" Height="32" Offset="0xFBF8" />
<Texture Name="object_obj_tokeidai_Tex_010BF8" OutName="tex_010BF8" Format="rgba16" Width="64" Height="32" Offset="0x10BF8" />
<Texture Name="object_obj_tokeidai_Tex_011BF8" OutName="tex_011BF8" Format="rgba16" Width="8" Height="8" Offset="0x11BF8" />
<Texture Name="gClockTowerClockFaceTopTLUT" OutName="clock_tower_clock_face_top_tlut" Format="rgba16" Width="4" Height="4" Offset="0x0" />
<Texture Name="gClockTowerClockFaceBottomTLUT" OutName="clock_tower_clock_face_bottom_tlut" Format="rgba16" Width="4" Height="4" Offset="0x20" />
<Texture Name="gClockTowerSpotlightShineTex" OutName="clock_tower_spotlight_shine" Format="i8" Width="64" Height="64" Offset="0x40" />
<!-- Generic brick texture used for multiple pieces of the Clock Tower (counterweight, unused tower wall, staircase to rooftop) -->
<Texture Name="gClockTowerBrickTex" OutName="clock_tower_bricks" Format="rgba16" Width="32" Height="32" Offset="0x1040" />
<Texture Name="gClockTowerCounterweightBeamSide1Tex" OutName="clock_tower_counterweight_beam_side1" Format="rgba16" Width="32" Height="32" Offset="0x1840" />
<Texture Name="gClockTowerCounterweightBeamSide2Tex" OutName="clock_tower_counterweight_beam_side2" Format="rgba16" Width="32" Height="32" Offset="0x2040" />
<Texture Name="gClockTowerExteriorGearFaceTex" OutName="clock_tower_exterior_gear_face" Format="rgba16" Width="32" Height="32" Offset="0x2840" />
<Texture Name="gClockTowerExteriorGearSidesAndMinuteRingBackTex" OutName="clock_tower_exterior_gear_sides_and_minute_ring_back" Format="rgba16" Width="16" Height="32" Offset="0x3040" />
<Texture Name="gClockTowerClockCenterTex" OutName="clock_tower_clock_center" Format="rgba16" Width="8" Height="32" Offset="0x3440" />
<Texture Name="gClockTowerClockCenterSidesTex" OutName="clock_tower_clock_center_sides" Format="rgba16" Width="16" Height="16" Offset="0x3640" />
<Texture Name="gClockTowerHandTex" OutName="clock_tower_hand" Format="rgba16" Width="16" Height="16" Offset="0x3840" />
<Texture Name="gClockTowerSunAndMoonPanelSidesTex" OutName="clock_tower_sun_and_moon_panel_sides" Format="rgba16" Width="16" Height="16" Offset="0x3A40" />
<Texture Name="gClockTowerSunAndMoonPanelMoonTex" OutName="clock_tower_sun_and_moon_panel_moon" Format="rgba16" Width="16" Height="32" Offset="0x3C40" />
<Texture Name="gClockTowerSunAndMoonPanelSunTex" OutName="clock_tower_sun_and_moon_panel_sun" Format="rgba16" Width="16" Height="16" Offset="0x4040" />
<Texture Name="gClockTowerMinuteRingFace1Tex" OutName="clock_tower_minute_ring_face_1" Format="rgba16" Width="32" Height="16" Offset="0x4240" />
<Texture Name="gClockTowerMinuteRingFace2Tex" OutName="clock_tower_minute_ring_face_2" Format="rgba16" Width="32" Height="16" Offset="0x4640" />
<Texture Name="gClockTowerMinuteRingFace3Tex" OutName="clock_tower_minute_ring_face_3" Format="rgba16" Width="32" Height="16" Offset="0x4A40" />
<Texture Name="gClockTowerMinuteRingSidesTex" OutName="clock_tower_minute_ring_sides" Format="rgba16" Width="32" Height="16" Offset="0x4E40" />
<Texture Name="gClockTowerClockFaceTopTex" OutName="clock_tower_clock_face_top" Format="ci4" Width="64" Height="64" Offset="0x5240" />
<Texture Name="gClockTowerClockFaceBottomTex" OutName="clock_tower_clock_face_bottom" Format="ci4" Width="64" Height="64" Offset="0x5A40" />
<Texture Name="gClockTowerClockFacePanelBarTex" OutName="clock_tower_clock_face_panel_bar" Format="rgba16" Width="8" Height="8" Offset="0x6240" />
<Texture Name="gClockTowerUnusedBrickTex" OutName="clock_tower_unused_bricks" Format="rgba16" Width="32" Height="32" Offset="0x62C0" />
<Texture Name="gClockTowerUnusedMaskTex" OutName="clock_tower_unused_mask" Format="i4" Width="64" Height="64" Offset="0x6AC0" />
<Texture Name="gClockTowerSpotlightBeamTex" OutName="clock_tower_spotlight_beam" Format="ia8" Width="32" Height="64" Offset="0x72C0" />
<Texture Name="gClockTowerSpotlightMaskTex" OutName="clock_tower_spotlight_mask" Format="i8" Width="32" Height="32" Offset="0x7AC0" />
<Texture Name="gClockTowerCounterweightMaskTex" OutName="clock_tower_counterweight_mask" Format="i4" Width="64" Height="64" Offset="0x7EC0" />
<Texture Name="gClockTowerUnusedTowerWallMaskTex" OutName="clock_tower_unused_tower_wall_mask" Format="i4" Width="64" Height="64" Offset="0x86C0" />
<Texture Name="gClockTowerStaircaseToRooftopMaskTex" OutName="clock_tower_staircase_to_rooftop_mask" Format="i4" Width="64" Height="64" Offset="0x8EC0" />
<!-- Probably intended to be used as the xluDList for Clock Tower Termina Field Walls -->
<DList Name="gClockTowerUnusedEmpty1DL" Offset="0x9A00" />
<DList Name="gClockTowerTerminaFieldWallsDL" Offset="0x9A08" />
<Texture Name="gClockTowerTerminaFieldWallsBrickTex" OutName="clock_tower_termina_field_walls_brick" Format="rgba16" Width="32" Height="32" Offset="0x9B48" />
<Texture Name="gClockTowerTerminaFieldWallsMask" OutName="clock_tower_termina_field_walls_mask" Format="i4" Width="64" Height="64" Offset="0xA348" />
<DList Name="gClockTowerSpotlightDL" Offset="0xB0C0" />
<DList Name="gClockTowerCounterweightDL" Offset="0xB208" />
<TextureAnimation Name="gClockTowerUnusedTexAnim" Offset="0xB4E4" />
<!-- Probably intended to be used as the xluDList for Clock Tower Exterior Gear -->
<DList Name="gClockTowerUnusedEmpty2DL" Offset="0xBA70" />
<DList Name="gClockTowerExteriorGearDL" Offset="0xBA78" />
<!-- Probably intended to be used as the xluDList for Clock Tower Center and Hand -->
<DList Name="gClockTowerUnusedEmpty3DL" Offset="0xBEE0" />
<DList Name="gClockTowerClockCenterAndHandDL" Offset="0xBEE8" />
<!-- Probably intended to be used as the xluDList for Clock Tower Sun and Moon Panel -->
<DList Name="gClockTowerUnusedEmpty4DL" Offset="0xC360" />
<DList Name="gClockTowerSunAndMoonPanelDL" Offset="0xC368" />
<!-- Probably intended to be used as the xluDList for Clock Tower Minute Ring -->
<DList Name="gClockTowerUnusedEmpty5DL" Offset="0xCF20" />
<DList Name="gClockTowerMinuteRingDL" Offset="0xCF28" />
<!-- Probably intended to be used as the xluDList for Clock Tower Unused Tower Wall -->
<DList Name="gClockTowerUnusedEmpty6DL" Offset="0xD380" />
<DList Name="gClockTowerUnusedTowerWallDL" Offset="0xD388" />
<!-- Used as the xluDList for Staircase to Rooftop -->
<DList Name="gClockTowerEmptyDL" Offset="0xD8E0" />
<DList Name="gClockTowerStaircaseToRooftopDL" Offset="0xD8E8" />
<Texture Name="gClockTowerClockFaceBackTex" OutName="clock_tower_clock_face_back" Format="rgba16" Width="16" Height="32" Offset="0xDAC0" />
<!-- Probably intended to be used as the xluDList for Clock Tower Clock Face -->
<DList Name="gClockTowerUnusedEmpty7DL" Offset="0xE810" />
<DList Name="gClockTowerClockFace" Offset="0xE818" />
<!-- Probably intended to be used as the xluDList for Wall Clock Clock Face -->
<DList Name="gClockTowerUnusedEmpty8DL" Offset="0xF510" />
<DList Name="gWallClockClockFace" Offset="0xF518" />
<Texture Name="gWallClockClockFaceBackTex" OutName="wall_clock_clock_face_back" Format="rgba16" Width="16" Height="32" Offset="0xF7F8" />
<Texture Name="gWallClockClockFaceBottomTex" OutName="wall_clock_clock_face_bottom" Format="rgba16" Width="64" Height="32" Offset="0xFBF8" />
<Texture Name="gWallClockClockFaceTopTex" OutName="wall_clock_clock_face_top" Format="rgba16" Width="64" Height="32" Offset="0x10BF8" />
<Texture Name="gWallClockClockFacePanelBarTex" OutName="wall_clock_clock_face_panel_bar" Format="rgba16" Width="8" Height="8" Offset="0x11BF8" />
</File>
</Root>

View File

@ -1,17 +1,32 @@
/*
* File: z_obj_tokeidai.c
* Overlay: ovl_Obj_Tokeidai
* Description: Components of the Clock Tower (gears, clock face, counterweight, etc). Also used for wall clocks.
* Description: Components of the Clock Tower. Also used for wall clocks. The specific components are:
* - ClockFace: The decorated face of the clock that spins every hour.
* - MinuteRing: The ring around the clock face that spins every two minutes.
* - ExteriorGear: The two gears on the side of the tower that spin every two minutes.
* - SunAndMoonPanel: A panel with a sun and moon image that tells whether it is day or night.
* - Counterweight: The spinning weight on top of the tower that emits a spotlight at night.
* - StaircaseToRooftop: The staircase to tower's rooftop that opens after midnight on the Final Day.
* - TerminaFieldWalls: The walls of the Clock Tower visible from Termina Field.
* - UnusedWall: A single wall of the Clock Tower, unused in the final game.
*
* This actor handles most of the functionality related to the Clock Tower and the various
* wall clocks around Clock Town. Among its responsibilities are making the clocks correctly
* tell the time by spinning the various pieces and gears and controlling the spotlight that
* is emitted from the Clock Tower at night.
* Sometimes, the ClockFace, MinuteRing, and SunAndMoonPanel are treated as a single clock entity.
* This is called Clock if it applies to both the Clock Tower clock and wall clocks, and
* TowerClock/WallClock, respectively, if it only applies to one of them.
*
* On the midnight of the Final Day, the Clock Tower opens up, and the various pieces of it
* are moved around. This actor is responsible for managing all of this movement. Additionally,
* if the moon crashes into Termina, this actor is responsible for making the pieces of the
* Clock Tower collapse.
* are moved around. This actor is responsible for managing all of this movement, which is handled
* via the series of action functions labeled with TowerOpening.
*
* All components have at least one of these three actions:
* - Idle: The "default" action, and for some components the only action.
* The component is either completely still, or it's telling the time, depending on the component.
* - OpenedIdle: The action for certain Clock Tower components after midnight on the Final Day.
* The TowerClock, ExteriorGears, and Counterweight no longer tell time and are moved to a different position.
* Called "opened" because it corresponds to when the staircase to the tower's rooftop is opened up.
* - Collapse: The action for certain Clock Tower components when the moon crashes into Termina.
* This action is responsible for making the component fall during the moon crash cutscene.
*/
#include "z_obj_tokeidai.h"
@ -21,10 +36,11 @@
#define THIS ((ObjTokeidai*)thisx)
#define GET_CURRENT_HOUR(this) ((s32)((this)->currentTime * (24.0f / 0x10000)))
#define GET_CURRENT_MINUTE(this) ((s32)((this)->currentTime * (360 * 2.0f / 0x10000)) % 30)
#define GET_CLOCK_FACE_ROTATION(currentHour) ((s16)(currentHour * (0x10000 / 24.0f)))
#define GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute) ((s16)(currentMinute * (0x10000 * 12.0f / 360)))
#define GET_CURRENT_CLOCK_HOUR(this) ((s32)((this)->clockTime * (24.0f / 0x10000)))
#define GET_CURRENT_CLOCK_MINUTE(this) ((s32)((this)->clockTime * (360 * 2.0f / 0x10000)) % 30)
#define GET_CLOCK_FACE_ROTATION(currentClockHour) ((s16)(currentClockHour * (0x10000 / 24.0f)))
#define GET_MINUTE_RING_OR_EXTERIOR_GEAR_ROTATION(currentClockMinute) \
((s16)(currentClockMinute * (0x10000 * 12.0f / 360)))
void ObjTokeidai_Init(Actor* thisx, GlobalContext* globalCtx);
void ObjTokeidai_Destroy(Actor* thisx, GlobalContext* globalCtx);
@ -33,18 +49,18 @@ void ObjTokeidai_Draw(Actor* thisx, GlobalContext* globalCtx);
void ObjTokeidai_DoNothing(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_TowerClock_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_TowerGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_ExteriorGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_Counterweight_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_WallClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_TowerGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_ExteriorGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_Counterweight_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_Walls_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_StaircaseIntoTower_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_TerminaFieldWalls_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_StaircaseToRooftop_Idle(ObjTokeidai* this, GlobalContext* globalCtx);
void ObjTokeidai_SetupTowerOpening(ObjTokeidai* this);
void ObjTokeidai_Clock_Draw(Actor* thisx, GlobalContext* globalCtx);
void ObjTokeidai_Counterweight_Draw(Actor* thisx, GlobalContext* globalCtx);
void ObjTokeidai_TowerGear_Draw(Actor* thisx, GlobalContext* globalCtx);
void ObjTokeidai_ExteriorGear_Draw(Actor* thisx, GlobalContext* globalCtx);
const ActorInit Obj_Tokeidai_InitVars = {
ACTOR_OBJ_TOKEIDAI,
@ -67,43 +83,43 @@ static InitChainEntry sInitChain[] = {
/**
* Returns the angle necessary to show the correct side of
* the sun and moon disk based on the time of day. The actual
* angle can differ from the target angle if the disk is in
* the sun and moon panel based on the time of day. The actual
* angle can differ from the target angle if the panel is in
* the middle of rotating.
*/
s32 ObjTokeidai_GetTargetSunMoonDiskRotation() {
s32 ObjTokeidai_GetTargetSunMoonPanelRotation() {
if (gSaveContext.isNight) {
return 0x8000;
}
return 0;
}
void ObjTokeidai_SetupClockOrGear(ObjTokeidai* this) {
s32 currentMinute = GET_CURRENT_MINUTE(this);
void ObjTokeidai_SetupClockOrExteriorGear(ObjTokeidai* this) {
s32 currentClockMinute = GET_CURRENT_CLOCK_MINUTE(this);
this->clockMinute = currentMinute;
this->outerRingOrGearRotation = GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute);
this->outerRingOrGearRotationalVelocity = 0x3C;
this->outerRingOrGearRotationTimer = 0;
this->clockMinute = currentClockMinute;
this->minuteRingOrExteriorGearRotation = GET_MINUTE_RING_OR_EXTERIOR_GEAR_ROTATION(currentClockMinute);
this->minuteRingOrExteriorGearRotationalVelocity = 0x3C;
this->minuteRingOrExteriorGearRotationTimer = 0;
}
void ObjTokeidai_Clock_Init(ObjTokeidai* this) {
s32 currentHour;
s32 currentClockHour;
ObjTokeidai_SetupClockOrGear(this);
currentHour = GET_CURRENT_HOUR(this);
this->clockHour = currentHour;
this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentHour);
ObjTokeidai_SetupClockOrExteriorGear(this);
currentClockHour = GET_CURRENT_CLOCK_HOUR(this);
this->clockHour = currentClockHour;
this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentClockHour);
this->clockFaceRotationalVelocity = 0;
this->clockFaceRotationTimer = 0;
this->sunMoonDiskRotationalVelocity = 0;
this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation();
this->sunMoonPanelRotationalVelocity = 0;
this->sunMoonPanelRotation = ObjTokeidai_GetTargetSunMoonPanelRotation();
}
void ObjTokeidai_TowerGear_Init(ObjTokeidai* this, GlobalContext* globalCtx) {
this->actor.draw = ObjTokeidai_TowerGear_Draw;
this->opaDList = object_obj_tokeidai_DL_00BA78;
ObjTokeidai_SetupClockOrGear(this);
void ObjTokeidai_ExteriorGear_Init(ObjTokeidai* this, GlobalContext* globalCtx) {
this->actor.draw = ObjTokeidai_ExteriorGear_Draw;
this->opaDList = gClockTowerExteriorGearDL;
ObjTokeidai_SetupClockOrExteriorGear(this);
if (((globalCtx->sceneNum == SCENE_CLOCKTOWER) && (gSaveContext.sceneSetupIndex == 2) &&
(globalCtx->csCtx.unk_12 == 0)) ||
@ -111,12 +127,12 @@ void ObjTokeidai_TowerGear_Init(ObjTokeidai* this, GlobalContext* globalCtx) {
(globalCtx->csCtx.unk_12 == 0))) {
ObjTokeidai_SetupTowerOpening(this);
} else if ((CURRENT_DAY == 3 && gSaveContext.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) {
this->actionFunc = ObjTokeidai_TowerGear_OpenedIdle;
this->actionFunc = ObjTokeidai_ExteriorGear_OpenedIdle;
this->actor.world.pos.y += this->actor.scale.y * 1900.0f;
this->actor.shape.yOffset = 1500.0f;
gSaveContext.weekEventReg[8] |= 0x40;
} else {
this->actionFunc = ObjTokeidai_TowerGear_Idle;
this->actionFunc = ObjTokeidai_ExteriorGear_Idle;
}
}
@ -133,11 +149,14 @@ void ObjTokeidai_TowerClock_Init(ObjTokeidai* this, GlobalContext* globalCtx) {
this->actor.world.pos.y += (this->actor.scale.y * 5191.0f) - 50.0f;
this->actor.world.pos.x += Math_SinS(this->actor.world.rot.y) * this->actor.scale.z * 1791.0f;
this->actor.world.pos.z += -Math_CosS(this->actor.world.rot.y) * this->actor.scale.z * 1791.0f;
this->clockFaceZTranslation = -0x140;
this->actor.shape.rot.x = -0x4000;
this->actor.home.pos = this->actor.world.pos;
this->actor.home.pos.y -= 1178.0f;
this->actor.home.pos.z += 13.0f;
this->actionFunc = ObjTokeidai_TowerClock_OpenedIdle;
} else {
this->actionFunc = ObjTokeidai_TowerClock_Idle;
@ -148,8 +167,8 @@ void ObjTokeidai_Counterweight_Init(ObjTokeidai* this, GlobalContext* globalCtx)
s32 type;
this->actor.draw = ObjTokeidai_Counterweight_Draw;
this->opaDList = object_obj_tokeidai_DL_00B208;
this->xluDList = object_obj_tokeidai_DL_00B0C0;
this->opaDList = gClockTowerCounterweightDL;
this->xluDList = gClockTowerSpotlightDL;
if (gSaveContext.isNight) {
this->spotlightIntensity = 100;
} else {
@ -162,6 +181,7 @@ void ObjTokeidai_Counterweight_Init(ObjTokeidai* this, GlobalContext* globalCtx)
(globalCtx->csCtx.unk_12 == 0))) {
this->spotlightIntensity = 0;
ObjTokeidai_SetupTowerOpening(this);
if (this->actor.child == NULL) {
type = OBJ_TOKEIDAI_TYPE(&this->actor);
if (type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN ||
@ -171,6 +191,7 @@ void ObjTokeidai_Counterweight_Init(ObjTokeidai* this, GlobalContext* globalCtx)
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0);
}
}
if (this->actor.child != NULL) {
if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) {
this->actor.child->home.rot.x = 0x384;
@ -200,55 +221,65 @@ void ObjTokeidai_Init(Actor* thisx, GlobalContext* globalCtx) {
this->xRotation = 0;
this->yTranslation = 0;
this->clockFaceZTranslation = 0;
this->currentTime = gSaveContext.time;
this->clockTime = gSaveContext.time;
this->actor.home.rot.x = 0;
switch (OBJ_TOKEIDAI_TYPE(&this->actor)) {
case OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD:
case OBJ_TOKEIDAI_TYPE_EXTERIOR_GEAR_TERMINA_FIELD:
Actor_SetScale(&this->actor, 0.15f);
ObjTokeidai_TowerGear_Init(this, globalCtx);
ObjTokeidai_ExteriorGear_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_TOWER_GEAR_CLOCK_TOWN:
ObjTokeidai_TowerGear_Init(this, globalCtx);
case OBJ_TOKEIDAI_TYPE_EXTERIOR_GEAR_CLOCK_TOWN:
ObjTokeidai_ExteriorGear_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_UNUSED_WALL:
this->opaDList = object_obj_tokeidai_DL_00D388;
this->opaDList = gClockTowerUnusedTowerWallDL;
break;
case OBJ_TOKEIDAI_TYPE_TOWER_WALLS_TERMINA_FIELD:
Actor_SetScale(&this->actor, 1.0f);
this->opaDList = object_obj_tokeidai_DL_009A08;
this->actionFunc = ObjTokeidai_Walls_Idle;
this->opaDList = gClockTowerTerminaFieldWallsDL;
this->actionFunc = ObjTokeidai_TerminaFieldWalls_Idle;
break;
case OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD:
Actor_SetScale(&this->actor, 0.15f);
ObjTokeidai_TowerClock_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN:
ObjTokeidai_TowerClock_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_WALL_CLOCK:
Actor_SetScale(&this->actor, 0.02f);
this->actor.draw = ObjTokeidai_Clock_Draw;
ObjTokeidai_Clock_Init(this);
this->actionFunc = ObjTokeidai_WallClock_Idle;
break;
case OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK:
Actor_SetScale(&this->actor, 0.01f);
this->actor.draw = ObjTokeidai_Clock_Draw;
ObjTokeidai_Clock_Init(this);
this->actionFunc = ObjTokeidai_WallClock_Idle;
break;
case OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD:
Actor_SetScale(&this->actor, 0.15f);
ObjTokeidai_Counterweight_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN:
ObjTokeidai_Counterweight_Init(this, globalCtx);
break;
case OBJ_TOKEIDAI_TYPE_STAIRCASE_INTO_TOWER:
this->opaDList = object_obj_tokeidai_DL_00D8E8;
this->xluDList = object_obj_tokeidai_DL_00D8E0;
this->actionFunc = ObjTokeidai_StaircaseIntoTower_Idle;
case OBJ_TOKEIDAI_TYPE_STAIRCASE_TO_ROOFTOP:
this->opaDList = gClockTowerStaircaseToRooftopDL;
this->xluDList = gClockTowerEmptyDL;
this->actionFunc = ObjTokeidai_StaircaseToRooftop_Idle;
break;
}
}
@ -257,41 +288,43 @@ void ObjTokeidai_Destroy(Actor* thisx, GlobalContext* globalCtx) {
}
void ObjTokeidai_RotateOnMinuteChange(ObjTokeidai* this, s32 playSfx) {
s32 currentMinute = GET_CURRENT_MINUTE(this);
s32 currentClockMinute = GET_CURRENT_CLOCK_MINUTE(this);
if (currentMinute != this->clockMinute) {
if (this->outerRingOrGearRotationTimer == 8 && playSfx) {
if (currentClockMinute != this->clockMinute) {
if (this->minuteRingOrExteriorGearRotationTimer == 8 && playSfx) {
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CLOCK_TOWER_SECOND_HAND);
}
if (this->outerRingOrGearRotationTimer > 8) {
if (this->minuteRingOrExteriorGearRotationTimer > 8) {
// This actually performs the rotation to the next minute
// for the outer ring or gear.
this->outerRingOrGearRotationalVelocity += 0x3C;
this->outerRingOrGearRotation += this->outerRingOrGearRotationalVelocity;
// for the minute ring or exterior gear.
this->minuteRingOrExteriorGearRotationalVelocity += 0x3C;
this->minuteRingOrExteriorGearRotation += this->minuteRingOrExteriorGearRotationalVelocity;
} else {
// This makes the outer ring or gear wiggle in place for a bit
// This makes the minute ring or exterior gear wiggle in place for a bit
// before rotating to the next position.
if ((this->outerRingOrGearRotationTimer & 3) == 0) {
this->outerRingOrGearRotation += 0x5A;
if ((this->minuteRingOrExteriorGearRotationTimer & 3) == 0) {
this->minuteRingOrExteriorGearRotation += 0x5A;
}
if ((this->outerRingOrGearRotationTimer & 3) == 1) {
this->outerRingOrGearRotation -= 0x5A;
if ((this->minuteRingOrExteriorGearRotationTimer & 3) == 1) {
this->minuteRingOrExteriorGearRotation -= 0x5A;
}
}
this->outerRingOrGearRotationTimer++;
if ((currentMinute == 15 && this->outerRingOrGearRotation < 0) ||
(currentMinute != 15 && this->outerRingOrGearRotation > GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute))) {
this->outerRingOrGearRotation = GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute);
this->clockMinute = currentMinute;
this->outerRingOrGearRotationalVelocity = 0x5A;
this->outerRingOrGearRotationTimer = 0;
this->minuteRingOrExteriorGearRotationTimer++;
if ((currentClockMinute == 15 && this->minuteRingOrExteriorGearRotation < 0) ||
(currentClockMinute != 15 &&
this->minuteRingOrExteriorGearRotation > GET_MINUTE_RING_OR_EXTERIOR_GEAR_ROTATION(currentClockMinute))) {
this->minuteRingOrExteriorGearRotation = GET_MINUTE_RING_OR_EXTERIOR_GEAR_ROTATION(currentClockMinute);
this->clockMinute = currentClockMinute;
this->minuteRingOrExteriorGearRotationalVelocity = 0x5A;
this->minuteRingOrExteriorGearRotationTimer = 0;
}
}
}
void ObjTokeidai_TowerGear_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_ExteriorGear_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) {
if ((this->actor.bgCheckFlags & 1) || this->actor.world.pos.y < 0.0f) {
this->actionFunc = ObjTokeidai_DoNothing;
} else {
@ -302,9 +335,9 @@ void ObjTokeidai_TowerGear_Collapse(ObjTokeidai* this, GlobalContext* globalCtx)
}
}
void ObjTokeidai_TowerGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_ExteriorGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx) {
if (func_800EE29C(globalCtx, 0x84) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 2) {
this->actionFunc = ObjTokeidai_TowerGear_Collapse;
this->actionFunc = ObjTokeidai_ExteriorGear_Collapse;
this->actor.speedXZ = this->actor.scale.y * 5.0f;
this->actor.velocity.y = 0.0f;
this->actor.terminalVelocity = this->actor.scale.y * -50.0f;
@ -313,15 +346,15 @@ void ObjTokeidai_TowerGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCt
}
/**
* This is hard to see in the final game. This, used in conjunction
* with the following function, makes the tower's clock slide off the
* tower and spin through the air when the moon crashes.
* This, used in conjunction with the following function, makes the
* tower's clock slide off the tower and spin through the air when the moon crashes.
*/
void ObjTokeidai_TowerClock_Fall(ObjTokeidai* this, GlobalContext* globalCtx) {
this->actor.shape.rot.x += this->fallingClockFaceRotationalVelocity;
if (this->fallingClockFaceRotationalVelocity > 0xA0) {
this->fallingClockFaceRotationalVelocity -= 5;
}
this->actor.world.pos.z += 4.0f;
Actor_MoveWithGravity(&this->actor);
if (this->actor.world.pos.y < 0.0f) {
@ -330,8 +363,8 @@ void ObjTokeidai_TowerClock_Fall(ObjTokeidai* this, GlobalContext* globalCtx) {
}
/**
* This is hard to see in the final game. This makes the
* tower's clock slide off as the moon crashes into it.
* This makes the tower's clock slide off as the moon crashes into it. It's
* the tower clock's equivalent to other components' Collapse functions.
*/
void ObjTokeidai_TowerClock_SlideOff(ObjTokeidai* this, GlobalContext* globalCtx) {
f32 cos;
@ -396,20 +429,15 @@ void ObjTokeidai_Counterweight_OpenedIdle(ObjTokeidai* this, GlobalContext* glob
}
}
/**
* This is hard to see in the final game. It makes the walls of
* the clock tower tip over as the moon crashes into it, but the
* giant moon mostly obscures it.
*/
void ObjTokeidai_Walls_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_TerminaFieldWalls_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) {
if (this->actor.shape.rot.x < 0x4000) {
this->actor.shape.rot.x += 0x28;
}
}
void ObjTokeidai_Walls_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_TerminaFieldWalls_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
if (func_800EE29C(globalCtx, 0x84) != 0 && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 1) {
this->actionFunc = ObjTokeidai_Walls_Collapse;
this->actionFunc = ObjTokeidai_TerminaFieldWalls_Collapse;
}
}
@ -480,9 +508,11 @@ void ObjTokeidai_TowerOpening_DropCounterweight(ObjTokeidai* this, GlobalContext
case 0:
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_0);
break;
case 1:
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_1);
break;
case 2:
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_2);
break;
@ -565,7 +595,7 @@ void ObjTokeidai_TowerOpening_Start(ObjTokeidai* this, GlobalContext* globalCtx)
}
/**
* Sets up the sequence where the Clock Tower "transforms" and opens up
* Sets up the sequence where the Clock Tower opens up
* on the midnight of the Final Day.
*/
void ObjTokeidai_SetupTowerOpening(ObjTokeidai* this) {
@ -580,7 +610,7 @@ void ObjTokeidai_SetupTowerOpening(ObjTokeidai* this) {
void ObjTokeidai_DoNothing(ObjTokeidai* this, GlobalContext* globalCtx) {
}
void ObjTokeidai_StaircaseIntoTower_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_StaircaseToRooftop_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
if (((CURRENT_DAY == 3 && gSaveContext.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) ||
(gSaveContext.weekEventReg[8] & 0x40)) {
this->actor.draw = ObjTokeidai_Draw;
@ -601,9 +631,9 @@ s32 ObjTokeidai_IsPostFirstCycleFinalHours(ObjTokeidai* this, GlobalContext* glo
}
void ObjTokeidai_RotateOnHourChange(ObjTokeidai* this, GlobalContext* globalCtx) {
s32 currentHour = GET_CURRENT_HOUR(this);
s32 currentClockHour = GET_CURRENT_CLOCK_HOUR(this);
if (currentHour != this->clockHour) {
if (currentClockHour != this->clockHour) {
if (this->clockFaceRotationTimer > 12) {
// This actually performs the rotation to the next hour
// for the clock face.
@ -621,32 +651,33 @@ void ObjTokeidai_RotateOnHourChange(ObjTokeidai* this, GlobalContext* globalCtx)
}
this->clockFaceRotationTimer++;
if ((currentHour == 12 && this->clockFaceRotation < 0) ||
(currentHour != 12 && this->clockFaceRotation > GET_CLOCK_FACE_ROTATION(currentHour))) {
this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentHour);
this->clockHour = currentHour;
if ((currentClockHour == 12 && this->clockFaceRotation < 0) ||
(currentClockHour != 12 && this->clockFaceRotation > GET_CLOCK_FACE_ROTATION(currentClockHour))) {
this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentClockHour);
this->clockHour = currentClockHour;
this->clockFaceRotationalVelocity = 0;
this->clockFaceRotationTimer = 0;
}
}
// If the sun and moon disk doesn't have the target rotation (e.g., the time of day
// If the sun and moon panel doesn't have the target rotation (e.g., the time of day
// just changed), rotate it until it matches the target.
if (this->sunMoonDiskRotation != ObjTokeidai_GetTargetSunMoonDiskRotation()) {
if (this->sunMoonPanelRotation != ObjTokeidai_GetTargetSunMoonPanelRotation()) {
if (this->clockHour == 6) {
this->sunMoonDiskRotationalVelocity += 0x222;
this->sunMoonDiskRotation += this->sunMoonDiskRotationalVelocity;
if (this->sunMoonDiskRotation > 0x10000) {
this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation();
this->sunMoonDiskRotationalVelocity = 0;
this->sunMoonPanelRotationalVelocity += 0x222;
this->sunMoonPanelRotation += this->sunMoonPanelRotationalVelocity;
if (this->sunMoonPanelRotation > 0x10000) {
this->sunMoonPanelRotation = ObjTokeidai_GetTargetSunMoonPanelRotation();
this->sunMoonPanelRotationalVelocity = 0;
}
}
if (this->clockHour == 18) {
this->sunMoonDiskRotationalVelocity += 0x222;
this->sunMoonDiskRotation += this->sunMoonDiskRotationalVelocity;
if (this->sunMoonDiskRotation > 0x8000) {
this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation();
this->sunMoonDiskRotationalVelocity = 0;
this->sunMoonPanelRotationalVelocity += 0x222;
this->sunMoonPanelRotation += this->sunMoonPanelRotationalVelocity;
if (this->sunMoonPanelRotation > 0x8000) {
this->sunMoonPanelRotation = ObjTokeidai_GetTargetSunMoonPanelRotation();
this->sunMoonPanelRotationalVelocity = 0;
}
}
}
@ -662,7 +693,7 @@ void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
if (globalCtx->csCtx.state != 0) {
this->actor.home.rot.x = 1;
this->currentTime += 3;
this->clockTime += 3;
this->actor.draw = ObjTokeidai_Clock_Draw;
} else {
if (!(globalCtx->actorCtx.unk5 & 2) &&
@ -670,7 +701,7 @@ void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
ActorCutscene_GetCurrentIndex() == -1) {
this->actor.draw = NULL;
}
this->currentTime = gSaveContext.time;
this->clockTime = gSaveContext.time;
if (this->actor.home.rot.x != 0) {
ObjTokeidai_Clock_Init(this);
this->actor.home.rot.x = 0;
@ -684,28 +715,28 @@ void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
}
void ObjTokeidai_WallClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
this->currentTime = gSaveContext.time;
this->clockTime = gSaveContext.time;
ObjTokeidai_RotateOnMinuteChange(this, true);
ObjTokeidai_RotateOnHourChange(this, globalCtx);
}
void ObjTokeidai_TowerGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
void ObjTokeidai_ExteriorGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx) {
if (ObjTokeidai_IsPostFirstCycleFinalHours(this, globalCtx)) {
this->actor.draw = ObjTokeidai_TowerGear_Draw;
this->actor.draw = ObjTokeidai_ExteriorGear_Draw;
} else {
if (globalCtx->csCtx.state != 0) {
this->actor.home.rot.x = 1;
this->currentTime += 3;
this->actor.draw = ObjTokeidai_TowerGear_Draw;
this->clockTime += 3;
this->actor.draw = ObjTokeidai_ExteriorGear_Draw;
} else {
if ((globalCtx->actorCtx.unk5 & 2) == 0 &&
OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD &&
OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_EXTERIOR_GEAR_TERMINA_FIELD &&
ActorCutscene_GetCurrentIndex() == -1) {
this->actor.draw = NULL;
}
this->currentTime = gSaveContext.time;
this->clockTime = gSaveContext.time;
if (this->actor.home.rot.x != 0) {
ObjTokeidai_SetupClockOrGear(this);
ObjTokeidai_SetupClockOrExteriorGear(this);
this->actor.home.rot.x = 0;
}
}
@ -718,6 +749,7 @@ void ObjTokeidai_Counterweight_Idle(ObjTokeidai* this, GlobalContext* globalCtx)
if (ObjTokeidai_IsPostFirstCycleFinalHours(this, globalCtx)) {
this->spotlightIntensity = 0;
if (this->actor.child == NULL) {
type = OBJ_TOKEIDAI_TYPE(&this->actor);
if (type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN ||
@ -727,6 +759,7 @@ void ObjTokeidai_Counterweight_Idle(ObjTokeidai* this, GlobalContext* globalCtx)
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0);
}
}
if (this->actor.child != NULL) {
if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) {
this->actor.child->home.rot.x = 0x384;
@ -751,6 +784,9 @@ void ObjTokeidai_Update(Actor* thisx, GlobalContext* globalCtx) {
this->actionFunc(this, globalCtx);
}
/**
* Used for TerminaFieldWalls StaircaseToRooftop, and UnusedWall
*/
void ObjTokeidai_Draw(Actor* thisx, GlobalContext* globalCtx) {
ObjTokeidai* this = THIS;
@ -761,6 +797,7 @@ void ObjTokeidai_Draw(Actor* thisx, GlobalContext* globalCtx) {
func_8012C28C(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, this->opaDList);
}
if (this->xluDList != NULL) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
func_8012C2DC(globalCtx->state.gfxCtx);
@ -780,26 +817,30 @@ void ObjTokeidai_Clock_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_InsertTranslation(0.0f, 0.0f, -1791.0f, MTXMODE_APPLY);
Matrix_InsertXRotation_s(-this->xRotation, MTXMODE_APPLY);
Matrix_InsertTranslation(0.0f, 0.0f, 1791.0f, MTXMODE_APPLY);
Matrix_StatePush();
Matrix_InsertZRotation_s(-this->outerRingOrGearRotation, MTXMODE_APPLY);
Matrix_InsertZRotation_s(-this->minuteRingOrExteriorGearRotation, 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_obj_tokeidai_DL_00CF28);
gSPDisplayList(POLY_OPA_DISP++, gClockTowerMinuteRingDL);
Matrix_StatePop();
Matrix_InsertTranslation(0.0f, 0.0f, this->clockFaceZTranslation, 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_obj_tokeidai_DL_00BEE8);
gSPDisplayList(POLY_OPA_DISP++, gClockTowerClockCenterAndHandDL);
Matrix_InsertZRotation_s(-this->clockFaceRotation * 2, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_WALL_CLOCK ||
OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK) {
gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00F518);
gSPDisplayList(POLY_OPA_DISP++, gWallClockClockFace);
} else {
gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00E818);
gSPDisplayList(POLY_OPA_DISP++, gClockTowerClockFace);
}
Matrix_InsertTranslation(0.0f, -1112.0f, -19.6f, MTXMODE_APPLY);
Matrix_RotateY((s16)this->sunMoonDiskRotation, MTXMODE_APPLY);
Matrix_RotateY((s16)this->sunMoonPanelRotation, 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_obj_tokeidai_DL_00C368);
gSPDisplayList(POLY_OPA_DISP++, gClockTowerSunAndMoonPanelDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
@ -818,11 +859,16 @@ void ObjTokeidai_Counterweight_Draw(Actor* thisx, GlobalContext* globalCtx) {
OPEN_DISPS(globalCtx->state.gfxCtx);
// For scrolling the spotlight's mask texture down the length of the light beam.
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, -gameplayFrames, 0, 0x20, 0x20));
// Draws the counterweight
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
func_8012C28C(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, this->opaDList);
// Draws the spotlight
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
func_8012C2DC(globalCtx->state.gfxCtx);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 255, 255, 235, 180, (s32)(this->spotlightIntensity * 2.55f));
@ -831,7 +877,7 @@ void ObjTokeidai_Counterweight_Draw(Actor* thisx, GlobalContext* globalCtx) {
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void ObjTokeidai_TowerGear_Draw(Actor* thisx, GlobalContext* globalCtx) {
void ObjTokeidai_ExteriorGear_Draw(Actor* thisx, GlobalContext* globalCtx) {
ObjTokeidai* this = THIS;
OPEN_DISPS(globalCtx->state.gfxCtx);
@ -842,10 +888,10 @@ void ObjTokeidai_TowerGear_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_InsertXRotation_s(-this->xRotation, MTXMODE_APPLY);
Matrix_RotateY(thisx->shape.rot.y, MTXMODE_APPLY);
Matrix_InsertTranslation(0.0f, 0.0f, 1791.0f, MTXMODE_APPLY);
Matrix_InsertZRotation_s(this->outerRingOrGearRotation, MTXMODE_APPLY);
Matrix_InsertZRotation_s(this->minuteRingOrExteriorGearRotation, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
func_8012C28C(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00BA78);
gSPDisplayList(POLY_OPA_DISP++, gClockTowerExteriorGearDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}

View File

@ -6,17 +6,17 @@
#define OBJ_TOKEIDAI_TYPE(thisx) (((thisx)->params & 0xF000) >> 12)
typedef enum {
/* 0 */ OBJ_TOKEIDAI_TYPE_TOWER_GEAR_CLOCK_TOWN,
/* 0 */ OBJ_TOKEIDAI_TYPE_EXTERIOR_GEAR_CLOCK_TOWN,
/* 1 */ OBJ_TOKEIDAI_TYPE_UNUSED_WALL,
/* 2 */ OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN,
/* 3 */ OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN,
/* 4 */ OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD,
/* 4 */ OBJ_TOKEIDAI_TYPE_EXTERIOR_GEAR_TERMINA_FIELD,
/* 5 */ OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD,
/* 6 */ OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD,
/* 8 */ OBJ_TOKEIDAI_TYPE_TOWER_WALLS_TERMINA_FIELD = 8,
/* 9 */ OBJ_TOKEIDAI_TYPE_WALL_CLOCK,
/* 10 */ OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK,
/* 11 */ OBJ_TOKEIDAI_TYPE_STAIRCASE_INTO_TOWER,
/* 11 */ OBJ_TOKEIDAI_TYPE_STAIRCASE_TO_ROOFTOP,
} ObjTokeidaiType;
struct ObjTokeidai;
@ -27,9 +27,9 @@ typedef struct ObjTokeidai {
/* 0x000 */ Actor actor;
/* 0x144 */ Gfx* opaDList;
/* 0x148 */ Gfx* xluDList;
/* 0x14C */ s16 outerRingOrGearRotation;
/* 0x14E */ s16 outerRingOrGearRotationalVelocity;
/* 0x150 */ s16 outerRingOrGearRotationTimer;
/* 0x14C */ s16 minuteRingOrExteriorGearRotation;
/* 0x14E */ s16 minuteRingOrExteriorGearRotationalVelocity;
/* 0x150 */ s16 minuteRingOrExteriorGearRotationTimer;
/* 0x152 */ s16 clockFaceRotation;
/* 0x154 */ union {
s16 clockFaceRotationalVelocity;
@ -44,9 +44,9 @@ typedef struct ObjTokeidai {
s16 counterweightRotationalAcceleration;
s16 aerialClockFaceSpeed;
};
/* 0x158 */ s32 sunMoonDiskRotation;
/* 0x158 */ s32 sunMoonPanelRotation;
/* 0x15C */ union {
s16 sunMoonDiskRotationalVelocity;
s16 sunMoonPanelRotationalVelocity;
s16 fallingClockFaceRotationalVelocity;
};
/* 0x15E */ s16 yTranslation;
@ -58,7 +58,7 @@ typedef struct ObjTokeidai {
s32 clockHour;
s32 spotlightIntensity;
};
/* 0x170 */ u16 currentTime;
/* 0x170 */ u16 clockTime; // can differ from the actual time, e.g., in cutscenes
/* 0x174 */ ObjTokeidaiActionFunc actionFunc;
} ObjTokeidai; // size = 0x178

View File

@ -11667,24 +11667,24 @@
0x80AB2544:("DmChar09_Update",),
0x80AB25D8:("func_80AB25D8",),
0x80AB261C:("DmChar09_Draw",),
0x80AB2790:("ObjTokeidai_GetTargetSunMoonDiskRotation",),
0x80AB27B4:("ObjTokeidai_SetupClockOrGear",),
0x80AB2790:("ObjTokeidai_GetTargetSunMoonPanelRotation",),
0x80AB27B4:("ObjTokeidai_SetupClockOrExteriorGear",),
0x80AB2834:("ObjTokeidai_Clock_Init",),
0x80AB28C8:("ObjTokeidai_TowerGear_Init",),
0x80AB28C8:("ObjTokeidai_ExteriorGear_Init",),
0x80AB29F8:("ObjTokeidai_TowerClock_Init",),
0x80AB2BBC:("ObjTokeidai_Counterweight_Init",),
0x80AB2DEC:("ObjTokeidai_Init",),
0x80AB3000:("ObjTokeidai_Destroy",),
0x80AB3010:("ObjTokeidai_RotateOnMinuteChange",),
0x80AB319C:("ObjTokeidai_TowerGear_Collapse",),
0x80AB3240:("ObjTokeidai_TowerGear_OpenedIdle",),
0x80AB319C:("ObjTokeidai_ExteriorGear_Collapse",),
0x80AB3240:("ObjTokeidai_ExteriorGear_OpenedIdle",),
0x80AB32F0:("ObjTokeidai_TowerClock_Fall",),
0x80AB3370:("ObjTokeidai_TowerClock_SlideOff",),
0x80AB34CC:("ObjTokeidai_TowerClock_OpenedIdle",),
0x80AB3544:("ObjTokeidai_Counterweight_Collapse",),
0x80AB3598:("ObjTokeidai_Counterweight_OpenedIdle",),
0x80AB363C:("ObjTokeidai_Walls_Collapse",),
0x80AB365C:("ObjTokeidai_Walls_Idle",),
0x80AB363C:("ObjTokeidai_TerminaFieldWalls_Collapse",),
0x80AB365C:("ObjTokeidai_TerminaFieldWalls_Idle",),
0x80AB36C4:("ObjTokeidai_TowerTransformation_EndCutscene",),
0x80AB3808:("ObjTokeidai_TowerOpening_FinishOpening",),
0x80AB3880:("ObjTokeidai_TowerOpening_Wait",),
@ -11694,18 +11694,18 @@
0x80AB3B34:("ObjTokeidai_TowerOpening_Start",),
0x80AB3BB0:("ObjTokeidai_SetupTowerOpening",),
0x80AB3BD8:("ObjTokeidai_DoNothing",),
0x80AB3BE8:("ObjTokeidai_StaircaseIntoTower_Idle",),
0x80AB3BE8:("ObjTokeidai_StaircaseToRooftop_Idle",),
0x80AB3C50:("ObjTokeidai_IsPostFirstCycleFinalHours",),
0x80AB3CCC:("ObjTokeidai_RotateOnHourChange",),
0x80AB3ED0:("ObjTokeidai_TowerClock_Idle",),
0x80AB4040:("ObjTokeidai_WallClock_Idle",),
0x80AB4080:("ObjTokeidai_TowerGear_Idle",),
0x80AB4080:("ObjTokeidai_ExteriorGear_Idle",),
0x80AB4160:("ObjTokeidai_Counterweight_Idle",),
0x80AB4278:("ObjTokeidai_Update",),
0x80AB429C:("ObjTokeidai_Draw",),
0x80AB4394:("ObjTokeidai_Clock_Draw",),
0x80AB4664:("ObjTokeidai_Counterweight_Draw",),
0x80AB4894:("ObjTokeidai_TowerGear_Draw",),
0x80AB4894:("ObjTokeidai_ExteriorGear_Draw",),
0x80AB4D10:("func_80AB4D10",),
0x80AB4E34:("func_80AB4E34",),
0x80AB4E58:("func_80AB4E58",),