Landing lag
The time a character can't act after landing from an air attack, and the inputs that shorten it.
On this page
Landing lag is the time a character spends in a landing animation after an air attack touches down. In Super Smash Bros. Melee, a trigger press shortly before landing divides an aerial’s landing lag, so long as the move’s script has turned the lag on1. Super Smash Bros. skips the air-landing status outright when Z was pressed within the last 10 counts2.
- Press skips itSuper Smash Bros. (1999). Z within 10 counts before an air attack lands skips its air-landing status.2
- Press reduces itSuper Smash Bros. Melee (2001). A trigger or Z press shortly before an aerial lands divides its landing lag.1
Games
| Game | Year | How | Note |
|---|---|---|---|
| Super Smash Bros. | 1999 | Press skips it | Z within 10 counts before an air attack lands skips its air-landing status |
| Super Smash Bros. Melee | 2001 | Press reduces it | a trigger or Z press shortly before an aerial lands divides its landing lag |
Every claim about this mechanic, by game (2)
References
- ^ abIn the NTSC 1.02 version of Super Smash Bros. Melee, an aerial attack (statuses
ftCo_MS_AttackAirNtoftCo_MS_AttackAirLw) that touches down callsftCo_LandingAir_EnterWithLagfrom its collision routineftCo_AttackAir_Coll, throughft_80082C74, which calls it when the unnamedft_80081D0Creturns true. If the move's command script has setcmd_vars[0], which entering the aerial clears, the fighter enters that aerial's LandingAir status with the fighter's landing-lag attribute for it (landingairn_lagand the four like it), and the animation plays at a rate of (ftAnim_8006F484+ 0.1) / lag, whereftAnim_8006F484returns the animation's end frame. If the unnamed countx67Fis below c_E4 at that moment, the lag is first divided by c_E8, truncated to a whole number, and raised to 1 if that's 0; c_E4 and c_E8 arep_ftCommonDatafields from PlCo.dat, so the window and divisor aren't in the code.Fighter_procInputsetsx67Fto 0 on an update where theHSD_PAD_LRbit is newly pressed and otherwise adds 1, up to 255. That bit is on while L or R is held, while the analog trigger is past its deadzone, or while Z is held unlessgm_GetDbPauseFlag(0)is true, and it's off while the unnamedgm_8016B0FCis true. Withoutcmd_vars[0], the fighter takes the basic landing (ftCo_Landing_Enter_Basic). Super Smash Bros. reads the same moment differently (ftCommonAttackAirProcMap): when the aerial'sflag1is clear or Z was pressed no more than 10 counts before (tics_since_last_z≤ 10), it skips the aerial's landing lag outright, landing in Wait if the air speed is above −20 and in Landing otherwise, where Melee divides the lag.Codedoldecomp/melee · VetriTheRetri/ssb-decomp-reHow we know
14void ftCo_LandingAir_EnterWithLag(Fighter_GObj* gobj) ⋮ 20 if (fp->cmd_vars[0]) { 21 switch (fp->motion_id) { 22 case ftCo_MS_AttackAirN: 23 lag = fp->co_attrs.landingairn_lag; 24 msid = ftCo_MS_LandingAirN; 25 break; ⋮ 29 break; ⋮ 33 break; ⋮ 37 break; ⋮ 41 break; ⋮ 43 if (msid != ftCo_MS_None && fp->x67F < p_ftCommonData->xE4) { ⋮
src/melee/ft/kinds/ftCommon/ftCo_LandingAir.c lines 14–56 at f0cdbb0 · upstream ↗ 59void ftCo_LandingAir_EnterWithMsidLag(Fighter_GObj* gobj, FtMotionId msid, 60 float lag) ⋮ 64 Fighter_ChangeMotionState(gobj, msid, Ft_MF_None, 0, 1, 0, NULL); 65 ftAnim_SetAnimRate(gobj, (ftAnim_8006F484(gobj) + 0.1f) / lag);
src/melee/ft/kinds/ftCommon/ftCo_LandingAir.c lines 59–65 at f0cdbb0 · upstream ↗ 575float ftAnim_8006F484(Fighter_GObj* fighter_gobj) ⋮ 580 return lbGetJObjEndFrame(jobj); ⋮ 582 return lbGetJObjEndFrame(fp->x8AC_animSkeleton);
src/melee/ft/ftanim.c lines 575–582 at f0cdbb0 · upstream ↗ 125void ftCo_AttackAir_EnterFromMsid(Fighter_GObj* gobj, FtMotionId msid) ⋮ 129 fp->cmd_vars[0] = 0;
src/melee/ft/kinds/ftCommon/ftCo_AttackAir.c lines 125–129 at f0cdbb0 · upstream ↗ 189void ftCo_AttackAir_Coll(Fighter_GObj* gobj) ⋮ 191 ft_80082C74(gobj, ftCo_LandingAir_EnterWithLag);
src/melee/ft/kinds/ftCommon/ftCo_AttackAir.c lines 189–191 at f0cdbb0 · upstream ↗ 850 // ftCo_MS_AttackAirN = 65 ⋮ 857 ftCo_AttackAir_Coll,
src/melee/ft/ftmotionstates.c lines 850–857 at f0cdbb0 · upstream ↗ 548void ft_80082C74(Fighter_GObj* gobj, HSD_GObjEvent cb) ⋮ 550 bool var_r0 = ft_80081D0C(gobj); 551 PAD_STACK(8); 552 if (var_r0) { 553 cb(gobj);
src/melee/ft/ft_081B.c lines 548–554 at f0cdbb0 · upstream ↗ 456void ftAction_80071820(Fighter_GObj* gobj, CommandInfo* cmd) ⋮ 460 switch (cmd->x8.u->set_cmd_var.idx) { 461 case 0: 462 fp->cmd_vars[0] = cmd->x8.u->set_cmd_var.value;
src/melee/ft/ftaction.c lines 456–462 at f0cdbb0 · upstream ↗ 947 /* +0E8 fp+1F8 */ float landingairn_lag; 948 /* +0EC fp+1FC */ float landingairf_lag; 949 /* +0F0 fp+200 */ float landingairb_lag; 950 /* +0F4 fp+204 */ float landingairhi_lag; 951 /* +0F8 fp+208 */ float landingairlw_lag;
src/melee/ft/types.h lines 947–951 at f0cdbb0 · upstream ↗ 1879 if (gm_8016B0FC()) { 1880 fp->input.triggers[0] = 0.0f; 1881 if (ftCo_IsCpuControlled(fp)) { 1882 fp->input.held_buttons[0] &= HSD_PAD_A | HSD_PAD_XY; 1883 } else { 1884 fp->input.held_buttons[0] &= HSD_PAD_A; ⋮ 1886 } else { 1887 if (fp->input.held_buttons[0] & (HSD_PAD_L | HSD_PAD_R)) { 1888 fp->input.held_buttons[0] |= HSD_PAD_LR; 1889 fp->input.triggers[0] = 1.0f; 1890 } else if (fp->input.triggers[0]) { 1891 fp->input.held_buttons[0] |= HSD_PAD_LR; ⋮
src/melee/ft/fighter.c lines 1879–1898 at f0cdbb0 · upstream ↗ 1866 if (fp->input.triggers[0] <= 1867 p_ftCommonData->analog_shoulder_deadzone) ⋮ 1869 fp->input.triggers[0] = 0.0f;
src/melee/ft/fighter.c lines 1866–1869 at f0cdbb0 · upstream ↗ 1759static void Fighter_procInput_Inner1(Fighter* fp) ⋮ 1764 temp0_loc_0 = (fp->input.held_buttons[0] & 1765 (fp->input.held_buttons[1] ^ fp->input.held_buttons[0]));
src/melee/ft/fighter.c lines 1759–1765 at f0cdbb0 · upstream ↗ 1902 Fighter_procInput_Inner1(fp);src/melee/ft/fighter.c line 1902 at f0cdbb0 · upstream ↗ 2105 if (fp->input.pressed_buttons & HSD_PAD_LR) { 2106 fp->x67F = 0; 2107 } else if (fp->x67F < 255) { 2108 fp->x67F++;
src/melee/ft/fighter.c lines 2105–2109 at f0cdbb0 · upstream ↗ 53void ftCommonAttackAirProcMap(GObj *fighter_gobj) ⋮ 57 if (mpCommonCheckFighterLanding(fighter_gobj) != FALSE) ⋮ 59 if ((fp->motion_vars.flags.flag1 != 0) && (fp->tics_since_last_z > FTCOMMON_ATTACKAIR_SMOOTHLANDING_TICS_MAX)) ⋮ 65 ftCommonLandingAirSetStatus(fighter_gobj); ⋮ 67 else ftCommonLandingAirNullSetStatus(fighter_gobj, F_PCT_TO_DEC(fp->motion_vars.flags.flag1)); ⋮ 69 else if (fp->physics.vel_air.y > FTCOMMON_ATTACKAIR_SKIPLANDING_VEL_Y_MAX) ⋮ 71 ftCommonWaitSetStatus(fighter_gobj); ⋮ 73 else ftCommonLandingSetStatus(fighter_gobj);
src/ft/ftcommon/ftcommonattackair.c lines 53–74 at 572a747 · upstream ↗ 361#define FTCOMMON_ATTACKAIR_SMOOTHLANDING_TICS_MAX 10 362#define FTCOMMON_ATTACKAIR_SKIPLANDING_VEL_Y_MAX (-20.0F)
src/ft/ftcommon.h lines 361–362 at 572a747 · upstream ↗ 1373 if (this_fp->tics_since_last_z < FTINPUT_ZTRIGLAST_TICS_MAX) ⋮ 1375 this_fp->tics_since_last_z++; ⋮ 1377 if (this_fp->input.pl.button_tap & this_fp->input.button_mask_z) ⋮ 1379 this_fp->tics_since_last_z = 0;
src/ft/ftmain.c lines 1373–1380 at 572a747 · upstream ↗ 190 fp->motion_vars.flags.flag1 = 0;src/ft/ftcommon/ftcommonattackair.c line 190 at 572a747 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abIn the US version of Super Smash Bros., when a fighter in an air attack lands,
ftCommonAttackAirProcMapenters the move's air-landing status only when the motion'sflag1is nonzero and more than 10 counts have passed since Z was last pressed (tics_since_last_z: set to 0 on a Z press, counted up each update, and set to its maximum when the air attack starts, so a press before the attack doesn't count); otherwise it skips that status and enters Wait if the fighter's vertical speed is above −20, or the plain Landing status if not. Readingflag1as the move's switch for landing lag is the atlas's.CodeVetriTheRetri/ssb-decomp-rerevisedHow we know
53void ftCommonAttackAirProcMap(GObj *fighter_gobj) ⋮ 59 if ((fp->motion_vars.flags.flag1 != 0) && (fp->tics_since_last_z > FTCOMMON_ATTACKAIR_SMOOTHLANDING_TICS_MAX)) ⋮ 65 ftCommonLandingAirSetStatus(fighter_gobj); ⋮ 69 else if (fp->physics.vel_air.y > FTCOMMON_ATTACKAIR_SKIPLANDING_VEL_Y_MAX) ⋮ 71 ftCommonWaitSetStatus(fighter_gobj); ⋮ 73 else ftCommonLandingSetStatus(fighter_gobj);
src/ft/ftcommon/ftcommonattackair.c lines 53–74 at 572a747 · upstream ↗ 361#define FTCOMMON_ATTACKAIR_SMOOTHLANDING_TICS_MAX 10 362#define FTCOMMON_ATTACKAIR_SKIPLANDING_VEL_Y_MAX (-20.0F)
src/ft/ftcommon.h lines 361–362 at 572a747 · upstream ↗ 1373 if (this_fp->tics_since_last_z < FTINPUT_ZTRIGLAST_TICS_MAX) ⋮ 1375 this_fp->tics_since_last_z++; ⋮ 1377 if (this_fp->input.pl.button_tap & this_fp->input.button_mask_z) ⋮ 1379 this_fp->tics_since_last_z = 0;
src/ft/ftmain.c lines 1373–1380 at 572a747 · upstream ↗ 202 fp->tics_since_last_z = FTINPUT_ZTRIGLAST_TICS_MAX;src/ft/ftcommon/ftcommonattackair.c line 202 at 572a747 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-27.
Revised after a check by a second AI model, 2026-10-27: Starting an air attack sets the Z counter to its maximum, so a press before the attack doesn't count.
Sources
Code
- doldecomp. 2026. “melee: a decompilation of Super Smash Bros. Melee (doldecomp/melee).” Commit f0cdbb0. doldecomp/melee @ f0cdbb0 · licence, all uses
- VetriTheRetri. 2026. “ssb-decomp-re: a decompilation of Super Smash Bros. (VetriTheRetri/ssb-decomp-re).” Commit 572a747. VetriTheRetri/ssb-decomp-re @ 572a747 · licence, all uses