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. | WOLFSRC/README/RELEASE.TXT L6–7WOLFSRC/README/RELEASE.TXT L10WOLFSRC/README/RELEASE.TXT L51–52WOLFSRC/VERSION.H L1–3 | 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. | README.rst L89 | Dev blog |
| John 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". | WOLFSRC/README/RELEASE.TXT L20–22WOLFSRC/README/RELEASE.TXT L51–52 | 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". | WOLFSRC/WL_DR_A.ASM L7WOLFSRC/WL_DR_A.ASM L207–213WOLFSRC/WL_DR_A.ASM L517–523WOLFSRC/WL_MAIN.C L653–654WOLFSRC/WL_MAIN.C L674–681 | 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. | WOLFSRC/WL_DEF.H L122WOLFSRC/WL_DR_A.ASM L232–252WOLFSRC/WL_DR_A.ASM L438–469WOLFSRC/WL_DR_A.ASM L479–508 | 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. | WOLFSRC/WL_DRAW.C L366–382WOLFSRC/WL_DRAW.C L488WOLFSRC/WL_DRAW.C L1307–1308 | Code |
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. | WOLFSRC/WL_AGENT.C L1196–1242WOLFSRC/WL_MAIN.C L1283WOLFSRC/WL_STATE.C L1030–1032WOLFSRC/ID_US_A.ASM L80–95 | 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. | WOLFSRC/WL_ACT2.C L3449–3490WOLFSRC/WL_DEF.H L75 | Code |
Wolfenstein 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). | WOLFSRC/WL_AGENT.C L18–19WOLFSRC/WL_AGENT.C L156WOLFSRC/WL_AGENT.C L205–214WOLFSRC/WL_AGENT.C L943–953WOLFSRC/WL_DEF.H L115WOLFSRC/WL_PLAY.C L246–247WOLFSRC/WL_PLAY.C L343–357WOLFSRC/WL_DEF.H L97–98WOLFSRC/ID_SD.H L17 | 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). | WOLFSRC/WL_PLAY.C L354–357WOLFSRC/WL_AGENT.C L205–207WOLFSRC/WL_AGENT.C L156WOLFSRC/WL_AGENT.C L164–175WOLFSRC/WL_AGENT.C L943WOLFSRC/WL_ACT2.C L3464WOLFSRC/WL_DEF.H L75 | Code |
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). | WOLFSRC/WL_AGENT.C L164–183WOLFSRC/WL_AGENT.C L205–207WOLFSRC/WL_PLAY.C L343–353WOLFSRC/WL_PLAY.C L540–548 | Code |
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). | WOLFSRC/ID_US_A.ASM L4–6WOLFSRC/ID_US_A.ASM L19WOLFSRC/ID_US_A.ASM L60–73WOLFSRC/ID_US_A.ASM L85–96WOLFSRC/WL_GAME.C L641–644 | 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). | WOLFSRC/ID_US_A.ASM L19–20WOLFSRC/ID_US_A.ASM L37WOLFSRC/ID_US_A.ASM L17 | Code |