Marine Rescue is an action game in which the player dives underwater to rescue sailors from a sunken submarine while avoiding sharks and managing an oxygen supply. The game uses six REM lines at the start (lines 1–6) to store Z80 machine code routines that handle movement, collision detection, scoring, and shark behavior, accessed via USR calls to specific memory addresses such as 16531, 16676, and 16914. A DIM array M$(38,62) holds 37 humorous taunt and congratulation messages that are randomly selected based on the player’s score range at game over. The score is tracked by reading two consecutive memory locations (PEEK 16518 and PEEK 16519) to reconstruct a 16-bit value, while the oxygen countdown is maintained in PEEK 16521 and displayed in real time. Block graphics characters are used to render the underwater scene, safety zone, oxygen tank, submarine, and seabed decorations entirely within PRINT AT statements.
Program Analysis
Program Structure
The program is organized into several distinct functional regions:
- Lines 1–6: REM lines storing Z80 machine code routines (~200 bytes total).
- Lines 7–35: Initialization — variables, screen setup, POKE configuration of machine code parameters.
- Lines 40–450: Main game loop in two phases (200 iterations then 100 iterations), with increasing shark frequency.
- Lines 452–499: Time-expired and stop handlers.
- Lines 500–699: Scene-drawing subroutine.
- Lines 800–870: Diagnostic/development utilities (POKE loop and memory dump), left in the final listing.
- Lines 900–1099: Death/end-of-game handling, score display, and play-again logic.
- Lines 1100–1199: Message array initialization (M$) and flag reset.
- Lines 1600–1650: Unused collision-test stub.
- Lines 3000–3690: Title screen, instructions, and scrolling intro sequence.
- Lines 4000–5020: Delay and keypress wait subroutines.
- Line 9000: SAVE and restart.
Machine Code Usage
Six REM lines (1–6) hold Z80 machine code, loaded into the system RAM area starting around address 16384 (the start of the ZX81 display file region offset). The routines are invoked via USR calls throughout the main loop:
| USR Address | Apparent Role |
|---|---|
| 16531 | Shark collision / player movement handler (returns 45 on hit) |
| 16676 | Secondary event check (returns 41 on trigger) |
| 16914 | Oxygen depletion check (returns 40 when empty) |
| 16557 | Collision test stub called from line 1610 |
The machine code uses POKE’d parameters before each USR call: POKE 16514,C and POKE 16515,R pass the player’s column and row coordinates; POKE 16521,60 sets the initial oxygen count; POKE 16783,38 and related POKEs configure sprite or movement data. The score is maintained as a 16-bit value by the machine code at addresses 16518–16519.
Key BASIC Idioms
- Score reconstruction:
LET SC=PEEK 16518+256*PEEK 16519reads a little-endian 16-bit integer maintained by the machine code. - Decade display filter:
IF PEEK 16521=(INT (PEEK 16521/10))*10updates the oxygen counter display only on multiples of 10, reducing flicker. - Keypress wait: Lines 5000–5020 implement a two-stage INKEY$ debounce: first wait for the key to be released, then wait for a new press.
- Random positioning: Shark print positions use
INT (RND*10)+5and similar expressions; in phase 2 (lines 310–450) positions are snapped to even rows with(INT (RND*5))*2+6. - Z$ padding string:
LET Z$=" "(32 spaces) is reused throughout for clearing screen lines. - High-score persistence:
HSis never reset between games within a session; it survives replays via the GOTO 11 branch.
Message System
DIM M$(38,62) allocates a 38-row by 62-character string array. Rows 1–5 are oxygen-death taunts, rows 6–10 are low-score insults, rows 11–32 are score-tier messages, and rows 33–37 are shark-death messages. Row 38 is allocated but never explicitly assigned. Score tiers are:
| Score Range | Message Rows |
|---|---|
| 0–100 | 6–10 (random 5) |
| 101–500 | 11–15 (random 5) |
| 501–1000 | 16–20 (random 5) |
| 1001–2000 | 21–25 (random 5) |
| 2001+ | 26–33 (random 8) |
Notable Techniques
- The submarine’s horizontal position is randomized at startup via
LET Z=(INT (RND*17))+1and passed to the scene-drawing subroutine at line 500, making the rescue target appear at a different column each game. - The two-phase loop structure (200 then 100 iterations at lines 90 and 310) increases game pressure: phase 2 adds sharks on the left side (
PRINT AT ... ,0) and checks a different USR address (16939 vs. 16531), suggesting a second machine code scan path for phase 2. SLOWat line 40 andFASTat line 1067 are used deliberately: the game runs in SLOW mode for display sync during play, then switches to FAST for the title/intro sequence after a replay.- Lines 800–870 are clearly development artifacts — a POKEing INPUT loop and a PEEK memory dump with
PAUSE 40000— left in the shipped listing. - Line 135 is an exact duplicate of line 134 (
IF USR 16531=45 THEN GOTO 950), which appears to be an unintentional copy. - Line 1038 (
M$(38)) is dimensioned but its slot is never assigned, leaving it as blank padding. - The GOSUB at line 3575 calls line 1100 mid-intro solely to initialize the M$ array, then returns to continue the instructions sequence — a deferred data-initialization pattern.
Bugs and Anomalies
- Duplicate line 134/135: The shark-collision check is issued twice in succession with identical conditions, meaning a hit at that point triggers two GOTOs (the first fires). This is harmless but redundant.
- Line 1038 dead slot:
M$(38)is allocated in the DIM but never populated; if somehow selected, it prints 62 spaces. - Developer utilities in release: Lines 800–870 provide full memory inspection and POKE-entry tools with no protection, accessible simply by RUNning from line 800.
- Line 1600–1650 unreachable stub: The subroutine starting at 1600 is never called from the main game flow, and likely represents an earlier collision-detection approach superseded by the machine code.
- M$(37) is the last assigned row but the array is DIM’d to 38 rows; the shark-death random picker uses
INT (RND*5+33)which can return values 33–37, safely within bounds.
Content
Source Code
1 REM 1C 416 5 0 0 0 0 0 02A E404E 6 0C9ED4B8240 CCDF5 8CD8C403E13B920 4 12D 0C9 03A8F415F 176 A2A10402B7EB928 218F910F7 176 A16 02B7EBB28FBB928 4725718F410F0C924251C
2 REM ED4B8440 C3E 4B838 1C93E FB830 1C9ED43844079FE1D281FCDF5 8AFD7CD8C40B920 53E17D718D61119 02A864019228640AFD7D7D7C9CDF5 8AFD7D7C9C9222324251C
3 REM CDBB 27DFEFF20 1C9444DCDBD 77EED4B8240FE3320 8ED438440CDD840C9FE3B20 8ED438440CDB142C9FE2120 8AFB920 1C9 D181AFE2420 93E1FB920 1C9 C18 DFE2220 3 418 6FE2328 1C9 5C5CDF5 8CD8C40AFB9205FED4B8240CDF5 8AFD7C1C5CDF5 83E26D7C1ED4382403E 4B8202E3E 7B938 53E3C3289403E18B9301F3A8F41573E32BA20161196 02A8640192286403E26328F413A88403C3288403E11B820 F3E CB928 53E DB920 53E32328F41C93E12B928 B3CB928 73E38B928 2C1C9C1AF473E294FC92020202020202021212121212121212121212121212121
4 REM 3A89403D32894057AFBA20 3 128 0C9232425
5 REM ED4B8240C5 CCDF5 8CD8C403E13B928 FC1 DCDF5 8CD8C403E12B928 318 5C1 12D 0C93A8F415F 176 52A C40237EB928 218F910F7 176 A16 0237EBB28FBB928 4725718F4 5237EB928 218F910E8 176 A2A10402B7EB928 218F910F7 176 A16 02B7EBB28FBB928 4725718F4 52B7EB928 218F910E8C91F1F1F
6 REM ED4B8440 D3E 4B838 1C93E FB830 1C9ED438440 D79FE 2281BCDF5 8CD8C40AFB920 73E17D7AFD718D41119 02A864019228640ED4B8440 D D DCDF5 8AFD7D7D7D7D7C91E1F2021222324251C1D1E1F2021222324251C
7 LET HS=0
8 LET Z$=" "
9 GOSUB 3000
11 IF F=1 THEN GOSUB 3640
13 LET Z=(INT (RND*17))+1
14 GOSUB 500
15 LET C=28
16 LET R=4
17 LET X=26
18 LET Y=15
20 PRINT AT R,C;"A"
22 POKE 16783,38
23 POKE 16519,0
24 POKE 16518,0
25 POKE 16514,C
26 POKE 16515,R
29 POKE 16852,Z+7
30 POKE 16521,60
31 POKE 16847,Z+6
34 POKE 16520,0
35 PRINT AT 3,3;"60";AT 3,27;"0"
40 SLOW
90 FOR I=1 TO 200
93 IF PEEK 16521=(INT (PEEK 16521/10))*10 THEN PRINT AT 3,3;" ";AT 3,3;PEEK 16521
95 IF USR 16676=41 THEN GOSUB 950
110 IF USR 16914=40 THEN GOTO 900
134 IF USR 16531=45 THEN GOTO 950
135 IF USR 16531=45 THEN GOTO 950
137 IF USR 16676=41 THEN GOSUB 950
145 PRINT AT INT (RND*10)+5,29;"<S>"
151 IF USR 16531=45 THEN GOTO 950
165 PRINT AT 3,27;PEEK 16520
170 IF USR 16676=41 THEN GOSUB 950
180 IF I>100 THEN PRINT AT INT (RND*10)+5,29;"<S>"
210 IF USR 16531=45 THEN GOTO 950
230 IF USR 16676=41 THEN GOSUB 950
260 IF USR 16531=45 THEN GOTO 950
290 IF USR 16676=41 THEN GOSUB 950
300 NEXT I
310 FOR I=1 TO 100
315 IF PEEK 16521=(INT (PEEK 16521/10))*10 THEN PRINT AT 3,3;" ";AT 3,3;PEEK 16521
320 IF USR 16676=41 THEN GOTO 950
322 IF USR 16914=40 THEN GOTO 900
333 IF USR 16939=45 THEN GOTO 950
340 PRINT AT (INT (RND*5))*2+6,29;"<S>"
345 IF USR 16676=41 THEN GOTO 950
360 IF USR 16939=45 THEN GOTO 950
400 PRINT AT (INT (RND*5))*2+5,0;"<S>"
410 IF USR 16676=41 THEN GOTO 950
417 IF USR 16939=45 THEN GOTO 950
420 PRINT AT 3,27;PEEK 16520
450 NEXT I
452 CLS
455 PRINT AT 0,0;"YOUR TIME HAS EXPIRED."
460 GOTO 1005
499 STOP
500 PRINT AT 0,24;" .% % % % % % . ";AT 1,24;"% % ";AT 2,24;"% % "
510 PRINT AT 1,25;"SAFETY";AT 3,24;"% % ";AT 4,24;"% % "
520 PRINT AT 0,0;" .############. ";AT 1,0;"## ##";AT 2,0;"## ##";AT 3,0;"## ##";AT 4,0;"## ##";AT 1,1;"OXYGEN"
540 PRINT AT 4,8;"................"
550 PRINT AT 21,0;"% % ####,,@@!!,,!!##:..:..,,..% % % ..,,.::.% % % % % ##,,@@..,,"
600 PRINT AT 20,Z+1;"% % % % % % % % % :'"
610 PRINT AT 19,Z;" :";AT 18,Z+1;".:";AT 17,Z+2;".......: :...... "
620 PRINT AT 16,Z+5;" : : ";AT 18,Z+11;":.";AT 19,Z+11;":'"
630 PRINT AT 19,Z+1;"SUB"
699 RETURN
799 STOP
800 FOR I=16642 TO 17050
810 INPUT A
820 POKE I,A
830 IF I=(INT (I/20))*20 THEN CLS
835 PRINT I,A
840 NEXT I
850 STOP
860 FOR I=16600 TO 17100
863 PRINT PEEK I,I
864 IF I<>(INT (I/20))*20 THEN GOTO 869
865 PAUSE 40000
867 CLS
869 NEXT I
870 STOP
900 CLS
905 PRINT AT 2,0;"YOUR OXYGEN IS GONE."
908 LET N=INT (RND*5+1)
910 PRINT AT 4,0;M$(N)
920 GOTO 1002
950 CLS
955 PRINT AT 2,0;"YOU WERE A SHARKS DINNER."
958 LET N=INT (RND*5+33)
960 PRINT AT 4,0;M$(N)
970 GOTO 1002
1000 CLS
1002 PRINT AT 0,0;"SORRY, YOU ARE DEAD."
1005 LET SC=PEEK 16518+256*PEEK 16519
1008 IF SC>HS THEN LET HS=SC
1009 PRINT AT 7,5;"% % % % % % % % % % % % % % % % % % % % % % "
1010 PRINT AT 8,5;"% % % % % % % % % % % % % % % % % % % % % % ";AT 9,5;"% % SCORE: ";SC;AT 9,25;"% % ";AT 10,5;"% % ";AT 10,25;"% % ";AT 11,5;"% % HIGH SCORE: ";HS;AT 11,25;"% % ";AT 12,5;"% % % % % % % % % % % % % % % % % % % % % % "
1011 PRINT AT 13,5;"% % % % % % % % % % % % % % % % % % % % % % "
1020 IF SC<101 THEN PRINT AT 18,0;M$((INT (RND*5))+6)
1025 IF SC>=101 AND SC<=500 THEN PRINT AT 18,0;M$((INT (RND*5))+11)
1027 IF SC>=501 AND SC<=1000 THEN PRINT AT 18,0;M$((INT (RND*5))+16)
1029 IF SC>=1001 AND SC<=2000 THEN PRINT AT 18,0;M$((INT (RND*5))+21)
1031 IF SC>=2001 THEN PRINT AT 18,0;M$((INT (RND*8))+26)
1035 FOR I=1 TO 25
1036 NEXT I
1037 PRINT AT 18,0;Z$;Z$
1040 FOR I=1 TO 6
1043 SCROLL
1045 NEXT I
1050 PRINT AT 12,2;"I HAVE DECIDED TO GIVE YOU ";AT 14,2;"ANOTHER CHANCE."
1055 PRINT AT 17,2;"TYPE ""Y"" TO PLAY AGAIN";AT 19,2;"OR ""N"" IF YOU GIVE UP."
1060 LET L$=INKEY$
1065 IF L$="" THEN GOTO 1060
1067 IF L$="Y" THEN FAST
1070 IF L$(1)="Y" THEN CLS
1073 LET F=1
1075 IF L$(1)="Y" THEN GOTO 11
1080 PRINT AT 12,2;"GOOD-BYE SHARK-KILLER. ";AT 14,0;Z$;AT 17,2;"MAY THE WAVES BE WITH YOU. ";AT 19,0;Z$
1099 STOP
1100 DIM M$(38,62)
1101 LET M$(1)="DID YOU THINK YOU COULD HOLD YOUR BREATH FOREVER?"
1102 LET M$(2)="YOU ARE NOT A SHARK YOU KNOW. "
1103 LET M$(3)="HOW DID YOU EVER BECOME A DIVER?"
1104 LET M$(4)="ARE YOU TRYING TO GROW GILLS? "
1105 LET M$(5)="YOU DRINK WATER, YOU DO NOT BREATHE IT."
1106 LET M$(6)="WERE YOU PLAYING WITH YOUR EYES CLOSED?"
1107 LET M$(7)="NEXT TIME TRY THE GAME WHEN YOU ARE AWAKE."
1108 LET M$(8)="WITH THIS SCORE, MAYBE YOU SHOULD TRY TIDDLY-WINKS."
1109 LET M$(9)="PERHAPS IT IS PAST YOUR BEDTIME."
1110 LET M$(10)="I DO NOT THINK I SHOULD LET YOU PLAY AGAIN."
1111 LET M$(11)="NOT BAD, NOT GOOD, BUT NOT BAD."
1112 LET M$(12)="ARE YOU REALLY TRYING?"
1113 LET M$(13)="MAYBE YOU SHOULD READ THE RULES OF THE GAME."
1114 LET M$(14)="ON A SCALE OF 1 TO 10, I WILL GIVE YOU A 0."
1115 LET M$(15)="IT IS OBVIOUS THAT YOU DO NOT DO THIS FOR A LIVING."
1116 LET M$(16)="YOU ARE PRETTY GOOD AT THIS GAME."
1117 LET M$(17)="DOES YOUR BOSS KNOW HOW MUCH TIME YOU SPEND PLAYING GAMES."
1118 LET M$(18)="DO NOT QUIT YOUR REGULAR JOB YET."
1119 LET M$(19)="NOT BAD FOR A FIRST TRY. WAS THIS YOUR FIRST TRY?"
1120 LET M$(20)="ARE YOU REALLY PROUD OF THIS SCORE?"
1121 LET M$(21)="THERE IS NO HOPE FOR YOU YET."
1122 LET M$(22)="SINCE ALL ELSE IS FAILING, WHY NOT READ THE INSTRUCTIONS?"
1123 LET M$(23)="IS THIS SCORE A REFECTION OF YOU OR A BAD TV?"
1124 LET M$(24)="I DARE YOU TO TRY AGAIN."
1125 LET M$(25)="HAVE YOU CONSIDERED FISHING INSTEAD OF PLAYING THIS GAME?"
1126 LET M$(26)="FANTASTIC RESCUE OPERATION, WELL DONE."
1127 LET M$(27)="THIS IS GOOD SCORE. I BET YOU CAN NOT BEAT IT."
1128 LET M$(28)="THAT IS A GREAT SCORE. ARE YOU A VIDEO GAME HUSTLER?"
1129 LET M$(29)="THIS IS A HIGH SCORE. DID YOU HAVE A PARTNER HELPING YOU?"
1130 LET M$(30)="IF YOU KEEP SCORING THIS HIGH, I WILL QUIT."
1131 LET M$(31)="I AM LUCKY THE GAME ENDED BEFORE YOU KILLED ALL MY SHARKS."
1132 LET M$(32)="NOTHING ""SUB""-NORMAL ABOUT THIS SCORE."
1133 LET M$(33)="YOU HAVE TO SWIM FASTER THAN THAT."
1134 LET M$(34)="DID YOU REALLY GRADUATE FROM THE SCHOOL OF DIVING?"
1135 LET M$(35)="NEXT TIME TRY SHOOTING THE SHARK BEFORE IT EATS YOU."
1136 LET M$(36)="I HOPE YOU DO NOT GIVE MY PET INDIGESTION."
1137 LET M$(37)="YOU SHOULD NEVER TAKE A SHARK TO DINNER."
1160 LET F=0
1199 RETURN
1600 POKE 16553,C+1
1605 POKE 16554,R
1607 PRINT AT 6,29;"<S>"
1610 LET L=USR 16557
1650 RETURN
3000 PRINT AT 0,2;"INTERNATIONAL PUBLISHING AND SOFTWARE";AT 3,10;"PRESENTS"
3005 FOR I=1 TO 10
3006 NEXT I
3010 PRINT AT 9,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ";AT 10,0;"% % %M% %A% %R% %I% %N% %E% % % % %R% %E% %S% %C% %U% %E% % % % ";AT 11,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
3015 PRINT AT 17,2;"COPYRIGHT 1982 BY";AT 18,2;"INTERNATIONAL PUBLISHING";AT 19,2;"AND SOFTWARE.";AT 20,2;"ALL RIGHTS RESERVED."
3020 GOSUB 4000
3025 PRINT AT 17,0;Z$;Z$;Z$;Z$
3030 FOR I=1 TO 9
3035 SCROLL
3040 NEXT I
3050 PRINT AT 4,4;"A SUB HAS GONE DOWN.";AT 6,0;"YOU MUST SAVE THE CREW.";AT 8,0;"YOU MUST DIVE DOWN TO THE";AT 10,0;"SUB AND RESCUE THE SAILORS."
3055 PRINT AT 12,0;"YOU MUST CARRY EACH SAILOR";AT 14,0;"BACK TO SAFETY."
3520 PRINT AT 21,0;"PRESS ANY KEY TO GO ON."
3530 GOSUB 5000
3550 PRINT AT 4,4;"YOU WIN 150 POINTS ";AT 6,0;Z$;AT 8,0;" FOR EVERY SAILOR "
3560 PRINT AT 10,0;Z$;AT 12,0;" YOU SAVE. ";AT 14,0;Z$;AT 16,4;"GOOD LUCK.....";AT 21,0;Z$
3570 GOSUB 4000
3575 GOSUB 1100
3580 PRINT AT 4,0;"OH, I FORGOT TO TELL YOU. ";AT 8,0;"YOU CAN BE EATEN BY SHARKS ";AT 12,0;"OR YOU CAN RUN OUT OF OXYGEN";AT 16,0;"AND DROWN. "
3590 PRINT AT 21,0;"PRESS ANY KEY TO GO ON."
3600 GOSUB 5000
3610 PRINT AT 4,0;"YOU CAN SHOOT THE SHARKS. ";AT 6,0;"FOR EVERY SHARK YOU KILL";AT 8,0;"YOU SCORE 25 POINTS. ";
3620 PRINT AT 10,0;"YOU CAN GET MORE ";AT 12,0;"OXYGEN BY GOING TO THE ";AT 14,0;"OXYGEN TANK BEFORE YOURS ";AT 16,0;"RUNS OUT. "
3636 GOSUB 5000
3640 PRINT AT 4,0;Z$;AT 6,0;"MOVE LEFT: 5 FIRE LEFT: V";AT 8,0;"MOVE RIGHT: 8 FIRE RIGHT: N"
3650 PRINT AT 10,0;"MOVE UP: 7 ";AT 12,0;"MOVE DOWN: 6 ";AT 14,0;Z$;AT 16,0;Z$;AT 21,0;"PRESS ANY KEY TO START THE GAME."
3655 SLOW
3660 GOSUB 5000
3670 FAST
3680 CLS
3690 RETURN
4000 FOR Q=1 TO 15
4010 NEXT Q
4020 RETURN
5000 IF INKEY$<>"" THEN GOTO 5000
5010 IF INKEY$="" THEN GOTO 5010
5020 RETURN
9000 SAVE "MARIN%E"
9010 GOTO 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

