'                        Q B a s i c  N i b b l e s
'
'                 Copyright (C) Microsoft Corporation 1990
'            Additional levels and functions by Stanislav Sokolov
'
'Nibbles is a game for one or two players.  Navigate your snakes
'around the game board trying to eat up numbers while avoiding
'running into walls or other snakes.  The more numbers you eat up,
'the more points you gain and the longer your snake becomes.
'
'To run this game, press Shift+F5.
'
'To exit QBasic, press Alt, F, X.
'
'To get help on a BASIC keyword, move the cursor to the keyword and press
'F1 or click the right mouse button.
'

'This game was extended by Stanislav Sokolov. These new elements were added:
'   - 7 new levels (one of which is random);
'   - Possibility of saving your game;
'   - Starting with 40 lives;
'   - Possibility of buying lives (4500 points per life);
'   - Possibility of turning sounds on/off.


'Set default data type to integer for faster game play.
DEFINT A-Z

'User-defined TYPEs
TYPE snakeBody
     row AS INTEGER
     col AS INTEGER
END TYPE

'This type defines the player's snake
     TYPE snakeType
     head      AS INTEGER
     length    AS INTEGER
     row       AS INTEGER
     col       AS INTEGER
     direction AS INTEGER
     lives     AS INTEGER
     score     AS INTEGER
     scolor    AS INTEGER
     alive     AS INTEGER
END TYPE

'This type is used to represent the playing screen in memory.
'It is used to simulate graphics in text mode, and has some interesting
'and slightly advanced methods to increasing the speed of operation.
'Instead of the normal 80x25 text graphics using chr$(219) "Û", we will be
'using chr$(220) "Ü" and chr$(223) "ß" and chr$(219) "Û" to mimic an 80x50
'pixel screen.
'Check out sub-programs SET and POINTISTHERE to see how this is implemented.
'Feel free to copy these (as well as arenaType and the DIM ARENA smt and the
'initialization code in the DrawScreen sub-program) and use them in your own
'programs.
TYPE arenaType
     realRow   AS INTEGER          'Maps the 80x50 point into the real 80x25
     acolor    AS INTEGER          'Stores the current color of the point
     sister    AS INTEGER          'Each char has 2 points in it.  .SISTER is
END TYPE                           '-1 if sister point is above, +1 if below

'Sub Declarations
DECLARE SUB SaveGame ()
DECLARE SUB Center (row, text$)
DECLARE SUB DrawScreen ()
DECLARE SUB EraseSnake (snake() AS ANY, snakeBody() AS ANY, snakeNum%)
DECLARE SUB GetInputs (NumPlayers, speed, diff$, monitor$, Snd, Load)
DECLARE SUB InitColors ()
DECLARE SUB Intro ()
DECLARE SUB Level (WatToDO, sammy() AS ANY)
DECLARE SUB PlayNibbles (NumPlayers, speed, diff$, Snd, Load)
DECLARE SUB PrintScore (NumPlayers%, score1%, score2%, lives1%, lives2%)
DECLARE SUB Set (row, col, acolor)
DECLARE SUB SpacePause (text$, nonum, row, col, num)
DECLARE SUB SparklePause ()
DECLARE FUNCTION PointIsThere (row, col, backColor)
DECLARE FUNCTION StillWantsToPlay ()

'Constants
CONST TRUE = -1
CONST FALSE = NOT TRUE
CONST MAXSNAKELENGTH = 1000
CONST STARTOVER = 1                'Parameters to 'Level' SUB
CONST SAMELEVEL = 2
CONST NEXTLEVEL = 3

CONST SPDAJUST = 2500               'The higher nimber, the slower game goes.

'Global Variables
DIM SHARED arena(1 TO 50, 1 TO 80) AS arenaType
DIM SHARED curLevel, colorTable(10), Er, LineNum
DIM SHARED number, diff$, NumPlayers, Snd, speed, monitor$
DIM SHARED sammy(1 TO 2) AS snakeType, KeyFlags
ON ERROR GOTO Trap
     LineNum = CSRLIN
     SCREEN 0, , 1, 1
     CLS

     RANDOMIZE TIMER
     GOSUB ClearKeyLocks
     Intro
     GetInputs NumPlayers, speed, diff$, monitor$, Snd, Load
     GOSUB SetColors
     DrawScreen

     DO
          PlayNibbles NumPlayers, speed, diff$, Snd, Load
     LOOP WHILE StillWantsToPlay

     GOSUB RestoreKeyLocks
     COLOR 15, 0
     CLS
    
     SCREEN 0, , 0, 0
     LOCATE LineNum, 1
END

ClearKeyLocks:
     DEF SEG = 0              'Turn off CapLock, NumLock and ScrollLock
     KeyFlags = PEEK(1047)
     POKE 1047, &H0
     DEF SEG
     RETURN

RestoreKeyLocks:
     DEF SEG = 0               'Restore CapLock, NumLock and ScrollLock states
     POKE 1047, KeyFlags
     DEF SEG
     RETURN

SetColors:
     IF monitor$ = "M" THEN
          RESTORE mono
     ELSE
          RESTORE normal
     END IF

     FOR a = 1 TO 6
          READ colorTable(a)
     NEXT a
     RETURN

              
Trap:           
    CLOSE #1
    OPEN "nibbles.sav" FOR OUTPUT AS #1: CLOSE #1
    Er = TRUE
    RESUME NEXT

               'snake1    snake2   Walls  Background   Dialogs-Fore  Back
mono:     DATA   15,       7,        7,        0,           15,        0
normal:   DATA   14,       13,       12,       1,           15,        4

'Center:
'Centers text on a given row
SUB Center (row, text$)
     LOCATE row, 41 - LEN(text$) / 2
     PRINT text$;
END SUB

'DrawScreen:
'    Drraws playing field
SUB DrawScreen

     'Initialize screen
     VIEW PRINT
     COLOR colorTable(1), colorTable(4)
     CLS

     'Print title & message
     Center 1, "Nibbles!"
     Center 11, "Initializing Playing Field..."

     'Initialize arena array
     FOR row = 1 TO 50
          FOR col = 1 TO 80
               arena(row, col).realRow = INT((row + 1) / 2)
               arena(row, col).sister = (row MOD 2) * 2 - 1
          NEXT col
     NEXT row
END SUB

'EraseSnake:
'    Erases snake to facilitate moving through playing field
SUB EraseSnake (snake() AS snakeType, snakeBod() AS snakeBody, snakeNum)

     FOR c = 0 TO 9
          FOR b = snake(snakeNum).length - c TO 0 STEP -10
               tail = (snake(snakeNum).head + MAXSNAKELENGTH - b) MOD MAXSNAKELENGTH
               Set snakeBod(tail, snakeNum).row, snakeBod(tail, snakeNum).col, colorTable(4)
          FOR a = 1 TO 200: NEXT a
          NEXT b
     NEXT c

END SUB

'GetInputs:
'    Gets player inputs
SUB GetInputs (NumPlayers, speed, diff$, monitor$, Snd, Load)

     COLOR 7, 0: CLS

     DO
          LOCATE 11, 47: PRINT SPACE$(34);
          LOCATE 11, 20
          INPUT "Will you load previously saved game? (Y/N)"; z$
     z$ = UCASE$(z$)
     LOOP UNTIL z$ = "Y" OR z$ = "N"
     IF z$ = "Y" THEN
        Er = FALSE
        OPEN "nibbles.sav" FOR INPUT AS #1: CLOSE
        IF NOT Er THEN
            Load = TRUE
            OPEN "nibbles.sav" FOR INPUT AS #1
                INPUT #1, number, curLevel, speed, diff$, NumPlayers, Snd, monitor$
                FOR z = 1 TO 2
                    INPUT #1, sammy(z).score, sammy(z).lives
                NEXT z
            CLOSE #1
            
            EXIT SUB
        END IF
     ELSE
        Load = FALSE
     END IF
    
     COLOR 7, 0: CLS
     DO
          LOCATE 5, 47: PRINT SPACE$(34);
          LOCATE 5, 20
          INPUT "How many players (1 or 2)"; num$
     LOOP UNTIL VAL(num$) = 1 OR VAL(num$) = 2
     NumPlayers = VAL(num$)

     LOCATE 8, 21: PRINT "Skill level (1 to 100)"
     LOCATE 9, 22: PRINT "1   = Novice"
     LOCATE 10, 22: PRINT "50  = Expert"
     LOCATE 11, 20: PRINT "100 = Twiddle Fingers"
     LOCATE 12, 15: PRINT "(Computer speed may affect your skill level)"
     DO
          LOCATE 8, 44: PRINT SPACE$(35);
          LOCATE 8, 43
          INPUT gamespeed$
     LOOP UNTIL VAL(gamespeed$) >= 1 AND VAL(gamepeed$) <= 100
     speed = VAL(gamespeed$)
     speed = (100 - speed) * 2 + 10

     DO
          LOCATE 15, 56: PRINT SPACE$(25);
          LOCATE 15, 15
          INPUT "Increase game speed during play (Y or N)"; diff$
          diff$ = UCASE$(diff$)
     LOOP UNTIL diff$ = "Y" OR diff$ = "N"

     DO
          LOCATE 17, 46: PRINT SPACE$(34);
          LOCATE 17, 17
          INPUT "Monochrome or color monitor (M or C)"; monitor$
          monitor$ = UCASE$(monitor$)
     LOOP UNTIL monitor$ = "M" OR monitor$ = "C"

     DO
          LOCATE 19, 51: PRINT SPACE$(25);
          LOCATE 19, 19
          INPUT "Play game with sounds On (Y or N)"; Sound$
          Sound$ = UCASE$(Sound$)
     LOOP UNTIL Sound$ = "Y" OR Sound$ = "N"
     IF Sound$ = "Y" THEN Snd = TRUE ELSE Snd = FALSE

     ON ERROR GOTO 0
     startTime# = TIMER                           'Calculate speed of system
     FOR i# = 1 TO 9000: NEXT i#                    'and do some compensation
     stopTime# = TIMER
     speed = speed * .5 / ((stopTime# - startTime#) / 2.5) + SPDAJUST

END SUB

'InitColors:
'    Initializes playing field colors
SUB InitColors

     FOR row = 1 TO 50
          FOR col = 1 TO 80
                arena(row, col).acolor = colorTable(4)
          NEXT col
     NEXT row

     CLS

     'Set (turn on) pixels for screen border
     FOR col = 1 TO 80
          Set 3, col, colorTable(3)
          Set 50, col, colorTable(3)
     NEXT col

     FOR row = 4 TO 49
          Set row, 1, colorTable(3)
          Set row, 80, colorTable(3)
     NEXT row

END SUB

'Intro:
'    Displays game introduction
SUB Intro

     SCREEN 0
     WIDTH 80, 25
     COLOR 31, 0
     CLS

     Center 3, "Q B a s i c   N i b b l e s"
     COLOR 7
     Center 5, "Copyright (C) Microsoft Corporation 1990"
     Center 6, "Additional levels and functions by Stanislav Sokolov"
     Center 8, "Nibbles is a game for one or two players.  Navigate your snakes"
     Center 9, "around the game board trying to eat up numbers while avoiding"
     Center 10, "running into walls or other snakes.  The more numbers you eat up,"
     Center 11, "the more points you gain and the longer your snake becomes.  You"
     Center 12, "can buy a life by pressing 'Z' or 'L', it costs 4500 points."
     Center 14, "Game Controls"
     Center 16, "   General              Player 1               Player 2    "
     Center 17, "                          (Up)                   (Up)      "
     Center 18, "SpaceBar = Pause           " + CHR$(24) + "                      W       "
     Center 19, "    Esc = Game Over   (Left) " + CHR$(27) + "   " + CHR$(26) + " (Right)   (Left) A   D (Right)  "
     Center 20, "M = Sound On/Off           " + CHR$(25) + "                      S       "
     Center 21, "                         (Down)                 (Down)     "
     Center 22, "                     Z = Buy a Life         L = Buy a life "
     Center 24, "Press any key to continue"

     'PLAY "MBT160O1L8CDEDCDL4ECC"
     SparklePause

END SUB

'Level:
'    Sets game level
SUB Level (WhatToDO, sammy() AS snakeType) STATIC

    SELECT CASE (WhatToDO)

    CASE STARTOVER
        curLevel = 1
    CASE NEXTLEVEL
        curLevel = curLevel + 1
    END SELECT
          
    sammy(1).head = 1
    sammy(1).length = 2
    sammy(1).alive = TRUE
    sammy(2).head = 1
    sammy(2).length = 2
    sammy(2).alive = TRUE
     
    InitColors
            
    SELECT CASE curLevel

    CASE 1
        Set 25, 40, colorTable(3)
        sammy(1).row = 25: sammy(2).row = 25
        sammy(1).col = 50: sammy(2).col = 30
        sammy(1).direction = 4: sammy(2).direction = 3

    CASE 2
        FOR i = 20 TO 60
            Set 25, i, colorTable(3)
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 60: sammy(2).col = 20
        sammy(1).direction = 3: sammy(2).direction = 4

    CASE 3
        FOR i = 10 TO 40
            Set i, 20, colorTable(3)
            Set i, 60, colorTable(3)
        NEXT i
        sammy(1).row = 25: sammy(2).row = 25
        sammy(1).col = 50: sammy(2).col = 30
        sammy(1).direction = 1: sammy(2).direction = 2
    
    CASE 4
        FOR i = 4 TO 30
            Set i, 20, colorTable(3)
            Set 53 - i, 60, colorTable(3)
        NEXT i
        FOR i = 2 TO 40
            Set 38, i, colorTable(3)
            Set 15, 81 - i, colorTable(3)
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 60: sammy(2).col = 20
        sammy(1).direction = 3: sammy(2).direction = 4

    CASE 5
        FOR i = 13 TO 39
            Set i, 21, colorTable(3)
            Set i, 59, colorTable(3)
        NEXT i
        FOR i = 23 TO 57
            Set 11, i, colorTable(3)
            Set 41, i, colorTable(3)
        NEXT i
        sammy(1).row = 25: sammy(2).row = 25
        sammy(1).col = 50: sammy(2).col = 30
        sammy(1).direction = 1: sammy(2).direction = 2


    CASE 6
        FOR i = 4 TO 49
            IF i > 30 OR i < 23 THEN
                Set i, 10, colorTable(3)
                Set i, 20, colorTable(3)
                Set i, 30, colorTable(3)
                Set i, 40, colorTable(3)
                Set i, 50, colorTable(3)
                Set i, 60, colorTable(3)
                Set i, 70, colorTable(3)
            END IF
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 2: sammy(2).direction = 1

    CASE 7                                'By Stanislav
        FOR i = 3 TO 78
            IF i < 26 OR i > 54 THEN
                Set 16, i, colorTable(3)
                Set 34, i, colorTable(3)
            END IF
        NEXT i
        FOR i = 5 TO 48
            IF i < 17 OR i > 33 THEN
                Set i, 25, colorTable(3)
                Set i, 55, colorTable(3)
            END IF
        NEXT i
        FOR i = 13 TO 36
            Set i, 35, colorTable(3)
            Set i, 45, colorTable(3)
        NEXT i
        Set 25, 40, colorTable(3)
        sammy(1).row = 42: sammy(2).row = 10
        sammy(1).col = 72: sammy(2).col = 8
        sammy(1).direction = 3: sammy(2).direction = 4
    
    CASE 8
        FOR i = 4 TO 49 STEP 2
            Set i, 40, colorTable(3)
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 2: sammy(2).direction = 1
     
    CASE 9                                             'By Stanislav
        FOR j = 5 TO 27 STEP 22
            FOR i = 8 TO 72
                Set j + 3, i, colorTable(3)
                Set j + 19, i, colorTable(3)
            NEXT i
        NEXT j

        FOR j = 8 TO 72 STEP 16
            FOR i = 9 TO 20
                Set i, j, colorTable(3)
                Set i + 25, j, colorTable(3)
            NEXT i
        NEXT j
       
        FOR j = 16 TO 64 STEP 16
            FOR i = 12 TO 23
                Set i, j, colorTable(3)
                Set i + 19, j, colorTable(3)
            NEXT i
        NEXT j
        sammy(1).row = 5: sammy(2).row = 48
        sammy(1).col = 74: sammy(2).col = 10
        sammy(1).direction = 3: sammy(2).direction = 4
       
    CASE 10                                            'By Stanislav
        FOR i = 12 TO 68
            Set 10, i, colorTable(3)
            Set 40, i, colorTable(3)
        NEXT i
        FOR i = 15 TO 35
            Set i, 22, colorTable(3)
            Set i, 58, colorTable(3)
        NEXT i
        FOR i = 32 TO 48
            Set 20, i, colorTable(3)
            Set 30, i, colorTable(3)
        NEXT i
        FOR i = 10 TO 40
            IF i <> 25 THEN
                Set i, 12, colorTable(3)
                Set i, 68, colorTable(3)
            END IF
        NEXT i
        FOR i = 22 TO 58
            IF i <> 40 THEN
                Set 15, i, colorTable(3)
                Set 35, i, colorTable(3)
            END IF
        NEXT i
        FOR i = 20 TO 30
            IF i <> 25 THEN
                Set i, 32, colorTable(3)
                Set i, 48, colorTable(3)
            END IF
        NEXT i
        sammy(1).row = 32: sammy(2).row = 18
        sammy(1).col = 53: sammy(2).col = 27
        sammy(1).direction = 1: sammy(2).direction = 2

    CASE 11
        FOR i = 4 TO 40
            Set i, 10, colorTable(3)
            Set 53 - i, 20, colorTable(3)
            Set i, 30, colorTable(3)
            Set 53 - i, 40, colorTable(3)
            Set i, 50, colorTable(3)
            Set 53 - i, 60, colorTable(3)
            Set i, 70, colorTable(3)
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 2: sammy(2).direction = 1

    CASE 12
        FOR i = 6 TO 47
           Set i, i, colorTable(3)
           Set i, i + 28, colorTable(3)
        NEXT i
        sammy(1).row = 40: sammy(2).row = 15
        sammy(1).col = 75: sammy(2).col = 5
        sammy(1).direction = 1: sammy(2).direction = 2
   
    CASE 13                                            'By Stanislav
        FOR i = 33 TO 47
            IF i <> 38 AND i <> 42 THEN
                Set 20, i, colorTable(3)
                Set 32, i, colorTable(3)
            END IF
        NEXT i
        FOR i = 20 TO 32
            IF i <> 24 AND i <> 28 THEN
                Set i, 33, colorTable(3)
                Set i, 47, colorTable(3)
            END IF
        NEXT i
        FOR i = 5 TO 75
            IF i < 33 OR i > 47 THEN Set 26, i, colorTable(3)
        NEXT i
        FOR i = 7 TO 46
            IF i < 20 OR i > 32 THEN Set i, 40, colorTable(3)
        NEXT i
        FOR i = 8 TO 34
           Set (i * .5 + 3), i, colorTable(3)
           Set (i * .5 + 28), i + 38, colorTable(3)
        NEXT i
        FOR i = 8 TO 32
            Set (53 - i * .5 - 4), i, colorTable(3)
            Set (53 - i * .5 - 30), i + 40, colorTable(3)
        NEXT i
      
        sammy(1).row = 48: sammy(2).row = 5
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 3: sammy(2).direction = 4

    CASE 14                                            'By Stanislav
        FOR i = 6 TO 47
            Set 53 - i, i, colorTable(3)
            Set 53 - i, i + 21, colorTable(3)
                IF i + 41 < 78 THEN
                    Set 53 - i, i + 41, colorTable(3)
                END IF
                IF 32 - i > 4 THEN
                    Set 32 - i, i, colorTable(3)
                END IF

        NEXT i
        sammy(1).row = 45: sammy(2).row = 7
        sammy(1).col = 75: sammy(2).col = 5
        sammy(1).direction = 1: sammy(2).direction = 2
                        
    CASE 15                                            'By Stanislav
          FOR j = 10 TO 45 STEP 16
               FOR i = 2 TO 79 STEP 2
                    Set j, i, colorTable(3)
                    Set j + 8, i + 1, colorTable(3)
               NEXT i
          NEXT j
          sammy(1).row = 4: sammy(2).row = 49
          sammy(1).col = 65: sammy(2).col = 15
          sammy(1).direction = 3: sammy(2).direction = 4
   
    CASE 16
       
        FOR i = 4 TO 49 STEP 2
            Set i, 10, colorTable(3)
            Set i + 1, 20, colorTable(3)
            Set i, 30, colorTable(3)
            Set i + 1, 40, colorTable(3)
            Set i, 50, colorTable(3)
            Set i + 1, 60, colorTable(3)
            Set i, 70, colorTable(3)
        NEXT i
        sammy(1).row = 7: sammy(2).row = 43
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 2: sammy(2).direction = 1

    CASE ELSE                                          'By Stanislav
        RANDOMIZE TIMER
        FOR i = 1 TO 240
            Set INT(RND(1) * 45 + 3), INT(RND(1) * 77 + 2), colorTable(3)
        NEXT i
        sammy(1).row = 48: sammy(2).row = 49
        sammy(1).col = 65: sammy(2).col = 15
        sammy(1).direction = 3: sammy(2).direction = 4

    END SELECT

END SUB

'PlayNibbles:
'    Main routine that controls game play
SUB PlayNibbles (NumPlayers, speed, diff$, Snd, Load)

    'Initialize snakes
     DIM sammyBody(MAXSNAKELENGTH - 1, 1 TO 2) AS snakeBody
     IF NOT Load THEN
         sammy(1).lives = 40
         sammy(1).score = 0
     END IF
     sammy(1).scolor = colorTable(1)
    
     IF NOT Load THEN
        sammy(2).lives = 40
        sammy(2).score = 0
     END IF
     sammy(2).scolor = colorTable(2)

     PLAY "MBT160O1L8"
    
     'Play Nibbles until finished
     curSpeed = speed
    
     IF NOT Load THEN
        Level STARTOVER, sammy()
     ELSE
        Level curLevel, sammy()
     END IF
    
     startRow1 = sammy(1).row: startCol1 = sammy(1).col
     startRow2 = sammy(2).row: startCol2 = sammy(2).col
    
     SpacePause "     Level" + STR$(curLevel) + ",  Push Space", TRUE, 0, 0, 0
     gameOver = FALSE
     
     DO
          IF NumPlayers = 1 THEN sammy(2).row = 0
         
          playerDied = FALSE
          PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
          nonum = TRUE      'nonum = TRUE if a number is not on the scrren
          IF Snd THEN PLAY "T160O1>L20CDEDCDL10ECC"
          IF NOT Load THEN number = 1        'Current number that snakes are trying to run into
          DO
              
               IF Load THEN Load = FALSE: GOTO Cont
              
               'Print number if no number exists
               IF nonum = TRUE THEN
                    DO
                        numberRow = INT(RND(1) * 47 + 3)
                        numberCol = INT(RND(1) * 78 + 2)
                        sisterRow = numberRow + arena(numberRow, numberCol).sister
                    LOOP UNTIL NOT PointIsThere(numberRow, numberCol, colorTable(4)) AND NOT PointIsThere(sisterRow, numberCol, colorTable(4))
                    numberRow = arena(numberRow, numberCol).realRow
                    nonum = FALSE
                    COLOR colorTable(1), colorTable(4)
                    LOCATE numberRow, numberCol
                    PRINT RIGHT$(STR$(number), 1);
                    count = 0
               END IF
Cont:
               'Delay game
               FOR a# = 1 TO curSpeed: NEXT a#
              
               'Get keyboard input & Change direction accordingly
               kbd$ = INKEY$
               SELECT CASE kbd$
                    CASE "w", "W": IF sammy(2).direction <> 2 THEN sammy(2).direction = 1
                    CASE "s", "S": IF sammy(2).direction <> 1 THEN sammy(2).direction = 2
                    CASE "a", "A": IF sammy(2).direction <> 4 THEN sammy(2).direction = 3
                    CASE "d", "D": IF sammy(2).direction <> 3 THEN sammy(2).direction = 4
                    CASE CHR$(0) + "H": IF sammy(1).direction <> 2 THEN sammy(1).direction = 1
                    CASE CHR$(0) + "P": IF sammy(1).direction <> 1 THEN sammy(1).direction = 2
                    CASE CHR$(0) + "K": IF sammy(1).direction <> 4 THEN sammy(1).direction = 3
                    CASE CHR$(0) + "M": IF sammy(1).direction <> 3 THEN sammy(1).direction = 4
                    CASE " ": SpacePause " Game Paused ... Push Space  ", nonum, numberRow, numberCol, number
                    CASE "m", "M": Snd = NOT Snd
                    CASE "l", "L"
                        IF sammy(1).score >= 45 THEN
                            sammy(1).score = sammy(1).score - 45
                            sammy(1).lives = sammy(1).lives + 1
                            IF Snd THEN PLAY "MBO3L15>GABO2L13F"
                            PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
                        END IF
                    CASE "z", "Z"
                        IF sammy(2).score >= 45 THEN
                            sammy(2).score = sammy(2).score - 45
                            sammy(2).lives = sammy(2).lives + 1
                            IF Snd THEN PLAY "MBO3L15>GABO2L13F"
                            PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
                        END IF
                    CASE CHR$(12)
                        Level NEXTLEVEL, sammy()
                    CASE CHR$(27)
                        SaveGame
                    CASE ELSE
               END SELECT

               FOR a = 1 TO NumPlayers
                    'Move Snake
                    SELECT CASE sammy(a).direction
                         CASE 1: sammy(a).row = sammy(a).row - 1
                         CASE 2: sammy(a).row = sammy(a).row + 1
                         CASE 3: sammy(a).col = sammy(a).col - 1
                         CASE 4: sammy(a).col = sammy(a).col + 1
                    END SELECT

                    'If snake hits number, respond accordingly
                    IF numberRow = INT((sammy(a).row + 1) / 2) AND numberCol = sammy(a).col THEN
                        IF Snd THEN PLAY "MBO0L16>CCCE"
                         IF sammy(a).length < (MAXSNAKELENGTH - 30) THEN
                              sammy(a).length = sammy(a).length + number * 4
                         END IF
                         sammy(a).score = sammy(a).score + number
                         PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
                         number = number + 1
                         IF number = 10 THEN
                              EraseSnake sammy(), sammyBody(), 1
                              EraseSnake sammy(), sammyBody(), 2
                              LOCATE numberRow, numberCol: PRINT " "
                              Level NEXTLEVEL, sammy()
                              PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
                              nonum = TRUE
                              SpacePause "     Level" + STR$(curLevel) + ",  Push Space", nonum, numberRow, numberCol, number
                              IF NumPlayers = 1 THEN sammy(2).row = 0
                              number = 1
                              IF diff$ = "Y" THEN speed = speed - 3: curSpeed = speed
                         END IF
                         nonum = TRUE
                         IF curSpeed < 1 THEN curSpeed = 1
                    END IF
               NEXT a

               FOR a = 1 TO NumPlayers
                    'If player runs into any point, or the head of the other snake,
                    'it dies.
                    IF PointIsThere(sammy(a).row, sammy(a).col, colorTable(4)) OR (sammy(1).row = sammy(2).row AND sammy(1).col = sammy(2).col) THEN
                         IF Snd THEN PLAY "MBO0L32EFGEFDC"
                         COLOR , colorTable(4)
                         LOCATE numberRow, numberCol
                         PRINT " "

                         playerDied = TRUE
                         sammy(a).alive = FALSE
                         sammy(a).lives = sammy(a).lives - 1

                    'Otherwise, move the snake, and erase the tail
                    ELSE
                         sammy(a).head = (sammy(a).head + 1) MOD MAXSNAKELENGTH
                         sammyBody(sammy(a).head, a).row = sammy(a).row
                         sammyBody(sammy(a).head, a).col = sammy(a).col
                         tail = (sammy(a).head + MAXSNAKELENGTH - sammy(a).length) MOD MAXSNAKELENGTH
                         Set sammyBody(tail, a).row, sammyBody(tail, a).col, colorTable(4)
                         sammyBody(tail, a).row = 0
                         Set sammy(a).row, sammy(a).col, sammy(a).scolor
                    END IF
               NEXT a

          LOOP UNTIL playerDied

          curSpeed = speed                   'Reset speed to initial value

          FOR a = 1 TO NumPlayers
               'If dead, then erase snake in really cool way
               EraseSnake sammy(), sammyBody(), a

               IF sammy(a).alive = FALSE THEN
                    'Update score
                    sammy(a).score = sammy(a).score - 5
                    PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives
                    nonum = TRUE
                    IF a = 1 THEN
                         SpacePause " Sammy Dies! Push Space! --->", nonum, numberRow, numberCol, number
                    ELSE
                         SpacePause " <--- Jake Dies! Push Space! ", nonum, numberRow, numberCol, number
                    END IF
               END IF
          NEXT a

          Level SAMELEVEL, sammy()
          PrintScore NumPlayers, sammy(1).score, sammy(2).score, sammy(1).lives, sammy(2).lives

     'Play next round, until either of snake's lives have run out.
     LOOP UNTIL sammy(1).lives = 0 OR sammy(2).lives = 0

END SUB

'PointIsThere:
'    Checks the globak arena array to see if the boolean flag is set
FUNCTION PointIsThere (row, col, acolor)

     IF row <> 0 THEN
          IF arena(row, col).acolor <> acolor THEN
               PointIsThere = TRUE
          ELSE
               PointIsThere = FALSE
          END IF
     END IF

END FUNCTION

'PrintScore:
'    Prints players scores' and number of lives remaining
SUB PrintScore (NumPlayers, score1, score2, lives1, lives2)

     COLOR 15, colorTable(4)
     LOCATE 1, 1: PRINT SPACE$(78)
     IF NumPlayers = 2 THEN
          LOCATE 1, 1
          PRINT USING "#,###,#00 Lives: ##  <-- JAKE"; score2; lives2
     END IF
     LOCATE 1, 36: PRINT "Level"; curLevel
     LOCATE 1, 49
     PRINT USING "SAMMY-->  Lives: ## ##,###,#00"; lives1; score1

END SUB

SUB SaveGame
    DEF SEG = 0           'Restore CapLock, NumLock and ScrollLock states
    POKE 1047, KeyFlags
    DEF SEG
    COLOR 15, 0: CLS
    Center 11, "Do you wish to save the game? (Y/N)"
    DO: z$ = UCASE$(INKEY$): LOOP UNTIL z$ = "Y" OR z$ = "N"
    IF z$ = "Y" THEN
        IF number = 10 THEN number = 1
        OPEN "nibbles.sav" FOR OUTPUT AS #1
            WRITE #1, number, curLevel, speed, diff$, NumPlayers, Snd, monitor$
            FOR z = 1 TO 2
                WRITE #1, sammy(z).score, sammy(z).lives
            NEXT z
        CLOSE #1
    END IF
    SCREEN 0, , 0, 0
    LOCATE LineNum, 1
   
    END

END SUB

'Set:
'    Sets row and colomn on playing field to given color to facilitate moving
'    of snakes around the field.
SUB Set (row, col, acolor)

      IF row <> 0 THEN
          arena(row, col).acolor = acolor              'Assign color to arena
          realRow = arena(row, col).realRow            'Get real row of pixel
          topFlag = arena(row, col).sister + 1 / 2     'Deduce whether pixel
          'is on topß, or bottomÜ
          sisterRow = row + arena(row, col).sister     'Get arena row of sister
          sisterColor = arena(sisterRow, col).acolor   'Determine sister's color

          LOCATE realRow, col

          IF acolor = sisterColor THEN
               COLOR acolor, acolor                    'If both points are same,
               PRINT CHR$(219);                        'Print chr$(219) "Û"
          ELSE
               IF topFlag THEN                         'Since you cannot have
                    IF acolor > 7 THEN                 'bright backgrounds
                         COLOR acolor, sisterColor     'determine the best combo
                         PRINT CHR$(223);              'to use.  Prints "ß"
                    ELSE
                         COLOR sisterColor, acolor
                         PRINT CHR$(220);              'Prints "Ü"
                    END IF
               ELSE
                    IF acolor > 7 THEN
                         COLOR acolor, sisterColor
                         PRINT CHR$(220);
                    ELSE
                         COLOR sisterColor, acolor
                         PRINT CHR$(223);
                    END IF
               END IF
          END IF
     END IF

END SUB

'SpacePause:
'    Pauses game play and waits for space bar to be pressed before continuing
SUB SpacePause (text$, nonum, row, col, num)

     COLOR colorTable(5), colorTable(6)
     Center 11, "ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ"
     Center 12, "Û " + LEFT$(text$ + SPACE$(29), 29) + " Û"
     Center 13, "ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ"
     WHILE INKEY$ <> "": WEND           'Clear keyboard buffer
     DO: x$ = INKEY$: LOOP UNTIL x$ = " " OR x$ = CHR$(27)
    
     IF x$ = CHR$(27) THEN SaveGame
    
     COLOR 15, colorTable(4)

     FOR i = 21 TO 26                      'Restore the screen background
          FOR j = 24 TO 56
               Set i, j, arena(i, j).acolor
          NEXT j
     NEXT i
                                          
     IF nonum THEN EXIT SUB                'Restore the current number
     COLOR colorTable(1), colorTable(4)    'if it is on screen
     LOCATE row, col
     PRINT RIGHT$(STR$(num), 1);
     
END SUB

'SparklePause:
'    Creates flashing border for intro screen
SUB SparklePause


     COLOR 4, 0
     a$ = "*    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    *    "
     WHILE INKEY$ <> "": WEND                'Clear keyboard buffer

      WHILE INKEY$ = ""
          FOR a = 1 TO 5
               LOCATE 1, 1                   'Print horizontal sparkles
               PRINT MID$(a$, a, 80);
               LOCATE 23, 1
               PRINT MID$(a$, 6 - a, 80);

               FOR b = 2 TO 23
                    c = (a + b) MOD 5
                    IF c = 1 THEN
                         LOCATE b, 80
                         PRINT "*";
                         LOCATE 24 - b, 1
                         PRINT "*";
                    ELSE
                         LOCATE b, 80
                         PRINT " ";
                         LOCATE 24 - b, 1
                         PRINT " ";
                    END IF
               NEXT b
          NEXT a
     WEND

END SUB
                        

'StillWantsToPlay:
'    Determines if users want to play game again.
FUNCTION StillWantsToPlay

     COLOR colorTable(5), colorTable(6)
     Center 10, "ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ"
     Center 11, "Û       G A M E   O V E R       Û"
     Center 12, "Û                               Û"
     Center 13, "Û      Play Again?   (Y/N)      Û"
     Center 14, "ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ"

     WHILE INKEY$ <> "": WEND                'Clear keyboard buffer
     DO
          kbd$ = UCASE$(INKEY$)
     LOOP UNTIL kbd$ = "Y" OR kbd$ = "N"

     COLOR 15, colorTable(4)
     Center 10, "                                 "
     Center 11, "                                 "
     Center 12, "                                 "
     Center 13, "                                 "
     Center 14, "                                 "

     IF kbd$ = "Y" THEN
          StillWantsToPlay = TRUE
     ELSE
          StillWantsToPlay = FALSE
          COLOR 7, 0
          CLS
     END IF

END FUNCTION

