UFO Alien Massacre is a little SCADS game I wrote, which appeared on Fred 53. It's a little shooter, where you control a UFO over a planet and must destroy the other UFOs without hitting the ground bases.
You can only drop bombs, while other UFOs can fire missiles sideways & bases launch missiles upwards, meaning you have precisely the wrong weapon for your task. Fun!
From memory I thought this game worked differently: you were the attacker and must destroy all ground bases and other UFOs. I suspect this might have been how it started, but I later flipped it to make it more challenging. It's confusing since the player sprite is red (looks bad) and the other UFOs are blue -- but so are the ground bases.
There's a nice twist that when you get hit your UFO "malfunctions" for a few seconds, careering out of control (taking momentum from the missile that hits you) and being harder to steer. The gradual acceleration/deceleration of the ship goes some way to hide the SCADs slowness.
Gameplay screenshot, dropping bombs.
Malfunction counter showing in top right.
Post game review score & rank
It's a simple game, but fairly playable -- the description in FRED is shown below.
This month, in slot 'D' we have a SCADs game (!) by Martin Fitzpatrick. It's called 'UFO' and is a bit of a shoot-em-up. It took me a few goes to work out what I was supposed to do, but I think this is right. You're supposed to shoot the things that are flying in the air, not the groundbases. Although the ground bases can harm you, they also harm the UFOs.
You are a little ship (I've double-checked that bit for spelling mistakes!). You and your groundbases must shoot the UFOs. If you get shot, you lose control of flight and firing temporarily.
Too many shots, and it's that nasty little Game Over. Complete the levels and you go up a rank or two. When you complete all the levels (which, if I can do it can't be too hard), you're given an assessment of your progress. It takes a little to get into, but when you do, it's very playable.
Source code
Main game
10 GO TO 30
20 ~FILE "draw1"
30 LET score1=0,level=1,lives=5,rnk=1,rank=0,sht=0,fir=0,bas=0,crsh=0,energy=6
40 ~INIT
50 IF level=1 THEN GO SUB begin
60 ~INKBLACK
70 LET axs=0,ays=0,sx=0,sy=0,c=0,miss=0,hit=0,sp=0,hp=-1,con=0,onscr=0,l=0,re=0,mal=0,msy=0,msx=0
80 DIM dead(63): FOR a=1 TO 63: LET dead(a)=5: NEXT a
90 ~LINK 0,1
100 FOR a=5 TO 8:~LINK a,14: NEXT a
110 FOR a=9 TO 12:~LINK a,15: NEXT a
120 FOR a=13 TO 16:~LINK a,16: NEXT a
130 FOR a=17 TO 20:~LINK a,17: NEXT a
140 FOR a=21 TO 24:~LINK a,18: NEXT a
150 FOR a=25 TO 28:~LINK a,19: NEXT a
160 FOR a=29 TO 34:~LINK a,31:~ANIMATE a,2: NEXT a
170 FOR a=35 TO 40:~LINK a,33:~ANIMATE a,3: NEXT a
180 FOR a=41 TO 46:~LINK a,35:~ANIMATE a,4: NEXT a
190 ~AUTOSOUND 0,0,3:~AUTOSOUND 0,7,3
200 FOR a=5 TO 31:~AUTOSOUND a,0,4: NEXT a
210 ~MISSRANGE 50,63
220 ~MISSOUND 1
230 ~MISSILE 0,255,2,50,53,128,255,64:~AMMO 0,255
240 FOR a=5 TO 46:~MISSILE a,255,10,54,63,128,255,64:~AMMO a,255: NEXT a
250 ~YEDGE 0,2,2
260 ~XEDGE 0,1,1
270 FOR a=29 TO 46:~XEDGE a,1,1:~YEDGE a,0,0: NEXT a
280 ~ROOM 0
290 DIM sp$(24)
300 FOR a=0 TO 240 STEP 16+(26-level)
310 LET b=1+ RND (23)
320 IF sp$(b)=" " THEN ~SPUT b+4,a,32,128: LET sp$(b)=" STEP ": ELSE GO TO 310
330 NEXT a
340 ~SPUT 0,122,100,128
350 DIM ons(15)
360 FOR a=1 TO level+1
370 REM LET l=l+1: IF l>=level+1 THEN FOR a=1 TO 15: IF ons(a)<>0 THEN NEXT a: ELSE GO TO 341
380 LET b=1+ RND (14)
390 IF a >= level+1 THEN GO TO 440
400 IF ons(b)=0 THEN LET ons(b)=1: ELSE GO TO 380
410 ~SPUT b+29, RND (240),32+ RND (158),128:~SPEED b+29, RND (5)- RND (5),0
420 LET onscr=onscr-1
430 NEXT a
440 GO SUB disp
450 IF level=16 THEN GO TO ending
460 ~PNUMA 0,180,2,48,level
470 ~COLOUR
480 DO
490 IF onscr=0 THEN LET level=level+1: GO TO 40
500 LET r=5+ RND (41):~FIRE r
510 LET r=5+ RND (41):~FIRE r
520 LET r=29+ RND (17):~SPEED r,( RND (dead(r))- RND (dead(r))), RND (dead(r))- RND (dead(r))
530 FOR b=1 TO 2
540 ~MOVEALL:~VIEW
550 ON b: GO SUB control
560 ~MISSHIT LENGTH (0,miss): IF miss <> 255 THEN GO SUB misshit
570 NEXT b
580 IF sp=0 AND lives>0 THEN ~HIT 0, LENGTH (0,hit): IF hit <> 0 THEN ~NEXTHIT LENGTH (0,hit): GO SUB hitit
590 IF lives=0 THEN ~TEXTA 82,100,"GAME OVER":~VIEW: PAUSE : GO SUB rating
600 LET hp=hp-1
610 IF hp <> 0 THEN LOOP
620 IF sp-1=0 THEN ~SPUT 0,122,100,128: LET axs=0,ays=0,sx=0,sy=0: LET sp=sp-1,energy=6,re=0,mal=0
630 GO SUB disp
640 LET sp=0
650 LOOP
660 LABEL control
670 IF re>0 THEN IF RND (re)>2 THEN GO TO 730
680 ~GETINP 1, LENGTH (0,c)
690 IF c=1 OR c=2 OR c=8 THEN LET ays=ays+((energy-1)/5)
700 IF c=5 OR c=6 OR c=4 THEN LET ays=ays-1
710 IF c=7 OR c=6 OR c=8 THEN LET axs=axs-1
720 IF c=3 OR c=2 OR c=4 THEN LET axs=axs+1
730 IF sx<axs THEN LET sx=sx+1
740 IF sx>axs THEN LET sx=sx-1
750 IF sy<ays THEN LET sy=sy+1
760 IF sy>ays THEN LET sy=sy-1
770 IF axs>5 THEN LET axs=5
780 IF axs<-5 THEN LET axs=-5
790 IF ays>5 THEN LET ays=5
800 IF ays<-5 THEN LET ays=-5
810 LET ays=ays-0.125
820 ~SPEED 0,sx,sy
830 IF c>32 AND c<255 AND RND (re)<2 THEN ~FIRE 0: LET ays=ays+0.12,fir=fir+1
840 IF re>1 AND mal=1 THEN ~TEXTA 242,183,"M"
850 IF re=0 OR mal=0 THEN ~TEXTA 242,183," "
860 IF re>0 THEN LET mal= NOT mal: ELSE LET mal=1
870 ~PNUMA 240,175,2,48,re
880 LET re=re-1: IF re<0 THEN LET re=0
890 RETURN
900 LABEL misshit
910 IF miss=0 THEN GO TO mainmiss
920 LET dead(miss)=dead(miss)-1
930 ~FIRE miss:~SCOM 4
940 IF miss>28 THEN ~SPEED miss,( RND (dead(miss))- RND (dead(miss))),( RND (dead(miss))- RND (dead(miss)))
950 IF dead(miss)=0 THEN ~TOGGLE miss:~TOGGLE miss:~ANIMOFF miss,64,9,1:~SCOM 4: IF miss<29 THEN LET score1=score1-100: LET rank=rank-10: IF score1<0 THEN LET score1=0,bas=bas+1
960 IF dead(miss)=0 AND miss>28 THEN LET onscr=onscr+1
970 LET who= PEEK (147456+(14592)+(64*miss)+51)
980 IF miss>28 AND who>49 AND who<55 THEN LET score1=score1+10,rank=rank+2,sht=sht+1
990 IF miss<29 AND who>49 AND who<55 THEN LET score1=score1-10,rank=rank-2: IF score1<0 THEN LET score1=0
1000 GO SUB disp
1010 RETURN
1020 LABEL hitit
1030 ~ANIMOFF 0,64,9,1
1040 ~ANIMOFF hit,64,9,1
1050 ~SCOM 1
1060 LET lives=lives-1,bas=bas+1: IF hit>28 THEN LET onscr=onscr+1,crsh=crsh+1
1070 IF hit<29 THEN LET score1=score1-25: ELSE LET score1=score1+5,rank=rank+1,bas=bas+1
1080 IF score1<0 THEN LET score1=0
1090 LET sp=1
1100 LET hp=6
1110 IF lives=0 THEN LET sp=0
1120 GO SUB disp
1130 RETURN
1140 LABEL mainmiss
1150 LET who= PEEK (147456+(14592)+51)
1160 LET msy= PEEK ((147456+14592)+(64*who)+12)
1170 LET msx= PEEK ((147456+14592)+(64*who)+11)
1180 IF msx>15 THEN LET msx=-(255-msx)
1190 IF msy>15 THEN LET msy=-(255-msy)
1200 LET sx=sx+msx: LET sy=sy-msy
1210 LET re=re+15
1220 LET energy=energy-1
1230 IF energy=0 THEN LET crsh=crsh+1: GO TO 1260
1240 GO SUB disp
1250 RETURN
1260 ~ANIMOFF miss,64,9,1
1270 LET sp=sp+miss+1
1280 LET lives=lives-1
1290 IF lives=0 THEN LET sp=0
1300 GO SUB disp
1310 LET hp=6
1320 RETURN
1330 LABEL disp
1340 IF rnk<1 THEN LET rnk=1
1350 IF rank>9 THEN LET rnk=rnk+1,rank=rank-10
1360 ~PNUMA 94,158,5,48,score1
1370 IF energy>0 THEN ~PNUMA 140,158,1,48,energy-1
1380 ~PNUMA 152,158,1,48,lives
1390 ~TEXTA 88,170,"RANK - "+ STRS rnk
1400 RETURN
1410 LABEL ending
1420 ~TEXTA 72,100,"WELL DONE"
1430 ~SCOM 2: DO
1440 PAUSE 2:~COLOUR
1450 ~MOVEALL:~VIEW
1460 LOOP UNTIL INKEY$ <> ""
1470 GO SUB rating
1480 RUN
1490 LABEL begin
1500 ~INIT:~ROOM 0:~COLOUR
1510 ~TEXTA 30,100,"METROPOLIS SOFTWARE"
1520 ~SCOM 2:~VIEW: PAUSE 250:~CTEXT
1530 ~TEXTA 80,100,"PRESENTS"
1540 ~SCOM 2:~VIEW: PAUSE 250:~CTEXT
1550 ~TEXTA 20,100,"UFO - ALIEN MASSACRE!"
1560 ~SCOM 2:~VIEW: PAUSE
1570 ~TEXTA 24,50,"BY MARTIN FITZPATRICK"
1580 ~VIEW: PAUSE 100:~CTEXT
1590 RETURN
1600 LABEL rating
1610 ~INKBLACK
1620 ~MAINSCR:~FULLCLEAR:~CTEXT:~COPYSCREEN
1630 ~TEXTA 10,170,"BULLETS USED "
1640 ~TEXTA 10,160,"ENEMIES SHOT "
1641 ~TEXTA 10,150,"ENEMIES RAMMED "
1650 ~TEXTA 10,140,"BASES DESTROYED "
1651 ~TEXTA 10,130,"LEVEL "
1652 ~TEXTA 10,120,"RANK "
1653 ~TEXTA 10,110,"SCORE "
1660 ~PNUMA 200,170,2,48,fir
1665 ~PNUMA 200,160,2,48,sht
1670 ~PNUMA 200,150,2,48,crsh
1671 ~PNUMA 200,140,2,48,bas
1672 ~PNUMA 200,130,2,48,level
1673 ~PNUMA 200,120,2,48,rnk
1674 ~PNUMA 200,110,2,48,score1
1680 LET rat= INT (((level*10)+(rnk*10)+((lives+score1)*10)+crsh))
1685 LET rat=rat- INT (10*(fir/(sht+1))+(bas))
1690 IF rat<0 THEN LET rat=0
1700 ~TEXTA 60,50,"RATING "+" - "
1710 ~PNUMA 160,50,3,48,rat
1720 ~VIEW:~COLOUR: PAUSE 0
1730 RUN
1740 RETURN
Loader
1 ON ERROR err
5 SCREEN 1: FOR a=2 TO 15: CLOSE SCREEN a: NEXT a
10 REM BASIC INTERPRETOR, GLENCO SOFTWARE 1992
20 CLEAR 65535: OPEN TO 3: LET MCODE=&14000: LET SCR2=&23000: MODE 4: DEF KEYCODE 193,"MODE 3:CLS#": DEF KEYCODE 192,"~:": LET A= UDG "~": FOR I=A TO A+7: READ B: POKE I,B: NEXT I: DATA 62,62,62,62,62,62,62,0: IF PEEK (&511F)=192 THEN GO TO MEM512: ELSE GO TO MEM256
30 LABEL {20}{1}MEM512{20}{1}{20}{0}
40 LET FLAG=0: LET SCR1=&83000: LET ms=30: FOR I=&5103 TO &511C: IF PEEK (I) <> 0 THEN LET FLAG=99
50 NEXT I: FOR I=&5108 TO &511C: POKE I,&F0: NEXT I: GO TO NEXT_PART
60 LABEL {20}{1}MEM256{20}{0}
70 LET FLAG=0: LET SCR1=&43000: LET ms=14: FOR I=&5103 TO &510C: IF PEEK (I) <> 0 THEN LET FLAG=99
80 NEXT I: IF FLAG=99 THEN GO TO MEM_ERROR: ELSE FOR I=&5108 TO &510C: POKE I,&F0: NEXT I: GO TO NEXT_PART
110 LABEL {20}{1}NEXT_PART{20}{0}
120 OPEN SCREEN 2,4: POKE &5103,&F0,&F0,&F0: PEN 1: CSIZE 8,16: CSIZE 8,8: LOAD "SCAD.S1" CODE MCODE: POKE MCODE+3,MS: LOAD "SCAD.S2" CODE SCR1: LOAD "SCAD.S2" CODE SCR2: CALL MCODE
130 ~INIT
140 LOAD "UFO"
150 DEF PROC err
160 ON ERROR STOP
170 ON ERROR err
180 GO TO lino
190 END PROC
To support developers in [[ countryRegion ]] I give a [[ localizedDiscount[couponCode] ]]% discount on all books and courses.
[[ activeDiscount.description ]] I'm giving a [[ activeDiscount.discount ]]% discount on all books and courses.