--- title: "Marine Rescue" id: 51914 type: "computer_media" slug: "marine-rescue" url: "http://localhost/computer_media/marine-rescue/" markdown_url: "http://localhost/computer_media/marine-rescue.md" published_at: "2023-08-16T01:42:21+00:00" modified_at: "2026-04-04T20:17:54+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "Dive underwater to rescue a submarine's crew, dodge patrolling sharks, and manage your oxygen in this machine-code-enhanced action game with 37 taunting end-game messages." 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: "International Publishing & Software Inc" slug: "international-publishing-software-inc" taxonomy: "post_tag" url: "http://localhost/tag/international-publishing-software-inc/" - 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: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/MarineRescue (1982)(IPS)(CA)(TS1000)(Cassette).zip" mediadate: "1982" producer_company: - id: 10960 title: "International Publishing & Software Inc" type: "company" url: "http://localhost/company/international-publishing-software-inc/" images: - url: "http://localhost/wp-content/uploads/2023/08/SCR-20260403-omwi.png" - url: "http://localhost/wp-content/uploads/2023/08/SCR-20260403-omrp.png" related_products: - id: 13176 title: "Marine Rescue" type: "product" url: "http://localhost/product/marine-rescue/" media_type_tags: "Game" --- 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: 1. **Lines 1–6:** REM lines storing Z80 machine code routines (~200 bytes total). 2. **Lines 7–35:** Initialization — variables, screen setup, POKE configuration of machine code parameters. 3. **Lines 40–450:** Main game loop in two phases (200 iterations then 100 iterations), with increasing shark frequency. 4. **Lines 452–499:** Time-expired and stop handlers. 5. **Lines 500–699:** Scene-drawing subroutine. 6. **Lines 800–870:** Diagnostic/development utilities (POKE loop and memory dump), left in the final listing. 7. **Lines 900–1099:** Death/end-of-game handling, score display, and play-again logic. 8. **Lines 1100–1199:** Message array initialization (M$) and flag reset. 9. **Lines 1600–1650:** Unused collision-test stub. 10. **Lines 3000–3690:** Title screen, instructions, and scrolling intro sequence. 11. **Lines 4000–5020:** Delay and keypress wait subroutines. 12. **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 16519` reads a little-endian 16-bit integer maintained by the machine code. - **Decade display filter:**`IF PEEK 16521=(INT (PEEK 16521/10))*10` updates 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)+5` and 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:**`HS` is 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))+1` and 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. - `SLOW` at line 40 and `FAST` at 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. ## Source Code ``` 1 REM 1C41650000002AE404E60C9ED4B8240CCDF58CD8C403E13B920412D0C903A8F415F176A2A10402B7EB928218F910F7176A1602B7EBB28FBB9284725718F410F0C924251C 2 REM ED4B8440C3E4B8381C93EFB8301C9ED43844079FE1D281FCDF58AFD7CD8C40B92053E17D718D6111902A864019228640AFD7D7D7C9CDF58AFD7D7C9C9222324251C 3 REM CDBB27DFEFF201C9444DCDBD77EED4B8240FE33208ED438440CDD840C9FE3B208ED438440CDB142C9FE21208AFB9201C9D181AFE242093E1FB9201C9C18DFE222034186FE23281C95C5CDF58CD8C40AFB9205FED4B8240CDF58AFD7C1C5CDF583E26D7C1ED4382403E4B8202E3E7B93853E3C3289403E18B9301F3A8F41573E32BA2016119602A8640192286403E26328F413A88403C3288403E11B820F3ECB92853EDB92053E32328F41C93E12B928B3CB92873E38B9282C1C9C1AF473E294FC92020202020202021212121212121212121212121212121 4 REM 3A89403D32894057AFBA2031280C9232425 5 REM ED4B8240C5CCDF58CD8C403E13B928FC1DCDF58CD8C403E12B9283185C112D0C93A8F415F17652AC40237EB928218F910F7176A160237EBB28FBB9284725718F45237EB928218F910E8176A2A10402B7EB928218F910F7176A1602B7EBB28FBB9284725718F452B7EB928218F910E8C91F1F1F 6 REM ED4B8440D3E4B8381C93EFB8301C9ED438440D79FE2281BCDF58CD8C40AFB92073E17D7AFD718D4111902A864019228640ED4B8440DDDCDF58AFD7D7D7D7D7C91E1F2021222324251C1D1E1F2021222324251C 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;"" 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;"" 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;"" 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;"" 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;"" 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 ```