ROLL OVER is a text animation routine that creates a “rolling” color-cycling effect on a string of characters printed to the screen. The subroutine at line 9000 first copies character bitmap data from the system font (via the `ch` pointer at address 23606/23607) into the display file area (via the `gr` pointer at address 23675/23676), doubling each row of pixels by writing it twice to consecutive byte pairs. It then animates the string by cycling through PAPER/INK attribute combinations using `CHR$ (142+2*z)` and scrolling the attribute value downward through positions 0–7 in a loop of 10 repetitions. System variables at 23675/23676 (D_FILE) and 23606/23607 (CHARS) are accessed directly via PEEK to locate the display file and character set in memory.
Program Structure
The program is short, consisting of a main section (lines 5–30) and a reusable subroutine (lines 9000–9120). The main section sets screen colors, calls the subroutine twice with different strings ("ROLL OVER" and "Try Again"), then halts. The subroutine is self-contained and driven entirely by the string passed in x$.
| Lines | Role |
|---|---|
| 5 | Set PAPER 6, BORDER 4 |
| 10–20 | Set x$ and call subroutine |
| 30 | STOP |
| 9000–9010 | Read system variable pointers for display file and character set |
| 9020–9060 | Copy font bitmaps into display file, doubled vertically |
| 9070–9110 | Animate by cycling attribute bytes and reprinting string |
| 9120 | Restore D_FILE low byte, return |
System Variable Access
The subroutine makes direct use of two Spectrum system variables:
23675/23676— D_FILE (display file address), read at line 9000 to locate where character cell bitmaps live in memory.23606/23607— CHARS (character set base address), read at line 9010 to find the ROM font.
Both 16-bit values are assembled from their low and high bytes using the standard PEEK low + 256 * PEEK high idiom, storing results in gr and ch respectively.
Bitmap Copying with Vertical Doubling
Lines 9020–9060 iterate over every character in x$. For each character, its ASCII code is obtained with CODE x$(z+1). The eight pixel rows of that character’s font data are read from ch + (a*8) + n. Each row byte v is written to two consecutive positions in the display file: once at gr + (16*z) + n and again at gr + (16*z) + 8 + n. This doubles each character row, effectively stretching each glyph to occupy 16 bytes instead of the usual 8 — a simple vertical scaling technique using only PEEK and POKE.
Color Animation
The animation loop (lines 9070–9110) runs 10 repetitions (r). Within each repetition, the low byte of D_FILE is temporarily modified via POKE 23675, n+88 as n counts down from 7 to 0, shifting which part of the display file is addressed. Simultaneously, line 9100 rebuilds x$ by replacing each character with CHR$ (142 + 2*z), generating color attribute control characters that vary per character position. The string is then printed at a fixed screen position with PRINT AT 10,10;x$, causing each character to display with a different, cycling PAPER/INK combination.
Notable Techniques
- D_FILE manipulation: Temporarily altering the low byte of the display file pointer (
POKE 23675, n+88) redirects where the system reads display data, creating a scrolling or rolling visual without moving any pixel data. - Attribute color cycling: Using
CHR$ (142 + 2*z)produces embedded color-change escape sequences within a string, allowing per-character attribute control inside a singlePRINTstatement. - Subroutine reuse: The same subroutine handles strings of any length because all loops are bounded by
LEN x$.
Potential Anomalies
Line 9080 sets POKE 23675, 88+8 (= 96) immediately before the inner loop resets it in steps from 95 down to 88. This initial POKE may be a preparatory state or a minor redundancy, since the inner loop at line 9090 immediately overwrites it. Additionally, line 9100 permanently overwrites the contents of x$ with control characters on each pass through the outer loop, meaning the original string text is destroyed after the first animation frame. For the demo’s purposes this is harmless since the subroutine returns after the animation, but callers should be aware that x$ is not preserved.
Source Code
5 PAPER 6: BORDER 4
10 LET x$="ROLL OVER": GO SUB 9000
20 LET x$="Try Again": GO SUB 9000
30 STOP
9000 LET gr=PEEK 23675+256*PEEK 23676
9010 LET ch=PEEK 23606+256*PEEK 23607
9020 FOR z=0 TO (LEN x$-1): LET a=CODE x$(z+1)
9030 FOR n=0 TO 7: LET v=PEEK (ch+(a*8)+n)
9040 POKE (gr+(16*z)+n),v
9050 POKE (gr+(16*z)+8+n),v
9060 NEXT n: NEXT z
9070 FOR r=1 TO 10
9080 POKE 23675,88+8
9090 FOR n=7 TO 0 STEP -1: POKE 23675,(n+88)
9100 FOR z=1 TO LEN x$: LET x$(z)=CHR$ (142+2*z): NEXT z
9110 PRINT AT 10,10;x$: NEXT n: NEXT r
9120 POKE 23675,88: RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
