'===========================================================================
' Subject: helicopter game                    Date: 01-10-9  (  :  )       
'  Author: Peter Banot ?                      Code: Qbasic QB              
'  Origin: peterpumpkin79@aol.com           Packet: GAMES.ABC
'===========================================================================
'HELI.BAS - The 2-dimensional Helicopter rescue game.

'Your goal is to navigate your heli into the ground to rescue the folks
'that you'll find wandering its caverns. Use your firepower to break
'through the walls and, please, try not take make any hard landings.

'The game gets progresively more difficult in the following ways:
'- underground caverns gets larger each level
'- more people need to be rescued as you go up levels
'- more indestructable rocks appear and get in your way
'- 4 moving obstacles are introduced to you as you reach level 25
'- 2 obsticles that will eventually encompass more of the play area

'Features:
'- pc speaker sound (woo-hoo!)
'- colorful graphics in 320x200 mode using 256 colors
'- random colors, terrains and level openings add interesting variation
'- built-in help with graphical illustrations
'- warp code: Type "WARP" followed by a two-digit level # and press enter

'Written back in 1996, I believe
'Written by Peter Banot
'AOL: PeterPumpkin79@aol.com
'HOTMAIL: TalkingParakeet@hotmail.com

'----------------------------------------------------------------------------

DEFINT A-Z

'user-defined data-types
TYPE BulletType
  BX   AS INTEGER
  BY   AS INTEGER
  BXi  AS INTEGER
  BYi  AS INTEGER
END TYPE

TYPE PeopleType
  PX   AS INTEGER
  PY   AS INTEGER
  Pdir AS INTEGER
  Pclr AS INTEGER
END TYPE

TYPE StoneType
  SR   AS INTEGER
  SC   AS INTEGER
END TYPE

TYPE XYType
  x    AS INTEGER
  y    AS INTEGER
END TYPE

TYPE FillUpType
  x    AS INTEGER
  y    AS INTEGER
  D    AS INTEGER
END TYPE

'sub/function declaration
DECLARE SUB DrawStage ()
DECLARE SUB DrawHeli (frame, clr)
DECLARE SUB Snd (z)
DECLARE FUNCTION FSP (x, y)

'variables known to all procedures
COMMON SHARED StartX, StartY
COMMON SHARED HX, HY, Xi, Yi
COMMON SHARED frame, clr, Dir
COMMON SHARED Level, LvlClr
COMMON SHARED NextMine!, MC
COMMON SHARED PCSound

'constants
CONST MaxSpeed = 5   'number of pixels the heli will move in a single frame
CONST code$ = "WARP" 'the warp code, who'd have guessed?

RANDOMIZE TIMER

'this is not my code, I just wanted the numlock to turn on
DEF FnRan (x) = INT(RND(1) * x) + 1
DEF SEG = 0
KeyFlags = PEEK(1047)
IF (KeyFlags AND 32) = 0 THEN
  POKE 1047, KeyFlags OR 32
END IF
DEF SEG

GOSUB OpeningScreen

Lives = 5
GOTO LevelUp

NewLevel:
CALL DrawStage
StartX = HX
StartY = HY
LstBltXi = 0: LstBltYi = 1
NextMine! = TIMER + INT(RND * 5) + 1
FillUp! = TIMER + 45

x = Level * 3: IF x > 297 THEN x = 297
REDIM Stn(1 TO x) AS StoneType: GOSUB PlaceStones
x = Level * 5: IF x > 450 THEN x = 450
REDIM p(1 TO x) AS PeopleType: GOSUB PlaceDudes
x = Level * 2: IF x > 75 THEN x = 75
REDIM bullet(1 TO x) AS BulletType
IF Level > 4 THEN GOSUB PlaceMine
IF Level > 9 THEN GOSUB InitSparky
IF Level > 19 THEN GOSUB InitFireS
IF Level > 24 THEN GOSUB InitFillUp

'main game loop
Continue:
WHILE INKEY$ <> "": WEND 'clear the key buffer to avoid blipping if full
DO
start! = TIMER
GOSUB DrawStones
GOSUB MoveHeli
GOSUB MoveDudes
IF Level > 4 THEN GOSUB DrawMine
IF Level > 9 THEN GOSUB MoveSparky
IF Level > 19 THEN GOSUB MoveFireSnake: GOSUB MoveHeli
IF Level > 24 AND TIMER > FillUp! THEN GOSUB FillUp: GOSUB MoveHeli
WHILE TIMER < start! + .04: WEND
LOOP


'key handling
MoveHeli:
k$ = INKEY$
SELECT CASE k$
  CASE CHR$(0) + "H":
      Yi = Yi - 1
      IF Yi > MaxSpeed THEN Yi = MaxSpeed
  CASE CHR$(0) + "P":
      Yi = Yi + 1
      IF Yi < -MaxSpeed THEN Yi = -MaxSpeed
  CASE CHR$(0) + "K":
      Xi = Xi - 1
      IF Xi < -MaxSpeed THEN Xi = -MaxSpeed
  CASE CHR$(0) + "M":
      Xi = Xi + 1
      IF Xi > MaxSpeed THEN Xi = MaxSpeed
  CASE " ": Bultdir = 0: GOSUB FireBullet
  CASE "1": Bultdir = 1: LstBltXi = -1: LstBltYi = 1: GOSUB FireBullet
  CASE "2": Bultdir = 1: LstBltXi = 0: LstBltYi = 1: GOSUB FireBullet
  CASE "3": Bultdir = 1: LstBltXi = 1: LstBltYi = 1: GOSUB FireBullet
  CASE "4": Bultdir = 1: LstBltXi = -1: LstBltYi = 0: GOSUB FireBullet
  CASE "6": Bultdir = 1: LstBltXi = 1: LstBltYi = 0: GOSUB FireBullet
  CASE "7": Bultdir = 1: LstBltXi = -1: LstBltYi = -1: GOSUB FireBullet
  CASE "8": Bultdir = 1: LstBltXi = 0: LstBltYi = -1: GOSUB FireBullet
  CASE "9": Bultdir = 1: LstBltXi = 1: LstBltYi = -1: GOSUB FireBullet
  CASE CHR$(13): GOSUB DropBomb
  CASE "s", "S": IF PCSound = 1 THEN PCSound = 0 ELSE PCSound = 1
  CASE CHR$(27): GOTO GameOver
END SELECT

IF Level > 15 AND Level < 32 THEN COLOR 15 ELSE COLOR Level
LOCATE 1, 1: PRINT "LIVES ="; Lives;
LOCATE 1, 17: PRINT ; DudesTotal - DudesLeft; ":"; DudesLeft;
LOCATE 1, 40 - LEN("LEVEL =" + STR$(Level)): PRINT "LEVEL ="; Level
GOSUB CheckHeliSpot: IF hit > 0 THEN GOTO InstantDeath
DrawHeli frame, 0
HX = HX + Xi: IF HX < 0 THEN HX = 0: Xi = 0 ELSE IF HX > 313 THEN HX = 313:
Xi = 0
HY = HY + Yi: IF HY < 8 THEN HY = 8: Yi = 0 ELSE IF HY > 196 THEN HY = 196:
Yi = 0
IF Xi < 0 THEN Dir = 1 ELSE IF Xi = 0 THEN Dir = 2 ELSE IF Xi > 0 THEN Dir = 3
frame = frame + 1: IF frame > 5 THEN frame = 0
DrawHeli frame, 15
GOSUB MoveBullet
GOSUB MoveBomb
RETURN

'most of these GOSUB routines could be actual SUB procedures...
'but ofcourse, at the time I wrote this, this was my preferred method
'most of them are pretty straight-forward in what they do

FireBullet:
FOR x = 1 TO UBOUND(bullet)
  IF bullet(x).BX = 0 AND bullet(x).BY = 0 THEN
   IF (Xi <> 0 OR Yi <> 0) AND Bultdir = 0 THEN
    y = INT(RND * 5) + 1: z = INT(RND * 4)
    bullet(x).BX = HX + y: bullet(x).BY = HY + z
    bullet(x).BXi = Xi: bullet(x).BYi = Yi
    LstBltXi = Xi: LstBltYi = Yi
    Snd (1)
    EXIT FOR
   ELSEIF LstBltXi <> 0 OR LstBltYi <> 0 THEN
    y = INT(RND * 5) + 1: z = INT(RND * 4)
    bullet(x).BX = HX + y: bullet(x).BY = HY + z
    bullet(x).BXi = LstBltXi: bullet(x).BYi = LstBltYi
    Snd (1)
    EXIT FOR
   END IF
  END IF
NEXT x
RETURN


MoveBullet:
FOR x = 1 TO UBOUND(bullet)
  IF bullet(x).BX <> 0 AND bullet(x).BY <> 0 THEN
   PSET (bullet(x).BX, bullet(x).BY), 0
   bullet(x).BX = bullet(x).BX + bullet(x).BXi
   bullet(x).BY = bullet(x).BY + bullet(x).BYi
    y = POINT(bullet(x).BX, bullet(x).BY)
    IF y = LvlClr THEN
     GOSUB ExplodeBullet
    ELSEIF y = 8 THEN
     bullet(x).BX = 0: bullet(x).BY = 0: Snd (3)
    ELSEIF y = 42 OR y = 43 THEN
     bullet(x).BX = 0: bullet(x).BY = 0
    ELSE PSET (bullet(x).BX, bullet(x).BY), 15
    END IF
  END IF
  IF bullet(x).BX >= 319 OR bullet(x).BY >= 200 THEN GOSUB ExplodeBullet
  IF bullet(x).BX <= 0 AND bullet(x).BY <> 0 THEN GOSUB ExplodeBullet
  IF bullet(x).BY <= 0 AND bullet(x).BX <> 0 THEN GOSUB ExplodeBullet
NEXT x
RETURN


ExplodeBullet:
  Snd (2)
  LINE (bullet(x).BX - 2, bullet(x).BY - 2)-(bullet(x).BX + 2, bullet(x).BY + 2), 0, BF
  LINE (bullet(x).BX - 3, bullet(x).BY - 1)-(bullet(x).BX + 3, bullet(x).BY + 1), 0, BF
  bullet(x).BX = 0: bullet(x).BY = 0
RETURN


DropBomb:
IF BombX = 0 AND BombY = 0 THEN
  BombX = HX + 3: BombY = HY + 2
ELSE Snd (4)
END IF
RETURN


MoveBomb:
IF BombX <> 0 AND BombY <> 0 THEN
PSET (BombX, BombY), 0: PSET (BombX + 1, BombY), 0
BombY = BombY + 1
x = POINT(BombX, BombY + 1): y = POINT(BombX + 1, BombY + 1)
  IF x = LvlClr OR x = 8 OR y = LvlClr OR y = 8 THEN
   GOTO ExplodeBomb
  ELSEIF BombY >= 200 THEN
   GOTO ExplodeBomb
  ELSEIF (x = 42) OR (x = 43) OR (y = 42) OR (y = 43) THEN
   PSET (BombX, BombY), 0: PSET (BombX + 1, BombY), 0
   BombX = 0: BombY = 0
  ELSE
   PSET (BombX, BombY), 15: PSET (BombX + 1, BombY), 15
   PSET (BombX, BombY + 1), 15: PSET (BombX + 1, BombY + 1), 15
  END IF
END IF
RETURN


ExplodeBomb:
FOR x = 0 TO 1
  FOR y = 1 TO 2
   c = INT(RND * 3) + 1
   IF c = 1 THEN c = 4
   IF c = 2 THEN c = 12
   IF c = 3 THEN c = 14
   CIRCLE (BombX + x, BombY + y), 8, c: PAINT (BombX + x, BombY + y), c, c
   Snd (9)
   CIRCLE (BombX + x, BombY + y), 8, 0: PAINT (BombX + x, BombY + y), 0, 0
  NEXT y
NEXT x
CIRCLE (BombX, BombY), 8, 42: PAINT (BombX, BombY), 42, 42
GOSUB CheckHeliSpot
CIRCLE (BombX, BombY), 8, 0: PAINT (BombX, BombY), 0, 0
BombX = 0: BombY = 0
IF hit > 0 THEN GOTO InstantDeath
RETURN


PlaceStones:
FOR x = 1 TO UBOUND(Stn)
DO
  y = 0
  Stn(x).SR = INT(RND * 23) + 3
  Stn(x).SC = INT(RND * 40) + 1
  IF Stn(x).SR = (StartY + 8) / 8 AND Stn(x).SC = (StartX + 8) / 8 THEN y = 1
LOOP UNTIL y = 0
  IF SCREEN(Stn(x).SR, Stn(x).SC) = 32 THEN
   LOCATE Stn(x).SR, Stn(x).SC: COLOR 8: PRINT CHR$(254);
  ELSE
   LOCATE Stn(x).SR, Stn(x).SC: COLOR LvlClr: PRINT CHR$(219);
   LINE ((Stn(x).SC - 1) * 8 + 2, (Stn(x).SR - 1) * 8 + 2)-((Stn(x).SC - 1) * 8 + 5, (Stn(x).SR - 1) * 8 + 5), 8, BF
  END IF
NEXT x
RETURN


DrawStones:
FOR x = 1 TO UBOUND(Stn)
LINE ((Stn(x).SC - 1) * 8 + 2, (Stn(x).SR - 1) * 8 + 2)-((Stn(x).SC - 1) * 8 + 5, (Stn(x).SR - 1) * 8 + 5), 8, BF
NEXT x
RETURN


'I'm not sure WHY I called them "dudes", but I guess that "dudes" was
'shorter than writing "people" all the time...

PlaceDudes:
FOR x = 1 TO UBOUND(p)
  DO
  y = 1
  p(x).PX = INT(RND * 304) + 8
  p(x).PY = INT(RND * 183) + 9
  IF POINT(p(x).PX, p(x).PY) = 0 AND POINT(p(x).PX, p(x).PY - 1) = 0 THEN y = 0
  LOOP UNTIL y = 0
  p(x).Pdir = INT(RND * 2) + 1
  DO: p(x).Pclr = INT(RND * 247) + 1
  LOOP WHILE (p(x).Pclr = 12) OR (p(x).Pclr = LvlClr) OR (p(x).Pclr > 15 AND p(x).Pclr < 30)
  PSET (p(x).PX, p(x).PY), p(x).Pclr: PSET (p(x).PX, p(x).PY - 1), 12
NEXT x
DudesTotal = UBOUND(p)
DudesLeft = UBOUND(p)
RETURN


MoveDudes:
FOR x = 1 TO UBOUND(p)
IF p(x).PX <> 0 OR p(x).PY <> 0 THEN
   SELECT CASE -1
   CASE p(x).PY < 200 AND POINT(p(x).PX, p(x).PY + 1) = 0:
    PSET (p(x).PX, p(x).PY - 1), 0: PSET (p(x).PX, p(x).PY), 12
    p(x).PY = p(x).PY + 1
   CASE p(x).Pdir = 1 AND POINT(p(x).PX - 1, p(x).PY) = 0 AND POINT(p(x).PX - 1, p(x).PY - 1) = 0:
    PSET (p(x).PX, p(x).PY), 0: PSET (p(x).PX, p(x).PY - 1), 0
    p(x).PX = p(x).PX - 1
   CASE p(x).Pdir = 1 AND POINT(p(x).PX - 1, p(x).PY - 1) = 0 AND POINT(p(x).PX - 1, p(x).PY - 2) = 0:
    PSET (p(x).PX, p(x).PY), 0: PSET (p(x).PX, p(x).PY - 1), 0
    p(x).PX = p(x).PX - 1: p(x).PY = p(x).PY - 1
   CASE p(x).Pdir = 2 AND POINT(p(x).PX + 1, p(x).PY) = 0 AND POINT(p(x).PX + 1, p(x).PY - 1) = 0:
    PSET (p(x).PX, p(x).PY), 0: PSET (p(x).PX, p(x).PY - 1), 0
    p(x).PX = p(x).PX + 1
   CASE p(x).Pdir = 2 AND POINT(p(x).PX + 1, p(x).PY - 1) = 0 AND POINT(p(x).PX + 1, p(x).PY - 2) = 0:
    PSET (p(x).PX, p(x).PY), 0: PSET (p(x).PX, p(x).PY - 1), 0
    p(x).PX = p(x).PX + 1: p(x).PY = p(x).PY - 1
   CASE ELSE: p(x).Pdir = INT(RND * 2) + 1
   END SELECT
   PSET (p(x).PX, p(x).PY - 1), 12: PSET (p(x).PX, p(x).PY), p(x).Pclr

   IF HX <= p(x).PX AND HX + 6 >= p(x).PX THEN
    IF HY - 1 <= p(x).PY AND HY + 5 >= p(x).PY THEN
     PSET (p(x).PX, p(x).PY), 0: PSET (p(x).PX, p(x).PY - 1), 0
     p(x).PX = 0: p(x).PY = 0
     IF IntroPeople = 0 THEN
      Snd (5)
      DudesLeft = DudesLeft - 1
      IF Level > 15 AND Level < 32 THEN COLOR 15 ELSE COLOR Level
      LOCATE 1, 17: PRINT ; DudesTotal - DudesLeft; ":"; DudesLeft;
      IF DudesLeft = 0 THEN GOTO LevelUp
     END IF
    END IF
   END IF
END IF
NEXT x
RETURN


PlaceMine:
IF TIMER >= NextMine! THEN
  start! = TIMER
  DO
   w = 0: z = 0: MX = INT(RND * 320): MY = INT(RND * 168) + 32
   FOR x = MX TO (MX + 2): FOR y = MY TO (MY + 2)
   IF POINT(x, y) <> LvlClr THEN z = 1: EXIT FOR
   NEXT y: NEXT x
  LOOP UNTIL (z = 0) OR TIMER > start! + 2
  MC = LvlClr
  NextMine! = 2147483647
  IF z <> 0 THEN MX = 0: MY = 0
  IF z = 0 THEN Snd (6): GOSUB DrawMine: GOSUB DrawMine
ELSE MX = 0: MY = 0
END IF
RETURN


DrawMine:
IF (MX <> 0) AND (MY <> 0) THEN
  FOR x = MX TO MX + 2
   FOR y = MY TO MY + 2
   IF POINT(x, y) <> MC THEN GOTO ExplodeMine
   NEXT y
  NEXT x
  MC = INT(RND * 225) + 16 'it flashes random colors to get your attention
  LINE (MX, MY)-(MX + 2, MY + 2), MC, BF
ELSE GOSUB PlaceMine
END IF
ExitDrawMine:
RETURN


ExplodeMine:
PLAY "T240 MS MF L64"
  FOR x = 1 TO 65
   CIRCLE (MX + 1, MY + 1), x, x MOD 2 + 42, , , -.6
   IF PCSound = 1 THEN IF x MOD 2 = 0 THEN PLAY "N2" ELSE PLAY "N" + STR$(INT(RND * 10) + 10)
  NEXT x
  GOSUB CheckHeliSpot
  GOSUB MoveBullet
  GOSUB MoveBomb
  FOR x = 65 TO 1 STEP -1
   CIRCLE (MX + 1, MY + 1), x, 0, , , -.6
   IF PCSound = 1 THEN IF x MOD 2 = 0 THEN PLAY "N2" ELSE PLAY "N" + STR$(INT(RND * 10) + 10)
  NEXT x
MX = 0: MY = 0
NextMine! = TIMER + INT(RND * 140) + 15
IF hit >= 5 THEN GOTO InstantDeath ELSE GOTO ExitDrawMine


'what is FillUp you ask? It is a neat little landslide that
'shows itself in level 25 and up, it was originally water from a water
'demo I did, but because of the number of drops I'd have to track I
'modified its behavior, and changed the color to look like liquid dirt

InitFillUp:
REDIM fl(1 TO 200) AS FillUpType
RETURN


FillUp:
FOR z = 1 TO 100
  IF fl(z).x <> 0 OR fl(z).y <> 0 THEN
    SELECT CASE -1
    CASE POINT(fl(z).x, fl(z).y + 1) = 0:
     PSET (fl(z).x, fl(z).y), 0: fl(z).y = fl(z).y + 1
     PSET (fl(z).x, fl(z).y), LvlClr
     fl(z).D = INT(RND * 2) + 1
    CASE fl(z).D = 1 AND POINT(fl(z).x - 1, fl(z).y + 1) = 0:
     PSET (fl(z).x, fl(z).y), 0: fl(z).x = fl(z).x - 1: fl(z).y = fl(z).y + 1
     PSET (fl(z).x, fl(z).y), LvlClr
    CASE fl(z).D = 1 AND POINT(fl(z).x - 1, fl(z).y) = 0:
     PSET (fl(z).x, fl(z).y), 0: fl(z).x = fl(z).x - 1
     PSET (fl(z).x, fl(z).y), LvlClr
    CASE fl(z).D = 2 AND POINT(fl(z).x + 1, fl(z).y + 1) = 0:
     PSET (fl(z).x, fl(z).y), 0: fl(z).x = fl(z).x + 1: fl(z).y = fl(z).y + 1
     PSET (fl(z).x, fl(z).y), LvlClr
    CASE fl(z).D = 2 AND POINT(fl(z).x + 1, fl(z).y) = 0:
     PSET (fl(z).x, fl(z).y), 0: fl(z).x = fl(z).x + 1
     PSET (fl(z).x, fl(z).y), LvlClr
    CASE ELSE: PSET (fl(z).x, fl(z).y), LvlClr: fl(z).x = 0: fl(z).y = 0
    END SELECT
  ELSE
    fl(z).x = INT(RND * 2) * 319
    fl(z).y = 8
    fl(z).D = INT(RND * 2) + 1
  END IF
NEXT z
RETURN


'the spark idea came to me while playing Super Mario Brothers 2...
'you know the one. A lot of stuff happens near the walls so this is a
'perfect pain-in-the-ass obstacle to pay attention to

InitSparky:
SpX = 318
SPy = 9: SpZ = 5: SpDrop = INT(RND * 200) + 15
RETURN

MoveSparky:
SparkyStuck = 0
FOR MoveSparky = 1 TO 4
GOSUB EraseSpark
SELECT CASE SpZ
CASE 0:
  IF FSP(SpX - 1, SPy + 2) AND FSP(SpX, SPy + 2) AND FSP(SpX + 1, SPy + 2) THEN
  SPy = SPy + 1
  ELSE SpZ = 4
  END IF
CASE 1:
  IF FSP(SpX + 2, SPy - 1) AND FSP(SpX + 2, SPy) AND FSP(SpX + 2, SPy + 1) THEN
  SpX = SpX + 1: SpZ = 4: SparkyStuck = SparkyStuck + 1
  ELSEIF FSP(SpX - 1, SPy - 2) AND FSP(SpX, SPy - 2) AND FSP(SpX + 1, SPy - 2) THEN
  SPy = SPy - 1
  ELSE SpZ = 3
  END IF
CASE 2:
  IF FSP(SpX - 2, SPy - 1) AND FSP(SpX - 2, SPy) AND FSP(SpX - 2, SPy + 1) THEN
  SpX = SpX - 1: SpZ = 3: SparkyStuck = SparkyStuck + 1
  ELSEIF FSP(SpX - 1, SPy + 2) AND FSP(SpX, SPy + 2) AND FSP(SpX + 1, SPy + 2) THEN
  SPy = SPy + 1
  ELSE SpZ = 4
  END IF
CASE 3:
  IF FSP(SpX - 1, SPy - 2) AND FSP(SpX, SPy - 2) AND FSP(SpX + 1, SPy - 2) THEN
  SPy = SPy - 1: SpZ = 1: SparkyStuck = SparkyStuck + 1
  ELSEIF FSP(SpX - 2, SPy - 1) AND FSP(SpX - 2, SPy) AND FSP(SpX - 2, SPy + 1) THEN
  SpX = SpX - 1
  ELSE SpZ = 2
  END IF
CASE 4:
  IF FSP(SpX - 1, SPy + 2) AND FSP(SpX, SPy + 2) AND FSP(SpX + 1, SPy + 2) THEN
  SPy = SPy + 1: SpZ = 2: SparkyStuck = SparkyStuck + 1
  ELSEIF FSP(SpX + 2, SPy - 1) AND FSP(SpX + 2, SPy) AND FSP(SpX + 2, SPy + 1) THEN
  SpX = SpX + 1
  ELSE SpZ = 1
  END IF
CASE 5:
  IF FSP(SpX - 2, SPy - 1) AND FSP(SpX - 2, SPy) AND FSP(SpX - 2, SPy + 1) AND SpX > SpDrop THEN
  SpX = SpX - 1
  ELSE SpZ = 0
  END IF
END SELECT
IF SPy < 10 THEN SPy = 10: SpZ = 5: SpDrop = INT(RND * 200) + 15
GOSUB DrawSpark
NEXT MoveSparky
IF SparkyStuck = 4 THEN SpZ = 0
RETURN


EraseSpark:
LINE (SpX - 1, SPy - 1)-(SpX + 1, SPy + 1), 0, BF
RETURN
DrawSpark:
LINE (SpX - 1, SPy - 1)-(SpX + 1, SPy + 1), INT(RND * 2) + 42, B, (INT(RND * 2) * 18000 + 720)
RETURN


LevelUp:
start! = TIMER
IF Level > 180 THEN Level = 180 ELSE IF Level < 0 THEN Level = 0
Level = Level + 1
Xi = 0: Yi = 0: BombX = 0: BombY = 0
IF Level <> 16 THEN c = Level ELSE c = 15
COLOR c
LOCATE 10, 10: PRINT STRING$(20, "U");
FOR x = 11 TO 13
  LOCATE x, 10: PRINT "U"; SPACE$(18); "U";
NEXT x
LOCATE 14, 10: PRINT STRING$(20, "U");
LOCATE 12, 16: PRINT "LEVEL"; Level
Snd (7)
DO: LOOP UNTIL TIMER > start! + 1.5
WHILE INKEY$ <> "": WEND
GOTO NewLevel


'this is my state-of-the-art-super-advanced collsion detection routine
'believe me I can do a hell of a lot better now, with much more accuracy

CheckHeliSpot:
hit = 0
  FOR x = HX + 1 TO HX + 5
   FOR y = HY TO HY + 3
    IF (POINT(x, y + 1) = LvlClr OR POINT(x, y + 1) = 8) AND Yi > 0 THEN
     Yi = 0
    ELSEIF (POINT(x, y) = LvlClr OR POINT(x, y) = 8) AND Yi <= 0 THEN
     GOTO Crash
    ELSEIF (POINT(x, y) = 42) OR (POINT(x, y) = 43) THEN
    hit = hit + 1: IF PCSound = 1 THEN SOUND INT(RND * 800) + 40, .1
    END IF
   NEXT y
  NEXT x
RETURN


Crash:
  WHILE INKEY$ <> "": WEND
  start! = TIMER
  DO
   DrawHeli frame, 14
    IF PCSound = 1 THEN SOUND INT(RND * 800) + 40, .1
   DrawHeli frame, 12
    IF PCSound = 1 THEN SOUND INT(RND * 800) + 40, .1
   DrawHeli frame, 4
    IF PCSound = 1 THEN SOUND INT(RND * 800) + 40, .1
  LOOP WHILE TIMER < start! + 2
InstantDeath:
   DrawHeli frame, 0
  CIRCLE (HX + 3, HY + 2), 4, 14: PAINT (HX + 3, HY + 2), 14, 14
  start! = TIMER: WHILE TIMER < start! + .04: WEND
  CIRCLE (HX + 3, HY + 2), 4, 0: PAINT (HX + 3, HY + 2), 0, 0
Lives = Lives - 1
IF Lives >= 0 THEN
  Snd (8)
  LOCATE 1, 1: COLOR 8: PRINT "LIVES ="; Lives;
  LINE (0, 8)-(14, 13), 0, BF
  HX = StartX: HY = StartY: Xi = 0: Yi = 0: GOTO Continue
END IF
GOTO GameOver


OpeningScreen:
SCREEN 13
a = INT(RND * 2) + 1
IF a > 1 THEN
  w = INT(RND * 40) + 10: y = INT(RND * 220) + 15: z = INT(RND * 10) + 1
  FOR x = 0 TO 400 STEP 1
  LINE (0, x / 2)-(x * z, 200), y + (x / w)
  NEXT x
  LINE (0, 199)-(320, 199), y + (x / 32): LOCATE 1, 1: PRINT " ";
ELSE
  x = 0: y = 45: c = INT(RND * 180) + 15: PSET (x, y), c
  DO
  z = INT(RND * 5) + 1
  SELECT CASE z
  CASE 1: y = y - 1: x = x + 1: IF y < 45 THEN y = 45
  CASE 2, 3, 4: y = y + 1: x = x + 1: IF y > 199 THEN y = 199
  CASE 5: x = x + 1
  END SELECT
  PSET (x, y), c
  LOOP UNTIL x = 319
  tile$ = ""
  FOR x = 2 TO INT(RND * 50) + 2
  tile$ = tile$ + CHR$(c + x)
  NEXT x
  PAINT (1, 199), tile$, c
END IF
COLOR INT(RND * 6) + 9
LOCATE 1, 20: PRINT "HELI-LIFT";
LOCATE 2, 20: PRINT "ŽŽŽŽŽŽŽŽŽ";
LOCATE 3, 20: PRINT "By Peter Banot";
LOCATE 4, 20: PRINT "SOUND= On";
LOCATE 5, 20: PRINT "F1= Help"
LOCATE 6, 20: PRINT "ENTER= Start!";
LOCATE 7, 20: PRINT "ESC= Quit";
HX = 305: HY = 0: Dir = 1: Level = 0: z = 1
DIM s(1 TO INT(RND * 45) + 5) AS XYType
REDIM p(1 TO 20) AS PeopleType: IntroPeople = 1
a$ = ""
PCSound = 1
start! = TIMER
DO
  IF TIMER > start! + .2 THEN
  FOR x = 1 TO UBOUND(p)
   IF p(x).PX = 0 AND p(x).PY = 0 AND POINT(1, 6) = 0 THEN
   p(x).PX = 1: p(x).PY = 7
   p(x).Pdir = INT(RND * 2) + 1
   DO: p(x).Pclr = INT(RND * 14) + 1: LOOP WHILE (p(x).Pclr = 12)
   PSET (p(x).PX, p(x).PY), p(x).Pclr: PSET (p(x).PX, p(x).PY - 1), 12
   END IF
  NEXT x
  DudesTotal = 1: DudesLeft = UBOUND(p): start! = TIMER
  END IF
  IF z = 0 THEN GOSUB MoveStars
  DrawHeli frame, 0
   FOR x = HX + 1 TO HX + 5
    IF POINT(x, HY + 5) <> 0 THEN z = 0
   NEXT x
  IF z <> 0 THEN HY = HY + 1
  frame = frame + 1: IF frame > 5 THEN frame = 0
  DrawHeli frame, 15
  GOSUB MoveDudes
k$ = UCASE$(INKEY$)
a$ = a$ + k$
IF k$ = "S" THEN IF PCSound = 1 THEN PCSound = 0 ELSE PCSound = 1
LOCATE 4, 27: IF PCSound = 1 THEN PRINT "On ";  ELSE PRINT "Off";
LOOP UNTIL k$ = CHR$(13) OR k$ = CHR$(27) OR k$ = CHR$(0) + ";"
IntroPeople = 0
IF INSTR(a$, code$) <> 0 THEN
  Level = VAL(MID$(a$, INSTR(a$, code$) + LEN(code$), 2)) - 1
ELSE Level = 0
END IF
ERASE s
IF k$ = CHR$(27) THEN GOTO GameOver ELSE IF k$ = CHR$(0) + ";" THEN GOTO Help
RETURN

'I don't know why I never put these in the actual game. The scrolling stars
'were a basis for a bunch of games I did, and they provide a neat look for
'my intro screen. The sky is black, so it must be night. :)
MoveStars:
FOR x = 1 TO UBOUND(s)
IF POINT(s(x).x - 1, s(x).y) <> 0 THEN
  PSET (s(x).x, s(x).y), 0
  y = INT(RND * 100)
  IF y = 0 THEN
  s(x).x = 320: s(x).y = INT(RND * 150) + 1
  END IF
ELSE
  PSET (s(x).x, s(x).y), 0
  s(x).x = s(x).x - 1
  PSET (s(x).x, s(x).y), INT(RND * 14) + 17
END IF
NEXT x
RETURN

'again, this "firesnake" made several appearances in a couple of trippy
'demos. Here he is featured in flashing orange/yellow and always seems to
'go where he is least welcome. Considering his movements are completely
'random you'd think its AI when you see him in the game

InitFireS:
w = Level - 19: IF w > 50 THEN w = 50
REDIM FireS(1 TO w) AS XYType
DO
x = INT(RND * 321)
y = INT(RND * 201)
z = 0
IF POINT(x, y) <> 0 THEN z = 1
IF POINT(x + 1, y) <> 0 THEN z = 1
IF POINT(x, y + 1) <> 0 THEN z = 1
IF POINT(x + 1, y + 1) <> 0 THEN z = 1
LOOP UNTIL z = 0
FireS(1).x = x
FireS(1).y = y
RETURN


MoveFireSnake:
n = INT(RND * 2) + 1
  IF n = 1 THEN FXi = FXi + 1: IF FXi > 4 THEN FXi = 4
   IF n = 2 THEN FXi = FXi - 1: IF FXi < -4 THEN FXi = -4
n = INT(RND * 2) + 1
  IF n = 1 THEN FYi = FYi + 1: IF FYi > 4 THEN FYi = 4
   IF n = 2 THEN FYi = FYi - 1: IF FYi < -4 THEN FYi = -4
IF FXi = 0 AND FYi = 0 THEN GOTO FireSNotMoved
x = FireS(1).x + FXi: y = FireS(1).y + FYi
IF FSP(x, y) = 0 THEN GOTO MoveFireSnake
IF FSP(x + 1, y) = 0 THEN GOTO MoveFireSnake
IF FSP(x, y + 1) = 0 THEN GOTO MoveFireSnake
IF FSP(x + 1, y + 1) = 0 THEN GOTO MoveFireSnake
IF x < 16 AND y < 12 THEN GOTO MoveFireSnake
  z = UBOUND(FireS)
  LINE (FireS(z).x, FireS(z).y)-(FireS(z).x + 1, FireS(z).y + 1), 0, BF
FOR z = UBOUND(FireS) TO 2 STEP -1
  FireS(z).x = FireS(z - 1).x: FireS(z).y = FireS(z - 1).y
NEXT z
  FireS(1).x = FireS(1).x + FXi: FireS(1).y = FireS(1).y + FYi
  IF FireS(1).x > 318 THEN FireS(1).x = 318: FXi = 0
  IF FireS(1).x < 0 THEN FireS(1).x = 0: FXi = 0
  IF FireS(1).y > 198 THEN FireS(1).y = 198: FYi = 0
  IF FireS(1).y < 9 THEN FireS(1).y = 9: FYi = 0
FOR z = UBOUND(FireS) TO 1 STEP -1
  IF FireS(z).x <> 0 OR FireS(z).y <> 0 THEN
  LINE (FireS(z).x, FireS(z).y)-(FireS(z).x + 1, FireS(z).y + 1), INT(RND * 2) + 42, BF
  END IF
NEXT z
FireSNotMoved:
RETURN

'this must be the only game I've ever finished which has built-in help
'the funny part is that of all the junk I wrote this one requires the
'least amount of information to play

Help:
CLS : c = INT(RND * 6) + 9: COLOR c
LOCATE 1, 14: PRINT "HELP PAGE";
LOCATE 2, 14: PRINT "ŽŽŽŽŽŽŽŽŽ";
COLOR c - 8: LOCATE 4, 8: PRINT "Your Heli: Try not to crash it.";
LOCATE 6, 8: PRINT "People: Pick them all up to win.";
LOCATE 8, 8: PRINT "Stones: Cannot be exploded.";
LOCATE 10, 8: PRINT "Mine: Explodes if it is touched!";
LOCATE 12, 8: PRINT "Spark: Follows along walls.";
LOCATE 14, 8: PRINT "FireSnake: Searches around.";
LOCATE 17, 2: PRINT "* Higher levels have more obsticles! *";
COLOR c: LOCATE 21, 1: PRINT CHR$(25); SPC(13); "KEY PAGE"; SPC(17); CHR$(25);
LOCATE 22, 15: PRINT "ŽŽŽŽŽŽŽŽ"; : COLOR c - 8
LINE (15, 33)-(45, 48), 6, BF: CIRCLE (30, 33), 15, 0: PAINT (30, 33), 0, 0
LINE (30, 58)-(33, 61), 8, BF: LINE (15, 83)-(48, 114), 6, BF
LINE (19, 86)-(44, 94), 0, BF: LINE (19, 98)-(44, 111), 0, BF
REDIM p(1 TO 8) AS PeopleType: IntroPeople = 1
REDIM FireS(1 TO 5) AS XYType
FireS(1).x = 24: FireS(1).y = 100
HX = 27: HY = 26: Dir = 3
MX = 30: MY = 74: MC = 0
SpX = 32: SPy = 90: SpZ = 5: SpDrop = SPy

WHILE INKEY$ <> "": WEND
DO
  FOR x = 1 TO UBOUND(p)
   IF p(x).PX = 0 AND p(x).PY = 0 AND POINT(1, 6) = 0 THEN
   p(x).PX = 30: p(x).PY = 40
   p(x).Pdir = INT(RND * 2) + 1
   DO: p(x).Pclr = INT(RND * 14) + 1: LOOP WHILE (p(x).Pclr = 12)
   PSET (p(x).PX, p(x).PY), p(x).Pclr: PSET (p(x).PX, p(x).PY - 1), 12
   END IF
  NEXT x
  DudesTotal = 1: DudesLeft = UBOUND(p)
GOSUB MoveDudes
GOSUB DrawMine
GOSUB MoveSparky
GOSUB MoveFireSnake
DrawHeli frame, 0
frame = frame + 1: IF frame > 5 THEN frame = 0
DrawHeli frame, 15
start! = TIMER: WHILE TIMER < start! + .04: WEND
LOOP WHILE INKEY$ = ""

COLOR c: LOCATE 24, 1
PRINT "ARROW KEYS"; : COLOR c - 8: PRINT ": increments movement of"
PRINT " the helicopter in that direction.": COLOR c: PRINT
PRINT "SPACEBAR"; : COLOR c - 8: PRINT ": if heli is moving it will"
PRINT " shoot bullet(s) in that direction,"
PRINT " otherwise in last direction fired.": COLOR c: PRINT
PRINT "NUMPAD #'S"; : COLOR c - 8: PRINT ": shoots bullet(s) and/or"
PRINT " sets the last fired direction.": COLOR c: PRINT
PRINT "ENTER"; : COLOR c - 8: PRINT ": drops a single bomb, avoid"
PRINT " the blast.": COLOR c: PRINT
PRINT "S"; : COLOR c - 8: PRINT ": toggles pc speaker on/off."
FOR x = 1 TO 6: PRINT : NEXT
LOCATE 22, 13: COLOR c: PRINT "-END OF HELP-";
WHILE INKEY$ = "": WEND
CLS
GOTO OpeningScreen


'a clever trick to drawing out the GAME OVER text: black 16 on black 0

GameOver:
CLS : COLOR 16: LOCATE 4, 1
PRINT "   /UUU\   /UU\   UU\   /UU  UUUUUU     "
PRINT "   U  \U  /U/\U\  U\U\ /U/U  U          "
PRINT "   U      U/  \U  U \U U/ U  U          "
PRINT "   U      UUUUUU  U  \U/  U  UUUUU      "
PRINT "   U  UU  U    U  U       U  U          "
PRINT "   U  \U  U    U  U       U  U          "
PRINT "   \UUU/  U    U  U       U  UUUUUU     "
PRINT "                                        "
PRINT "                                        "
PRINT "    /UUUU\  U    U  UUUUUU  UUUUU\      "
PRINT "    U    U  U    U  U       U    U      "
PRINT "    U    U  U    U  U       U    U      "
PRINT "    U    U  U    U  UUUUU   UUUUU/      "
PRINT "    U    U  U\  /U  U       U \U\       "
PRINT "    U    U  \U\/U/  U       U  \U\      "
PRINT "    \UUUU/   \UU/   UUUUUU  U   \U\     "
ClrStyle = INT(RND * 3) + 1
IF ClrStyle = 1 THEN DO: v = INT(RND * 247) + 1: LOOP WHILE v > 15 AND v < 32
stp = INT(RND * 3) + 1
w = INT(RND * 9) + 1: w = w * 10
FOR x = 0 TO w
FOR y = x TO 319 STEP w
  FOR z = 0 TO 199
   IF POINT(y, z) = 16 THEN
    IF ClrStyle = 2 THEN v = INT(RND * 7) + 9
    IF ClrStyle = 3 THEN v = z
    LINE (y, z)-(y + stp - 1, z + stp - 1), v, BF
   END IF
  NEXT z
NEXT y
NEXT x
SLEEP

SCREEN 0, 0, 0, 0: WIDTH 80, 25: COLOR 7, 0: CLS : LOCATE , , 1

'again, not my code, just wanted to restore numlock to original state
DEF SEG = 0
POKE 1047, KeyFlags
DEF SEG

END

SUB DrawHeli (frame, clr)

'this draws the heli using color clr, (black to erase), in one of 6 frames
'the heli has 3 directions, left, middle, and right
'when I wrote this game, this was the best way to draw and erase the heli
'...ofcourse these days I would not do it like this

COLOR clr
IF Dir = 1 THEN
      SELECT CASE frame
           CASE 0:
                LINE (HX, HY)-(HX + 6, HY): PSET (HX + 3, HY), 0
                PSET (HX + 3, HY + 1): PSET (HX + 7, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 7, HY + 2)
                LINE (HX + 1, HY + 3)-(HX + 4, HY + 3)
           CASE 1, 5:
                LINE (HX + 1, HY)-(HX + 5, HY): PSET (HX + 3, HY), 0
                PSET (HX + 3, HY + 1): PSET (HX + 7, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 7, HY + 2)
                LINE (HX + 1, HY + 3)-(HX + 4, HY + 3)
           CASE 2, 4:
                PSET (HX + 2, HY): PSET (HX + 4, HY)
                PSET (HX + 3, HY + 1): PSET (HX + 7, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 7, HY + 2)
                LINE (HX + 1, HY + 3)-(HX + 4, HY + 3)
           CASE 3:
                PSET (HX + 3, HY)
                PSET (HX + 3, HY + 1): PSET (HX + 7, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 7, HY + 2)
                LINE (HX + 1, HY + 3)-(HX + 4, HY + 3)
      END SELECT
ELSEIF Dir = 3 THEN
      SELECT CASE frame
           CASE 0:
                LINE (HX + 1, HY)-(HX + 7, HY): PSET (HX + 4, HY), 0
                PSET (HX, HY + 1): PSET (HX + 4, HY + 1)
                LINE (HX, HY + 2)-(HX + 5, HY + 2)
                LINE (HX + 3, HY + 3)-(HX + 6, HY + 3)
           CASE 1, 5:
                LINE (HX + 2, HY)-(HX + 6, HY): PSET (HX + 4, HY), 0
                PSET (HX, HY + 1): PSET (HX + 4, HY + 1)
                LINE (HX, HY + 2)-(HX + 5, HY + 2)
                LINE (HX + 3, HY + 3)-(HX + 6, HY + 3)
           CASE 2, 4:
                PSET (HX + 3, HY): PSET (HX + 5, HY)
                PSET (HX, HY + 1): PSET (HX + 4, HY + 1)
                LINE (HX, HY + 2)-(HX + 5, HY + 2)
                LINE (HX + 3, HY + 3)-(HX + 6, HY + 3)
           CASE 3:
                PSET (HX + 4, HY)
                PSET (HX, HY + 1): PSET (HX + 4, HY + 1)
                LINE (HX, HY + 2)-(HX + 5, HY + 2)
                LINE (HX + 3, HY + 3)-(HX + 6, HY + 3)
      END SELECT
ELSE
      SELECT CASE frame
           CASE 0:
                LINE (HX, HY)-(HX + 6, HY): PSET (HX + 3, HY), 0
                PSET (HX + 3, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 4, HY + 2): PSET (HX + 3, HY + 2), 0
                LINE (HX + 1, HY + 3)-(HX + 5, HY + 3)
           CASE 1, 5:
                LINE (HX + 1, HY)-(HX + 5, HY): PSET (HX + 3, HY), 0
                PSET (HX + 3, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 4, HY + 2): PSET (HX + 3, HY + 2), 0
                LINE (HX + 1, HY + 3)-(HX + 5, HY + 3)
           CASE 2, 4:
                PSET (HX + 2, HY): PSET (HX + 4, HY)
                PSET (HX + 3, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 4, HY + 2): PSET (HX + 3, HY + 2), 0
                LINE (HX + 1, HY + 3)-(HX + 5, HY + 3)
           CASE 3:
                PSET (HX + 3, HY)
                PSET (HX + 3, HY + 1)
                LINE (HX + 2, HY + 2)-(HX + 4, HY + 2): PSET (HX + 3, HY + 2), 0
                LINE (HX + 1, HY + 3)-(HX + 5, HY + 3)
      END SELECT
END IF
END SUB

SUB DrawStage

RANDOMIZE TIMER 'again? Well, heheh, just to be sure...

'choose a random level color
DO: LvlClr = INT(RND * 20) + 1: LOOP WHILE LvlClr = 8 OR LvlClr = 12
IF LvlClr >= 15 THEN
  DO: LvlClr = INT(RND * 144) + 32
  LOOP WHILE LvlClr = 42 OR LvlClr = 43
END IF
COLOR LvlClr

'use one of three random level openings
SELECT CASE INT(RND * 3) + 1
  CASE 1: 'horizontal & verticle lines
        FOR y = 0 TO 319 STEP 2
         LINE (y, 0)-(y, 199)
        NEXT y
        start! = TIMER: WHILE TIMER < start! + .5: WEND
        FOR y = 0 TO 199 STEP 2
         LINE (0, y)-(319, y)
        NEXT y
        start! = TIMER: WHILE TIMER < start! + .5: WEND
  CASE 2: 'zoom in to upper-left corner
        PSET (0, 0): PSET (2, 0)
        FOR stp = 2 TO 200
         FOR y = 0 TO 199 STEP stp
          FOR x = 0 TO 319 STEP stp
           LINE (x, y)-(x + stp - 1, y + stp - 1), POINT(x, y), BF
          NEXT x
         NEXT y
        NEXT stp
  CASE 3: 'growing boxes
        FOR z = 20 TO 0 STEP -1
         FOR y = 199 TO 0 STEP -20
          FOR x = 319 TO 0 STEP -20
          LINE (x, y)-(x - (20 - z), y - (20 - z)), , BF
          NEXT x
         NEXT y
         start! = TIMER: WHILE TIMER < start! + .04: WEND
        NEXT z
END SELECT


'patch some solid characters over the graphic
FOR x = 25 TO 1 STEP -1
LOCATE x, 1, 0: PRINT STRING$(40, CHR$(219));
NEXT
LOCATE 1, 1: PRINT SPACE$(40);

'give the solid area some dotted texture
IF LvlClr < 8 THEN w = LvlClr + 8 ELSE w = LvlClr - 8
FOR z = 1 TO 1000
x = INT(RND * 319)
y = INT(RND * 191) + 8
PSET (x, y), w
NEXT z

'throw in some diagnal patches
x = -1: y = 16: PSET (x, y), w
DO
  z = INT(RND * 5) + 1
  SELECT CASE z
   CASE 1: y = y + 1: IF POINT(x, y) <> w AND y > 16 THEN y = y - 1'|
   CASE 2: y = y - 1: x = x + 1: IF y <= 16 THEN y = y + 1 '/
   CASE 3: x = x + 1                                      '-
   CASE 4: y = y + 1: x = x + 1: IF y > 199 THEN y = y - 1'\
   CASE 5: y = y - 1: IF POINT(x, y) <> w THEN y = y + 1 '|
  END SELECT
  PSET (x, y), w: PSET (x, y - 1), 0
LOOP UNTIL x = 319
PAINT (0, 8), 0, 0
LOCATE 1, 15: PRINT "Please wait...";
REDIM Block(2 TO 25, 1 TO 40) AS INTEGER
FOR x = LBOUND(Block, 1) TO UBOUND(Block, 1)
  FOR y = LBOUND(Block, 2) TO UBOUND(Block, 2)
  Block(x, y) = 219
  NEXT y
NEXT x

'open a single cavern block
x = INT(RND * 22) + 3: y = INT(RND * 38) + 2
LOCATE x, y: PRINT " "; : Block(x, y) = 32

'randomly expand the cavern(s) to a calculated size
B = Level * 20: IF B > 750 THEN B = 750
FOR a = 1 TO B
  DO
   x = INT(RND * 22) + 3
   y = INT(RND * 38) + 2
   z = 0
   IF Block(x - 1, y) = 32 THEN z = z + 1
   IF Block(x + 1, y) = 32 THEN z = z + 1
   IF Block(x, y - 1) = 32 THEN z = z + 1
   IF Block(x, y + 1) = 32 THEN z = z + 1
   IF Block(x, y) = 32 THEN z = 0
  LOOP UNTIL z >= 1
  LOCATE x, y: PRINT " "; : Block(x, y) = 32
  IF a = (a \ 10) * 10 THEN
   x = INT(RND * 22) + 3
   y = INT(RND * 38) + 2
   LOCATE x, y: PRINT " "; : Block(x, y) = 32
  END IF
NEXT a

'try to patch in some diagnal edges
w = Level * 2: IF Level * 2 > 500 THEN w = 500
FOR w = 2 TO w
start! = TIMER
DO
  x = INT(RND * 22) + 3
  y = INT(RND * 38) + 2
  z = 1
IF Block(x - 1, y) = 32 AND Block(x + 1, y) = 219 THEN
  IF Block(x, y - 1) = 219 AND Block(x, y) = 32 AND Block(x, y + 1) = 32 THEN
   Block(x, y) = 0
   x = (x - 1) * 8: y = (y - 1) * 8: SWAP x, y
   FOR B = y TO y + 7: FOR a = x TO x + (B - y): PSET (a, B), LvlClr: NEXT
a: NEXT B: z = 0'\
  ELSEIF Block(x, y - 1) = 32 AND Block(x, y) = 32 AND Block(x, y + 1) = 219 THEN
   Block(x, y) = 0
   x = (x - 1) * 8: y = (y - 1) * 8: SWAP x, y
   FOR B = y TO y + 7: FOR a = x + (y + 7 - B) TO x + 7: PSET (a, B), LvlClr: NEXT a: NEXT B: z = 0'/

  ELSEIF Block(x, y - 1) = 219 AND Block(x, y) = 219 AND Block(x, y + 1) = 32 THEN
   LOCATE x, y: PRINT " "; : Block(x, y) = 0
   x = (x - 1) * 8: y = (y - 1) * 8: SWAP x, y
   FOR B = y TO y + 7: FOR a = x TO x + (B - y): PSET (a, B), LvlClr: NEXT a: NEXT B: z = 0'\
  ELSEIF Block(x, y - 1) = 32 AND Block(x, y) = 219 AND Block(x, y + 1) = 219 THEN
   LOCATE x, y: PRINT " "; : Block(x, y) = 0
   x = (x - 1) * 8: y = (y - 1) * 8: SWAP x, y
   FOR B = y TO y + 7: FOR a = x + (y + 7 - B) TO x + 7: PSET (a, B), LvlClr: NEXT a: NEXT B: z = 0'/
  END IF
END IF
LOOP UNTIL (z = 0 OR TIMER > start! + 3)
IF TIMER > start! + 3 THEN EXIT FOR
NEXT w
ERASE Block

LOCATE 1, 1: PRINT SPACE$(40);
HX = 8: HY = 8


END SUB

FUNCTION FSP (x, y)
'returns a 0 if FireSnake can move there
'and returns a 1 if it cannot.
SELECT CASE POINT(x, y)
  CASE 0, 15, 42, 43, MC: FSP = 1
  CASE ELSE: FSP = 0
END SELECT
END FUNCTION

SUB Snd (z)

'this plays the various sounds you'll hear in the game

IF PCSound = 1 THEN
SELECT CASE z
CASE 1: 'Fire Bullet
  PLAY "T240 MF MS L32 N1"
CASE 2: 'Bullet hits dirt
  PLAY "T240 MF MS L48 N25"
CASE 3: 'Bullet hits stone
  PLAY "T240 MS MF L32 N50"
CASE 4: 'Out of Bombs
  PLAY "T240 MF MS L32 N60"
CASE 5: 'Pick up a dude
  PLAY "MF MS T240 O2 L32 DEFG"
CASE 6: 'Mine Appears
  PLAY "T240 MF MS L40 N40 N30 N20 N10"
CASE 7: 'Level Completed
  PLAY "T240 O2 MS L6 cc ML egb- L3 a L6 gc"
CASE 8: 'Lose life
  PLAY "T240 MF MS L8 GF"
CASE 9: 'Bomb Explodes
  PLAY "T240 MF L64"
  FOR boom = 1 TO 10
  n = INT(RND * 20) + 1: PLAY "N" + STR$(n)
  NEXT boom
END SELECT
END IF

END SUB

