Mechanic · combat · fighting game
Hitstun
The time after a hit during which the character that was hit can't act.
On this page
Hitstun is the time a character can’t act after a hit. In Super Smash Bros. it’s the knockback divided by 1.8751, so harder launches stun for longer1. In its NTSC 1.02 version, Super Smash Bros. Melee multiplies the knockback instead, by a value from a disc file that the code doesn’t hold2.
- From knockbackSuper Smash Bros. (1999). The knockback divided by 1.875, as a whole count of at least 1.1Super Smash Bros. Melee (2001). The knockback times a data-file value, as a whole count of at least 1; an air jump or up special can end it early after a hit at an angle in a set range.2
Games
| Game | Year | How | Note |
|---|---|---|---|
| Super Smash Bros. | 1999 | From knockback | the knockback divided by 1.875, as a whole count of at least 1 |
| Super Smash Bros. Melee | 2001 | From knockback | the knockback times a data-file value, as a whole count of at least 1; an air jump or up special can end it early after a hit at an angle in a set range |
Every claim about this mechanic, by game (2)
References
- ^ abcIn the US version of Super Smash Bros.,
ftCommonDamageInitDamageVarssets a hit fighter'shitstun_tics, a whole-number count, to its knockback divided by 1.875 (ftParamGetHitStun), and to 1 if that comes to 0. The damage statuses' common update routines take 1 off the count each time they run. Until it reaches 0, their common interrupt routines don't run the standing, falling, or hammer interrupt checks (ftCommonWaitProcInterrupt,ftCommonFallProcInterrupt, and the hammer's), so the fighter can't act, and an airborne fighter gets friction in place of the usual drift and fast-fall. At 0, the status ends once its animation has run out. A knockback of 100 gives 53 counts (computed).CodeVetriTheRetri/ssb-decomp-reHow we know
1505f32 ftParamGetHitStun(f32 knockback) ⋮ 1507 return knockback / 1.875F;
src/ft/ftparam.c lines 1505–1508 at 572a747 · upstream ↗ 482 f32 hitstun_tics = ftParamGetHitStun(knockback); ⋮ 491 this_fp->status_vars.common.damage.hitstun_tics = hitstun_tics; ⋮ 493 if (this_fp->status_vars.common.damage.hitstun_tics == 0) ⋮ 495 this_fp->status_vars.common.damage.hitstun_tics = 1;
src/ft/ftcommon/ftcommondamage.c lines 482–496 at 572a747 · upstream ↗ 468typedef struct ftCommonDamageStatusVars ⋮ 470 s32 hitstun_tics;
src/ft/ftcommon.h lines 468–470 at 572a747 · upstream ↗ 662void ftCommonDamageGotoDamageStatus(GObj *fighter_gobj) ⋮ 674 else ftCommonDamageInitDamageVars(fighter_gobj, -1, fp->damage_queue, fp->damage_knockback, fp->damage_angle, fp->damage_lr, fp->damage_index, fp->damage_element, fp->damage_player_num, FALSE, FALSE, TRUE);
src/ft/ftcommon/ftcommondamage.c lines 662–674 at 572a747 · upstream ↗ 85void ftCommonDamageDecHitStunSetPublic(GObj *fighter_gobj) ⋮ 89 if (fp->status_vars.common.damage.hitstun_tics != 0) ⋮ 91 fp->status_vars.common.damage.hitstun_tics--; ⋮ 101void ftCommonDamageCommonProcUpdate(GObj *fighter_gobj) ⋮ 105 ftCommonDamageDecHitStunSetPublic(fighter_gobj); ⋮ 107 if ((fighter_gobj->anim_frame <= 0.0F) && (fp->status_vars.common.damage.hitstun_tics == 0)) ⋮ 109 mpCommonSetFighterWaitOrFall(fighter_gobj); ⋮ 114void ftCommonDamageAirCommonProcUpdate(GObj *fighter_gobj) ⋮ 119 ftCommonDamageDecHitStunSetPublic(fighter_gobj); ⋮ 121 if ((fighter_gobj->anim_frame <= 0.0F) && (fp->status_vars.common.damage.hitstun_tics == 0)) ⋮ 123 ftCommonDamageFallSetStatusFromDamage(fighter_gobj);
src/ft/ftcommon/ftcommondamage.c lines 85–123 at 572a747 · upstream ↗ 166void ftCommonDamageCommonProcInterrupt(GObj *fighter_gobj) ⋮ 170 if (fp->status_vars.common.damage.hitstun_tics == 0) ⋮ 172 fp->is_hitstun = FALSE; ⋮ 176 if (ftHammerCheckHoldHammer(fighter_gobj) != FALSE) ⋮ 178 ftCommonHammerFallProcInterrupt(fighter_gobj); ⋮ 180 else ftCommonFallProcInterrupt(fighter_gobj); ⋮ 182 else if (ftHammerCheckHoldHammer(fighter_gobj) != FALSE) ⋮ 184 ftHammerProcInterrupt(fighter_gobj); ⋮ 186 else ftCommonWaitProcInterrupt(fighter_gobj); ⋮ 191void ftCommonDamageAirCommonProcInterrupt(GObj *fighter_gobj) ⋮ 195 if (fp->status_vars.common.damage.hitstun_tics == 0) ⋮ 197 fp->is_hitstun = FALSE; ⋮
src/ft/ftcommon/ftcommondamage.c lines 166–199 at 572a747 · upstream ↗ 214void ftCommonDamageCommonProcPhysics(GObj *fighter_gobj) ⋮ 218 if (fp->ga == nMPKineticsAir) ⋮ 220 if (fp->status_vars.common.damage.hitstun_tics == 0) ⋮ 222 ftPhysicsApplyAirVelDriftFastFall(fighter_gobj); ⋮ 224 else ftPhysicsApplyAirVelFriction(fighter_gobj);
src/ft/ftcommon/ftcommondamage.c lines 214–224 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 NTSC 1.02 version of Super Smash Bros. Melee,
ftCo_8008DCE0, the routine that puts a hit fighter into a Damage status, sets the unnamed countmv.co.damage.x0to the knockback (kb_applied) timesp_ftCommonData->x154, a value from the disc file PlCo.dat, truncated to a whole number, and to 1 if that comes to 0. It also sets the flagx221C_b6, whichftLib_IsInHitstunreturns. Where Super Smash Bros. divides the knockback by 1.875 (ssb64/hitstun), Melee multiplies it by a value the code doesn't hold. The animation routines of the Damage statuses (75 to 86) and the DamageFly statuses (87 to 90) take 1 off the count while it's above 0 (ftCo_8008F744) and clear the flag once it's 0 or below; the status ends when its animation has run out with the flag clear. While the flag is set, their interrupt routines run onlydoIasa, as the decompilers name it, in place of the wait, fall, or hammer checks, so the fighter can't act, with one exception: after a hit whose angleftColl_8007AC68accepts (betweenunk_kb_angle_minandunk_kb_angle_max), once an unnamed countdown from c_7F0 runs out, an airborne fighter moving down can leave through an air up special (ftCo_800D69C4) or an air jump (ftCo_800CB8E0), which the atlas reads as the meteor cancel. A jump pressed in hitstun otherwise only records the count left. While the flag is set an airborne fighter gets gravity andaerial_friction(ft_80084EEC) in place of fast-fall and drift (ft_80084DB0). A change of motion state clears the flag unless the new state is entered withFt_MF_SkipHitStun. The DamageFlyRoll status's own routines aren't read here.Codedoldecomp/melee · VetriTheRetri/ssb-decomp-rerevisedHow we know
263void ftCo_8008DCE0(Fighter_GObj* gobj, int arg1, float facing_dir)src/melee/ft/kinds/ftCommon/ftCo_Damage.c line 263 at f0cdbb0 · upstream ↗ 282 float kb_applied = fp->dmg.kb_applied; ⋮ 287 scaled_kb_154 = kb_applied * p_ftCommonData->x154; 288 fp->mv.co.damage.x0 = (int) scaled_kb_154; 289 if (!fp->mv.co.damage.x0) { 290 fp->mv.co.damage.x0 = 1;
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 282–291 at f0cdbb0 · upstream ↗ 61int ftCo_803C5520[2][4][3] = { ⋮ 63 { 81, 78, 75 }, 64 { 82, 79, 76 }, 65 { 83, 80, 77 }, 66 { 89, 88, 87 }, ⋮ 69 { 84, 84, 84 }, 70 { 85, 85, 85 }, 71 { 86, 86, 86 }, 72 { 89, 88, 87 },
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 60–73 at f0cdbb0 · upstream ↗ 405 Fighter_ChangeMotionState(gobj, msid, 0x40U, 0, 1, 0, NULL);src/melee/ft/kinds/ftCommon/ftCo_Damage.c line 405 at f0cdbb0 · upstream ↗ 423 fp->x221C_b6 = true;src/melee/ft/kinds/ftCommon/ftCo_Damage.c line 423 at f0cdbb0 · upstream ↗ 665bool ftLib_IsInHitstun(HSD_GObj* gobj) ⋮ 667 Fighter* fp = GET_FIGHTER(gobj); 668 return fp->x221C_b6;
src/melee/ft/ftlib.c lines 665–669 at f0cdbb0 · upstream ↗ 843void ftCo_8008F744(Fighter_GObj* gobj) ⋮ 845 Fighter* fp = GET_FIGHTER(gobj); 846 if (fp->mv.co.damage.x0 > 0) { 847 fp->mv.co.damage.x0 -= 1; ⋮ 849 if (fp->x221C_b6) { 850 if (fp->mv.co.damage.x0 <= 0) { 851 fp->x221C_b6 = false;
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 843–852 at f0cdbb0 · upstream ↗ 872void ftCo_Damage_Anim(Fighter_GObj* gobj) ⋮ 874 Fighter* fp = GET_FIGHTER(gobj); 875 ftCo_8008F744(gobj); 876 if (!ftAnim_IsFramesRemaining(gobj) && !fp->x221C_b6) {
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 872–876 at f0cdbb0 · upstream ↗ 890bool doIasa(Fighter_GObj* gobj) ⋮ 892 Fighter* fp = gobj->user_data; 893 if (fp->mv.co.damage.x1A) { 894 if (fp->mv.co.damage.x1B) { 895 --fp->mv.co.damage.x1B; ⋮ 897 if (!fp->mv.co.damage.x1B && fp->ground_or_air == GA_Air && 898 fp->x8c_kb_vel.y < 0 && 899 (ftCo_800D69C4(gobj) || ftCo_800CB8E0(gobj))) ⋮ 905 return true; ⋮ 909 if (ftCo_Jump_GetInput(gobj)) { 910 fp->mv.co.damage.x14 = fp->mv.co.damage.x0; 911 return true; ⋮
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 890–914 at f0cdbb0 · upstream ↗ 916void ftCo_Damage_IASA(Fighter_GObj* gobj) ⋮ 918 Fighter* fp = gobj->user_data; 919 if (!fp->x221C_b6) { 920 if (ftCo_800C5240(gobj)) { 921 if (fp->ground_or_air == GA_Air) { 922 ftCo_HammerFall_IASA(gobj); 923 } else { 924 ftCo_HammerWait_IASA(gobj); ⋮ 926 } else { ⋮ 932 if (fp->ground_or_air == GA_Air) { 933 ftCo_Fall_IASA_Inner(gobj); 934 } else { ⋮
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 916–941 at f0cdbb0 · upstream ↗ 79float ftCo_Damage_CalcAngle(Fighter* fp, float f) ⋮ 81 if (fp->dmg.x1848_kb_angle != 361) { 82 if (ftColl_8007AC68(fp->dmg.x1848_kb_angle)) { 83 fp->mv.co.damage.x1A = 1; 84 fp->mv.co.damage.x1B = p_ftCommonData->x7F0;
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 79–85 at f0cdbb0 · upstream ↗ 312 fp->mv.co.damage.x1A = 0; 313 fp->mv.co.damage.x14 = 0; 314 kb_angle = ftCo_Damage_CalcAngle(fp, kb_applied);
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 312–314 at f0cdbb0 · upstream ↗ 2481bool ftColl_8007AC68(u32 kb_angle) ⋮ 2483 if (kb_angle != 361 && p_ftCommonData->unk_kb_angle_min <= kb_angle && 2484 kb_angle <= p_ftCommonData->unk_kb_angle_max) ⋮ 2486 return true; ⋮ 2488 return false;
src/melee/ft/ftcoll.c lines 2481–2489 at f0cdbb0 · upstream ↗ 103bool ftCo_800D69C4(Fighter_GObj* gobj) ⋮ 110 ftData_SpecialAirHi[fp->kind](gobj); 111 return true;
src/melee/ft/kinds/ftCommon/ftCo_Attack100.c lines 103–111 at f0cdbb0 · upstream ↗ 73bool ftCo_800CB8E0(Fighter_GObj* gobj) ⋮ 83 return ftCo_JumpAerial_CheckInput(gobj, true);
src/melee/ft/kinds/ftCommon/ftCo_JumpAerial.c lines 73–83 at f0cdbb0 · upstream ↗ 943void ftCo_Damage_Phys(Fighter_GObj* gobj) ⋮ 945 Fighter* fp = gobj->user_data; 946 if (fp->ground_or_air == GA_Air) { 947 if (!fp->x221C_b6) { 948 ft_80084DB0(gobj); 949 } else { 950 ft_80084EEC(gobj);
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 943–951 at f0cdbb0 · upstream ↗ 34void ft_80084EEC(Fighter_GObj* gobj) ⋮ 39 ftCommon_Fall(fp, co_attrs->gravity, co_attrs->terminal_velocity); 40 ftCommon_CalcSelfAccel_Deaccel(fp, co_attrs->aerial_friction);
src/melee/ft/ft_084E.c lines 34–41 at f0cdbb0 · upstream ↗ 1371void ft_80084DB0(Fighter_GObj* gobj) ⋮ 1376 ftCommon_CheckFallFast(fp); 1377 if (fp->fall_fast) { 1378 ftCommon_FallFast(fp); ⋮ 1382 ftCommon_CalcSelfAccel_Drift(fp);
src/melee/ft/ft_081B.c lines 1371–1382 at f0cdbb0 · upstream ↗ 1032void ftCo_DamageFly_Anim(Fighter_GObj* gobj) ⋮ 1036 ftCo_8008F744(gobj); 1037 if (!ftAnim_IsFramesRemaining(gobj) && !fp->x221C_b6) { ⋮ 1044void ftCo_DamageFly_IASA(Fighter_GObj* gobj) ⋮ 1046 if (!GET_FIGHTER(gobj)->x221C_b6) { 1047 ftCo_DamageFall_IASA(gobj); 1048 } else { 1049 RETURN_IF(doIasa(gobj));
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 1032–1050 at f0cdbb0 · upstream ↗ 1062static void inlineE0(Fighter_GObj* gobj) ⋮ 1064 Fighter* fp = GET_FIGHTER(gobj); 1065 if (!fp->x221C_b6) { 1066 ft_80084DB0(gobj); 1067 } else { 1068 ft_80084EEC(gobj);
src/melee/ft/kinds/ftCommon/ftCo_Damage.c lines 1062–1070 at f0cdbb0 · upstream ↗ 960 // ftCo_MS_DamageHi1 = 75 961 ftCo_SM_DamageHi1, 962 ftCo_MF_Damage, 963 FtMoveId_Default << 24, 964 ftCo_Damage_Anim, 965 ftCo_Damage_IASA, 966 ftCo_Damage_Phys,
src/melee/ft/ftmotionstates.c lines 960–966 at f0cdbb0 · upstream ↗ 1092 // ftCo_MS_DamageFlyHi = 87 ⋮ 1096 ftCo_DamageFly_Anim, 1097 ftCo_DamageFly_IASA, 1098 ftCo_DamageFly_Phys,
src/melee/ft/ftmotionstates.c lines 1092–1098 at f0cdbb0 · upstream ↗ 1035 if (((flags & Ft_MF_SkipHitStun) == 0) && (fp->x221C_b6 != 0U)) { 1036 fp->x221C_b6 = 0;
src/melee/ft/fighter.c lines 1035–1037 at f0cdbb0 · upstream ↗ 1505f32 ftParamGetHitStun(f32 knockback) ⋮ 1507 return knockback / 1.875F;
src/ft/ftparam.c lines 1505–1508 at 572a747 · 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.
Sources
Code
- 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
- doldecomp. 2026. “melee: a decompilation of Super Smash Bros. Melee (doldecomp/melee).” Commit f0cdbb0. doldecomp/melee @ f0cdbb0 · licence, all uses