Mechanic · combat · rail shooter, shooter
Locational damage
Damage that lands on one part of a character or craft, so a part can break and take an ability with it.
On this page
Locational damage gives parts of a body their own health. In Star Fox 64 each Arwing wing has its own health, side hits take it faster than hits from above or below, and a broken wing sets the lasers back to single1.
- Wing lossStar Fox 64 (1997). Each wing starts at 60 (10 in Expert); side hits take 20, others 15, and a broken or missing wing sets the lasers to single.1
- Hit locationPerfect Dark (2000). A head hit ×4 and a torso hit ×2; in solo a player's gun shot multiplies a head hit by 25 more.2
Games
| Game | Year | How | Note |
|---|---|---|---|
| Star Fox 64 | 1997 | Wing loss | each wing starts at 60 (10 in Expert); side hits take 20, others 15, and a broken or missing wing sets the lasers to single |
| Perfect Dark | 2000 | Hit location | a head hit ×4 and a torso hit ×2; in solo a player's gun shot multiplies a head hit by 25 more |
Every claim about this mechanic, by game (2)
References
- ^ abIn the US 1.1 version of Star Fox 64,
Player_Setupgives the player 255 shield units (less with a Versus handicap), and healing stops atPlay_GetMaxShields: 383 with three or more gold rings, otherwise 255. A hit's damage, doubled in Expert mode, drains from the shield at 2 units an update (Player_UpdateShields), and an enemy laser's damage is 20; a hit whilegHasShieldis set does none. Each Arwing wing starts at 60 health (10 in Expert mode). A hit the code gives direction 1 or 2 takes 20 from the right or left wing, directions 3 and 4 take 15 from one wing at random, and direction 0, which enemy shots pass, takes none; a wing at 0 breaks. While either wing is broken or absent (WINGSTATE_NONE; the test is<= WINGSTATE_BROKEN),Player_Shootsets the lasers back to single every update.Codesonicdcer/sf64revisedHow we know
4405void Player_Setup(Player* playerx) { ⋮ 4414 player->shields = 255; ⋮ 4416 if (gVersusMode) { 4417 switch (gHandicap[gPlayerNum]) { 4418 case 1: 4419 player->shields = 191; ⋮ 4422 player->shields = 127; ⋮ 4430 if (gExpertMode) { 4431 gLeftWingHealth[gPlayerNum] = 10; 4432 gRightWingHealth[gPlayerNum] = 10; 4433 } else { 4434 gLeftWingHealth[gPlayerNum] = 60; ⋮
src/engine/fox_play.c lines 4405–4436 at 4235c59 · upstream ↗ 64s32 Play_GetMaxShields(void) { 65 if (gGoldRingCount[0] >= 3) { 66 return 383; ⋮ 68 return 255;
src/engine/fox_play.c lines 64–69 at 4235c59 · upstream ↗ 5463void Player_UpdateShields(Player* player) { 5464 if (player->damage > 0) { 5465 player->damage -= 2; ⋮ 5469 player->shields -= 2; ⋮ 5476 if (player->heal > 0) { ⋮ 5482 player->shields += 2; 5483 if (player->shields >= Play_GetMaxShields()) { 5484 player->shields = Play_GetMaxShields();
src/engine/fox_play.c lines 5463–5484 at 4235c59 · upstream ↗ 867 if (gExpertMode) { 868 player->damage = damage * 2; 869 } else { 870 player->damage = damage; ⋮ 887 } else { ⋮ 891 if (gHasShield[player->num]) { ⋮ 895 player->damage = 0;
src/engine/fox_play.c lines 867–895 at 4235c59 · upstream ↗ 916 switch (player->hitDirection) { 917 case 0: ⋮ 924 case 1: ⋮ 932 Player_DamageWings(player, 1, 20); ⋮ 935 case 2: ⋮ 943 Player_DamageWings(player, 2, 20); ⋮ 946 case 3: ⋮ 958 if (Rand_ZeroOne() < 0.5f) { 959 Player_DamageWings(player, 1, 15); 960 } else { 961 Player_DamageWings(player, 2, 15); ⋮ 965 case 4: ⋮
src/engine/fox_play.c lines 916–978 at 4235c59 · upstream ↗ 819void Player_DamageWings(Player* player, s32 side, s32 damage) { 820 if ((player->form == FORM_ARWING) && (gShieldAlpha[player->num] < 1.0f)) { 821 if (side == 1) { ⋮ 823 if (player->arwing.rightWingState == WINGSTATE_INTACT) { 824 gRightWingHealth[player->num] -= damage; 825 if (gRightWingHealth[player->num] <= 0) { ⋮ 827 player->arwing.rightWingState = WINGSTATE_BROKEN;
src/engine/fox_play.c lines 819–827 at 4235c59 · upstream ↗ 3299void Player_Shoot(Player* player) { 3300 switch (player->form) { 3301 case FORM_ARWING: 3302 if ((player->arwing.rightWingState <= WINGSTATE_BROKEN) || 3303 (player->arwing.leftWingState <= WINGSTATE_BROKEN)) { 3304 gLaserStrength[player->num] = LASERS_SINGLE;
src/engine/fox_play.c lines 3299–3305 at 4235c59 · upstream ↗ 27 /* 0 */ WINGSTATE_NONE, 28 /* 1 */ WINGSTATE_BROKEN, 29 /* 2 */ WINGSTATE_INTACT
include/sf64player.h lines 27–29 at 4235c59 · upstream ↗ 2925 if ((gPlayer[0].barrelRollAlpha == 0) && (gPlayer[0].mercyTimer == 0)) { 2926 Player_ApplyDamage(&gPlayer[0], 0, this->info.damage);
src/engine/fox_effect.c lines 2925–2926 at 4235c59 · upstream ↗ 472 /* OBJ_EFFECT_ENEMY_LASER */ {(void*) Effect_EnemyLaser_Draw, 1, (ObjectFunc) Effect_EnemyShot_Update, NULL, 100.0f, 0, 0, 20, 0, 0.0f, 0 },src/engine/fox_edata_info.c line 472 at 4235c59 · upstream ↗ 153typedef struct ObjectInfo { ⋮ 161 /* 0x10 */ f32 cullDistance; // z coordinate of something 162 /* 0x14 */ s16 unk_14; // can be -1, 0, 1. governs camera-related behavior in effects (billboarding?) 163 /* 0x16 */ s16 unk_16; // can be 0, 1, 2. affects death behavior? 164 /* 0x18 */ u8 damage;
include/sf64object.h lines 153–168 at 4235c59 · 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.
- ^Perfect Dark's
chr_damagescales a hit by the body part (hitpart) it struck: a head hit is multiplied by 4 and a torso hit doubled, the limbs and pelvis keep the damage, and a hit on the held gun or a hat deals none. Outside normal multiplayer a gun shot fired by a player multiplies a head hit by a further 25 (headshotdamagescale), 100 in all, unless a shield took it; a Skedar's head is only doubled, and its tail takes 10 times. A hit with no part (HITPART_GENERAL, as when a guard's bullet hits the player) is halved and then doubled as the torso, so it keeps its damage. Doom'sP_LineAttackpasses a bullet's damage to the thing it hits with no body part.Coderyandwyer/perfect-dark · id-Software/DOOMHow we know
4262void chr_damage(struct chrdata *chr, f32 damage, struct coord *vector, struct gset *gset, 4263 struct prop *aprop, s32 hitpart, bool damageshield, struct prop *prop2, ⋮ 4273 f32 headshotdamagescale = 1;
src/game/chraction.c lines 4262–4273 at 46d3393 · upstream ↗ 4368 if (ismelee) { 4369 isshoot = false;
src/game/chraction.c lines 4368–4370 at 46d3393 · upstream ↗ 4390 // Apply damage scaling based on difficulty settings 4391 if (g_Vars.mplayerisrunning == false) { 4392 // Solo ⋮ 4397 } else if (aprop && aprop->type == PROPTYPE_PLAYER) { 4398 // Player is attacking 4399 damage *= g_PlayerDamageTxScale; 4400 headshotdamagescale = 25;
src/game/chraction.c lines 4390–4400 at 46d3393 · upstream ↗ 4414 } else if (g_Vars.coopplayernum >= 0) { ⋮ 4420 } else if (aprop && aprop->type == PROPTYPE_PLAYER && vprop->type != PROPTYPE_PLAYER) { 4421 damage *= g_PlayerDamageTxScale; 4422 headshotdamagescale = 25;
src/game/chraction.c lines 4413–4422 at 46d3393 · upstream ↗ 4707 if (hitpart == HITPART_GENERAL) { 4708 // Halve the damage because it's doubled for torso below 4709 hitpart = HITPART_TORSO; 4710 damage *= 0.5f; ⋮ 4713 hitpart = HITPART_TORSO; ⋮ 4717 // Hits to a Skedar's tail are 10x more lethal 4718 if (race == RACE_SKEDAR && hitpart == HITPART_TAIL) { 4719 damage *= 10; ⋮ 4724 if (hitpart == HITPART_HEAD) { 4725 if (race == RACE_SKEDAR) { 4726 damage += damage; 4727 chr_flinch_head(chr, angle); ⋮
src/game/chraction.c lines 4707–4751 at 46d3393 · upstream ↗ 1396#define HITPART_LFOOT 1 ⋮ 1402#define HITPART_PELVIS 7 1403#define HITPART_HEAD 8 ⋮ 1410#define HITPART_TORSO 15 1411#define HITPART_TAIL 16 1412#define HITPART_GUN 100 1413#define HITPART_HAT 110
src/include/constants.h lines 1396–1413 at 46d3393 · upstream ↗ 10361 if (hitplayer) { 10362 f32 damage = gset_get_damage(&gset); ⋮ 10385 chr_damage_by_impact(targetchr, damage, &vector, &gset, chr->prop, HITPART_GENERAL, targetprop, node, model, side, NULL);
src/game/chraction.c lines 10361–10385 at 46d3393 · upstream ↗ 1005 if (in->d.thing->flags & MF_NOBLOOD) 1006 P_SpawnPuff (x,y,z); 1007 else 1008 P_SpawnBlood (x,y,z, la_damage); ⋮ 1010 if (la_damage) 1011 P_DamageMobj (th, shootthing, shootthing, la_damage);
linuxdoom-1.10/p_map.c lines 1004–1011 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
Sources
Code
- sonicdcer and sf64 contributors. 2026. “sf64: a decompilation of Star Fox 64 (sonicdcer/sf64).” Commit 4235c59. sonicdcer/sf64 @ 4235c59 · licence, all uses