On this page
  1. Related
  2. Games
  3. References
  4. Sources

Wind gives a game’s world a direction to move with or against. In The Legend of Zelda: The Wind Waker, the Wind’s Requiem sets one of eight directions1, and each room’s wind level sets the strength the sail feels2.

Games

GameYearHowNote
The Legend of Zelda: The Wind Waker2002Player-setthe Wind's Requiem picks one of eight directions, 45° apart, kept in the save; each room's wind level sets the strength
Super Mario Bros.: The Lost Levels1986Area pusha steady push to the right in some outdoor stretches, on average a quarter of Mario's walking speed
Every claim about this mechanic, by game (5)
Super Mario Bros.: The Lost Levels 1986Wind blows the player to the right. An area object turns it on (WindOn) and another off (WindOff), and the setup that runs at the start of every area clears it. While it is on, and only in ground-type areas (underground, water, and castle areas stay calm), it moves the player 1 px right on every fourth frame while the frame counter is below 128 and on every second frame from 128 to 255: 96 px every 256 frames, 0.375 px a frame on average. The push is added to the position after the player's own move, on the ground and in the air but not while climbing, so it adds to a rightward speed and takes from a leftward one whatever the speed, and the screen scrolls with it. Its leaves and sound play while it is on, in every type of area. None of it runs until the game has loaded a disk file beyond worlds 1 to 4 (worlds 5 to 8, the ending, or worlds A to D): before that, FileListNumber is 0 and both calls are skipped.Code
GameCoreRoutine and ScrollHandler are Super Mario Bros.'s with three changes: the game mode's task list gains GameModeDiskRoutines at its head and the core no longer reads the current player's saved joypad bits; each frame of play calls SimulateWind once a disk file beyond worlds 1 to 4 is loaded; ScrollHandler waits for the status bar's timer IRQ before it scrolls and keeps the name table in NameTableSelect, where Super Mario Bros. sets it in its PPU control mirror. GetScreenPosition is byte for byte the same.Code
The player's control and movement code (GameRoutines through ImposeFriction) is Super Mario Bros.'s, instruction for instruction in 14 of its 19 regions, with these changes: OnGroundStateSub and the jump and swim code move the player through a new JmpMove, which lets the wind push them (BlowPlayerAround) once a disk file beyond worlds 1 to 4 is loaded; PlayerPhysicsSub's friction table moves up to follow the fall forces, inside the 17 bytes that LoadPhysicsData overwrites with Mario's or Luigi's set; PlayerEndLevel queues the level-end music once, guarded by a new FlagpoleMusicFlag, where Super Mario Bros. queues it whenever ScrollLock is set, and sets the hidden 1-up's flag on 10 coins in any world, where Super Mario Bros. reads a per-world table, and starts world 9 over after 9-4; PlayerDeath shares one RTS. The entrances, pipes, size change, injury blink, flagpole slide, falling, climbing, animation speed and ImposeFriction differ only in their addresses.Code
The Legend of Zelda: The Wind Waker 2002In 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).Code
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.Code

References

  1. ^ abIn 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.Codezeldaret/tww
    How we know
    372    if (stick->getValueStick() >= 0.89999998f && fabs(stick_value) - fabs(field_0x8b8) >= 0.0) {
    373        int stick_control = dOw_stickControl(field_0x8d0, stick->getAngleStick());
    ⋮
    377            switch (stick_control) {
    378            case 8:
    379                if (mDeg != 315) {
    380                    field_0x8ca = 7;
    381                    mDeg = 315;
    382                    mDoAud_seStart(JA_SE_TAKT_WIND_CURSOR);
    
    src/d/d_operate_wind.cpp lines 370–384 at cb24f55 · upstream ↗
    462void dOperate_wind_c::windSet() {
    463    switch (mDeg) {
    464    case 315:
    465        dKyw_tact_wind_set(0, -0x6000);
    466        break;
    467    case 0:
    468        dKyw_tact_wind_set(0, -0x8000);
    469        break;
    470    case 45:
    471        dKyw_tact_wind_set(0, 0x6000);
    472        break;
    473    case 90:
    ⋮
    
    src/d/d_operate_wind.cpp lines 462–488 at cb24f55 · upstream ↗
    613    cXyz* wind_vec = dKyw_get_wind_vec();
    614    s16 temp_r3 = cM_atan2s(wind_vec->x, wind_vec->z) + 0x8000;
    615    mDeg = dOw_angleRegular(((180.0f * temp_r3) / (f32)0x8000) - 90.0f);
    616    arrowRotate(&field_0xec, mDeg);
    
    src/d/d_operate_wind.cpp lines 613–616 at cb24f55 · upstream ↗
    661        if (CPad_CHECK_TRIG_A(0)) {
    662            windSet();
    663            dComIfGp_setOperateWindChangeOff();
    664        } else if (CPad_CHECK_TRIG_B(0)) {
    665            dComIfGp_setOperateWindCancelOff();
    
    src/d/d_operate_wind.cpp lines 661–666 at cb24f55 · upstream ↗
    1328void dKyw_tact_wind_set(s16 i_windX, s16 i_windY) {
    ⋮
    1332    env_light.mWind.mTactWindAngleX = i_windX;
    1333    env_light.mWind.mTactWindAngleY = i_windY;
    1334    dComIfGs_setWindX(i_windX);
    1335    dComIfGs_setWindY(i_windY);
    ⋮
    1338    env_light.mWind.mTactWindAngleFlags = 1;
    
    src/d/d_kankyo_wether.cpp lines 1328–1338 at cb24f55 · upstream ↗
    1010        } else if (g_env_light.mWind.mTactWindAngleFlags != 0) {
    1011            tact_wind_x = g_env_light.mWind.mTactWindAngleX;
    1012            tact_wind_y = g_env_light.mWind.mTactWindAngleY;
    ⋮
    1018        wind_vec.x = cM_scos(tact_wind_x) * cM_scos(tact_wind_y);
    1019        wind_vec.y = cM_ssin(tact_wind_x);
    1020        wind_vec.z = cM_scos(tact_wind_x) * cM_ssin(tact_wind_y);
    
    src/d/d_kankyo_wether.cpp lines 1010–1020 at cb24f55 · upstream ↗
    967    if (dComIfGs_getWindX() == -1 && dComIfGs_getWindY() == -1) {
    968        g_env_light.mWind.mTactWindAngleFlags = 0;
    ⋮
    972        g_env_light.mWind.mTactWindAngleFlags = 1;
    973        g_env_light.mWind.mTactWindAngleX = dComIfGs_getWindX();
    974        g_env_light.mWind.mTactWindAngleY = dComIfGs_getWindY();
    
    src/d/d_kankyo_wether.cpp lines 967–974 at cb24f55 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-22.

    In the claim ledger

  2. ^ abIn 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).Codezeldaret/twwrevised
    How we know
    990    if (g_env_light.mWind.mpWindVecOverride != NULL) {
    991        wind_vec = *g_env_light.mWind.mpWindVecOverride;
    992        strength = g_env_light.mWind.mWindStrengthOverride;
    ⋮
    1022        if (fili_p != NULL) {
    1023            wind_level = dStage_FileList_dt_GlobalWindLevel(fili_p);
    ⋮
    1026        switch (wind_level) {
    1027        case 0:
    1028            strength = 0.3f;
    1029            break;
    1030        case 1:
    1031            strength = 0.6f;
    1032            break;
    ⋮
    
    src/d/d_kankyo_wether.cpp lines 990–1040 at cb24f55 · upstream ↗
    1062    if (g_env_light.mWind.mCustomWindPower > 0.0f) {
    1063        strength = g_env_light.mWind.mCustomWindPower;
    ⋮
    1067    if (g_env_light.mWind.mEvtWindSet == 2) {
    1068        strength = 0.0f;
    ⋮
    1071    if (strength > 1.0f) {
    1072        strength = 1.0f;
    ⋮
    1075    if (g_env_light.mInitAnimTimer != 0) {
    1076        g_env_light.mWind.mWindVec = wind_vec;
    1077        g_env_light.mWind.mWindPower = strength;
    1078    } else {
    1079        f32 scale = 0.1f;
    1080        cLib_addCalc(&g_env_light.mWind.mWindVec.x, wind_vec.x, scale, 2.0f, 0.001f);
    ⋮
    
    src/d/d_kankyo_wether.cpp lines 1062–1084 at cb24f55 · upstream ↗
    1596        f32 targetSpeed = *dKyw_get_wind_power() / 0.5f;
    
    src/d/actor/d_a_ship.cpp line 1596 at cb24f55 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

Sources

Code