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

The atlas reads Wolfenstein 3D through the source code id Software released, which names no version number1. id first released it under a limited-use license and later relicensed it under the GPL2. Its build settings select Wolfenstein 3D rather than Spear of Destiny, and which shipped executable it matches is not known.

The view is a raycaster: one ray per column crosses a tile map of at most 64 by 64 tiles3, and the distance to each hit, measured along the facing, sets that column’s wall height4,5.

Neither side’s bullets trace a path. A gun shot picks the nearest visible target near the center of the screen and hits it if the line to it is clear, for a roll whose size falls with distance6. An enemy’s shot is a roll against a chance that falls with distance and drops when the player moves fast7, a threshold that a keyboard walk passes on any frame of 2 or more tics8. The player has no momentum, and a run moves 10,500 units a tic9,9; and a sideways move adds to a forward one10. Every roll reads one fixed table11, the same 256 bytes Doom uses12.

Mechanics

MechanicKindHow
RaycastingGrid raycastone ray per view column steps across a 64 by 64 tile map, and each wall slice's height comes from the hit's distance along the facing
HitscanTarget picka gun shot picks the nearest visible target near the screen's center and checks a clear line to it, and an enemy's shot is a roll against the distance and the player's speed
Damage formulaRoll by rangea roll of 0 to 255 divided down by distance band: a gun deals a quarter of it within 2 tiles and a sixth beyond, an enemy's shot a quarter, an eighth, or a sixteenth
RunningInstantno velocity: each frame moves the player by the keys' value, 5,250 units a tic walking and 10,500 running, and stops at once on release
Strafe-runningSeparately capped axeswith the strafe button held the side move is a second thrust, capped apart from the forward one, so a diagonal keyboard run is 1.41 times as fast
Random number generatorFixed tableone index walks a 256-byte table, the same table Doom uses, reset to 0 for demos and seeded from the clock otherwise
Every claim about this game, by concept (13)
generalid Software's released Wolfenstein 3D source names no version number: John Carmack's RELEASE.TXT calls it "all the source we have relating to the original PC wolfenstein 3D project", built in Borland C++ 3.0, and VERSION.H, which selects the build, leaves SPEAR (the Spear of Destiny build) commented out and defines GOODTIMES.Code
id Software first released the Wolfenstein 3D source under a limited-use license and later relicensed it under the GPL: the repo's LICENSE.DOC is the "LIMITED USE SOFTWARE LICENSE AGREEMENT", and John Carmack wrote in 2009 that he released the source "originally under a not-for-commercial purposes license, then later under the GPL", and in a 2011 mail, quoted in Debian's wolf4sdl copyright file, "Yes, we relicensed it under the gpl years ago." No source here dates the relicensing.Dev blog
HitscanA Wolfenstein 3D gun shot (GunAttack) picks a target instead of tracing a bullet's path: it takes the nearest visible shootable actor within shootdelta (a tenth of the view's width) of the screen's center column and hits it if CheckLine returns true, which its header comment describes as "a straight line between the player and ob is unobstructed"; as written, the loop's second pass looks only for actors nearer than that one, so a blocked line is a miss (computed). The damage is a roll of US_RndT (0 to 255) by the larger of the x and y tile distances: under 2 tiles the roll / 4 (0 to 63), under 4 the roll / 6 (0 to 42), and farther a miss when a first roll / 12 is below the distance, otherwise a second roll / 6.Code
An enemy's shot in Wolfenstein 3D (T_Shoot) traces no bullet either: when the shooter's area connects to the player's (areabyplayer) and CheckLine finds a clear line, it hits if a roll of US_RndT is below a chance of 256 less 16 per tile of distance, or less 8 per tile when the shooter isn't visible on the player's screen (FL_VISABLE), starting from 160 instead of 256 when the player's thrust this frame (thrustspeed) reached RUNSPEED (6,000); SS guards and bossobj bosses count two-thirds of the distance. A hit deals the roll >> 2 (0 to 63) under 2 tiles, >> 3 (0 to 31) under 4, and >> 4 (0 to 15) farther.Code
Because the player's thrust scales with the frame's tics, a Wolfenstein 3D player who only walks straight forward with the keyboard (5,250 units a tic) counts as running for T_Shoot's lower hit chance (thrustspeed at least RUNSPEED, 6,000) on any frame that spans 2 or more tics, and only a 1-tic frame leaves that walk below it; thrustspeed sums every Thrust call, so a walk that also strafes (5,250 + 5,250) passes it even in 1 tic (computed).Code
Random number generatorWolfenstein 3D's random numbers come from rndtable, a fixed table of 256 bytes: US_RndT adds 1 to one index, wraps it at 256, and returns that entry, and the file's comment calls it "John Carmack's table driven pseudo-random number generator". SetupGameLevel sets the index to 0 for each level of a demo being played or recorded, and otherwise to the low byte of DX from DOS's get-time call (int 21h, function 2Ch), the hundredths of a second, 0 to 99 (the atlas's reading of the DOS call).Code
Doom's rndtable holds the same 256 values in the same order as Wolfenstein 3D's (compared entry by entry, computed); Doom walks it with two indices (prndindex for P_Random, rndindex for M_Random), where Wolfenstein 3D uses one (rndindex).Code
RaycastingJohn Carmack's notes to the Wolfenstein 3D source release say the game's "ray casting refresh architecture is still reasonably appropriate for the game", and that "a BSP based texture mapper could go faster, but ray casting was a lot simpler to do at the time".Developer
Wolfenstein 3D finds its walls with one ray per column of the view: AsmRefresh steps pixx from 0 up to viewwidth, aiming each ray at the view angle plus pixelangle[pixx], in angles of 3,600 to a turn (FINEANGLES), and CalcProjection sets each column's offset to the arctangent of its whole-pixel distance from the center (scaled by VIEWGLOBAL/viewwidth) over facedist, the focal length plus MINDIST, so the rays cross a flat projection plane at even spacing rather than fanning out at even angles (the last part computed). The two middle columns both get an offset of 0, though the loop's comment says it starts "1/2 pixel over".Code
Each Wolfenstein 3D ray walks the tile map, 64 by 64 tiles at most (MAPSIZE), one grid line at a time: AsmRefresh alternates between the next vertical and the next horizontal grid line, taking whichever the ray crosses first, and steps by adding a tangent from finetangent (ystep or xstep) to the other coordinate's intercept; at each crossing it tests the tile beyond in tilemap, marking an empty one in spotvis, and the first nonzero tile ends the ray with a call to HitVertWall or HitHorizWall, or the door and pushwall code when the tile's top bit is set.Code
Wolfenstein 3D sizes each wall column by the hit point's distance along the facing, not along the ray: CalcHeight takes the hit point's offset from the view point, which WallRefresh sets focallength behind the player, projects it onto the view direction with viewcos and viewsin (nx = gxt-gyt), raises it to at least mindist, and divides heightnumerator by nx>>8, which the code's comment calls the "perspective ratio". Measuring along the facing is what keeps a flat wall straight on screen instead of bowed (fisheye), the atlas's reading.Code
RunningWolfenstein 3D keeps no velocity for the player: each frame ControlMovement zeroes thrustspeed, and Thrust moves the player straight through ClipMove by the frame's control value times MOVESCALE (150), or BACKMOVESCALE (100) backward. The keyboard sets that value to 35 a tic walking (BASEMOVE) or 70 running (RUNMOVE), times the frame's tics, so a walk moves 5,250 and a run 10,500 units a tic, with 65,536 units to a tile (TILEGLOBAL); Thrust clamps each move to MINDIST*2-1 (45,055), so those rates hold on frames of at most 8 tics walking or 4 running, and longer frames move less a tic. At the 70 tics a second of TickBase's comment a run is about 11.2 tiles a second (computed).Code
Strafe-runningWith the strafe button held, Wolfenstein 3D's side move is a second Thrust at 90° to the facing, and PollControls caps the side and forward control values separately at 100 a tic, so running forward and sideways on the keyboard (70 each) moves √2 ≈ 1.41 times as fast as running forward alone, about 14,849 units a tic (computed).Code

References

  1. ^id Software's released Wolfenstein 3D source names no version number: John Carmack's RELEASE.TXT calls it "all the source we have relating to the original PC wolfenstein 3D project", built in Borland C++ 3.0, and VERSION.H, which selects the build, leaves SPEAR (the Spear of Destiny build) commented out and defines GOODTIMES.Codeid-Software/wolf3d
    How we know
    6This is all the source we have relating to the original 
    7PC wolfenstein 3D project.  We haven't looked at this 
    
    WOLFSRC/README/RELEASE.TXT lines 6–7 at 0516778 · upstream ↗
    10about it. The original project was built in borland c++ 3.0.  
    
    WOLFSRC/README/RELEASE.TXT line 10 at 0516778 · upstream ↗
    51John Carmack
    52Technical Director
    
    WOLFSRC/README/RELEASE.TXT lines 51–52 at 0516778 · upstream ↗
    1//#define SPEAR
    2//#define JAPAN
    3#define GOODTIMES
    
    WOLFSRC/VERSION.H lines 1–3 at 0516778 · 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. ^id Software first released the Wolfenstein 3D source under a limited-use license and later relicensed it under the GPL: the repo's LICENSE.DOC is the "LIMITED USE SOFTWARE LICENSE AGREEMENT", and John Carmack wrote in 2009 that he released the source "originally under a not-for-commercial purposes license, then later under the GPL", and in a 2011 mail, quoted in Debian's wolf4sdl copyright file, "Yes, we relicensed it under the gpl years ago." No source here dates the relicensing.Dev blogid-Software/wolf3d · Carmack, Wolf3D iPhone source notes · Debian wolf4sdl copyrightrevised
    How we know
    89  	LIMITED USE SOFTWARE LICENSE AGREEMENT
    
    README.rst line 89 at 0516778 · upstream ↗
    originally under a not-for-commercial purposes license, then later under the GPL
    · archived copy ↗
    Yes, we relicensed it under the gpl years ago.
    · archived copy ↗

    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. ^Each Wolfenstein 3D ray walks the tile map, 64 by 64 tiles at most (MAPSIZE), one grid line at a time: AsmRefresh alternates between the next vertical and the next horizontal grid line, taking whichever the ray crosses first, and steps by adding a tangent from finetangent (ystep or xstep) to the other coordinate's intercept; at each crossing it tests the tile beyond in tilemap, marking an empty one in spotvis, and the first nonzero tile ends the ray with a call to HitVertWall or HitHorizWall, or the door and pushwall code when the tile's top bit is set.Codeid-Software/wolf3d
    How we know
    122#define MAPSIZE		64					// maps are 64*64 max
    
    WOLFSRC/WL_DEF.H line 122 at 0516778 · upstream ↗
    232entry90:
    233	mov	[xtilestep],1			; xtilestep = 1
    234	mov	[ytilestep],-1			; ytilestep = -1
    235	mov	[BYTE cs:horizop],OP_JGE	; patch a jge in
    236	mov	[BYTE cs:vertop],OP_JLE		; patch a jle in
    237	mov	bx,DEG90-1
    238	sub	bx,cx
    239	shl	bx,2
    240	mov	ax,[es:bx]
    241	mov	dx,[es:bx+2]
    242	mov	[WORD xstep],ax
    243	mov	[WORD xstep+2],dx		; xstep = finetangent[DEG90-1-angle]
    ⋮
    
    WOLFSRC/WL_DR_A.ASM lines 232–252 at 0516778 · upstream ↗
    438vertcheck:
    439	cmp	dx,bp
    440vertop:								; 0x7e = jle (ytilestep==-1)
    441	jle	horizentry					; 0x7d = jge (ytilestep==1)
    442vertentry:
    443	test [BYTE tilemap+si],0ffh		; tilehit = *((byte *)tilemap+xspot);
    444	jnz	hitvert
    445passvert:
    446	mov	[BYTE spotvis+si],1			; *((byte *)spotvis+xspot) = true;
    447	add	bx,[xtilestep]				; xtile+=xtilestep
    448	mov	ax,[WORD ystep]
    449	add	[WORD yintercept],ax		; yintercept += ystep
    ⋮
    
    WOLFSRC/WL_DR_A.ASM lines 438–469 at 0516778 · upstream ↗
    479horizcheck:
    480	cmp	cx,bx
    481horizop:							; 0x7e = jle (xtilestep==-1)
    482	jle	vertentry					; 0x7d = jge (xtilestep==1)
    483horizentry:
    484	test [BYTE tilemap+di],0ffh		; tilehit = *((byte *)tilemap+yspot);
    485	jnz	hithoriz
    486passhoriz:
    487	mov	[BYTE spotvis+di],1			; *((byte *)spotvis+yspot) = true;
    488	add	bp,[ytilestep]				; ytile+=ytilestep
    489	mov	ax,[WORD xstep]
    490	add	[WORD xintercept],ax		; xintercept += xstep
    ⋮
    
    WOLFSRC/WL_DR_A.ASM lines 479–508 at 0516778 · 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

  4. ^Wolfenstein 3D finds its walls with one ray per column of the view: AsmRefresh steps pixx from 0 up to viewwidth, aiming each ray at the view angle plus pixelangle[pixx], in angles of 3,600 to a turn (FINEANGLES), and CalcProjection sets each column's offset to the arctangent of its whole-pixel distance from the center (scaled by VIEWGLOBAL/viewwidth) over facedist, the focal length plus MINDIST, so the rays cross a flat projection plane at even spacing rather than fanning out at even angles (the last part computed). The two middle columns both get an offset of 0, though the loop's comment says it starts "1/2 pixel over".Codeid-Software/wolf3drevised
    How we know
    7FINEANGLES	=	3600
    
    WOLFSRC/WL_DR_A.ASM line 7 at 0516778 · upstream ↗
    207pixxloop:
    208	mov	ax,SEG finetangent
    209	mov	es,ax
    210	mov	cx,[midangle]			; center of view area
    211	mov	bx,[pixx]
    212	shl	bx,1
    213	add	cx,[pixelangle+bx]		; delta for this pixel
    
    WOLFSRC/WL_DR_A.ASM lines 207–213 at 0516778 · upstream ↗
    517nextpix:
    518	mov	ax,[pixx]
    519	inc	ax
    520	mov	[pixx],ax
    521	cmp	ax,[viewwidth]
    522	jge	done
    523	jmp	pixxloop
    
    WOLFSRC/WL_DR_A.ASM lines 517–523 at 0516778 · upstream ↗
    653	focallength = focal;
    654	facedist = focal+MINDIST;
    
    WOLFSRC/WL_MAIN.C lines 653–654 at 0516778 · upstream ↗
    674	for (i=0;i<halfview;i++)
    ⋮
    676	// start 1/2 pixel over, so viewangle bisects two middle pixels
    677		tang = (long)i*VIEWGLOBAL/viewwidth/facedist;
    678		angle = atan(tang);
    679		intang = angle*radtoint;
    680		pixelangle[halfview-1-i] = intang;
    681		pixelangle[halfview+i] = -intang;
    
    WOLFSRC/WL_MAIN.C lines 674–681 at 0516778 · 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

  5. ^Wolfenstein 3D sizes each wall column by the hit point's distance along the facing, not along the ray: CalcHeight takes the hit point's offset from the view point, which WallRefresh sets focallength behind the player, projects it onto the view direction with viewcos and viewsin (nx = gxt-gyt), raises it to at least mindist, and divides heightnumerator by nx>>8, which the code's comment calls the "perspective ratio". Measuring along the facing is what keeps a flat wall straight on screen instead of bowed (fisheye), the atlas's reading.Codeid-Software/wolf3d
    How we know
    366	gx = xintercept-viewx;
    367	gxt = FixedByFrac(gx,viewcos);
    ⋮
    369	gy = yintercept-viewy;
    370	gyt = FixedByFrac(gy,viewsin);
    ⋮
    372	nx = gxt-gyt;
    ⋮
    375  // calculate perspective ratio (heightnumerator/(nx>>8))
    ⋮
    377	if (nx<mindist)
    378		nx=mindist;			// don't let divide overflow
    ⋮
    380	asm	mov	ax,[WORD PTR heightnumerator]
    381	asm	mov	dx,[WORD PTR heightnumerator+2]
    382	asm	idiv	[WORD PTR nx+1]			// nx>>8
    
    WOLFSRC/WL_DRAW.C lines 366–382 at 0516778 · upstream ↗
    488	wallheight[pixx] = CalcHeight();
    
    WOLFSRC/WL_DRAW.C line 488 at 0516778 · upstream ↗
    1307	viewx = player->x - FixedByFrac(focallength,viewcos);
    1308	viewy = player->y + FixedByFrac(focallength,viewsin);
    
    WOLFSRC/WL_DRAW.C lines 1307–1308 at 0516778 · 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

  6. ^A Wolfenstein 3D gun shot (GunAttack) picks a target instead of tracing a bullet's path: it takes the nearest visible shootable actor within shootdelta (a tenth of the view's width) of the screen's center column and hits it if CheckLine returns true, which its header comment describes as "a straight line between the player and ob is unobstructed"; as written, the loop's second pass looks only for actors nearer than that one, so a blocked line is a miss (computed). The damage is a roll of US_RndT (0 to 255) by the larger of the x and y tile distances: under 2 tiles the roll / 4 (0 to 63), under 4 the roll / 6 (0 to 42), and farther a miss when a first roll / 12 is below the distance, otherwise a second roll / 6.Codeid-Software/wolf3drevised
    How we know
    1196	while (1)
    ⋮
    1198		oldclosest = closest;
    ⋮
    1200		for (check=ob->next ; check ; check=check->next)
    1201			if ( (check->flags & FL_SHOOTABLE)
    1202			&& (check->flags & FL_VISABLE)
    1203			&& abs (check->viewx-centerx) < shootdelta
    ⋮
    1206				if (check->transx < viewdist)
    ⋮
    1208					viewdist = check->transx;
    1209					closest = check;
    ⋮
    1213		if (closest == oldclosest)
    1214			return;						// no more targets, all missed
    ⋮
    1217	// trace a line from player to enemey
    ⋮
    
    WOLFSRC/WL_AGENT.C lines 1196–1242 at 0516778 · upstream ↗
    1283	shootdelta = viewwidth/10;
    
    WOLFSRC/WL_MAIN.C line 1283 at 0516778 · upstream ↗
    1030= CheckLine
    ⋮
    1032= Returns true if a straight line between the player and ob is unobstructed
    
    WOLFSRC/WL_STATE.C lines 1030–1032 at 0516778 · upstream ↗
    80; int US_RndT (void)
    81; Return a random # between 0-255
    ⋮
    94	mov	al,[es:rndtable+BX]
    95	xor	ah,ah
    
    WOLFSRC/ID_US_A.ASM lines 80–95 at 0516778 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-25.

    Revised after a check by a second AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-25.

    In the claim ledger

  7. ^An enemy's shot in Wolfenstein 3D (T_Shoot) traces no bullet either: when the shooter's area connects to the player's (areabyplayer) and CheckLine finds a clear line, it hits if a roll of US_RndT is below a chance of 256 less 16 per tile of distance, or less 8 per tile when the shooter isn't visible on the player's screen (FL_VISABLE), starting from 160 instead of 256 when the player's thrust this frame (thrustspeed) reached RUNSPEED (6,000); SS guards and bossobj bosses count two-thirds of the distance. A hit deals the roll >> 2 (0 to 63) under 2 tiles, >> 3 (0 to 31) under 4, and >> 4 (0 to 15) farther.Codeid-Software/wolf3d
    How we know
    3449	hitchance = 128;
    ⋮
    3451	if (!areabyplayer[ob->areanumber])
    3452		return;
    ⋮
    3454	if (!CheckLine (ob))			// player is behind a wall
    3455	  return;
    ⋮
    3457	dx = abs(ob->tilex - player->tilex);
    3458	dy = abs(ob->tiley - player->tiley);
    3459	dist = dx>dy ? dx:dy;
    ⋮
    3461	if (ob->obclass == ssobj || ob->obclass == bossobj)
    3462		dist = dist*2/3;					// ss are better shots
    ⋮
    3464	if (thrustspeed >= RUNSPEED)
    ⋮
    3466		if (ob->flags&FL_VISABLE)
    ⋮
    
    WOLFSRC/WL_ACT2.C lines 3449–3490 at 0516778 · upstream ↗
    75#define RUNSPEED   		6000
    
    WOLFSRC/WL_DEF.H line 75 at 0516778 · 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. ^Because the player's thrust scales with the frame's tics, a Wolfenstein 3D player who only walks straight forward with the keyboard (5,250 units a tic) counts as running for T_Shoot's lower hit chance (thrustspeed at least RUNSPEED, 6,000) on any frame that spans 2 or more tics, and only a 1-tic frame leaves that walk below it; thrustspeed sums every Thrust call, so a walk that also strafes (5,250 + 5,250) passes it even in 1 tic (computed).Codeid-Software/wolf3drevised
    How we know
    354	else
    ⋮
    356		if (Keyboard[dirscan[di_north]])
    357			controly -= BASEMOVE*tics;
    
    WOLFSRC/WL_PLAY.C lines 354–357 at 0516778 · upstream ↗
    205	if (controly < 0)
    ⋮
    207		Thrust (ob->angle,-controly*MOVESCALE);	// move forwards
    
    WOLFSRC/WL_AGENT.C lines 205–207 at 0516778 · upstream ↗
    156	thrustspeed = 0;
    
    WOLFSRC/WL_AGENT.C line 156 at 0516778 · upstream ↗
    164	if (buttonstate[bt_strafe])
    ⋮
    167	// strafing
    ⋮
    170		if (controlx > 0)
    ⋮
    172			angle = ob->angle - ANGLES/4;
    173			if (angle < 0)
    174				angle += ANGLES;
    175			Thrust (angle,controlx*MOVESCALE);	// move to left
    
    WOLFSRC/WL_AGENT.C lines 164–175 at 0516778 · upstream ↗
    943	thrustspeed += speed;
    
    WOLFSRC/WL_AGENT.C line 943 at 0516778 · upstream ↗
    3464	if (thrustspeed >= RUNSPEED)
    
    WOLFSRC/WL_ACT2.C line 3464 at 0516778 · upstream ↗
    75#define RUNSPEED   		6000
    
    WOLFSRC/WL_DEF.H line 75 at 0516778 · 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. ^ abWolfenstein 3D keeps no velocity for the player: each frame ControlMovement zeroes thrustspeed, and Thrust moves the player straight through ClipMove by the frame's control value times MOVESCALE (150), or BACKMOVESCALE (100) backward. The keyboard sets that value to 35 a tic walking (BASEMOVE) or 70 running (RUNMOVE), times the frame's tics, so a walk moves 5,250 and a run 10,500 units a tic, with 65,536 units to a tile (TILEGLOBAL); Thrust clamps each move to MINDIST*2-1 (45,055), so those rates hold on frames of at most 8 tics walking or 4 running, and longer frames move less a tic. At the 70 tics a second of TickBase's comment a run is about 11.2 tiles a second (computed).Codeid-Software/wolf3drevised
    How we know
    18#define MOVESCALE		150l
    19#define BACKMOVESCALE	100l
    
    WOLFSRC/WL_AGENT.C lines 18–19 at 0516778 · upstream ↗
    156	thrustspeed = 0;
    
    WOLFSRC/WL_AGENT.C line 156 at 0516778 · upstream ↗
    205	if (controly < 0)
    ⋮
    207		Thrust (ob->angle,-controly*MOVESCALE);	// move forwards
    ⋮
    209	else if (controly > 0)
    ⋮
    211		angle = ob->angle + ANGLES/2;
    212		if (angle >= ANGLES)
    213			angle -= ANGLES;
    214		Thrust (angle,controly*BACKMOVESCALE);		// move backwards
    
    WOLFSRC/WL_AGENT.C lines 205–214 at 0516778 · upstream ↗
    943	thrustspeed += speed;
    ⋮
    945// moving bounds speed
    ⋮
    947	if (speed >= MINDIST*2)
    948		speed = MINDIST*2-1;
    ⋮
    950	xmove = FixedByFrac(speed,costable[angle]);
    951	ymove = -FixedByFrac(speed,sintable[angle]);
    ⋮
    953	ClipMove(player,xmove,ymove);
    
    WOLFSRC/WL_AGENT.C lines 943–953 at 0516778 · upstream ↗
    115#define MINDIST		(0x5800l)
    
    WOLFSRC/WL_DEF.H line 115 at 0516778 · upstream ↗
    246#define BASEMOVE		35
    247#define RUNMOVE			70
    
    WOLFSRC/WL_PLAY.C lines 246–247 at 0516778 · upstream ↗
    343	if (buttonstate[bt_run])
    ⋮
    345		if (Keyboard[dirscan[di_north]])
    346			controly -= RUNMOVE*tics;
    347		if (Keyboard[dirscan[di_south]])
    348			controly += RUNMOVE*tics;
    349		if (Keyboard[dirscan[di_west]])
    350			controlx -= RUNMOVE*tics;
    351		if (Keyboard[dirscan[di_east]])
    352			controlx += RUNMOVE*tics;
    ⋮
    354	else
    ⋮
    356		if (Keyboard[dirscan[di_north]])
    357			controly -= BASEMOVE*tics;
    
    WOLFSRC/WL_PLAY.C lines 343–357 at 0516778 · upstream ↗
    97#define GLOBAL1		(1l<<16)
    98#define TILEGLOBAL  GLOBAL1
    
    WOLFSRC/WL_DEF.H lines 97–98 at 0516778 · upstream ↗
    17#define	TickBase	70		// 70Hz per tick - used as a base for timer 0
    
    WOLFSRC/ID_SD.H line 17 at 0516778 · 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

  10. ^With the strafe button held, Wolfenstein 3D's side move is a second Thrust at 90° to the facing, and PollControls caps the side and forward control values separately at 100 a tic, so running forward and sideways on the keyboard (70 each) moves √2 ≈ 1.41 times as fast as running forward alone, about 14,849 units a tic (computed).Codeid-Software/wolf3d
    How we know
    164	if (buttonstate[bt_strafe])
    ⋮
    167	// strafing
    ⋮
    170		if (controlx > 0)
    ⋮
    172			angle = ob->angle - ANGLES/4;
    173			if (angle < 0)
    174				angle += ANGLES;
    175			Thrust (angle,controlx*MOVESCALE);	// move to left
    ⋮
    177		else if (controlx < 0)
    ⋮
    179			angle = ob->angle + ANGLES/4;
    180			if (angle >= ANGLES)
    181				angle -= ANGLES;
    182			Thrust (angle,-controlx*MOVESCALE);	// move to right
    
    WOLFSRC/WL_AGENT.C lines 164–183 at 0516778 · upstream ↗
    205	if (controly < 0)
    ⋮
    207		Thrust (ob->angle,-controly*MOVESCALE);	// move forwards
    
    WOLFSRC/WL_AGENT.C lines 205–207 at 0516778 · upstream ↗
    343	if (buttonstate[bt_run])
    ⋮
    345		if (Keyboard[dirscan[di_north]])
    346			controly -= RUNMOVE*tics;
    347		if (Keyboard[dirscan[di_south]])
    348			controly += RUNMOVE*tics;
    349		if (Keyboard[dirscan[di_west]])
    350			controlx -= RUNMOVE*tics;
    351		if (Keyboard[dirscan[di_east]])
    352			controlx += RUNMOVE*tics;
    
    WOLFSRC/WL_PLAY.C lines 343–353 at 0516778 · upstream ↗
    540	max = 100*tics;
    541	min = -max;
    542	if (controlx > max)
    543		controlx = max;
    544	else if (controlx < min)
    545		controlx = min;
    ⋮
    547	if (controly > max)
    548		controly = max;
    
    WOLFSRC/WL_PLAY.C lines 540–548 at 0516778 · 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. ^Wolfenstein 3D's random numbers come from rndtable, a fixed table of 256 bytes: US_RndT adds 1 to one index, wraps it at 256, and returns that entry, and the file's comment calls it "John Carmack's table driven pseudo-random number generator". SetupGameLevel sets the index to 0 for each level of a demo being played or recorded, and otherwise to the low byte of DX from DOS's get-time call (int 21h, function 2Ch), the hundredths of a second, 0 to 99 (the atlas's reading of the DOS call).Codeid-Software/wolf3d
    How we know
    4;	Assembly portion of the User Mgr. This is just John Carmack's table
    5;		driven pseudo-random number generator, and we put it in the User Mgr
    6;		because we couldn't figure out where it should go
    
    WOLFSRC/ID_US_A.ASM lines 4–6 at 0516778 · upstream ↗
    19rndtable db    0,   8, 109, 220, 222, 241, 149, 107,  75, 248, 254, 140,  16,  66
    
    WOLFSRC/ID_US_A.ASM line 19 at 0516778 · upstream ↗
    60	mov	ax,[randomize]
    61	or	ax,ax
    62	jne	@@timeit		;if randomize is true, really random
    ⋮
    64	mov	dx,0			;set to a definite value
    65	jmp	@@setit
    ⋮
    67@@timeit:
    68	mov	ah,2ch
    69	int	21h			;GetSystemTime
    70	and	dx,0ffh
    ⋮
    72@@setit:
    73	mov	[es:rndindex],dx
    
    WOLFSRC/ID_US_A.ASM lines 60–73 at 0516778 · upstream ↗
    85PROC	US_RndT
    86	public	US_RndT
    ⋮
    88	mov	ax,SEG rndtable
    89	mov	es,ax
    90	mov	bx,[es:rndindex]
    91	inc	bx
    92	and	bx,0ffh
    93	mov	[es:rndindex],bx
    94	mov	al,[es:rndtable+BX]
    95	xor	ah,ah
    96	ret
    
    WOLFSRC/ID_US_A.ASM lines 85–96 at 0516778 · upstream ↗
    642	if (demoplayback || demorecord)
    643		US_InitRndT (false);
    644	else
    
    WOLFSRC/WL_GAME.C lines 641–644 at 0516778 · 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

  12. ^Doom's rndtable holds the same 256 values in the same order as Wolfenstein 3D's (compared entry by entry, computed); Doom walks it with two indices (prndindex for P_Random, rndindex for M_Random), where Wolfenstein 3D uses one (rndindex).Codeid-Software/wolf3d · id-Software/DOOM
    How we know
    19rndtable db    0,   8, 109, 220, 222, 241, 149, 107,  75, 248, 254, 140,  16,  66
    20	db   74,  21, 211,  47,  80, 242, 154,  27, 205, 128, 161,  89,  77,  36
    
    WOLFSRC/ID_US_A.ASM lines 19–20 at 0516778 · upstream ↗
    37	db  120, 163, 236, 249
    
    WOLFSRC/ID_US_A.ASM line 37 at 0516778 · upstream ↗
    17rndindex	dw	?
    
    WOLFSRC/ID_US_A.ASM line 17 at 0516778 · upstream ↗
    31unsigned char rndtable[256] = {
    32    0,   8, 109, 220, 222, 241, 149, 107,  75, 248, 254, 140,  16,  66 ,
    33    74,  21, 211,  47,  80, 242, 154,  27, 205, 128, 161,  89,  77,  36 ,
    
    linuxdoom-1.10/m_random.c lines 31–33 at a77dfb9 · upstream ↗
    50    120, 163, 236, 249
    
    linuxdoom-1.10/m_random.c lines 50–51 at a77dfb9 · upstream ↗
    53int	rndindex = 0;
    54int	prndindex = 0;
    ⋮
    56// Which one is deterministic?
    57int P_Random (void)
    ⋮
    59    prndindex = (prndindex+1)&0xff;
    60    return rndtable[prndindex];
    ⋮
    63int M_Random (void)
    ⋮
    65    rndindex = (rndindex+1)&0xff;
    66    return rndtable[rndindex];
    
    linuxdoom-1.10/m_random.c lines 53–67 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

Primary

Secondary