/*========================================================*/
/*
05-833 Applied Gadgets, Sensors and Activity Recognition in HCI
Class by Scott Hudson
Carnegie Mellon University
Spring 2012

*SpaceVaders* by Elwin Lee
Entertainment Technology Center
Carnegie Mellon University

Credits:
Drive matrix pattern http://arduino.cc/playground/Main/DirectDriveLEDMatrix
Play tones through speaker http://arduino.cc/en/Tutorial/Tone
*/
/*========================================================*/

#include "pitches.h"

/****TESTING****/
byte tempMatrix[8][8] = {  
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0} 
};

/*** Level 1 ***/
#define level1_ani { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}  \
}
#define level1 { \
  {0, 1, 0, 1, 0, 1, 0, 0}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 1, 0, 1, 0, 1, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** Level 2 ***/
#define level2_ani { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 0, 0, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}  \
}

#define level2 { \
  {0, 1, 0, 1, 0, 1, 0, 1}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 1, 0, 1, 0, 1, 0, 1}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** Level 3 ***/
#define level3_ani { \
  {1, 1, 1, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 0, 0, 1, 1}, \
  {1, 1, 1, 1, 0, 0, 0, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 1, 0, 0, 0, 1, 1}  \
}
#define level3 { \
  {0, 0, 0, 1, 1, 1, 0, 0}, \
  {0, 0, 1, 1, 1, 1, 1, 0}, \
  {0, 1, 1, 0, 1, 0, 1, 1}, \
  {0, 1, 0, 1, 1, 1, 0, 1}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** WIN ***/
#define win { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 0, 1, 0, 0, 1, 0, 1}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {1, 0, 1, 0, 0, 1, 0, 1}, \
  {1, 0, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}  \
}


/*** GENERAL ***/
const int cols[8] = { 12, 11, 10, 9, 8, 7, 6, 5 };    // Array of all the Column pin numbers
const int rows[8] = { 4, 3, 2, A0, A1, A2, A3, A4 };  // Array of all the Row pin numbers

// 2-dimensional array of pixels in LED Matrix:
int pixels[8][8];  

int loopDelay = 2;

boolean levelAni = true;  //true
boolean levelStart = false;
boolean levelComplete = false;

int levelsArrayIndex = 0;

const int _lvls = 7;  //2 * number of levels
byte levels[_lvls][8][8] = { 
  level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};

//copy of levels array for resetting purposes
byte initial[_lvls][8][8] = { 
  level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};

/*** SOUND ***/
int boom = NOTE_C4;

boolean loseSound = true;
int lose[] = { NOTE_F4, NOTE_A4, NOTE_C5 };
int loseNoteDurations[] = { 2, 4, 4};

/*** TIMERS ***/
unsigned long aniTime;
unsigned long completeTime;
unsigned long enemyTime;
unsigned long gameOverTime;

/*** PLAYER ***/
int bulletRow = 5;
int bulletCol;
byte bulletArray[6];

int bulletDelayCount = 0;
boolean fired = false;


/*** CONTROLS ***/
int btnPin = A5;
int potPin = A6;
int potVal;

boolean btnDown = false;

/*** ENEMY ***/
boolean enemyWon = false;
boolean enemyWaiting = false;
boolean enemyFired = false;
boolean enemyBulletCollision = false;

int enemyAttackSpeed[7] = {0, 150, 0, 100, 0, 25, 0};
int enemyBulletSpeed[7] = {0, 16, 0, 12, 0, 8, 0};
int enemyBulletRow;
int enemyBulletDelayCount = 0;
int enemyBulletArray[8][2] = { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} };
int enemyBottomCount = 0;
int randomBullet;

/*** SHIFTING ***/
boolean shiftLevel = false;
boolean shiftLeft = true;
boolean shiftDown = false;
boolean shiftRight = false;
boolean shiftUp = false;

int shiftCount = 0;
int shiftSpeed[2] = {70, 35};


void setup() {
  Serial.begin(9600);
  // initialize the I/O pins as outputs:

  // iterate over the pins:
  for (int thisPin = 0; thisPin < 8; thisPin++) {
    // initialize the output pins:
    pinMode(cols[thisPin], OUTPUT); 
    pinMode(rows[thisPin], OUTPUT);  
    // take the col pins (i.e. the cathodes) high to ensure that
    // the LEDS are off: 
    //both HIGH so no connection
    digitalWrite(cols[thisPin], HIGH);
    digitalWrite(rows[thisPin], HIGH);  
  }
  
  //set button and potentio meter as input
  pinMode(btnPin, INPUT);
  pinMode(potPin, INPUT);

  clearLeds();  //clear LED Matrix
//  shiftLevel = true;
  aniTime = millis();  //start level # animation timer
  
}

void loop() {
  
  /***reset all to no circuit***/
  for (int i = 0; i < 8; i++) {
    digitalWrite(rows[i], HIGH);  //all rows to high
    digitalWrite(cols[i], LOW);
  }
  
  
    
  /***Row 0***/
  for (int col = 0; col < 8; col++) {
    if (pixels[0][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[0], LOW);
  delay(loopDelay);
  digitalWrite(rows[0], HIGH);

  setPattern(levelsArrayIndex);  //create levels
  
  /***Row 1***/
  for (int col = 0; col < 8; col++) {
    if (pixels[1][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[1], LOW);
  delay(loopDelay);
  digitalWrite(rows[1], HIGH);
  
  if (levelAni) playLevelAni();  //play animation

  /***Row 2***/
  for (int col = 0; col < 8; col++) {
    if (pixels[2][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[2], LOW);
  delay(loopDelay);
  digitalWrite(rows[2], HIGH);
  
  if (levelStart) readPot();  //read potentiometer value

  /***Row 3***/
  for (int col = 0; col < 8; col++) {
    if (pixels[3][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[3], LOW);
  delay(loopDelay);
  digitalWrite(rows[3], HIGH);
  
  if (levelStart) refreshPlayer();  //update player's position based on potentiometer value
  if (levelStart) readBtn();      //read button state
  
  /***Row 4***/
  for (int col = 0; col < 8; col++) {
    if (pixels[4][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[4], LOW);
  delay(loopDelay);
  digitalWrite(rows[4], HIGH);
  
  if (levelStart && !enemyWon) readEnemy();  //get highest row # of enemy and fire bullet
  
  /***Row 5***/
  for (int col = 0; col < 8; col++) {
    if (pixels[5][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[5], LOW);
  delay(loopDelay);
  digitalWrite(rows[5], HIGH);
  
  if (levelStart && !levelComplete) checkLevelState();  //check all pixels of the level are gone
  if (levelComplete) levelFinished();                //win level

  
  /***Row 6***/
  for (int col = 0; col < 8; col++) {
    if (pixels[6][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[6], LOW);
  delay(loopDelay);
  digitalWrite(rows[6], HIGH);
  
  if (levelStart && shiftLevel)  shiftRow();  //shift pixels in the level
  
  /***Row 7***/
  for (int col = 0; col < 8; col++) {
    if (pixels[7][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[7], LOW);
  delay(loopDelay);
  digitalWrite(rows[7], HIGH);
  
  if (enemyWon) gameOver();  //lose if hit by enemy
  updatePixels();  //update all pixels of the LED Matrix 

}

void clearLeds() {
  // Clear display array
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      pixels[i][j] = 0;
    }
  }
}

/*** Populate Level on LED Matrix***/
void setPattern(int pattern) {
  
  if (levelsArrayIndex < 7) {  //if not last level
    for (int i = 0; i < 8; i++) {
      for (int j = 0; j < 8; j++) {
        if ( levels[levelsArrayIndex][i][j] == 1 ) {  //copy only "ones" to temporary matrix
          tempMatrix[i][j] = levels[levelsArrayIndex][i][j];  
        }
      }
    }
  } else {
    restart();  //restart if end of the game has been reached
  }
  
}


/***READ POTMETER***/
void readPot() {
  potVal = analogRead(potPin);      //read potentiometer value
  potVal = map(potVal, 0, 1024, 0, 6);  //map 1023 to 6 values for LED Matrix; 
                                          //only column 0~6 are used to display player
                                          //raise max_in and max_out by one for even value distribution http://arduino.cc/forum/index.php?topic=72153.0  
}
/*** Refresh PLAYER ***/
void refreshPlayer() {

  byte _playerRows[2][8] = {   //temp array to store player's position
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}
  };
  
  //draw player pixels
  _playerRows[0][potVal+1] = 1;
  _playerRows[1][potVal] = 1;
  _playerRows[1][potVal+1] = 1;
  _playerRows[1][potVal+2] = 1;

  for (int i = 6; i < 8; i++) {     //rows 6-7 (where the player is)
    for (int j = 7; j >= 0; j--) {  //update player positions
       if(_playerRows[i-6][j] == 1) {  //copy only "ones" to temporary matrix
         tempMatrix[i][j] = _playerRows[i-6][j];
       }
    }
  } 
}


/***READ BUTTON***/
void readBtn() {
  
  int btnPress = digitalRead(btnPin);  //read button state
  if (btnPress == 1 && !fired && !btnDown){      //if button is pressed
    bulletCol = potVal+1;      //bullet column value on matrix
    btnDown = true;
    fired = true;
  } 
  if (btnDown) {
    if (btnPress == 0) {
      btnDown = false;
    }  
  }
  if (fired) {   
    shoot(bulletCol);    //play shoot animation
  } 
}

/*** SHOOT ***/
void shoot(int _bulletCol) {
  
  if (bulletDelayCount == 2) {    //act as a delay & determines bullet's speed
    bulletRow--;
    
    if (bulletRow < 0) {  //if bullet reaches top (row 0)
      bulletRow = 5;    //reset bullet row position
      fired = false;    //bullet fire done
    } else {
      if (tempMatrix[bulletRow][_bulletCol] == 0) {  //check if next pixel position is empty or not
        tempMatrix[bulletRow][_bulletCol] = 1;  //new bullet pixel position and turn on
      } else {
        collisionBullet(bulletRow, _bulletCol);  //bullet collides with pixel
      }
     }
  } else {
    tempMatrix[bulletRow][_bulletCol] = 1;  //draw bullet pixel
  }
  bulletDelayCount = (bulletDelayCount+1) % 3;  //bullet's speed counter
  
}
/*** BULLET COLLISION ***/
void collisionBullet(int _row, int _col) {
  int boomNoteDuration = 1000/4;      //sound duration
  tone(13, boom, boomNoteDuration);      //play sound when hit
//  noTone(13);
  levels[levelsArrayIndex][_row][_col] = 0;    //remove 1 pixel that got shot from original level matrix
  tempMatrix[_row][_col] = 0;  //update temp matrix for pixel display
  
  bulletRow = 5;    //set original bullet row position back to 5
  fired = false;    //bullet fire done
}


/*** READ ENEMY ***/
void readEnemy() {
  
  if (!enemyWaiting && !enemyFired && !enemyBulletCollision){  //if enemy isn't doing anything
    enemyTime = millis();  //start timer
    enemyWaiting = true;
  }
  
  if (enemyWaiting) {
    if (millis() - enemyTime > enemyAttackSpeed[levelsArrayIndex]) {  //attack speed for each level according to array 
      
      int _row = 3;   //temp row value
      boolean dobreak = false;    //for double break;
      
      //loop to get the enemy's pixels of highest row (closest to the player) 
      for (int i = 3; !dobreak && i >= 0; i--) {  //backwards loop to get highest row
        for (int j = 0; j < 8; j++) {
            if(levels[levelsArrayIndex][i][j] == 1) {  //if a "one" is found in the row
              _row = i;          //save row index
              enemyBulletRow = _row + 1;  //value to put enemy bullet 1 row below enemy
              dobreak = true;    //double break;
              break;
            }
         }  
      }
      
      enemyBottomCount = 0; //counter for number of "one" pixels in highest row (closest to the player) 
      for (int c = 0; c < 8; c++) {  //loop through highest row
        if(levels[levelsArrayIndex][_row][c] == 1) {   //check if column contains "one" 
          enemyBulletArray[enemyBottomCount][0] = _row;  
          enemyBulletArray[enemyBottomCount][1] = c;
          enemyBottomCount++;  
        }
      }
       
      enemyWaiting = false;
      enemyFired = true;  //fire enemy bullet
      randomBullet = random(enemyBottomCount);  //randomly select one of the column pixels
    }
  }
  
  if (enemyFired) {
    if (enemyBulletDelayCount == (enemyBulletSpeed[levelsArrayIndex]-1)) {  //enemy bullet speed (higher value = slower)
      enemyBulletArray[randomBullet][0]++;  //row + 1
      if  (enemyBulletArray[randomBullet][0] > 7) {  //if bullet reaches bottom
        enemyBulletDelayCount = 0;  //reset and remove bullet
        enemyFired = false;
      } else {
        if (tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] == 0) {  //if next row is empty
          tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] = 1;  //bullet claims row
        } else {  //bullet hit something!!
          if (!levelComplete) {
            enemyBulletDelayCount = 0;  
            enemyFired = false;
            enemyBulletCollision = true;
          }
        }
      }
    } else {
      tempMatrix[enemyBulletArray[randomBullet][0]][enemyBulletArray[randomBullet][1]] = 1;
    }
    enemyBulletDelayCount = (enemyBulletDelayCount+1) % enemyBulletSpeed[levelsArrayIndex];  //enemy bullet speed
  }
  
  if (enemyBulletCollision) {
    if (enemyBulletArray[randomBullet][0] == 6 || enemyBulletArray[randomBullet][0] == 7) {  //check if enemy's bullet hit player
//      digitalWrite(13, HIGH);
      Serial.println("HIT!");
      enemyWon = true;
      gameOverTime = millis();
    }
    enemyBulletCollision = false;
  }
}




/*** SHIFTING LEVEL ***/
void shiftRow() {  //testing purposes
  int _speed;
  if (levelsArrayIndex == 3) {
      _speed = shiftSpeed[0];
  } else if (levelsArrayIndex == 5) {
      _speed = shiftSpeed[1];
  }
  byte _levelTemp[5][8] = {   //temp matrix array to store level pixel positions
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0}
  };
  for (int i = 0; i < 5; i++) {    //store in temp array
    for (int j = 0; j < 8; j++) {
        _levelTemp[i][j] = levels[levelsArrayIndex][i][j];
    }
  }
  
  if (shiftCount == (_speed-1)) {  //delay before shifting (roughly 100*18ms)
    if (shiftLeft == true) {  //shift left
      //loops through top 5x8 of the matrix
      for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 8; j++) {
          if (j == 7) {     //prevents shifting column index 8 which doesn't exist
            levels[levelsArrayIndex][i][7] = _levelTemp[i][0];
          } else {
            levels[levelsArrayIndex][i][j] = _levelTemp[i][j+1];
          }
        }
      }
      shiftCount = 0;
      shiftLeft = false;
      shiftDown = true;
    } else if (shiftDown == true) {  //shift down
      for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 8; j++) {
          if ( i == 0 ) {    //prevents shifting row index -1 which doesn't exist
            levels[levelsArrayIndex][i][j] = 0;
          } else {
            levels[levelsArrayIndex][i][j] = _levelTemp[i-1][j];  //shift down
          }
        }
      }
      shiftDown = false;
      shiftRight = true;
     } else if (shiftRight == true) {  //shift right
        for (int i = 0; i < 5; i++) {
          for (int j = 7; j >= 0; j--) {
            if (j == 0) {     //prevents shifting column index -1 which doesn't exist
              levels[levelsArrayIndex][i][0] = _levelTemp[i][7];
            } else {
              levels[levelsArrayIndex][i][j] = _levelTemp[i][j-1];
            }
          }
        }
        shiftCount = 0;
        shiftRight = false;
        shiftUp = true;
      
      } else if (shiftUp == true) {  //shift up
        for (int i = 0; i < 5; i++) {
          for (int j = 0; j < 8; j++) {
            if ( i == 4 ) {  //prevents shifting row index 5
              levels[levelsArrayIndex][i][j] = 0;
            } else {
              levels[levelsArrayIndex][i][j] = _levelTemp[i+1][j];  //shift down
            }
          }
        }
        shiftUp = false;
        shiftLeft = true;
      }
    }
    shiftCount = (shiftCount+1) % _speed;  //shifting delay
  
}




/*** PLAY LEVEL NUMBER ANIMATION ***/
void playLevelAni() {
  
  
  if (millis() - aniTime < 3000) {  //time before transition from level number to actual level    
//    if (levelsArrayIndex < 6 && millis() - aniTime > 3750) {  //3000
//      delay(500);
//    } 
  } else {
    levelAni = false;  //end animation
    levelStart = true;

    
    levelsArrayIndex++;
    if (levelsArrayIndex == 3 || levelsArrayIndex == 5) {  //if level 2 or 3, initiate shifting
      shiftLeft = true;
      shiftDown = false;
      shiftRight = false;
      shiftUp = false;
      shiftLevel = true;
    } else {
      shiftLevel = false;
    }
    clearLeds();
    
  }
}

void checkLevelState() {  //check if all level pixels (enemies) are dead
  int _countLevelPixels = 0;
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 8; j++) {
      if(levels[levelsArrayIndex][i][j] == 1){
        _countLevelPixels++;  //count the number of "one" pixels
      }
    }  
  }
  if((_countLevelPixels) == 0){  //if nothing left, congratz! you beat the level!
//    digitalWrite(13, HIGH);
//    Serial.println("COMPLETE!");
    completeTime = millis();
    levelComplete = true;
  }  
}

void levelFinished() { 
  
  if (millis() - completeTime > 2000) {  //time before transitioning to next level
  
    //reset all booleans
    enemyWaiting = false;
    enemyFired = false;
    enemyBulletCollision = false;

    levelStart = false;  
    levelComplete = false;
    levelAni = true;
    aniTime = millis();
    levelsArrayIndex++;
  }
}


/*** UPDATE PIXEL MATRIX ***/
void updatePixels() {
  //Use temporary 8x8 matrix to update actual matrix to prevent any bugs
  //Tends to get buggy when apply values straight to pixels[] matrix 
  //Instead, storing all matrix values in a temp and apply values to pixels[] at once is more stable
  
  //copy all temp matrix values to actual display matrix
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      pixels[i][j] = tempMatrix[i][j]; 
    }
  }
  
  //reset all values for temp matrix
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      tempMatrix[i][j] = 0;
    }
  }
}

void gameOver() {
  
  if( loseSound) {
    loseSound = false;
     for (int thisNote = 0; thisNote < 3; thisNote++) {
  
      // to calculate the note duration, take one second 
      // divided by the note type.
      int noteDuration = 250/loseNoteDurations[thisNote];
      tone(13, lose[thisNote],noteDuration);
  
      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      // stop the tone playing:
      noTone(13);
    }
  }
  
  if (millis() - gameOverTime < 3000) {  //time before restarting
    delay(250);
  } else {
    restart();  
  }
  

}

void restart() {
  //reset all booleans
  enemyWon = false;
  enemyWaiting = false;
  enemyFired = false;
  enemyBulletCollision = false;
  
  levelAni = true;
  levelStart = false;  
  levelComplete = false;
  levelsArrayIndex = 0;
  
  loseSound = true;
  
  //reset all levels
  for (int level = 0; level<_lvls; level++) {
     for (int x = 0; x<8; x++) {
       for (int y = 0; y<8; y++) {
         levels[level][x][y] = initial[level][x][y];
       }
     }
   }

  aniTime = millis();  //run level 1 animation 
};