Fortress Of Zorlac is a space shooter game in which the player pilots a ship to destroy an alien and the blocks of its fortress across multiple waves of increasing difficulty. The game uses extensive machine code stored across REM statements in lines 2 through 29, with USR calls throughout the main loop to drive all gameplay mechanics including movement, torpedo firing, collision detection, and rendering. Skill level (1–5) is selected at startup and affects the game speed via POKEs to timing variables as well as the point multiplier (F = 50*V). The score is stored as a two-byte value split across two memory locations and reconstructed with PEEK 18210 + 256*PEEK 18211. A wave counter (W) runs from 29 to 33, triggering a “Game Over” screen at W=34.
Program Analysis
Program Structure
The program is divided into several logical sections:
- Lines 1–29: REM statements holding machine code routines and data tables. Line 1 also encodes a title/banner graphic. Lines 2–29 contain Z80 machine code in hex byte sequences.
- Lines 30–110: Title screen setup — CLS, screen POKEs, welcome text with block-graphic logo, and a prompt for instructions.
- Lines 140–190: Initialization USR calls and branch to instructions or game setup.
- Lines 190–510 (main game loop): Wave management, USR calls for all gameplay mechanics, scoring, and wave progression.
- Lines 520–630: Alien-destroyed branch — score update, speed increase, and loop back.
- Lines 640–740: End-of-game (wave 34) screen and play-again prompt.
- Lines 1000–1140: Instructions subroutine (two pages of text with key layout).
- Lines 2000–2200: Skill level selection subroutine.
- Lines 3000–3100: SAVE and restart.
Machine Code Storage in REM Statements
All game logic is implemented in Z80 machine code, stored as raw bytes embedded in REM statements (lines 2–29). This is a common technique: the BASIC interpreter ignores REM content, so arbitrary binary data can be placed there and executed via USR with the appropriate address. The machine code spans many hundreds of bytes across 28 REM lines, covering routines for rendering, movement, collision detection, torpedo logic, alien AI, fortress block management, and scoring.
USR Call Dispatch
The main game loop invokes machine code exclusively through LET L=USR address. The return value is assigned to L but is generally discarded; the USR idiom is used purely for its side effects. Key USR entry points include:
| Address | Apparent Role |
|---|---|
17617 | Early init / display setup |
17926 | Keyboard / title screen handler |
18431 | Game field initialization / redraw |
17968 | Alien movement |
18526 | Fortress block rendering |
16684 | Ship movement |
17055 | Torpedo / firing logic |
17224 | Collision / hit detection |
18545 | Post-keypress processing |
18769 | Score / status update |
17860 | Per-block scoring loop body |
17413 | Wave reset |
18614 | Alien-death animation frame |
18867 | End-of-wave / end-of-game handler |
Key BASIC Idioms
- Two-byte score storage: The score
Sis stored across two adjacent memory bytes. It is read asPEEK 18210 + 256*PEEK 18211and written back by splitting onINT(S/256). This supports scores up to 65535. - Skill-level configuration via POKE: Lines 2110–2190 patch the machine code directly:
POKE 18767,1andPOKE 18768,5-Vset speed parameters; a loop POKEs ship-count values into addresses 18354–18358 based on the chosen level. - Speed escalation: Each time the alien is destroyed,
Ris decremented by 20 (down to a floor of 20) and POKEd to address 18146, tightening the game loop timing. - Point multiplier:
F = 50*Vwhere V is the skill level (1–5). Scoring in lines 560–590 addsF * (PEEK 17455 - 3), rewarding players who fire from farther left with a higher multiplier. - Wave counter:
Wstarts at 28 (line 195), increments each loop, and is POKEd to three addresses (17158, 17183, 17208) for the machine code to use. AtW=34, the game ends. - Keyboard wait: Line 155 uses
IF INKEY$="" THEN GOTO 140as a spin-wait for a keypress after the title USR calls complete.
Scoring Loop
Lines 430–460 iterate N from 1 to 32, calling USR 17860 each time and adding N to the result. This loop walks through all 32 possible fortress block positions; the machine code routine presumably checks and scores each surviving block. The accumulation of L=L+N within the loop has no meaningful effect on gameplay since L is a scratch variable, but it may be a stylistic artifact.
Graphics and Display
The title logo at lines 50–70 is constructed from ZX81 block graphics characters arranged to spell out the game title in a large font. Lines 660–690 use similar block graphics to render a “GAME OVER” box. The instruction screens (lines 1100–1110) use block graphics to draw a representation of a keyboard layout showing all control keys.
Skill Level Selection
The skill level subroutine (lines 2000–2200) reads a keypress, converts it to a numeric value with LET V=CODE INKEY$-28 (mapping digit characters ‘1’–’5′ to values 1–5 by subtracting the ZX81 character code offset), validates the range, and applies the result via POKEs and the F multiplier variable.
Notable Techniques and Observations
- The machine code at line 2 begins with
LD HL,(nn)andLD (nn),HLpairs, suggesting it copies pointers or initializes display addresses at startup. - Line 3 contains
LDIRandLDDR(block copy/move) opcodes, used for scrolling or copying screen regions. - Line 8’s machine code includes keyboard port reads (
3E F7,3E EF,3E DF— the standard ZX81 keyboard row port values) and compares against register C for keypress detection. - Lines 545–547 with
LET L=L+0appearing twice in the alien-death loop are effectively no-ops, likely serving as timing delays or placeholders left from development. - The
SAVE "ATTAC%K"at line 3000 uses an inverse-video K in the filename. - There is no apparent protection against
V=0at line 2090 if a non-digit is pressed and then INKEY$ changes between lines 2080 and 2090, but the validation at line 2100 catches out-of-range values and loops back safely.
Content
Source Code
1 REM % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ####################################################################################################% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % INPUT RND*INKEY$+ '(: D
2 REM 21BB40221A412182402218413E14321E413E 9321F413E39322041CD9141CD5B41CD5B41 5 5 D DED431C41C38A41 4 CED431C41ED5318413A2041D6 832204126 06F19221A413A1E41D6 2321E413A1F41D6 2321F41 0 0 0CD9141C9
3 REM ED5B1A411A2A1A412B 6 0F53A20414FF1EDB82A184177E5ED4B1C41CD1242EBE1C53A1E41 120 0EDA0 33DFE 028 5EB 9EB18F3ED4B1F41 6 0EDB03A1E41 122 0EDA0 33DFE 028 7EBA7ED42EB18F13A1F411B1BEDA03DFE 020F7C1EBC93EF7BC28 D3EEFBC28 83EDFBC28 3C3F543AFB9CAF543C3EA43
4 REM D5F52A C4023AF1121 0B828 4193C18F9791E 0BB28 41C2318F9F1D1C9 0 0
5 REM 218240ED5B1C41D5789216 05F19D17993FE 128 530 D36 0C916 03E39 05F1936 0C916 03E39 087D6 85F1936 0C9 0 0 0 0 0
6 REM 18 7 0 0 0 0 0 087 78084 4 084 3 7 0 0 280 1 0 0 78084 0 08780 4 0 081 082 0 0 0 0 0 02A1C417DC6 3327442ED4B7442C53AEF42FE 028 E 5CDD142C178FE 6C0AF32EF42C9 4CDD142C178FE AC03E 118EF 0 0ED437442CD1242EB2177423E 8 1 5 0EDB03DFE 0C8EB 11C 0 9EB18EF 1 0 0 0 0
7 REM 81808080828282818380 0802080 0 7 784 38084808080 781808080828281838281 0802080 0 784 3 78484808080 781808080828083828181 0802080 080 3 7848484808080 7 2 0 9ED4B4643CD1242EB2145433E 1BE20 93C32454321FA4218163E 2BE20 93C32454321134318 83E 1324543212C433E 5 1 5 0EDB03DFE 0C8EB 11C 0 9EB18EF 0 0 0 0 0
8 REM CDBB 2ED4B46433EFFBD28543DBD282B3DBD28273D3DBD282D3EF7BD28283EEFBD28383EDFBD28333EF79430243A1C41D6 8B9282BCD 544 C18253E10B82820CD 544 4181A3E 3B82815CD 544 518 FAFB928 BCD 544 D18 5C5CD3144C1ED434643CD4843C9 0 0
9 REM C5ED4B4643CD12423E 5111C 0 6 536 02310FB193DFE 020F3C1C9 0 0 0 0 0
10 REM 01112 A123A2C44FE 1C82A464324242C2C2C2C222D44222F44444DCD124236343E 1322C44C9 0 0 0 0 0
11 REM 0 0AF325E44325F443A2C44FE 0C8ED4B2D44CD12423E34BE20 236 0ED5B1C417B3D9128 B38 9233634 CED432D44C9237BC6 4912820AFBE28ED3E80BE28 C3E 8BE28 73E 1325F4418 B C36 0CD38423E 1325E44AF322C44C9 0 0 0 0 0 0 0 0 0
12 REM 8080 0 0 0 0 0 1 1 3CD1242EB 6 B21CA44EDA0EDA0EDA010F53E 5 6 321CA44C5 120 0EB 9C1EBEDA010F43DFE 020EA 120 0EB 9EB 6 A21CA447E12231B7E12231B7E12 01B10EF 120 0EBA7ED42EB3E 5 6 321CA44F57E12F1C5 121 0EBA7ED42C1EB2310EF3DFE 020E53ACA4432CD443ACB4432CA443ACC4432CB443ACD4432CC44 1 D BC34C43
13 REM 08184 7 08186 7828182 7 08184 7848186 7 08182 7 08180 0 782808180 7808081 0 780808180 7808481 080 7 084 782 0828184 682 782 0848184 682 784 0848182 081808080828282828280 080 080 0808484848484808080 7 41119 03AC3453CFE 520 23E 132C345214645471910FDE5ED4B4643CD1242EBE1C37743 0 0 0 0 0
14 REM 0 0 0 0 0 0 0 034 0 0 0 0 0 0 0 0FB452A 4462B 1F345A7ED4230 521FB4518 1 9E522 446 112 DCD1242D1EB 1 8 0EDB0C9
15 REM 3A1C41D6 24F 6 5CD4746 0CD4746CD4746 0CD4746C9CD124236811121 01936 2 4 4 4 4C9 0 0 0
16 REM 0 D 03A6246FE 1C83A1C41D6 36F3A4743673E 59438 426 518143E 99438 426 918 B3E D9438 426 D18 226112260463E 1326246C9
17 REM 0AF329F46ED4B6046CD124236 0AFB920 4326246C9 D2BBE28 53E34BE20 736 4ED436046C93432C6463E 1329F46C9 0 0 0 0 0
18 REM 2D 02ADB462311C8 0A7ED5228 51922DB46C921 0 022DB46CDE147ED4B1C41 DED431C41 D DCD12423E14 1 D 0545D23EDB02B36 0 114 0 93DFE 020ECC9
19 REM 0 0 01D1C241C1027E8 364 0 A 0 1 0 0 0 1AF3235472A2247223347 12447212947E5AFE15E23562BE52A3347A7ED5222334738 33C18F219FE 020 93A3547FE 03E 028 9C61CF53E 1323547F1223347 2 3E12323E57BFE 120C6E1C9 0 0 0 0 0 0 0 0 0 0
20 REM 3A5F44FE 1C83A5E44FE 0C8AF325E4411 3 02A2F4426 0A7ED52EB2A224719 0 0 0 0222247CD36472A C401112 019EB212447 6 57EFE 028 6EDA0 310F6C92310F2C9 0 0
21 REM ED4B2D44CD12423E34BEC036 0C9EDA06046CD124236 0C9
22 REM 63A21824036802310FB 63236 82310FB 62A36802310FB2115 2221C4121 0 022DB46225E4421 0 922464321 0 1226046AF322C44326246329F46C9 0 0
23 REM 2D2E39 026333E 0312A39392A37 03C2D2A33 0372A26293E 1 317CD1242EB214548 119 0EDB0C9 0 0 0 1 317CD1242 61936 02310FBC9 0 0 0
24 REM 085 185 0 0 280 3 0 08780 4 0 081 082 0 0 0 0 0 087 78084 4 084 3 7 0 0 280 1 0 0 0 0 0 0 1ED4B1C41 C C C 6 5CD1242111C 03E EF5 6 57EEE80772310F919F13DFE 020EFC9EB219C48C377433E 2BE201F3C32B548EB2336 52336 22336 5111F 01936 3232336 111A3 0193680C93E 132B548EB232336 02336851121 01936 311A5 0193680C9 0 0 0
25 REM ED4B1C41 C C C 6 5ED434643CD 544 6 EED434643CD 544C9 0 0 0 0 0 0 0 0
26 REM 1 4CDDD46CDD149CD9F42CD2C41CD6044CD93473A5F44FE 1C8CD3046CDA0463A9F46FE 1C8CD63462A4F4911 0 013A7ED52CA51491918F6 0 0 0 0 0 0 0
27 REM 3EBFBD28 63E7FBDC2F0433A1C41C3C543 0 0 0 0 0 0 0
28 REM ' 'LN >PIY=.'4Q 7( CLS 7X RETURN 4 NEXT TAN
29 REM FFFFCDBB 2ED4B464322CF4911FFFFA7ED52C82ACF49CB65CC31442ACF49ED4B4643CB6DCC31442ACF49ED4B4643CB5DCADB43CB55CADB43CB45CAD043CB4DCAD043CB7528 3CB7DC0 0 0 0 0 0CB6CCAE643CB64CAE643CB5CCAE643CB54CAC243CB4CCAC243C9 0 0 0 0 0 0
30 CLS
34 POKE 17924,252
35 POKE 17925,69
40 PRINT AT 5,11;"WELCOME TO";
50 PRINT AT 7,5;".''''. '':'' '':'' .''''. .''''. : .' ";
60 PRINT AT 8,5;":....: : : :....: : :''.";
70 PRINT AT 9,5;": : : : : : '....' : '.";
80 PRINT AT 17,3;"COPR., PAUL CARLSON, 1982";
90 PRINT AT 21,0;"DO YOU WANT INSTRUCTIONS? (Y/N)";
100 POKE 17158,128
110 POKE 17183,128
120 POKE 17208,128
140 LET L=USR 17617
150 LET L=USR 17926
155 IF INKEY$="" THEN GOTO 140
160 IF INKEY$="N" THEN GOTO 190
170 IF INKEY$<>"Y" THEN GOTO 140
180 GOSUB 1000
190 GOSUB 2000
195 LET W=28
200 LET S=0
202 LET R=200
205 POKE 18146,R
210 POKE 18210,0
220 POKE 18211,0
230 LET L=USR 18431
250 PRINT AT 0,10;"SCORE: 0"
260 LET W=W+1
270 IF W=34 THEN GOTO 640
280 POKE 17158,W
290 POKE 17183,W
300 POKE 17208,W
310 LET L=USR 17968
320 LET L=USR 18526
340 LET L=USR 16684
350 LET L=USR 17055
360 LET L=USR 17224
370 IF INKEY$="" THEN GOTO 340
380 LET L=USR 18545
390 LET L=USR 18769
400 LET L=USR 18401
410 LET L=USR 18415
420 IF PEEK 17503=1 THEN GOTO 520
430 FOR N=1 TO 32
440 LET L=USR 17860
450 LET L=L+N
460 NEXT N
470 LET L=USR 17413
475 POKE 18016,0
480 POKE 17452,0
485 POKE 18018,0
490 POKE 17222,0
500 POKE 17223,9
505 POKE 18079,0
510 GOTO 260
520 FOR N=1 TO 50
540 LET L=USR 18614
545 LET L=L+0
547 LET L=L+0
550 NEXT N
560 LET S=PEEK 18210+256*PEEK 18211
570 LET S=S+F*((PEEK 17455)-3)
575 PRINT AT 0,17;S
580 POKE 18211,INT (S/256)
590 POKE 18210,(S-256*PEEK 18211)
592 IF R>20 THEN LET R=R-20
595 POKE 18146,R
600 LET L=USR 18867
620 LET L=USR 18431
630 GOTO 310
640 LET L=USR 18867
650 PRINT AT 0,4;"FINAL";
660 PRINT AT 10,13;":'''''''''':"
670 PRINT AT 11,13;": GAME :"
680 PRINT AT 12,13;": OVER :"
690 PRINT AT 13,13;":..........:"
700 PRINT AT 16,6;"PLAY AGAIN? (Y OR N)"
720 IF INKEY$="N" THEN STOP
730 IF INKEY$="Y" THEN GOTO 190
740 GOTO 720
1000 CLS
1010 PRINT AT 0,10;"YOUR GOAL:"
1020 PRINT AT 2,0;"TO SCORE AS MANY POINTS AS YOU CAN BY DESTROYING THE ALIEN AND BLOCKS OF HIS FORTRESS."
1030 PRINT AT 6,0;"YOU HAVE FIVE SHIPS TO DESTROY THE ALIEN AS MANY TIMES AS YOU CAN. WARNING - THE ALIEN GUNS ARE INDESTRUCTIBLE."
1040 PRINT AT 11,0;"POINTS ARE AWARDED BASED ON SKILL LEVEL AND THE DISTANCE YOUR SHIP IS FROM THE LEFT EDGE OF THE SCREEN WHEN IT FIRES."
1050 PRINT AT 16,0;"DESTROYING THE ALIEN IS WORTH FIFTY TIMES THE POINTS AWARDED FOR DESTROYING A BLOCK OF HIS FORTRESS."
1060 PRINT AT 21,1;"HIT ANY LETTER TO CONTINUE..."
1070 IF INKEY$="" THEN GOTO 1070
1080 CLS
1090 PRINT AT 0,3;"YOUR SHIPS CONTROL PANEL:"
1100 PRINT AT 3,2;":'''''''''''''''''''''': :'''''''''''''''''''''': : 1 2 3 4 5 : : 6 7 8 9 0 : : Q W E R T : : Y U I O P : :......................: :......................: MOVE SHIP UP FIRE TORPEDO"
1110 PRINT AT 11,0;":'''''''''''''''''''': :'''''''''''''': :'''''''''''''''''':: A S D F G : : H J K : : L ENTER :: Z X C V : : B N M : : . SPACE ::....................: :..............: :..................: MOVE SHIP MOVE MOVE DOWN SHIP SHIP LEFT RIGHT"
1120 PRINT AT 21,1;"HIT ANY LETTER TO CONTINUE..."
1130 IF INKEY$="" THEN GOTO 1130
1140 RETURN
2000 CLS
2010 PRINT AT 2,1;"SKILL LEVELS:"
2020 PRINT AT 4,15;"1 = SLOW"
2030 PRINT AT 6,15;"2 = AVERAGE"
2040 PRINT AT 8,15;"3 = FAST"
2050 PRINT AT 10,15;"4 = VERY FAST"
2060 PRINT AT 12,15;"5 = SUICIDAL"
2070 PRINT AT 16,6;"PRESS SKILL LEVEL..."
2080 IF INKEY$="" THEN GOTO 2080
2090 LET V=CODE INKEY$-28
2100 IF V<1 OR V>5 THEN GOTO 2080
2105 CLS
2110 POKE 18767,1
2120 POKE 18768,5-V
2130 LET F=50*V
2150 FOR N=1 TO 5
2160 LET A=18353+N
2170 POKE A,0
2180 IF N<=V THEN POKE A,25
2190 NEXT N
2200 RETURN
3000 SAVE "ATTAC%K"
3100 GOTO 30
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

