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

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

GameYearHowNote
Star Fox 641997Wing losseach 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 Dark2000Hit locationa 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

  1. ^ abIn the US 1.1 version of Star Fox 64, Player_Setup gives the player 255 shield units (less with a Versus handicap), and healing stops at Play_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 while gHasShield is 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_Shoot sets the lasers back to single every update.Codesonicdcer/sf64revised
    How 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.

    In the claim ledger

  2. ^Perfect Dark's chr_damage scales 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's P_LineAttack passes a bullet's damage to the thing it hits with no body part.Coderyandwyer/perfect-dark · id-Software/DOOM
    How 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.

    In the claim ledger

Sources

Code