--- title: "Brick Buster" id: 57151 type: "computer_media" slug: "brick-buster" url: "http://localhost/computer_media/brick-buster/" markdown_url: "http://localhost/computer_media/brick-buster.md" published_at: "2024-10-04T00:55:17+00:00" modified_at: "2026-03-30T21:19:26+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/100_BrkB.png" excerpt: "A breakout-style brick-busting arcade game driven entirely by an embedded machine-code engine — complete with configurable speed, serve control, and persistent high-score tracking." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/100_BrkB.png" media_type_tags: "Arcade, Game" --- # Brick Buster Brick Buster is a breakout-style arcade game in which the player serves a ball to knock out rows of bricks displayed across the top of the screen. The game loop uses RAND USR 16514 to execute a machine-code routine embedded in the REM statement at line 0, which handles all real-time ball physics, collision detection, and display updates. Speed is configurable from 1 (fastest) to 9 and is POKEd into address 16773, while the serve angle is controlled by timing an INKEY$ poll waiting for “S”. The score is read back from display memory by inspecting character codes at offsets from the display file base address (calculated at startup via PEEK 16396/16397), and a high-score table with player name entry is maintained across successive plays. *** ## Program Analysis ### Program Structure The program is organised into several functional phases: 1. **Initialisation (lines 0–50):** The machine-code payload is stored in the `REM` at line 0. The display file base address is computed and stored in `DISP`. Speed is collected from the user and POKEd into memory. 2. **Screen setup (lines 60–130):** The playfield is drawn — a title bar, left/right border characters, and seven rows of brick characters filling columns 1–30. 3. **Game loop (lines 135–200):** Five serve cycles step through positions 5, 10, 15, 20, and 25. Each cycle waits for the player to press “S”, then calls the machine-code engine via `RAND USR 16514`. 4. **End sequence (lines 210–300):** Score is decoded from display RAM, compared to the best score, and a flashing “PRESS P TO PLAY AGAIN” prompt is shown using an alternating inverse/normal text loop. 5. **High-score entry (lines 410–450):** Called as a subroutine when a new best is achieved; stores score in `BEST` and name in `Z$`. 6. **Save/auto-run (lines 500–510):** Saves the program and re-runs it. ### Machine Code Engine The core game logic — ball movement, collision detection with bricks and borders, and score updating — is entirely implemented in the Z80 machine code embedded in the `REM` statement at line 0. The routine is entered via `RAND USR 16514`; address 16514 is the first byte of the `REM` payload (the `REM` token itself sits at 16512, the length bytes at 16513–16514 on a 16 KB machine, but the payload bytes begin immediately after the length field, placing executable code at the correct offset). Key observable behaviours from the raw hex include: - Reads from I/O port `$04` (`DB 04`) for keyboard input. - Uses `EXX` (`D9`) to switch between register banks, a classic Z80 trick for preserving state across inner loops. - Compares character codes against `$80` to detect whether a display cell contains a brick (set characters have bit 7 clear, while cleared cells or special graphics have bit 7 set — or vice versa depending on convention). - Writes `$80` and `$00` into display RAM cells to mark bricks as hit. - Stores ball direction state in addresses `$40AC` (16556) and `$40AD` (16557). - Uses `DJNZ` loops (`10 EC` sequence) for timing delays, with the delay count controlled by the speed value POKEd into 16773. - Returns to BASIC via `C9` (RET) when the ball is lost. ### Display File Score Reading Rather than maintaining a numeric score variable in BASIC, the score is read back from the display file itself at line 240: `LET SCORE=SCORE+(PEEK (DISP+R+1)-28)*10**(4-R)` The machine code writes digit characters directly into the top rows of the display (one digit per brick row destroyed). BASIC then reconstructs the numeric score by subtracting 28 (the character code offset for digits in the Spectrum/TS2068 character set, where `'0'` = 28 in display file encoding) and multiplying by the appropriate power of ten. This is an elegant technique that avoids any score variable passing between BASIC and machine code. ### Serve Angle Mechanism Lines 150–170 implement serve control: - `POKE 16556,5` sets the initial ball X-direction state. - `POKE 16518,F` sets the serve position (column), stepping in increments of 5 across the five cycles. - The spin loop at line 170 (`IF INKEY$<>"S" THEN GOTO 170`) waits for the player to press S, so the moment of keypress determines the serve timing. ### Flashing Prompt Technique Lines 280–300 implement a flashing “PRESS P TO PLAY AGAIN” message without using the Spectrum’s FLASH attribute. Instead, lines 282–287 alternate between printing the message in inverse video (`%P%R%E%S%S%...`) and in normal video, each separated by a short `FOR...NEXT` delay loop of 30 iterations. The `GOTO 280` at line 300 creates an infinite loop until P is pressed. ### Key Variables and Addresses | Name / Address | Purpose | | --- | --- | | `DISP` | Base address of display file (from PEEK 16396/16397) | | `BEST` | Highest score achieved this session | | `Z$` | Name of high-score holder | | `I` | Speed setting (1–9), POKEd to 16773 | | `F` | Serve loop counter (5, 10, 15, 20, 25) | | `B` | Remaining balls (starts at 5) | | 16514 | Entry point of machine-code game engine in REM | | 16556 ($40AC) | Ball X-direction state | | 16557 ($40AD) | Ball Y-direction state | | 16773 | Speed delay parameter for the MC engine | ### Notable Techniques and Observations - The ball lives counter `B` is displayed at `AT 0,30` and decremented each serve cycle, giving the player exactly five serves per game. - Block graphic characters (`\.. \:` etc.) are used for the border and title bar decorations, making use of the full Spectrum block graphic set. - The score reconstruction loop (lines 230–250) correctly handles a four-digit score with weights 1000, 100, 10, 1 via `10**(4-R)` for R=1..4. - The `RAND USR` idiom is the standard Spectrum BASIC method for calling machine code, using the fact that `RANDOMIZE USR addr` sets up HL and calls the address as a Z80 subroutine. ## Source Code ``` 0 REM \11\10\16\01\0A\16\78\FE\02\20\07\3E\04\32\AC\40\18\03\FE\18\C8\79\FE\02\20\07\3E\0C\32\AD\40\18\09\FE\1F\20\05\3E\0D\32\AD\40\05\0D\CD\55\41\7E\FE\08\20\16\CD\6A\41\3A\AC\40\FE\05\20\07\3E\04\32\AC\40\18\05\3E\05\32\AC\40\36\80\CD\E0\40\CD\82\41\CD\E0\40\CD\82\41\36\00\18\AA\00\00\E5\C5\42\4B\DB\04\FE\3B\20\08\79\FE\1D\28\0D\0C\18\0A\FE\2F\20\06\79\FE\01\28\01\0D\CD\55\41\36\00\23\36\03\23\36\03\23\36\00\05\CD\55\41\3A\AD\40\FE\0C\20\0F\7E\FE\80\20\0A\3E\0D\32\AD\40\3E\05\32\AC\40\06\02\23\7E\FE\80\20\0C\3E\05\32\AC\40\D9\C1\06\14\C5\D9\00\10\EC\23\3A\AD\40\FE\0D\20\0F\7E\FE\80\20\0A\3E\0C\32\AD\40\3E\05\32\AC\40\59\C1\E1\C9\D5\C5\2A\0C\40\C5\06\00\09\C1\11\21\00\10\03\C1\D1\C9\19\18\F8\E5\2A\0C\40\23\23\23\23\7E\3C\FE\26\28\03\77\18\05\36\1C\2B\18\F2\E1\C9\C5\01\00\09\0B\78\B1\20\FB\C1\C9\24\25\1C 5 LET DISP=PEEK 16396+256*PEEK 16397 10 LET BEST=0 15 CLS 20 PRINT "ENTER SPEED 1 TO 9 (1=FASTEST)" 25 PRINT AT 3,6;"<=5....8=> S=SERVE" 30 INPUT I 40 IF I<1 OR I>9 THEN GOTO 30 50 POKE 16773,I 60 CLS 70 PRINT "\ .0000\..\..\..\..\..BRICK BUSTER\..\..\..\..\..\..\..\..\..\. " 80 FOR F=1 TO 20 90 PRINT AT F,0;"\ :";TAB 31;"\: " 100 NEXT F 110 FOR F=1 TO 7 120 PRINT AT F,1;"\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##\##" 130 NEXT F 135 LET B=5 136 PRINT AT 0,30;B 140 FOR F=5 TO 25 STEP 5 150 POKE 16556,5 160 POKE 16518,F 170 IF INKEY$<>"S" THEN GOTO 170 175 LET B=B-1 176 PRINT AT 0,30;B 180 RAND USR 16514 190 PRINT AT 21,0;" " 200 NEXT F 210 PRINT AT 0,10;"\..GAME OVER\.." 220 LET SCORE=0 230 FOR R=1 TO 4 240 LET SCORE=SCORE+(PEEK (DISP+R+1)-28)*10**(4-R) 250 NEXT R 260 IF SCORE>BEST THEN GOSUB 400 270 PRINT AT 9,1;" BEST SCORE IS ";BEST;AT 10,INT ((32-LEN Z$-3)/2);"BY ";Z$ 280 PRINT AT 12,4;"%P%R%E%S%S% %"%P%"% %T%O% %P%L%A%Y% %A%G%A%I%N" 281 PRINT AT 0,10;"BRICK BUSTER" 282 FOR Q=0 TO 30 283 NEXT Q 284 PRINT AT 12,4;"PRESS ""P"" TO PLAY AGAIN" 285 PRINT AT 0,10;"\..GAME OVER\.." 286 FOR Q=0 TO 30 287 NEXT Q 290 IF INKEY$="P" THEN GOTO 15 300 GOTO 280 410 LET BEST=SCORE 420 PRINT AT 2,2;"YOU NOW HAVE THE BEST SCORE" 430 PRINT AT 4,1;"ENTER YOUR NAME (1-27 LETTERS)" 440 INPUT Z$ 450 RETURN 500 SAVE "1010%0" 510 RUN ```