Cite as
zeldaret/tww
Original
https://github.com/zeldaret/tww
Pinned
zeldaret/tww @ cb24f55fbbb183af5a04783d163468eb9b61536b
Accessed
2026-10-22
Licence
CC0 1.0 Universal (LICENSE at the pinned commit); the game is Nintendo's
Credit
The Zelda Reverse Engineering Team's (zeldaret) C++ decompilation of The Wind Waker for GameCube. Names and comments quoted in tww claims are theirs.
Notes
The README calls it a work-in-progress decompilation that supports every GameCube version: GZLE01 (USA Rev 0, and Korean Rev 48), GZLP01 (PAL), GZLJ01 (Japan), and D44J01 (a Japanese kiosk demo); it holds no assets or assembly. tww claims read the code GZLE01 compiles: include/global.h orders VERSION_DEMO 0, VERSION_JPN 1, VERSION_USA 2, VERSION_PAL 3, so blocks under `VERSION > VERSION_DEMO` or `VERSION > VERSION_JPN` are in the USA build and `VERSION == VERSION_DEMO` blocks are not; no cited range sits inside a version block it doesn't name. configure.py marks c_lib.cpp and d_operate_wind.cpp Matching, d_kankyo.cpp and d_kankyo_wether.cpp MatchingFor GZLJ01, GZLE01, and GZLP01, and the boat actor d_a_ship NonMatching: its C++ doesn't yet compile to the game's bytes as a whole, so claims on it read the decompilers' reconstruction (only execute() carries a "Nonmatching" comment). The boat's tuning constants (daShip_HIO_c0) are literals in the code, not disc data; the wind level each room sets is stage data the repo doesn't hold.

Cited on

Claims (6)

In the decompilation's C++ for the boat (d_a_ship, which doesn't yet match the game's bytes as a whole; the USA GZLE01 build), procSteerMove, while the boat isn't airborne (daSFLG_FLY_e off), takes the gap between the wind vector's yaw (cM_atan2s of its x and z) and the boat's facing shape_angle.y, as a 16-bit angle from 0 to 0x8000, and turns it into a wind factor: 1 − gap/0x10000 below 0x4000 (90°), 0.75 − (gap − 0x4000) × 5.493164e-05 up to 0x6000 (135°), then 0.3 − (gap − 0x6000) × 0.00032967035, floored at 0. So the factor is 1 with the wind along the boat's facing, 0.875 at 45°, 0.75 at 90°, 0.3 at 135°, and 0 from 140° to 180° (computed). The target speed is the wind power divided by 0.5, capped at 1, times the factor times 55. The branches then run in this order, one per update. First, on the body animation's frame 7, if speedF is below twice the target (at most 80) it is raised to that and mTargetSpeed is set to the target (10000 if the boat is being moved by force), and nothing else changes speedF that update. Otherwise, while mTargetSpeed is below speedF, firstDecrementShipSpeed lowers speedF toward mTargetSpeed (a tenth of the gap, at most 5, at least 1) and sets mTargetSpeed to 10000 once the gap is under 3; this comes before the sail check, so it applies with the sail flag off too. Otherwise, with the sail-on flag off or a target of 0, decrementShipSpeed eases speedF toward 10 × the stick's value × the cosine of its angle (a twentieth of the gap, at most 0.1, at least 0.015). Otherwise decrementShipSpeed eases it down to a lower target, and cLib_addCalc up to a higher one (a tenth of the gap, at most 0.5, at least 0.1).src/d/actor/d_a_ship.cpp L1594–1637src/d/actor/d_a_ship.cpp L1090–1098src/SSystem/SComponent/c_lib.cpp L22–32Code
In the USA build, dKyw_wind_set, when no actor has set a wind vector override (mpWindVecOverride), takes the wind's strength from the room's file list (dStage_FileList_dt_GlobalWindLevel): level 0 gives 0.3, level 1 gives 0.6, level 2 gives 0.9, any other level 0. A custom wind power above 0 replaces it, an event wind setting of 2 makes it 0, and it is capped at 1. While mInitAnimTimer is nonzero the wind vector and power jump to the new values; otherwise each call moves each vector component a tenth of the way (at most 2, at least 0.001) and the power a tenth of the way (at most 1, at least 0.005). Since the boat, in the decompilers' not-yet-matching C++ for d_a_ship (procSteerMove), divides the power by 0.5 and caps it at 1, a level-0 room tops out at 0.6 of the boat's 55, 33 units an update, and levels 1 and 2 at the full 55 (computed, once the power has settled).src/d/d_kankyo_wether.cpp L990–1040src/d/d_kankyo_wether.cpp L1062–1084src/d/actor/d_a_ship.cpp L1596Code
In the USA build, the wind-direction picker dOperate_wind_c (which the atlas reads as the Wind's Requiem's, from its TAKT_WIND sounds; "takt" is the baton) sets mDeg on opening from the current wind vector's yaw and then, with the stick pushed to at least 0.9, sets mDeg to one of eight compass values, 0 to 315 in 45-degree steps. A confirms it: windSet passes dKyw_tact_wind_set a pitch of 0 and a yaw of 180° − mDeg (0 gives −0x8000, 90 gives 0x4000, 270 gives −0x4000). dKyw_tact_wind_set stores both angles for the environment and in the save (dComIfGs_setWindX, setWindY) and sets the tact-wind flag; dKyw_wind_set then builds the wind vector as (cos pitch × cos yaw, sin pitch, cos pitch × sin yaw). dKyw_wind_init reloads the saved angles unless both are −1. B cancels the picker.src/d/d_operate_wind.cpp L370–384src/d/d_operate_wind.cpp L462–488src/d/d_operate_wind.cpp L613–616src/d/d_operate_wind.cpp L661–666src/d/d_kankyo_wether.cpp L1328–1338src/d/d_kankyo_wether.cpp L1010–1020src/d/d_kankyo_wether.cpp L967–974Code
In the decompilation's C++ for the boat (d_a_ship, not yet matching as a whole; the USA build), procSteerMove moves the unnamed angle m0366, which the atlas reads as the tiller, toward mStickMVal × 0x2000 × −sin(mStickMAng) with cLib_addCalcAngleS(…, 4, l_HIO.tiller_speed, 0x100), tiller_speed being 700, and, unless the boat is airborne, passes it to setMoveAngle. Unless the boat is being moved by force (checkForceMove), setMoveAngle sets a rate of 4 − |speedF| / 55 × 3, held between 0.1 and 3.6, blends it toward 3.6 by the unnamed counter m0388 over 15 (3.6 once m0388 reaches 15), and turns the facing by −rate × (m0366 >> 6). With m0388 at 0 and a tiller of 0x2000, that is about 461 units (2.5°) an update at rest and 128 units (0.7°) at speed 55 (computed): the boat turns slower the faster it sails.src/d/actor/d_a_ship.cpp L1586–1589src/d/actor/d_a_ship.cpp L71src/d/actor/d_a_ship.cpp L1113–1130Code
In the decompilation's C++ for the boat (d_a_ship, not yet matching as a whole; the USA build), procSteerMove allows a hop when no event runs, Link isn't barred from control (checkNoControll), the body animation is FN_MAST_ON2 at frame 7 or later, the boat isn't airborne, its forward speed mFwdVel is over 16.5, it isn't being moved by force, and the sailing target speed is at least 11. Then the R trigger's lock (mDoCPd_R_LOCK_TRIGGER) sets the airborne and jump flags and an upward speed equal to the target speed, held between 15 and 40, and sets mJumpRate to (speed.y − 11) × 0.014545455.src/d/actor/d_a_ship.cpp L1638–1658Code
In the USA build, the time of day is a float from 0 to 360, 15 to an hour (dKy_getdaytime_hour divides by 15); dKy_daynight_check calls 6:00 to 17:59 day. The environment's setup sets the advance mTimeAdv to 0.02, which dKy_custom_timeset can change. Each setDaytime call adds it only when no event-night stop is set, the save's get-item flag (2, 0) is set, no event runs, and (USA and PAL only) Link isn't on stage "sea" room 14 with stage layer 2 or 3. In rooms that pass time (getTimePass) the clock wraps from 360 to 0 and the day of the week goes up by one; in other rooms it advances only by day before 165 (11:00) and by night from 270 (18:00) to 345 (23:00). At 0.02 a day is 18,000 setDaytime calls (computed).src/d/d_kankyo.cpp L476src/d/d_kankyo.cpp L502–538src/d/d_kankyo.cpp L614–631src/d/d_kankyo.cpp L3361–3362Code