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

The atlas reads Duke Nukem 3D through the source 3D Realms released under the GPL in 2003, version 1.51,1. Much of the game’s tuning sits in its CON scripts, which the release includes; the Build engine underneath, with its hitscan trace, ships only as object files and a separately licensed source zip, so the claims here read the game code’s calls to it.

The game runs at 30 tics/s2,2. The pistol, shotgun, and chaingun are hitscan3, and each shot carries its weapon’s strength plus a small roll: strength + 0–54,4. A target’s pending damage rests at −1, so a single shot takes 1 less than it carries5. The shotgun and chaingun always spread their shots, but the pistol flies straight at a target autoaim has picked6. Autoaim turns the shot toward the nearest target within 8.4 °7 of the facing, across as well as up or down7. A pipe bomb’s blast rolls its damage in three distance bands8.

Movement adds a thrust each tic, in the air as on the ground9, against a friction of 53,200 / 65,53610 set by the CON script10. Forward and side moves are capped apart, the root of strafe-running11.

Mechanics

MechanicKindHow
HitscanHitscan beside projectilesthe pistol, shotgun, and chaingun trace a line in the call that fires them; the RPG fires a rocket sprite with a speed of its own
Damage formulaBase plus a rolla gun shot carries its CON strength plus 0 to 5, less 1 at the target; a blast rolls in three distance bands of the strength
AutoaimNearest in a conethe nearest target within 8.4° of the facing turns the shot both across and up or down
RunningMomentuma thrust each tic, in the air too, against 0.812 friction from the CON's RUNNINGSPEED
Strafe-runningSeparately capped axesforward and side moves are capped apart at 90, so a diagonal keyboard run is 1.41 times as fast
Every claim about this game, by concept (11)
generalThe Duke Nukem 3D source 3D Realms released on 2003-04-01 is version 1.5, the Atomic Edition: README.TXT calls it the "v1.5 CD Version" and "the complete source code for Duke Nukem 3D version 1.5", and the CON scripts in testdata/ call themselves part of "Duke Nukem 3D version 1.5 - Atomic Edition".Code
AutoaimWhen a Duke Nukem 3D player fires the pistol, shotgun, or chaingun, aim looks for a target within AUTO_AIM_ANGLE, 48 of 2,048 angle units (about 8.4°, computed), to either side of the facing; of those in sight, more than 512 along the facing, and with a height difference over that distance (scaled by 10) within 100 of the view's pitch, it takes the nearest along the facing, searching the sprite lists 10, 13, 1, and 2 in that order and stopping at the first list with a match, and skipping fellow players in co-op. The shot then turns to the target's angle (getangle) and takes the slope to a point ((xrepeat × tile height) << 1) + (5 << 8) above the target's z. Doom's P_BulletSlope traces only straight ahead and 5.625° to each side, and its bullet keeps the player's facing.Code
Damage formulaEach shot a Duke Nukem 3D player fires from the pistol, shotgun, or chaingun carries the strength its actor declares in the CON script plus TRAND%6 (0 to 5): 6 to 11 for the pistol (SHOTSPARK1), 10 to 15 for each of the shotgun's 7 pellets, and 9 to 14 for the chaingun; a monster's shot carries the strength alone. Each bullet from Doom's pistol, chaingun, or shotgun deals 5, 10, or 15.Code
A Duke Nukem 3D sprite's pending damage (hittype[].extra) is set to −1 when the sprite is created and again each time ifhitbyweapon takes it; a shot that checkhitsprite handles in its default branch adds its damage to the pending total, and ifhitbyweapon subtracts the total from the target's health, so a target hit once between checks loses 1 less than the shot carries, and several hits between checks take 1 less than their sum (computed). An explosion's hitradius sets the pending damage outright for the targets it rolls for, so those lose the full roll.Code
A Duke Nukem 3D pipe bomb that goes off passes its strength, 140 (HANDBOMB_WEAPON_STRENGTH), to hitradius with the radius PIPEBOMBRADIUS, 2,500; each sprite in lists 1, 6, 10, or 12 (not flammable) with extra of 0 or more that is a tripbomb, a monster (badguy), a QUEBALL, a STRIPEBALL, a DUKELYINGDEAD, or solid (cstat&257), within that dist and in sight of the blast, takes 105 to 139 inside a third of the radius, 70 to 104 inside two thirds, and 35 to 69 beyond: three quarters, a half, or a quarter of the strength plus TRAND modulo the next band's gap, 35 (computed). A monster in sprite list 2, which the hit wakes into list 1, goes through checkhitsprite instead unless a sight test at a random height fails, and loses 139 at any distance in the radius, the bomb's 140 added to its pending −1; a bomb set off by a hit first loses that hit's damage from its strength. A Doom rocket's blast falls off linearly, 128 minus the distance.Code
HitscanDuke Nukem 3D's pistol, shotgun, and chaingun are hitscan: shoot traces each shot with the Build engine's hitscan within the same call and spawns a SHOTSPARK1 sprite at the point hit, which carries the damage; the RPG instead spawns a rocket sprite with a velocity of 644. Doom's guns likewise trace a line with P_LineAttack in the tic they fire.Code
A Duke Nukem 3D player's shotgun and chaingun turn every shot by 16-(TRAND&31), −15 to +16 of the 2,048 angle units in a turn (up to about 2.8°, computed), and add 128-(TRAND&255) to its vertical speed, with or without an autoaim target; the pistol does both only when autoaim found none, so a pistol shot at an autoaim target flies straight to it. Doom's shotgun turns each of its 7 pellets by up to about 5.6°.Code
RunningDuke Nukem 3D schedules its timer with TS_ScheduleTask at a rate of TICRATE, 120, which the atlas reads as counts per second (the task manager's source isn't in the release), and faketimerhandler reads the player's input and queues one move every TICSPERFRAME counts, TICRATE/26, which integer division makes 4; domovethings runs once per queued move, so on that reading the game runs 30 tics a second (computed), where Doom runs 35.Code
A Duke Nukem 3D keyboard sets the forward and side moves to 40 walking or 80 running (NORMALKEYMOVE), each clamped apart to ±90 (MAXVEL, MAXSVEL); getinput turns the pair by the facing, and each tic processinput adds it to the player's velocity times TICSPERFRAME (4) and 64, doubled while steroids last and the jetpack is off, in the air as on the ground. A hard landing and a few other actions zero the velocity instead. Doom thrusts only on the floor, with moves of 25 or 50 forward and 24 or 40 sideways.Code
After the thrust, Duke Nukem 3D multiplies the player's velocity each tic by dukefriction, which the CON's gamestartup sets from RUNNINGSPEED, 53,200 of 65,536 (0.812; the C default is 0xcc00, 0.797): 0x2000 less when kicking or crouching on the ground, 0x1400 less underwater, and three quarters of it again while shrunk; the velocity drops to 0 once both axes are under 2,048. A steady run moves 4.31 times the per-tic thrust (0.812 / 0.188, computed), and a released run falls under half its speed within 4 tics (computed). Doom keeps 0.90625 of its momentum each tic.Code
Strafe-runningDuke Nukem 3D clamps the forward and side moves apart and adds them as perpendicular pushes, so running forward (80) while running sideways (80) gives √2 ≈ 1.41 times the forward run alone (computed); holding the strafe modifier with a turn key and a strafe key together reaches the side move's cap of 90, about 1.51 times. Doom's diagonal run, 50 forward and 40 sideways, is 1.28 times its forward run.Code

References

  1. ^ abThe Duke Nukem 3D source 3D Realms released on 2003-04-01 is version 1.5, the Atomic Edition: README.TXT calls it the "v1.5 CD Version" and "the complete source code for Duke Nukem 3D version 1.5", and the CON scripts in testdata/ call themselves part of "Duke Nukem 3D version 1.5 - Atomic Edition".Code3D Realms, duke3dsource.zip
    How we know
    2Duke Nukem 3D (v1.5 CD Version) Source Code Release - April 1, 2003
    
    README.TXT line 2 at e75bb06 · upstream ↗
    11This is the complete source code for Duke Nukem 3D version 1.5, buildable as detailed in the next section.
    
    README.TXT line 11 at e75bb06 · upstream ↗
    5This file is part of Duke Nukem 3D version 1.5 - Atomic Edition
    
    testdata/USER.CON line 5 at e75bb06 · 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. ^ abDuke Nukem 3D schedules its timer with TS_ScheduleTask at a rate of TICRATE, 120, which the atlas reads as counts per second (the task manager's source isn't in the release), and faketimerhandler reads the player's input and queues one move every TICSPERFRAME counts, TICRATE/26, which integer division makes 4; domovethings runs once per queued move, so on that reading the game runs 30 tics a second (computed), where Doom runs 35.Code3D Realms, duke3dsource.zip · id-Software/DOOMrevised
    How we know
    92#define TICRATE (120)
    93#define TICSPERFRAME (TICRATE/26)
    
    source/DUKE3D.H lines 92–93 at e75bb06 · upstream ↗
    106void timerhandler()
    ⋮
    108    totalclock++;
    ⋮
    113    TimerPtr = TS_ScheduleTask( timerhandler,TICRATE, 1, NULL );
    
    source/GAME.C lines 106–114 at e75bb06 · upstream ↗
    56task    *TS_ScheduleTask( void ( *Function )( task * ), int rate,
    
    source/TASK_MAN.H line 56 at e75bb06 · upstream ↗
    643    if ((totalclock < ototalclock+TICSPERFRAME) || (ready2send == 0)) return;
    644    ototalclock += TICSPERFRAME;
    ⋮
    652     getinput(myconnectindex);
    
    source/GAME.C lines 643–652 at e75bb06 · upstream ↗
    659     if (movefifoend[myconnectindex]&(movesperpacket-1))
    ⋮
    663          movefifoend[myconnectindex]++;
    664          return;
    ⋮
    673     movefifoend[myconnectindex]++;
    
    source/GAME.C lines 659–673 at e75bb06 · upstream ↗
    7973    while (movefifoend[myconnectindex]-movefifoplc > bufferjitter)
    ⋮
    7978        if( domovethings() ) return 1;
    
    source/GAME.C lines 7973–7978 at e75bb06 · upstream ↗
    121// State updates, number of tics / second.
    122#define TICRATE		35
    
    linuxdoom-1.10/doomdef.h lines 121–122 at a77dfb9 · 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

  3. ^Duke Nukem 3D's pistol, shotgun, and chaingun are hitscan: shoot traces each shot with the Build engine's hitscan within the same call and spawns a SHOTSPARK1 sprite at the point hit, which carries the damage; the RPG instead spawns a rocket sprite with a velocity of 644. Doom's guns likewise trace a line with P_LineAttack in the tic they fire.Code3D Realms, duke3dsource.zip · id-Software/DOOMrevised
    How we know
    481        case SHOTSPARK1:
    482        case SHOTGUN:
    483        case CHAINGUN:
    
    source/PLAYER.C lines 481–483 at e75bb06 · upstream ↗
    546            hitscan(sx,sy,sz,sect,
    547                sintable[(sa+512)&2047],
    548                sintable[sa&2047],
    549                zvel<<6,&hitsect,&hitwall,&hitspr,&hitx,&hity,&hitz,CLIPMASK1);
    ⋮
    559                k = EGS(hitsect,hitx,hity,hitz,SHOTSPARK1,-15,10,10,sa,0,0,i,4);
    560                sprite[k].extra = *actorscrptr[atwith];
    
    source/PLAYER.C lines 546–560 at e75bb06 · upstream ↗
    796        case RPG:
    ⋮
    801            vel = 644;
    
    source/PLAYER.C lines 796–801 at e75bb06 · upstream ↗
    843            j = EGS(sect,
    ⋮
    846                sz-(1<<8),atwith,0,14,14,sa,vel,zvel,i,4);
    
    source/PLAYER.C lines 843–846 at e75bb06 · upstream ↗
    2994short EGS(short whatsect,long s_x,long s_y,long s_z,short s_pn,signed char s_s,signed char s_xr,signed char s_yr,short s_a,short s_ve,long s_zv,short s_ow,signed char s_ss)
    
    source/GAME.C line 2994 at e75bb06 · upstream ↗
    3021    s->xvel = s_ve;
    
    source/GAME.C line 3021 at e75bb06 · upstream ↗
    626P_GunShot
    ⋮
    639    P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
    
    linuxdoom-1.10/p_pspr.c lines 625–639 at a77dfb9 · 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

  4. ^ abEach shot a Duke Nukem 3D player fires from the pistol, shotgun, or chaingun carries the strength its actor declares in the CON script plus TRAND%6 (0 to 5): 6 to 11 for the pistol (SHOTSPARK1), 10 to 15 for each of the shotgun's 7 pellets, and 9 to 14 for the chaingun; a monster's shot carries the strength alone. Each bullet from Doom's pistol, chaingun, or shotgun deals 5, 10, or 15.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    557            if(p >= 0)
    ⋮
    559                k = EGS(hitsect,hitx,hity,hitz,SHOTSPARK1,-15,10,10,sa,0,0,i,4);
    560                sprite[k].extra = *actorscrptr[atwith];
    561                sprite[k].extra += (TRAND%6);
    
    source/PLAYER.C lines 557–561 at e75bb06 · upstream ↗
    674                k = EGS(hitsect,hitx,hity,hitz,SHOTSPARK1,-15,24,24,sa,0,0,i,4);
    675                sprite[k].extra = *actorscrptr[atwith];
    
    source/PLAYER.C lines 674–675 at e75bb06 · upstream ↗
    849            scriptptr--;
    850            parsing_actor = scriptptr;
    ⋮
    853            scriptptr--;
    854            actorscrptr[*scriptptr] = parsing_actor;
    ⋮
    865                        scriptptr--;
    ⋮
    881                    *(parsing_actor+j) = *(scriptptr-1);
    
    source/GAMEDEF.C lines 849–881 at e75bb06 · upstream ↗
    3165actor CHAINGUN CHAINGUN_WEAPON_STRENGTH enda
    3166actor SHOTGUN SHOTGUN_WEAPON_STRENGTH enda
    
    testdata/GAME.CON lines 3165–3166 at e75bb06 · upstream ↗
    3200actor SHOTSPARK1 PISTOL_WEAPON_STRENGTH WEAP2FRAMES
    
    testdata/GAME.CON line 3200 at e75bb06 · upstream ↗
    148define PISTOL_WEAPON_STRENGTH            6
    
    testdata/USER.CON line 148 at e75bb06 · upstream ↗
    163define SHOTGUN_WEAPON_STRENGTH          10
    164define CHAINGUN_WEAPON_STRENGTH          9
    
    testdata/USER.CON lines 163–164 at e75bb06 · upstream ↗
    3647            case PISTOL_WEAPON:
    3648                if( (*kb)==1)
    ⋮
    3650                    shoot(pi,SHOTSPARK1);
    
    source/PLAYER.C lines 3647–3650 at e75bb06 · upstream ↗
    3690            case SHOTGUN_WEAPON:
    ⋮
    3694                if(*kb == 4)
    ⋮
    3696                    shoot(pi,SHOTGUN);
    3697                    shoot(pi,SHOTGUN);
    3698                    shoot(pi,SHOTGUN);
    3699                    shoot(pi,SHOTGUN);
    3700                    shoot(pi,SHOTGUN);
    3701                    shoot(pi,SHOTGUN);
    3702                    shoot(pi,SHOTGUN);
    
    source/PLAYER.C lines 3690–3702 at e75bb06 · upstream ↗
    3759                        shoot(pi,CHAINGUN);
    
    source/PLAYER.C line 3759 at e75bb06 · upstream ↗
    626P_GunShot
    ⋮
    633    damage = 5*(P_Random ()%3+1);
    
    linuxdoom-1.10/p_pspr.c lines 625–639 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

  5. ^A Duke Nukem 3D sprite's pending damage (hittype[].extra) is set to −1 when the sprite is created and again each time ifhitbyweapon takes it; a shot that checkhitsprite handles in its default branch adds its damage to the pending total, and ifhitbyweapon subtracts the total from the target's health, so a target hit once between checks loses 1 less than the shot carries, and several hits between checks take 1 less than their sum (computed). An explosion's hitradius sets the pending damage outright for the targets it rolls for, so those lose the full roll.Code3D Realms, duke3dsource.ziprevised
    How we know
    3038    hittype[i].extra = -1;
    
    source/GAME.C line 3038 at e75bb06 · upstream ↗
    3143        hittype[i].extra = -1;
    
    source/GAME.C line 3143 at e75bb06 · upstream ↗
    2329                if( sprite[i].statnum != 2 )
    ⋮
    2334                    hittype[i].picnum = sprite[sn].picnum;
    2335                    hittype[i].extra += sprite[sn].extra;
    
    source/SECTOR.C lines 2329–2335 at e75bb06 · upstream ↗
    994short ifhitbyweapon(short sn)
    ⋮
    999    if( hittype[sn].extra >= 0 )
    ⋮
    1018                npc->extra -= hittype[sn].extra;
    
    source/ACTORS.C lines 994–1018 at e75bb06 · upstream ↗
    1063                npc->extra -= hittype[sn].extra;
    ⋮
    1068            hittype[sn].extra = -1;
    1069            return hittype[sn].picnum;
    ⋮
    1073    hittype[sn].extra = -1;
    
    source/ACTORS.C lines 1063–1073 at e75bb06 · upstream ↗
    538                        if ( d < r/3 )
    ⋮
    540                            if(hp4 == hp3) hp4++;
    541                            hittype[j].extra = hp3 + (TRAND%(hp4-hp3));
    
    source/ACTORS.C lines 538–541 at e75bb06 · 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

  6. ^A Duke Nukem 3D player's shotgun and chaingun turn every shot by 16-(TRAND&31), −15 to +16 of the 2,048 angle units in a turn (up to about 2.8°, computed), and add 128-(TRAND&255) to its vertical speed, with or without an autoaim target; the pistol does both only when autoaim found none, so a pistol shot at an autoaim target flies straight to it. Doom's shotgun turns each of its 7 pellets by up to about 5.6°.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    489                j = aim( s, AUTO_AIM_ANGLE );
    
    source/PLAYER.C line 489 at e75bb06 · upstream ↗
    511                if(atwith == SHOTSPARK1)
    ⋮
    513                    if(j == -1)
    ⋮
    515                        sa += 16-(TRAND&31);
    516                        zvel = (100-ps[p].horiz-ps[p].horizoff)<<5;
    517                        zvel += 128-(TRAND&255);
    ⋮
    520                else
    ⋮
    522                    sa += 16-(TRAND&31);
    523                    if(j == -1) zvel = (100-ps[p].horiz-ps[p].horizoff)<<5;
    524                    zvel += 128-(TRAND&255);
    
    source/PLAYER.C lines 511–525 at e75bb06 · upstream ↗
    546            hitscan(sx,sy,sz,sect,
    547                sintable[(sa+512)&2047],
    548                sintable[sa&2047],
    
    source/PLAYER.C lines 546–548 at e75bb06 · upstream ↗
    627( mobj_t*	mo,
    628  boolean	accurate )
    ⋮
    636    if (!accurate)
    637	angle += (P_Random()-P_Random())<<18;
    
    linuxdoom-1.10/p_pspr.c lines 626–639 at a77dfb9 · upstream ↗
    684    P_BulletSlope (player->mo);
    ⋮
    686    for (i=0 ; i<7 ; i++)
    687	P_GunShot (player->mo, false);
    
    linuxdoom-1.10/p_pspr.c lines 684–687 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

  7. ^ abWhen a Duke Nukem 3D player fires the pistol, shotgun, or chaingun, aim looks for a target within AUTO_AIM_ANGLE, 48 of 2,048 angle units (about 8.4°, computed), to either side of the facing; of those in sight, more than 512 along the facing, and with a height difference over that distance (scaled by 10) within 100 of the view's pitch, it takes the nearest along the facing, searching the sprite lists 10, 13, 1, and 2 in that order and stopping at the first list with a match, and skipping fellow players in co-op. The shot then turns to the target's angle (getangle) and takes the slope to a point ((xrepeat × tile height) << 1) + (5 << 8) above the target's z. Doom's P_BulletSlope traces only straight ahead and 5.625° to each side, and its bullet keeps the player's facing.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    62#define AUTO_AIM_ANGLE          48
    
    source/DUKE3D.H line 62 at e75bb06 · upstream ↗
    204short aim(spritetype *s,short aang)
    ⋮
    208    short aimstats[] = {10,13,1,2};
    ⋮
    222    dx1 = sintable[(a+512-aang)&2047];
    223    dy1 = sintable[(a-aang)&2047];
    224    dx2 = sintable[(a+512+aang)&2047];
    225    dy2 = sintable[(a+aang)&2047];
    
    source/PLAYER.C lines 204–227 at e75bb06 · upstream ↗
    230    for(k=0;k<4;k++)
    ⋮
    232        if( j >= 0 )
    233            break;
    ⋮
    240                    if( PN == APLAYER &&
    ⋮
    242                        ud.coop == 1 &&
    243                        s->picnum == APLAYER &&
    244                        s != &sprite[i])
    245                            continue;
    
    source/PLAYER.C lines 230–246 at e75bb06 · upstream ↗
    273                if( (dy1*xv) <= (dx1*yv) )
    274                    if( ( dy2*xv ) >= (dx2*yv) )
    ⋮
    276                    sdist = mulscale(dx3,xv,14) + mulscale(dy3,yv,14);
    277                    if( sdist > 512 && sdist < smax )
    ⋮
    279                        if(s->picnum == APLAYER)
    280                            a = (klabs(scale(SZ-s->z,10,sdist)-(ps[s->yvel].horiz+ps[s->yvel].horizoff-100)) < 100);
    ⋮
    287                        if( a && cans )
    ⋮
    289                            smax = sdist;
    290                            j = i;
    
    source/PLAYER.C lines 273–291 at e75bb06 · upstream ↗
    489                j = aim( s, AUTO_AIM_ANGLE );
    490                if(j >= 0)
    ⋮
    492                    dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1)+(5<<8);
    ⋮
    507                    zvel = ( ( sprite[j].z-sz-dal )<<8 ) / ldist(&sprite[ps[p].i], &sprite[j]) ;
    508                    sa = getangle(sprite[j].x-sx,sprite[j].y-sy);
    
    source/PLAYER.C lines 489–508 at e75bb06 · upstream ↗
    601void P_BulletSlope (mobj_t*	mo)
    ⋮
    606    an = mo->angle;
    607    bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
    ⋮
    611	an += 1<<26;
    612	bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
    ⋮
    615	    an -= 2<<26;
    616	    bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
    
    linuxdoom-1.10/p_pspr.c lines 601–619 at a77dfb9 · upstream ↗
    627( mobj_t*	mo,
    628  boolean	accurate )
    ⋮
    634    angle = mo->angle;
    ⋮
    639    P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
    
    linuxdoom-1.10/p_pspr.c lines 626–639 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

  8. ^A Duke Nukem 3D pipe bomb that goes off passes its strength, 140 (HANDBOMB_WEAPON_STRENGTH), to hitradius with the radius PIPEBOMBRADIUS, 2,500; each sprite in lists 1, 6, 10, or 12 (not flammable) with extra of 0 or more that is a tripbomb, a monster (badguy), a QUEBALL, a STRIPEBALL, a DUKELYINGDEAD, or solid (cstat&257), within that dist and in sight of the blast, takes 105 to 139 inside a third of the radius, 70 to 104 inside two thirds, and 35 to 69 beyond: three quarters, a half, or a quarter of the strength plus TRAND modulo the next band's gap, 35 (computed). A monster in sprite list 2, which the hit wakes into list 1, goes through checkhitsprite instead unless a sight test at a random height fails, and loses 139 at any distance in the radius, the bomb's 140 added to its pending −1; a bomb set off by a hit first loses that hit's damage from its strength. A Doom rocket's blast falls off linearly, 128 minus the distance.Code3D Realms, duke3dsource.zip · id-Software/DOOMrevised
    How we know
    127define PIPEBOMBRADIUS           2500
    
    testdata/USER.CON line 127 at e75bb06 · upstream ↗
    149define HANDBOMB_WEAPON_STRENGTH        140
    
    testdata/USER.CON line 149 at e75bb06 · upstream ↗
    3168actor HEAVYHBOMB HANDBOMB_WEAPON_STRENGTH enda
    
    testdata/GAME.CON line 3168 at e75bb06 · upstream ↗
    1358                    case 9:pipebombblastradius = *scriptptr;break;
    
    source/GAMEDEF.C line 1358 at e75bb06 · upstream ↗
    3048    if( actorscrptr[s_pn] )
    ⋮
    3050        s->extra = *actorscrptr[s_pn];
    
    source/GAME.C lines 3048–3050 at e75bb06 · upstream ↗
    3989                if(t[3] == 0 )
    ⋮
    3991                    j = ifhitbyweapon(i);
    3992                    if(j >= 0)
    ⋮
    3994                        t[3] = 1;
    ⋮
    3998                        goto DETONATEB;
    
    source/ACTORS.C lines 3988–3998 at e75bb06 · upstream ↗
    4076                DETONATEB:
    ⋮
    4084                        x = s->extra;
    ⋮
    4088                            case HEAVYHBOMB: m = pipebombblastradius;break;
    ⋮
    4093                        hitradius( i, m,x>>2,x>>1,x-(x>>2),x);
    
    source/ACTORS.C lines 4076–4093 at e75bb06 · upstream ↗
    486    q = -(16<<8)+(TRAND&((32<<8)-1));
    ⋮
    496            if( x == 0 || x >= 5 || AFLAMABLE(sj->picnum) )
    ⋮
    499                    if( dist( s, sj ) < r )
    ⋮
    501                        if( badguy(sj) && !cansee( sj->x, sj->y,sj->z+q, sj->sectnum, s->x, s->y, s->z+q, s->sectnum) )
    502                            goto BOLT;
    503                        checkhitsprite( j, i );
    ⋮
    506            else if( sj->extra >= 0 && sj != s && ( sj->picnum == TRIPBOMB || badguy(sj) || sj->picnum == QUEBALL || sj->picnum == STRIPEBALL || (sj->cstat&257) || sj->picnum == DUKELYINGDEAD ) )
    
    source/ACTORS.C lines 486–506 at e75bb06 · upstream ↗
    433    char statlist[] = {0,1,6,10,12,2,5};
    
    source/ACTORS.C line 433 at e75bb06 · upstream ↗
    519                if(sj->picnum == APLAYER) sj->z -= PHEIGHT;
    520                d = dist( s, sj );
    521                if(sj->picnum == APLAYER) sj->z += PHEIGHT;
    ⋮
    523                if ( d < r && cansee( sj->x, sj->y, sj->z-(8<<8), sj->sectnum, s->x, s->y, s->z-(12<<8), s->sectnum) )
    
    source/ACTORS.C lines 519–523 at e75bb06 · upstream ↗
    536                    if(s->picnum != SHRINKSPARK)
    ⋮
    538                        if ( d < r/3 )
    ⋮
    540                            if(hp4 == hp3) hp4++;
    541                            hittype[j].extra = hp3 + (TRAND%(hp4-hp3));
    ⋮
    543                        else if ( d < 2*r/3 )
    ⋮
    545                            if(hp3 == hp2) hp3++;
    546                            hittype[j].extra = hp2 + (TRAND%(hp3-hp2));
    ⋮
    548                        else if ( d < r )
    ⋮
    550                            if(hp2 == hp1) hp2++;
    551                            hittype[j].extra = hp1 + (TRAND%(hp2-hp1));
    
    source/ACTORS.C lines 536–552 at e75bb06 · upstream ↗
    2282                if( badguy(&sprite[i]) == 1)
    ⋮
    2321                    if(sprite[i].statnum == 2)
    ⋮
    2323                        changespritestat(i,1);
    2324                        hittype[i].timetosleep = SLEEPTIME;
    ⋮
    2329                if( sprite[i].statnum != 2 )
    ⋮
    2335                    hittype[i].extra += sprite[sn].extra;
    
    source/SECTOR.C lines 2282–2335 at e75bb06 · upstream ↗
    1598void A_Explode (mobj_t* thingy)
    ⋮
    1600    P_RadiusAttack ( thingy, thingy->target, 128 );
    
    linuxdoom-1.10/p_enemy.c lines 1598–1600 at a77dfb9 · upstream ↗
    1182    dist = dx>dy ? dx : dy;
    1183    dist = (dist - thing->radius) >> FRACBITS;
    ⋮
    1194	P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
    
    linuxdoom-1.10/p_map.c lines 1180–1194 at a77dfb9 · 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

  9. ^A Duke Nukem 3D keyboard sets the forward and side moves to 40 walking or 80 running (NORMALKEYMOVE), each clamped apart to ±90 (MAXVEL, MAXSVEL); getinput turns the pair by the facing, and each tic processinput adds it to the player's velocity times TICSPERFRAME (4) and 64, doubled while steroids last and the jetpack is off, in the air as on the ground. A hard landing and a few other actions zero the velocity instead. Doom thrusts only on the floor, with moves of 25 or 50 forward and 24 or 40 sideways.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    1771#define NORMALKEYMOVE 40
    1772#define MAXVEL       ((NORMALKEYMOVE*2)+10)
    1773#define MAXSVEL      ((NORMALKEYMOVE*2)+10)
    
    source/PLAYER.C lines 1771–1773 at e75bb06 · upstream ↗
    1914    if (running)
    ⋮
    1916        turnamount = NORMALTURN<<1;
    1917        keymove = NORMALKEYMOVE<<1;
    ⋮
    1919    else
    ⋮
    1921        turnamount = NORMALTURN;
    1922        keymove = NORMALKEYMOVE;
    
    source/PLAYER.C lines 1913–1923 at e75bb06 · upstream ↗
    1974    if ( BUTTON(gamefunc_Move_Forward) )
    1975        vel += keymove;
    ⋮
    1980    if(vel < -MAXVEL) vel = -MAXVEL;
    1981    if(vel > MAXVEL) vel = MAXVEL;
    1982    if(svel < -MAXSVEL) svel = -MAXSVEL;
    1983    if(svel > MAXSVEL) svel = MAXSVEL;
    
    source/PLAYER.C lines 1974–1983 at e75bb06 · upstream ↗
    2004    momx = mulscale9(vel,sintable[(daang+2560)&2047]);
    2005    momy = mulscale9(vel,sintable[(daang+2048)&2047]);
    ⋮
    2007    momx += mulscale9(svel,sintable[(daang+2048)&2047]);
    2008    momy += mulscale9(svel,sintable[(daang+1536)&2047]);
    ⋮
    2013    loc.fvel = momx;
    2014    loc.svel = momy;
    
    source/PLAYER.C lines 2004–2014 at e75bb06 · upstream ↗
    2603    doubvel = TICSPERFRAME;
    
    source/PLAYER.C line 2603 at e75bb06 · upstream ↗
    3002    if ( p->fist_incs ||
    3003         p->transporter_hold > 2 ||
    3004         p->hard_landing ||
    3005         p->access_incs > 0 ||
    3006         p->knee_incs > 0 ||
    ⋮
    3011        doubvel = 0;
    3012        p->posxv = 0;
    3013        p->posyv = 0;
    
    source/PLAYER.C lines 3002–3013 at e75bb06 · upstream ↗
    3117    if ( p->posxv || p->posyv || sync[snum].fvel || sync[snum].svel )
    
    source/PLAYER.C line 3117 at e75bb06 · upstream ↗
    3156        if(p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400)
    3157            doubvel <<= 1;
    ⋮
    3159        p->posxv += ((sync[snum].fvel*doubvel)<<6);
    3160        p->posyv += ((sync[snum].svel*doubvel)<<6);
    
    source/PLAYER.C lines 3156–3160 at e75bb06 · upstream ↗
    156    // Do not let the player control movement
    157    //  if not onground.
    158    onground = (player->mo->z <= player->mo->floorz);
    ⋮
    160    if (cmd->forwardmove && onground)
    161	P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
    
    linuxdoom-1.10/p_user.c lines 156–164 at a77dfb9 · upstream ↗
    175fixed_t		forwardmove[2] = {0x19, 0x32}; 
    176fixed_t		sidemove[2] = {0x18, 0x28}; 
    
    linuxdoom-1.10/g_game.c lines 175–176 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

  10. ^ abAfter the thrust, Duke Nukem 3D multiplies the player's velocity each tic by dukefriction, which the CON's gamestartup sets from RUNNINGSPEED, 53,200 of 65,536 (0.812; the C default is 0xcc00, 0.797): 0x2000 less when kicking or crouching on the ground, 0x1400 less underwater, and three quarters of it again while shrunk; the velocity drops to 0 once both axes are under 2,048. A steady run moves 4.31 times the per-tic thrust (0.812 / 0.188, computed), and a released run falls under half its speed within 4 tics (computed). Doom keeps 0.90625 of its momentum each tic.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    156long myhorizbak[MOVEFIFOSIZ],dukefriction = 0xcc00, show_shareware;
    
    source/GLOBAL.C line 156 at e75bb06 · upstream ↗
    112define RUNNINGSPEED 53200
    
    testdata/USER.CON line 112 at e75bb06 · upstream ↗
    134gamestartup     DEFAULTVISIBILITY GENERICIMPACTDAMAGE MAXPLAYERHEALTH
    135                STARTARMORHEALTH  RESPAWNACTORTIME RESPAWNITEMTIME
    136                RUNNINGSPEED GRAVITATIONALCONSTANT RPGBLASTRADIUS
    
    testdata/USER.CON lines 134–136 at e75bb06 · upstream ↗
    105    "gamestartup",      // 60
    
    source/GAMEDEF.C line 105 at e75bb06 · upstream ↗
    1328        case 60:
    1329            j = 0;
    1330            while(j < 30)
    ⋮
    1339                        break;
    ⋮
    1342                        break;
    ⋮
    1345                        break;
    ⋮
    1348                        break;
    ⋮
    1353                    case 6:
    1354                        dukefriction = *scriptptr;break;
    
    source/GAMEDEF.C lines 1328–1354 at e75bb06 · upstream ↗
    1833    loc.bits |=   BUTTON(gamefunc_Crouch)<<1;
    
    source/PLAYER.C line 1833 at e75bb06 · upstream ↗
    3162        if( ( p->curr_weapon == KNEE_WEAPON && *kb > 10 && p->on_ground ) || ( p->on_ground && (sb_snum&2) ) )
    ⋮
    3164            p->posxv = mulscale(p->posxv,dukefriction-0x2000,16);
    ⋮
    3169            if(psectlotag == 2)
    ⋮
    3171                p->posxv = mulscale(p->posxv,dukefriction-0x1400,16);
    ⋮
    3176                p->posxv = mulscale(p->posxv,dukefriction,16);
    ⋮
    3181        if( abs(p->posxv) < 2048 && abs(p->posyv) < 2048 )
    3182            p->posxv = p->posyv = 0;
    ⋮
    3184        if( shrunk )
    ⋮
    3186            p->posxv =
    3187                mulscale16(p->posxv,dukefriction-(dukefriction>>1)+(dukefriction>>2));
    3188            p->posyv =
    
    source/PLAYER.C lines 3162–3190 at e75bb06 · upstream ↗
    3193    HORIZONLY:
    ⋮
    3204            p->posx += p->posxv>>14;
    3205            p->posy += p->posyv>>14;
    
    source/PLAYER.C lines 3193–3205 at e75bb06 · upstream ↗
    111#define STOPSPEED		0x1000
    112#define FRICTION		0xe800
    
    linuxdoom-1.10/p_mobj.c lines 111–112 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

  11. ^Duke Nukem 3D clamps the forward and side moves apart and adds them as perpendicular pushes, so running forward (80) while running sideways (80) gives √2 ≈ 1.41 times the forward run alone (computed); holding the strafe modifier with a turn key and a strafe key together reaches the side move's cap of 90, about 1.51 times. Doom's diagonal run, 50 forward and 40 sideways, is 1.28 times its forward run.Code3D Realms, duke3dsource.zip · id-Software/DOOM
    How we know
    1925    if (BUTTON(gamefunc_Strafe))
    ⋮
    1927        if ( BUTTON(gamefunc_Turn_Left))
    ⋮
    1929           svel -= -keymove;
    ⋮
    1931        if ( BUTTON(gamefunc_Turn_Right))
    ⋮
    1933           svel -= keymove;
    
    source/PLAYER.C lines 1925–1934 at e75bb06 · upstream ↗
    1968    if ( BUTTON( gamefunc_Strafe_Left ) )
    1969        svel += keymove;
    ⋮
    1974    if ( BUTTON(gamefunc_Move_Forward) )
    1975        vel += keymove;
    ⋮
    1981    if(vel > MAXVEL) vel = MAXVEL;
    ⋮
    1983    if(svel > MAXSVEL) svel = MAXSVEL;
    
    source/PLAYER.C lines 1965–1983 at e75bb06 · upstream ↗
    2004    momx = mulscale9(vel,sintable[(daang+2560)&2047]);
    2005    momy = mulscale9(vel,sintable[(daang+2048)&2047]);
    ⋮
    2007    momx += mulscale9(svel,sintable[(daang+2048)&2047]);
    2008    momy += mulscale9(svel,sintable[(daang+1536)&2047]);
    
    source/PLAYER.C lines 2004–2008 at e75bb06 · upstream ↗
    160    if (cmd->forwardmove && onground)
    161	P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
    ⋮
    163    if (cmd->sidemove && onground)
    164	P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);
    
    linuxdoom-1.10/p_user.c lines 160–164 at a77dfb9 · upstream ↗
    175fixed_t		forwardmove[2] = {0x19, 0x32}; 
    176fixed_t		sidemove[2] = {0x18, 0x28}; 
    
    linuxdoom-1.10/g_game.c lines 175–176 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