'                              StarFighter.BAS
'                    (c) September 1997  Garfield Benjamin
'
' NOTE: You must set the current file-path to point the drawer containing
'       the STARFTR.BAS source-file.
'


' These are my custom EGA-GFX game library routines...
DECLARE SUB CenterTXT (txt$, row%, col%)
DECLARE SUB LoadGFX (file$, aseg%, ptr&)
DECLARE FUNCTION SizeGFX% (file$)
DECLARE SUB FadeOutGFX (begreg%, endreg%, SPEED%)
DECLARE SUB InitFadeGFX ()
DECLARE SUB SetGFX (seg1%, ptr1&, seg2%, ptr2&, numptrs%)
DECLARE SUB WaitVBl ()
DECLARE SUB BlackGFX ()
DECLARE FUNCTION YsizeGFX% (aseg%, ptr&)
DECLARE FUNCTION XsizeGFX% (aseg%, ptr&)
DECLARE SUB FadeInGFX (begreg%, endreg%, SPEED%)
DIM SHARED palfadeseq(15, 2) AS INTEGER
DIM SHARED buffer$

' ----------------------------------------------------------------------------

' These are the StarFighter-specific procedures...
DECLARE SUB dotitle ()
DECLARE SUB info1 (infodelay AS INTEGER)
DECLARE SUB info2 (infodelay AS INTEGER)
DECLARE SUB info3 (infodelay AS INTEGER)
DECLARE SUB initstars ()
DECLARE SUB dostars (startype AS INTEGER)

DECLARE SUB initgame ()
DECLARE SUB updatetimers ()
DECLARE SUB dofighter ()
DECLARE SUB dosaucers ()
DECLARE SUB domissiles ()

'-----------------------------------------------------------------------------

' >> CONSTANT declarations follow <<
' ----------------------------------
' Define standard Truth-constants...
CONST TRUE = -1
CONST FALSE = 0

' Define key-handles for Fighter-Control...
CONST MOVELEFT = 4
CONST MOVERIGHT = 8
CONST FIRE = 32
CONST QUITGAME = 27


' >> GLOBAL declarations follow <<
' --------------------------------
DIM SHARED score(6) AS INTEGER
DIM SHARED rep AS INTEGER
DIM SHARED gamespeed AS INTEGER, gamedelay AS INTEGER
DIM SHARED timer1 AS INTEGER, timer2  AS INTEGER
DIM SHARED movespeed AS INTEGER, numsaucers AS INTEGER
DIM SHARED TitleDone AS INTEGER, GameOver AS INTEGER, UserQuits AS INTEGER
DIM SHARED numstars AS INTEGER
DIM SHARED saucertofire AS INTEGER, saucershot AS INTEGER
DIM SHARED saucerfiretimer AS INTEGER, saucerfiredelay AS INTEGER
DIM SHARED maxsaucershots AS INTEGER

' Create a new type for easy object-processing...
TYPE BOB
   xpos AS INTEGER
   ypos AS INTEGER
   oxpos AS INTEGER
   oypos AS INTEGER
   xspd AS INTEGER
   yspd AS INTEGER
   image AS INTEGER
   oimage AS INTEGER
   status AS INTEGER
   update AS INTEGER
   time AS INTEGER
   frame AS INTEGER
END TYPE

DIM SHARED fighter AS BOB
DIM SHARED missile(3) AS BOB
DIM SHARED star(280) AS BOB
DIM SHARED saucer(15) AS BOB

DIM SHARED explode(0 TO 17) AS INTEGER
explode(0) = 16: explode(1) = 17: explode(2) = 18
explode(3) = 19: explode(4) = 20: explode(5) = 21
explode(6) = 22: explode(7) = 23: explode(8) = 23
explode(9) = 24: explode(10) = 24: explode(11) = 25
explode(12) = 25: explode(13) = 23: explode(14) = 24
explode(15) = 25

' Allocate space for the GFX-Sets...
buffer$ = SPACE$(16384)
DIM SHARED TITLE(SizeGFX("GFX/TITLE.GFX")) AS INTEGER
DIM SHARED Tptr(3) AS INTEGER
DIM SHARED STATGFX(SizeGFX("GFX/PANEL.GFX")) AS INTEGER
DIM SHARED Sptr(12) AS INTEGER
DIM SHARED MAINGFX(SizeGFX("GFX/MAIN.GFX")) AS INTEGER
DIM SHARED MPtr(34) AS INTEGER

' ----------------------------------------------------------------------------

' Load the Title-Images & Set the Image-Pointers...
CALL LoadGFX("GFX/TITLE.GFX", VARSEG(TITLE(0)), VARPTR(TITLE(0)))
CALL SetGFX(VARSEG(TITLE(0)), VARPTR(TITLE(0)), VARSEG(Tptr(0)), VARPTR(Tptr(0)), 3)

' Load the StatusPanel-Images & Set the Image-Pointers...
CALL LoadGFX("GFX/PANEL.GFX", VARSEG(STATGFX(0)), VARPTR(STATGFX(0)))
CALL SetGFX(VARSEG(STATGFX(0)), VARPTR(STATGFX(0)), VARSEG(Sptr(0)), VARPTR(Sptr(0)), 12)

' Load the Fighter(player)-Images & Set the Image-Pointers...
CALL LoadGFX("GFX/MAIN.GFX", VARSEG(MAINGFX(0)), VARPTR(MAINGFX(0)))
CALL SetGFX(VARSEG(MAINGFX(0)), VARPTR(MAINGFX(0)), VARSEG(MPtr(0)), VARPTR(MPtr(0)), 34)

' ----------------------------------------------------------------------------

' Initialize the GFX-library Fades...
CALL InitFadeGFX

' Initialize the default-settings...
gamespeed = 3

' Open our 16-color EGA-mode screen & Black-out the palette...
SCREEN 7, 0, 1, 0
CALL BlackGFX


UserQuits = FALSE
DO
   dotitle

   IF TitleDone = 1 THEN
      initgame
      DO
         WaitVBl
         PCOPY 1, 0
         GOSUB clearbobs
         GOSUB drawbobs
         updatetimers
         dofighter
         dosaucers
         domissiles
         dostars (0)
      LOOP UNTIL GameOver
      CALL FadeOutGFX(0, 15, 5 + gamespeed)
      CLS
      PCOPY 1, 0
   END IF

LOOP UNTIL UserQuits
END

clearbobs:
 ' Clear the Player's Ship...
 PUT (fighter.oxpos, fighter.oypos), MAINGFX(MPtr(fighter.oimage))

 ' Clear the Saucer Bobs...
 FOR rep = 0 TO numsaucers - 1
    PUT (saucer(rep).oxpos, saucer(rep).oypos), MAINGFX(MPtr(saucer(rep).oimage))
 NEXT rep

 ' Clear the Missile Bobs...
 FOR rep = 0 TO 2
    IF missile(rep).status THEN
       PUT (missile(rep).oxpos, missile(rep).oypos), MAINGFX(MPtr(missile(rep).oimage)), PSET
       PUT (missile(rep).oxpos, missile(rep).oypos), MAINGFX(MPtr(missile(rep).oimage))
    END IF
 NEXT rep

 'Clear the Stars...
 FOR rep = 0 TO numstars - 1
    PSET (star(rep).oxpos, star(rep).oypos), 0
 NEXT rep
RETURN



drawbobs:
 REM  Draw the stars in their new positions...
 FOR rep = 0 TO numstars - 1
    PSET (star(rep).xpos, star(rep).ypos), star(rep).image
    star(rep).oypos = star(rep).ypos
    star(rep).oxpos = star(rep).xpos
 NEXT rep

 ' Draw the Missile Bobs...
 FOR rep = 0 TO 2
    IF missile(rep).status = 1 THEN
       PUT (missile(rep).xpos, missile(rep).ypos), MAINGFX(MPtr(missile(rep).image)), PSET
       missile(rep).oypos = missile(rep).ypos
    END IF
 NEXT rep

 ' Draw the Saucer Bobs...
 FOR rep = 0 TO numsaucers - 1
    ' Draw the Saucer in the new position...
    PUT (saucer(rep).xpos, saucer(rep).ypos), MAINGFX(MPtr(saucer(rep).image)), PSET
    saucer(rep).oxpos = saucer(rep).xpos
    saucer(rep).oypos = saucer(rep).ypos
    saucer(rep).oimage = saucer(rep).image
 NEXT rep

 ' Draw the player's ship...
 PUT (fighter.xpos, fighter.ypos), MAINGFX(MPtr(fighter.image)), PSET
 fighter.oxpos = fighter.xpos
 fighter.oypos = fighter.ypos
 fighter.oimage = fighter.image
RETURN

SUB BlackGFX
 FOR rep% = 0 TO 15
    PALETTE rep%, 0
 NEXT rep%
END SUB

SUB CenterTXT (txt$, row%, col%)
 COLOR col%
 LOCATE row%, 21 - (LEN(txt$) / 2): PRINT txt$; : LOCATE 1, 1
END SUB

SUB dofighter
 STATIC fireflag AS INTEGER, misstimer AS INTEGER
 IF fighter.status = 4 THEN  ' FIghter is exploding...
    fighter.time = fighter.time + 1
    IF fighter.time > gamedelay THEN
       fighter.frame = fighter.frame + 1
       IF fighter.frame > 15 THEN
          fighter.image = 0
          fighter.xpos = fighter.xpos - 2
          fighter.ypos = fighter.ypos - 2
          fighter.status = 1
       ELSE
          fighter.image = explode(fighter.frame)
       END IF
       fighter.time = 0
    END IF
 ELSE
    REM  Check for player Firing and Quitting Game here...
    k$ = INKEY$
    IF k$ <> "" THEN
       IF LEN(k$) = 1 THEN
          thekey = ASC(k$)
          IF thekey = FIRE THEN
             fireflag = 1
          ELSE
             IF thekey = QUITGAME THEN
                GameOver = -1
             END IF
          END IF
       END IF
    END IF
  
    REM  See if the player has requested to fire a missile...
    IF misstimer > 20 THEN
       IF fireflag = 1 THEN
          FOR rep = 0 TO 2
             IF missile(rep).status = 0 THEN
                 missile(rep).xpos = fighter.xpos + 9
                 missile(rep).ypos = 185
                 missile(rep).oxpos = missile(rep).xpos
                 missile(rep).oypos = missile(rep).ypos - 3
                 missile(rep).image = 12
                 missile(rep).oimage = 12
                 missile(rep).status = 1
                 fireflag = 0
                 misstimer = 0
                 EXIT FOR
             END IF
          NEXT rep
       END IF
    ELSE
       misstimer = misstimer + 1
    END IF

    REM  Check for player Moving ship here...
    DEF SEG = 0
    thekey = PEEK(&H417): nullkey = PEEK(&H418)
    DEF SEG
    IF (thekey AND MOVELEFT) THEN
       fighter.xpos = fighter.xpos - movespeed
       IF fighter.xpos < 0 THEN fighter.xpos = 0
    ELSE
       IF (thekey AND MOVERIGHT) THEN
          fighter.xpos = fighter.xpos + movespeed
          IF fighter.xpos > 300 THEN fighter.xpos = 300
       END IF
    END IF
   
    REM  Animate the Players-ship here...
    IF timer1 = 0 THEN
       fighter.image = fighter.image + 1
       IF fighter.image > 1 THEN fighter.image = 0
    END IF
 END IF
END SUB

SUB domissiles
 FOR rep = 0 TO 2
    IF missile(rep).status THEN
       missile(rep).ypos = missile(rep).ypos - 3
       IF missile(rep).ypos < 13 THEN
          PUT (missile(rep).oxpos, missile(rep).oypos), MAINGFX(MPtr(missile(rep).oimage))
          missile(rep).status = 0
       END IF
    END IF
 NEXT rep
END SUB

SUB dosaucers
 FOR rep = 0 TO numsaucers - 1
    IF saucer(rep).status = 1 THEN
       ' Update saucers positions...
       saucer(rep).xpos = saucer(rep).xpos + saucer(rep).xspd
       saucer(rep).ypos = saucer(rep).ypos + saucer(rep).yspd
       ' Horizontal boundary-checking...
       IF saucer(rep).xpos < 4 THEN
          saucer(rep).xpos = 4: saucer(rep).xspd = -saucer(rep).xspd
       ELSE
          IF saucer(rep).xpos > 300 THEN
             saucer(rep).xpos = 300: saucer(rep).xspd = -saucer(rep).xspd
          END IF
       END IF
       ' Vertical boundary-checking...
       IF saucer(rep).ypos < 15 THEN
          saucer(rep).ypos = 15: saucer(rep).yspd = -saucer(rep).yspd
       ELSE
          IF saucer(rep).ypos > 170 THEN
             saucer(rep).ypos = 170: saucer(rep).yspd = -saucer(rep).yspd
          END IF
       END IF
       ' Animation (running-lights)...
       IF timer1 = 1 THEN
          saucer(rep).image = saucer(rep).image + 1
          IF saucer(rep).image > 32 THEN saucer(rep).image = 27
       END IF
    END IF
 NEXT rep

 ' Check for saucers firing will go here...
 saucerfiretimer = saucerfiretimer + 1
 IF saucerfiretimer > saucerfiredelay THEN
    saucerfiretimer = 0
 END IF
END SUB

SUB dostars (startype AS INTEGER)
' startype=1 is for the slower, title-screen starfield
 ' startype=0 is for the faster, game-screen starfield

IF startype = 1 THEN
    WaitVBl
    REM  Clear old stars (last frame) and update position for this frame...
    FOR rep = 0 TO numstars - 1
       IF star(rep).oimage = 0 THEN
          PSET (star(rep).xpos, star(rep).ypos), 0
       END IF
       star(rep).ypos = star(rep).ypos + star(rep).yspd
       IF star(rep).ypos > 199 THEN
          star(rep).ypos = star(rep).ypos - 199
          star(rep).xpos = RND * 320
       END IF
    NEXT rep
    REM  Save background pixels
    FOR rep = 0 TO numstars - 1
       star(rep).oimage = POINT(star(rep).xpos, star(rep).ypos)
    NEXT rep
    REM  Draw the stars in their new positions...
    FOR rep = 0 TO numstars - 1
       IF star(rep).oimage = 0 THEN
          PSET (star(rep).xpos, star(rep).ypos), star(rep).image
       END IF
    NEXT rep

 ELSE
    REM  Update position of stars...
    FOR rep = 0 TO numstars - 1
       star(rep).ypos = star(rep).ypos + star(rep).yspd
       IF star(rep).ypos > 199 THEN
          star(rep).ypos = (star(rep).ypos - 199) + 15
          star(rep).xpos = RND * 320
       END IF
    NEXT rep
 END IF
END SUB

SUB dotitle
 ' Define key-handles for Title-Options...
 CONST BEGINKEY = 66
 CONST SPEEDKEY = 83
 CONST INFOKEY = 73
 CONST QUITKEY = 81

 CONST BEGIN = 1
 CONST SPEED = 2
 CONST INFO = 3
 CONST QUIT = -1
 CONST ATTRACTMODE = 4

 DIM showtimer AS INTEGER, showpage AS INTEGER
 DIM thekey AS INTEGER, fadespeed AS INTEGER


 numstars = 45 * (6 - gamespeed)

 ' Determine xpos for centering purposes...
 tx% = 159 - (XsizeGFX(VARSEG(TITLE(0)), VARPTR(TITLE(Tptr(0)))) / 2)
 ox% = 159 - (XsizeGFX(VARSEG(TITLE(0)), VARPTR(TITLE(Tptr(1)))) / 2)
 cx% = 159 - (XsizeGFX(VARSEG(TITLE(0)), VARPTR(TITLE(Tptr(2)))) / 2)

 showpage = 1
 DO
    REM  Draw the Title-Screen...
    PUT (tx%, 0), TITLE(Tptr(0)), PSET
    PUT (ox%, 60), TITLE(Tptr(1)), PSET
    PUT (cx%, 150), TITLE(Tptr(2)), PSET
    PUT (199, 91), STATGFX(Sptr(gamespeed)), PSET

    initstars
    ' Now, Fade-In palette to show the fully-drawn screen...
    PCOPY 1, 0
    CALL FadeInGFX(0, 15, 5 + gamespeed)
    showtimer = 0
    TitleDone = 0
    fadespeed = 5 + gamespeed
    DO
       PCOPY 1, 0
       dostars (1)
       k$ = INKEY$: thekey = 0
       IF k$ = "" THEN
          showtimer = showtimer + 1
          IF showtimer > 600 THEN
             TitleDone = ATTRACTMODE
          END IF
       ELSE
          thekey = ASC(k$): IF thekey > 90 THEN thekey = thekey - 32
      
          IF thekey = BEGINKEY THEN
             TitleDone = 1
          ELSE
             IF thekey = SPEEDKEY THEN
                gamespeed = gamespeed + 1: IF gamespeed > 5 THEN gamespeed = 1
                showtimer = 0
                fadespeed = 10
                TitleDone = SPEED
             ELSE
                IF thekey = INFOKEY THEN
                   TitleDone = INFO
                ELSE
                   IF thekey = QUITKEY THEN
                      TitleDone = QUIT: UserQuits = TRUE
                   END IF
                END IF
             END IF
          END IF
       END IF
    LOOP UNTIL TitleDone
 
    CALL FadeOutGFX(1, 15, fadespeed)
    CLS
   
    ' If player pressed "I"nstructions key, show the three Info-pages...
    IF TitleDone = INFO THEN
       CALL info1(900)
       CALL info2(900)
       CALL info3(900)
    END IF
  
    ' If the automated-show has kicked in, update it here...
    IF TitleDone = ATTRACTMODE THEN
       IF showpage = 1 THEN
          CALL info1(600)
       END IF
       IF showpage = 2 THEN
          CALL info2(600)
       END IF
       IF showpage = 3 THEN
          CALL info3(600)
       END IF
       showtimer = 0
       showpage = showpage + 1
       IF showpage > 3 THEN showpage = 1
    END IF

 LOOP UNTIL (TitleDone <> INFO) AND (TitleDone <> ATTRACTMODE)

END SUB

SUB FadeInGFX (begreg%, endreg%, SPEED%)
   IF begreg% > endreg% THEN SWAP begreg%, endreg%
   IF begreg% < 0 THEN begreg% = 0
   IF endreg% > 15 THEN endreg% = 15

   IF SPEED% < 1 THEN SPEED% = 1
   IF SPEED% > 10 THEN SPEED% = 10
   delay% = (11 - SPEED%) ^ 2

   FOR rep% = 0 TO 2
      FOR col% = begreg% TO endreg%
         PALETTE col%, palfadeseq(col%, rep%)
      NEXT col%
      IF SPEED% < 10 THEN
         FOR del% = 1 TO delay%
            WaitVBl
         NEXT del%
      END IF
   NEXT rep%
END SUB

SUB FadeOutGFX (begreg%, endreg%, SPEED%)
   IF begreg% > endreg% THEN SWAP begreg%, endreg%
   IF begreg% < 0 THEN begreg% = 0
   IF endreg% > 15 THEN endreg% = 15

   IF SPEED% < 1 THEN SPEED% = 1
   IF SPEED% > 10 THEN SPEED% = 10
   delay% = (11 - SPEED%) ^ 2

   FOR rep% = 2 TO 0 STEP -1
      FOR col% = begreg% TO endreg%
         PALETTE col%, palfadeseq(col%, rep%)
      NEXT col%
      IF SPEED% < 10 THEN
         FOR del% = 1 TO delay%
            WaitVBl
         NEXT del%
      END IF
   NEXT rep%
   FOR col% = begreg% TO endreg%
      PALETTE col%, 0
   NEXT col%
END SUB

SUB info1 (infodelay AS INTEGER)
 CALL CenterTXT(">> INSTRUCTIONS  <<", 1, 15)
 REM  Page ONE of Instructions...
 PUT (157, 11), STATGFX(Sptr(1)), PSET
 CALL CenterTXT("L.Ctrl moves left   L.Alt moves right", 6, 3)
 CALL CenterTXT(" Spacebar fires     Esc exit to Title", 7, 3)
 CALL CenterTXT("Configure the SpeedLevel to suit your", 9, 9)
 CALL CenterTXT("system. The SpeedLevel acts as a sort", 10, 9)
 CALL CenterTXT("of reverse detail-setting.           ", 11, 9)
 CALL CenterTXT("As the SpeedLevel increases the      ", 13, 5)
 CALL CenterTXT("DetailLevel decreases...             ", 14, 5)
 CALL CenterTXT("SPEEDLEVEL     RECOMMENDED SYSTEM    ", 16, 1)
 CALL CenterTXT("    1           200MHz or higher     ", 18, 9)
 CALL CenterTXT("    2                166MHz          ", 19, 9)
 CALL CenterTXT("    3                133MHz          ", 20, 9)
 CALL CenterTXT("    4                100MHz          ", 21, 3)
 CALL CenterTXT("    5            66MHz or lower      ", 22, 3)
 CALL CenterTXT("Press Any Key...", 24, 15)
 
 initstars
 PCOPY 1, 0
 CALL FadeInGFX(0, 15, 5 + gamespeed)
 SHOWTIME = 0
 DO
    PCOPY 1, 0
    dostars (1)
    SHOWTIME = SHOWTIME + 1
 LOOP UNTIL (INKEY$ <> "") OR (SHOWTIME > infodelay)

 CALL FadeOutGFX(0, 15, 5 + gamespeed): CLS
 FOR ckb = 2 TO 23
    k$ = INKEY$: LOCATE ckb, 1: PRINT "                                       ";
 NEXT ckb
END SUB

SUB info2 (infodelay AS INTEGER)
 REM  Page TWO of Instructions...
 CALL CenterTXT(">> INSTRUCTIONS  <<", 1, 15)
 PUT (157, 11), STATGFX(Sptr(2)), PSET
 CALL CenterTXT("This is just a simple shooter...     ", 6, 12)
 CALL CenterTXT("The object is to blow away as many of", 8, 12)
 CALL CenterTXT("the alien ships as possible.         ", 9, 12)
 CALL CenterTXT("Occasionally, an exploding alien will", 11, 6)
 CALL CenterTXT("release a power capsule.             ", 12, 6)
 CALL CenterTXT("Catching this power-up will do one of", 14, 4)
 CALL CenterTXT("two things:                          ", 15, 4)
 CALL CenterTXT("F increases your firepower    ", 17, 6)
 CALL CenterTXT("S gives you a temporary shield", 18, 6)
 CALL CenterTXT("Despite what the Title Screen shows, ", 20, 12)
 CALL CenterTXT("this demo has actually taken SIX days", 21, 12)
 CALL CenterTXT("so far...                            ", 22, 12)
 CALL CenterTXT("Press Any Key...", 24, 15)

 initstars
 PCOPY 1, 0
 CALL FadeInGFX(0, 15, 5 + gamespeed)
 SHOWTIME = 0
 DO
    PCOPY 1, 0
    dostars (1)
    SHOWTIME = SHOWTIME + 1
 LOOP UNTIL (INKEY$ <> "") OR (SHOWTIME > infodelay)

 CALL FadeOutGFX(0, 15, 5 + gamespeed): CLS
 FOR ckb = 2 TO 23
    k$ = INKEY$: LOCATE ckb, 1: PRINT "                                       "
 NEXT ckb
END SUB

SUB info3 (infodelay AS INTEGER)
 REM  Page THREE of Instructions...
 CALL CenterTXT(">> INSTRUCTIONS  <<", 1, 15)
 PUT (157, 11), STATGFX(Sptr(3)), PSET
 CALL CenterTXT("My name is Garfield Benjamin and this is", 6, 14)
 CALL CenterTXT("my first game developed in QBasic.      ", 7, 14)
 CALL CenterTXT("I have been programming for 17 years now", 9, 10)
 CALL CenterTXT("primarily on the C64 and AMIGA.         ", 10, 10)
 CALL CenterTXT("If you have an AMIGA (the BEST computer ", 12, 2)
 CALL CenterTXT("ever created) you can download three of ", 13, 2)
 CALL CenterTXT("my AMIGA games from Aminet:             ", 14, 2)
 CALL CenterTXT("shoot/tinvaders.lha, actio/SS2000.lha   ", 16, 10)
 CALL CenterTXT("and actio/tsmash.lha                    ", 17, 10)
 CALL CenterTXT("THANKS for playing this game!!", 19, 14)
 CALL CenterTXT("Look out for more releases soon!!!", 20, 14)
 CALL CenterTXT("Press Any Key...", 24, 15)
    
 initstars
 PCOPY 1, 0
 CALL FadeInGFX(0, 15, 5 + gamespeed)
 SHOWTIME = 0
 DO
    PCOPY 1, 0
    dostars (1)
    SHOWTIME = SHOWTIME + 1
 LOOP UNTIL (INKEY$ <> "") OR (SHOWTIME > infodelay)
      
 CALL FadeOutGFX(0, 15, 5 + gamespeed): CLS
 FOR ckb = 2 TO 23
    k$ = INKEY$: LOCATE ckb, 1: PRINT "                                       "
 NEXT ckb
END SUB

SUB InitFadeGFX
 ' Create Fade-sequence tables...
   palfadeseq(0, 0) = 0: palfadeseq(0, 1) = 0: palfadeseq(0, 2) = 0
   palfadeseq(1, 0) = 0: palfadeseq(1, 1) = 1: palfadeseq(1, 2) = 1
   palfadeseq(2, 0) = 0: palfadeseq(2, 1) = 2: palfadeseq(2, 2) = 2
   palfadeseq(3, 0) = 1: palfadeseq(3, 1) = 9: palfadeseq(3, 2) = 3

   palfadeseq(4, 0) = 0: palfadeseq(4, 1) = 1: palfadeseq(4, 2) = 4
   palfadeseq(5, 0) = 0: palfadeseq(5, 1) = 1: palfadeseq(5, 2) = 5
   palfadeseq(6, 0) = 0: palfadeseq(6, 1) = 4: palfadeseq(6, 2) = 6
   palfadeseq(7, 0) = 8: palfadeseq(7, 1) = 8: palfadeseq(7, 2) = 7

   palfadeseq(8, 0) = 0: palfadeseq(8, 1) = 8: palfadeseq(8, 2) = 8
   palfadeseq(9, 0) = 1: palfadeseq(9, 1) = 1: palfadeseq(9, 2) = 9
   palfadeseq(10, 0) = 2: palfadeseq(10, 1) = 2: palfadeseq(10, 2) = 10
   palfadeseq(11, 0) = 1: palfadeseq(11, 1) = 3: palfadeseq(11, 2) = 11

   palfadeseq(12, 0) = 4: palfadeseq(12, 1) = 6: palfadeseq(12, 2) = 12
   palfadeseq(13, 0) = 1: palfadeseq(13, 1) = 5: palfadeseq(13, 2) = 13
   palfadeseq(14, 0) = 2: palfadeseq(14, 1) = 10: palfadeseq(14, 2) = 14
   palfadeseq(15, 0) = 8: palfadeseq(15, 1) = 7: palfadeseq(15, 2) = 15
END SUB

SUB initgame
 gamedelay = 6 - gamespeed
 movespeed = gamespeed + 2
 numstars = 4 * gamedelay: initstars

 REM  Draw the 'SCORE:' at top left of screen...
 PUT (0, 2), STATGFX(Sptr(11)), PSET
 FOR rep = 0 TO 5
    score(rep) = 0
    PUT (40 + (rep * 8), 2), STATGFX(Sptr(score(rep))), PSET
 NEXT rep

 REM  Draw the 'LIVES:' at top left of screen...
 Lives = 2
 PUT (248, 2), STATGFX(Sptr(10)), PSET
 FOR rep = 0 TO Lives - 1
    PUT (284 + (rep * 17), 0), MAINGFX(MPtr(0)), PSET
 NEXT rep

 REM  Initialize Player's-Ship...
 fighter.xpos = 150: fighter.oxpos = 150
 fighter.ypos = 185: fighter.oypos = 185
 fighter.image = 0: fighter.oimage = 0
 fighter.status = 1
 PUT (fighter.xpos, 185), MAINGFX(MPtr(fighter.image)), PSET

 REM  Initialize the player's Missiles...
 FOR rep = 0 TO 2
    missile(rep).status = 0
 NEXT rep

 REM  Initialize the Saucers...
 numsaucers = (gamedelay * 3)
 yspacing% = (185 - 15) / (numsaucers + 1)
 ypos% = yspacing% + 4
 image% = 27
 FOR rep = 0 TO numsaucers - 1
    saucer(rep).xpos = INT(RND * 280) + 10
'    saucer(rep).ypos = INT(RND * 100) + 16
    saucer(rep).ypos = ypos%
    ypos% = ypos% + yspacing%
    saucer(rep).xspd = (INT(RND * 4) * 2) - 3
    'saucer(rep).yspd = (INT(RND * 2) * 2) - 1
    saucer(rep).oxpos = saucer(rep).xpos + saucer(rep).xspd
    saucer(rep).oypos = saucer(rep).ypos + saucer(rep).yspd
    saucer(rep).image = image%
    saucer(rep).oimage = image%
    saucer(rep).status = 1
    image% = image% + 1: IF image% > 32 THEN image% = 27
 NEXT rep
 saucerfiredelay = 105 ' gamespeed * 60

 PCOPY 1, 0
 CALL FadeInGFX(0, 15, 5 + gamespeed)

 ' Speed-up Keyboard reading to MAXIMUM...
 OUT &H60, &HF3
 CALL WaitVBl
 OUT &H60, &H0
                                                       
 GameOver = 0
END SUB

SUB initstars
 cstar = INT(numstars * .2): mstar = INT(numstars * .4) + cstar
 REM  Initialize the stars...
 FOR s = 0 TO numstars - 1
    star(s).xpos = RND * 319
    star(s).ypos = (RND * 170) + 15
    star(s).oxpos = star(s).xpos + star(s).xspd
    star(s).oypos = star(s).ypos + star(s).yspd
    IF s < cstar THEN
       star(s).yspd = 5:  star(s).image = 3
    ELSE
       IF s < mstar THEN
          star(s).yspd = 3: star(s).image = 9
       ELSE
          star(s).yspd = 1: star(s).image = 1
       END IF
    END IF
    star(s).oimage = POINT(star(s).xpos, star(s).ypos)
 NEXT s
END SUB

SUB LoadGFX (file$, aseg%, ptr&)
 DEF SEG = aseg%
 OPEN file$ FOR BINARY AS 1
    GET #1, , buffer$
    FOR x% = 1 TO LOF(1)
       POKE ptr&, ASC(MID$(buffer$, x%, 1))
       ptr& = ptr& + 1
    NEXT x%
 CLOSE 1

 DEF SEG
END SUB

SUB SetGFX (seg1%, ptr1&, seg2%, ptr2&, numptrs%)
 offset% = 0
 FOR rep = 1 TO numptrs%
    DEF SEG = seg1%
    xsize% = PEEK(ptr1&) + (256 * PEEK(ptr1& + 1))
    ysize% = PEEK(ptr1& + 2) + (256 * PEEK(ptr1& + 3))
    size% = 4 + ((xsize% + 7) / 8) * 4 * ysize%
    ptr1& = ptr1& + size%

    DEF SEG = seg2%
    halfoffset% = offset% / 2
    byte1% = halfoffset% MOD 256: byte2% = halfoffset% / 256
    IF (byte2% * 256) > halfoffset% THEN byte2% = byte2% - 1
    POKE ptr2&, byte1%: POKE ptr2& + 1, byte2%
    ptr2& = ptr2& + 2

    offset% = offset% + size%
    IF (offset% MOD 2) > 0 THEN
       offset% = offset% + 1
       ptr1& = ptr1& + 1
    END IF

 NEXT rep

 DEF SEG
END SUB

FUNCTION SizeGFX% (file$)
 OPEN file$ FOR BINARY AS 1
   SizeGFX% = LOF(1)
 CLOSE 1
END FUNCTION

SUB updatetimers
 timer1 = timer1 + 1
 IF timer1 > gamedelay THEN
    timer1 = 0
 END IF
 timer2 = timer2 + 1
 IF timer2 > 10 THEN
    timer2 = 0
 END IF
END SUB

SUB WaitVBl
 DO
 LOOP UNTIL (INP(&H3DA) AND 8)
END SUB

FUNCTION XsizeGFX% (aseg%, ptr&)
 DEF SEG = aseg%
 XsizeGFX% = PEEK(ptr&) + (256 * PEEK(ptr& + 1))
 DEF SEG
END FUNCTION

FUNCTION YsizeGFX% (aseg%, ptr&)
 DEF SEG = aseg%
 YsizeGFX% = PEEK(ptr& + 2) + (256 * PEEK(ptr& + 3))
 DEF SEG
END FUNCTION

