Analysis model: gpt-5.5 xhigh

Disorder by Halcyon - Technical Dissection

Disorder is Halcyon's four-minute MS-DOS demo from Juhla 1995. The archive looks modest: one 56,812-byte executable, one Scream Tracker module and two short text files. Restoring the COMPACK carrier exposes a much larger program: 119,232 bytes of load image, 1,111 relocations, an early sequence of segmented 16-bit renderers, and a second scene controller reached through a far call for the final hundred seconds.

That late controller is important. Stopping at the first code segment makes the demo appear to finish at its 500-point effect while the actual show continues through bars, grids, rings and closing graphics. The analysis below follows both controllers, the tracker order and row fields, and the inner loops that produce the pictures.

Release year: 1995

Identity And Original Evidence

Item Recovered fact
Production Disorder by Halcyon
Release 14 January 1995; third in the Juhla 1995 PC demo competition
Code Blitz
Music Croaker
Graphics Placidity
Party archive h_disord.zip, 265,594 bytes
Party archive SHA-256 42d0b798bcfa5723fcbef9087c7d90dcb62ce15dc0dba96c2b7e966a43d1a0fa
DISORDER.EXE 56,812 bytes; SHA-256 932fcf26e92b8a8629aab706fbe14a8e31dcf4ca4daf67dac5ca4620f6070e0d
_HALCYON.JOO 277,042 bytes; SHA-256 e884f51bf54e25bf9ca3e1ecdd958d679924289bc2794d0f0aabd53161da41d4

The date, platform, credits and placing agree across the Demozoo production record, the Pouet record and the original Scene.org party archive. The archive's DIZ says gus & nosound. HALCYON!.NFO identifies Blitz as the coder, Croaker as a musician and Placidity as the graphician, and dates H!DISORD.ZIP to 14 January 1995.

A later copy in Halcyon's Scene.org group directory has a different ZIP hash because it adds TRIP1601.COM and a Scene.org marker. Its four production files are byte-identical to the party archive. The smaller party ZIP is used as the primary object here.

COMPACK Restoration And The Real Program Boundary

The distributed entry contains W. Collis's COMPACK signature. UNP 4.12, running inside DOS, identifies COMPACK V4.5 and restores the executable from 56,812 to 123,712 bytes. The restored SHA-256 is:

4531efbbb49ca31d116f4a7a0e6e619a1dbef48a5f02279f9e628ceb5e4f71cd

Its MZ header is unusually relocation-heavy:

Header field Value
Header size 4,480 bytes (0118h paragraphs)
Load image 119,232 bytes
Relocations 1,111 (0457h)
Initial SS:SP 2A64:4000
Initial CS:IP 0000:A429
Physical file entry B5A9h
Load-image SHA-256 09bc41a077c3ab9941d29f19eca330754f9799a0e45ea8349e423a3efad6f80b

The relocation targets range from load-image offset 0015h to 1CDF8h. That spread matters: the executable is not one tiny routine followed by opaque data. It is a segmented Borland-era program with demo code and several runtime libraries distributed throughout the full image. The code is predominantly 16-bit real mode, with selected 386 instructions and 32-bit arithmetic where the compiler or renderer benefits from them.

The program contains both No Sound Sound Device v1.10 and the literal module name _halcyon.joo. A complete DOSBox-X run of the original four-file party archive, with the no-sound path selected and host audio disabled, reaches the ending and returns normally after about 4:17. No audio was played or captured.

The S3M Is The Show Clock

_HALCYON.JOO is a Scream Tracker III module titled Se vilkuilee mua.... Its header declares 36 order slots, 28 instruments and 99 pattern slots, with initial speed 6 and tempo 128. Only patterns 0 through 21 are used:

15 00 01 02 03 04 04 05 05 05 06 07 08 09 09 0A 0B 0A
0B 0C 0D 0E 0E 0E 0E 0F 0F 10 11 11 11 12 13 14 FF FF

The field read at player-object offset +08h is the current order-list position, not the pattern number. The proof is in the ending: the controller waits for 21h, or order position 33, while the highest used pattern number is 21 decimal. Offset +0Ch is the row. Confusing those two identities breaks the timeline wherever patterns 4, 5, 9, 11, 14, 15 and 17 repeat.

The module contains almost no timing tricks. Every normal order lasts 7.5 seconds. In order 32, rows 45 through 63 step tempo from 124 down to 106; a structural S3M simulation gives 256.814 seconds, while libopenmpt reports 256.681 seconds. The preservation run is 257.040 seconds. Agreement within a fraction of a second ties the code comparisons to the visible cuts.

Two Controllers, One Complete Schedule

Addresses through A429h below are offsets in the restored load image's first code segment. The later physical offsets are shown separately because they are reached through a relocated far pointer.

Order boundary Approx. song time Code path and established job
2 15.000 s 0E96h opening 3D/line scene returns
3 22.500 s 296Eh five-panel preparation, then common renderer with target 3
3 to 5 22.500-37.500 s 3204h two-phase woven line field
5 to 7 37.500-52.500 s 395Eh nested line tunnel
7 to 8, row 52 52.500-66.094 s 4EA8h projected object/scanline scene
8, row 52 to 9, row 44 66.094-72.656 s 5DF6h short cube construction
9 to 11 67.500-82.500 s 6D8Ah multi-object raster scene; its opening condition is already true when entered
11 to 13 82.500-97.500 s 7C7Fh larger mesh scene
13, row 56 104.063 s 8683h returns after its row-timed mesh pass
15 112.500 s 915Dh fifteen-record object engine returns
16, row 32 onward 123.750 s onward 99DBh 1,024-phase procedural field changes state
18, row 52 to 19 141.094-142.500 s 9E27h stops spawning and drains its 500-point system
19 through 21 142.500-157.500 s late-controller setup, two additional renderers and palette transitions
21 to 23 157.500-172.500 s physical 13E25h renderer
23 to 25 172.500-187.500 s physical 165BCh scanline field
25 to 28 187.500-210.000 s physical 15368h plus 15CCBh object/grid pair
28 to 33 210.000-247.757 s physical 16FBCh radial/ring engine
33, row 52 about 255.1 s final wait, shutdown and normal DOS return

The first controller calls the late one at far address 13C1:4713, physical load-image offset 18323h, passing the player and framebuffer objects. That routine allocates 768 local bytes, creates another 4,097-byte random table, loads palettes into the work pages, and dispatches the renderers at physical offsets 13E25h, 165BCh, 15368h, 15CCBh and 16FBCh. It returns only after the long order-28-to-33 effect. This far call is the missing half of any analysis that sees the early AFA7h file-offset routine and declares the show finished.

Five 106x66 Tiles Feed The Twister

At load offset 296Eh, the program allocates five blocks of 2100h bytes -- 8,448 bytes each -- and clears every byte. It then copies five 106x66 windows from a 320-wide source into 128-byte-stride destinations. The source windows form a cross around the central region: left, middle, right, above and below. The unused destination padding is deliberate; the renderer wants power-of-two row addressing, not tightly packed pictures.

Those five pages are passed to the routine at 1DECh. Its first loop doubles all three components of sixteen stored vertices. It then builds transformed coordinate arrays, projects edges and feeds scanline workers before freeing all five allocations. The code therefore makes one articulated textured object from five small panels. It does not store several frames of a prerecorded twist.

Five-panel twister in motion

The animation is visual concordance for the order-2-to-3 routine. The byte dimensions, allocations and stride come from the restored executable.

The Woven-Line Inner Loop

The scene at 3204h reserves 1716h stack bytes. Before drawing, it generates 400 random words and two 1,025-word phase tables, plus a 200-byte scanline selector. Each frame advances two angles by 10 and 5 modulo 1,024. For every one of the 200 rows it combines those lookup values with the selector and calls the span worker at 319Ch twice.

The worker is a one-dimensional 8.8 fixed-point texture mapper. In compact form its hot loop is:

mov  bl,dh              ; integer part of the 8.8 source phase
mov  ah,[bx+si]         ; sample one byte from the line texture
add  ah,color_bias      ; bias is 64 - span_length
cmp  ah,63
jb   store
mov  ah,63              ; saturate to the VGA ramp
store: mov es:[di],ah
add  dx,phase_step
inc  di
dec  cx
jnz  loop

Span length controls brightness as well as geometry: shorter spans receive a larger bias. DX advances independently of the framebuffer address, so each horizontal stroke samples a moving one-dimensional color waveform. Two spans per row, 200 rows, and independently moving phase tables create the woven bundle without a stored bitmap.

Woven line bundle

A 36-Layer Integer Line Tunnel

The following routine at 395Eh reserves 0402h local bytes and initializes four phase indices in the range 0..4095. It builds two banks of 36 records, each record 280 bytes. Paired lookup tables at 1BBEh and 3BC0h supply rotation components; radii 85 and 60 define the rectangular cross-section. Sixteen projected points per active layer are divided by depth and sent to the line clipper at 38BFh.

The layer state advances while the tracker moves from order 5 to order 7. Every frame is synchronized by polling VGA status port 3DAh; palettes go through the DAC path, and the line geometry is regenerated rather than copied.

Nested line tunnel

The Repeated 3D Core Is A Family, Not One Mystery Call

The middle of the demo contains several visibly different solids, but the code shows deliberate reuse. Routines beginning at 4EA8h, 5DF6h, 6D8Ah, 7C7Fh, 8683h and 915Dh repeat the same structural pieces:

They are not byte-identical. 4EA8h keeps 32 projected records and switches at order 8 row 52. 5DF6h is a compact four-face construction with dedicated edge routines at 682Dh and 6A97h. 6D8Ah can maintain two separately transformed objects and six independent angles. 7C7Fh reserves 06A2h local bytes and draws a larger record set. 8683h reserves 0638h, includes direct DAC programming and stops on row 56. 915Dh triples the XYZ components of fifteen stored vertices before entering its matrix and projection loop.

This is the useful code-level reading of the succession of cubes and awkward solids: Blitz kept replacing the object data and scene state around a small set of integer polygon techniques instead of shipping a general-purpose 3D engine.

The 1,024-Phase Procedural Field

At 99DBh, two 1,025-word tables are populated from different numeric ranges. The frame loop advances their indices by 6 and 3 modulo 1,024 and combines one sample from each:

y = base_y - table_b[phase_b] + table_a[phase_a]

It does this for all 320 x positions. Around a moving center it looks up a 20x20 binary mask at load offset 10AEh. Set mask cells invoke the small additive kernel at 9D93h: four corner neighbours receive color, four axial neighbours receive color+3, and the center receives color+6. The result is a procedural height trace with a pulsing, nine-tap additive object embedded in it. Retrace polling brackets each full 320-column pass.

Procedural terrain field

Five Hundred Points With Individual State

The scene at 9E27h reserves 17A8h bytes. It clears 501 triples of signed coordinates and parallel state arrays, then admits points until the active count reaches 500 (01F4h). New movement deltas come from a five-value random range, shifted to -2..+2, while three global drift terms are kept inside -40..40. Each live point is transformed, projected and drawn; its lifetime and velocity state survive to the next frame.

At order 18 row 52 the code increases the drain term. At order 19 it stops the loop, restores the work page and returns. That explicit lifetime machinery is why the particle cloud can coalesce and disappear without a frame sequence.

The Late Ring Engine And Its Inner Geometry

The final long renderer at physical offset 16FBCh reserves 215Eh bytes -- 8,542 bytes of local state. Its first nested loop constructs a radial lookup field for radii 0 through 60. For every signed x from -r through +r, it evaluates the integer form of:

y = sqrt(r*r - x*x)
radial[x][r] = y

The compiler emits the square, subtraction, square-root runtime call and byte store explicitly; signed-x rows have a 61-byte stride (3Dh). The routine then builds two 256-word phase tables, copies a 256x200 window from a 320-stride page into a 256-stride work page, and initializes a tracker-row-driven state machine.

Every eighth tracker row begins a new color transition. Two RGB triples move one component per update toward their targets, DAC entries are rewritten, and the active work page changes after nine and then five completed transitions. The radial table supplies the ring boundaries while the phase tables distort their centers and thickness. Order 32 row 48 begins the closing state; order 33 ends the renderer.

Late radial circles

VGA Timing And Why The Demo Is Stable

The renderers repeatedly poll bit 3 of VGA input status port 3DAh, first waiting for retrace to begin or end and then doing the complementary wait. DAC updates use color components in the 0..63 VGA range. Work segments are copied or selected outside the hottest pixel loops, so the inner loops mostly perform integer address arithmetic and writes.

The opening main routine also builds two 4,097-word numeric lookup tables and a 4,097-byte random table once. Later scenes reuse them with modulo-1,024 or modulo-4,096 phase arithmetic. The memory cost is small, but it removes trigonometric and random-number work from most frames.

This is conventional 1995 VGA engineering done thoroughly: precompute the expensive curves, clip before writing, draw to another segment, wait for the display boundary, then reveal or copy the completed page.

What The Preserved Images Do And Do Not Prove

The GIFs are short excerpts generated without audio from the preservation video linked by the Pouet record. They are used to correlate recovered routines with visible intervals. No video or H.264 asset is embedded in this page.

DOSBox-X's built-in AVI capture path crashed on this executable's early mode switch in the test environment, so those broken captures were discarded. The separate no-capture run of the original archive completed normally. File dimensions, order/row thresholds, allocation sizes, lookup-table lengths and inner-loop behavior above come from the original module and restored program, not from reverse-engineering a compressed video.

Assessment

Disorder is not one spectacular algorithm surrounded by filler. Its strength is the amount of authored machinery behind a 56 KiB packed carrier: five-panel texture preparation, a fixed-point line mapper, a 36-layer tunnel, several specialized polygon variants, a 1,024-phase procedural field, 500 independently tracked points, and a separate late controller with a radial renderer that runs almost to the last order.

The rough cubes and handwritten disclaimers are honest presentation. Underneath them is a carefully scheduled real-mode program that keeps changing methods for more than four minutes and still returns cleanly to DOS.