Armageddon - a missile commad clone by Wuuff, originally for Gamebuino. Conversion by Jonne

Dependencies:   PokittoLib

Fork of Asterocks by Pokitto Community Team

ageddon.cpp

Committer:
HomineLudens
Date:
2017-10-14
Revision:
6:22d706e5dd6e
Parent:
5:56c4f2f12ec0
Child:
13:b133c46dbda7

File content as of revision 6:22d706e5dd6e:

/* This file was automatically parsed from an Arduino sourcefile  */
/* by PokittoParser v0.1 Copyright 2016 Jonne Valola              */
/* USE AT YOUR OWN RISK - NO GUARANTEES GIVEN OF 100% CORRECTNESS */

#include "PokittoCore.h"
/* Auto-generated function declarations */
void setup();
void nextStage();
void nextLull();
void drawScore();
void drawTargets();
void drawCities();
void drawAmmo();
void drawMissiles();
void drawDetonations();
void launchMissile(uint8_t);
void tryLaunchEnemy();
void stepMissiles();
void stepDetonations();
void stepCollision();
void checkMenu();
void checkWin();
void checkLose();
void stepGame();
void drawLull();
void stepLull();
void stepDead();
void stepPregame();
void loop();
void loadHighscores();
uint8_t isHighscore(uint32_t);
void saveHighscore(char);
void drawHighscores();
void initSound();
void playSound(uint8_t);
Pokitto::Core gb;

int main() {
    setup();
    while (gb.isRunning()) {
        loop();
    }
}

const byte armageddon[] PROGMEM = {64,36,
B11111111,B11110000,B00000000,B00000000,B00000000,B00000000,B00001111,B11111111,
B11111100,B00001111,B11111111,B11111111,B11111111,B11111111,B11110000,B00111111,
B11100011,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11000111,
B10011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111001,
B01110111,B10011110,B11101110,B11111001,B11000010,B01111001,B11110111,B10111010,
B01110111,B10101110,B01001110,B11110110,B11011110,B10111010,B11101011,B10011010,
B01101011,B10001110,B01001101,B01110111,B11000110,B11011011,B01011101,B10101010,
B01100011,B10101110,B10101100,B01110100,B11011110,B11011011,B01011101,B10110010,
B01101011,B10100110,B11101101,B01110110,B11011110,B10111010,B11101011,B10111010,
B01001001,B10110110,B11101001,B00111001,B11000010,B01111001,B11110111,B10111010,
B10111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111101,
B11011111,B11111111,B11100000,B11111111,B11111111,B00000111,B11111111,B11111011,
B11100011,B11111110,B00011111,B00011111,B11111000,B11111000,B01111111,B11000111,
B11111000,B11100001,B11111111,B11101111,B11110111,B11111111,B10000111,B00011111,
B11111110,B00001111,B11111111,B11110111,B11101111,B11111111,B11110000,B01111111,
B11111111,B11111111,B11111111,B11110111,B11101111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111011,B11011111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111011,B11011111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111110,B00000011,B11000000,B01111111,B11111111,B11111111,
B11111111,B11111111,B11100001,B11111011,B11011111,B10000111,B11111111,B11111111,
B11111111,B11111111,B11011111,B11110011,B11001111,B11111011,B11111111,B11111111,
B11111111,B11111111,B11011111,B11110011,B11001111,B11111011,B11111111,B11111111,
B11111111,B11111111,B11011111,B11110011,B11001111,B11111011,B11111111,B11111111,
B11111111,B11111111,B11100001,B11110011,B11001111,B10000111,B11111111,B11111111,
B11111111,B11111111,B11111110,B00010111,B11101000,B01111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11100000,B00000111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11110111,B11101111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11100111,B11100111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11100111,B11100111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11101111,B11110111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11101111,B11110111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11101111,B11110111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11011111,B11111011,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B10111111,B11111101,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111110,B01111111,B11111110,B01111111,B11111111,B11111111,
B11111111,B11111111,B11111101,B11111111,B11111111,B10111111,B11111111,B11111111,
};

/*const byte city[] PROGMEM = {8,8,
B00000000,
B00000000,
B00000000,
B00000000,
B00100010,
B01110110,
B01111110,
B11111111,
};*/

const byte city[] PROGMEM = {8,8,
B00000000,
B00000000,
B00000000,
B00000000,
B01100100,
B01101110,
B01111111,
B11111111,
};

const byte deadcity[] PROGMEM = {8,8,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00100000,
B01100010,
};

const byte launcher[] PROGMEM = {8,8,
B00011000,
B00011000,
B00011000,
B00100100,
B00100100,
B01000010,
B01000010,
B10000001,
};

const byte deadlauncher[] PROGMEM = {8,8,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B01100110,
B01011010,
B10000001,
};

#define SOUND_PLAUNCH 0
#define SOUND_ELAUNCH 1
#define SOUND_DETONATE 2
#define SOUND_SCORE 3
#define SOUND_DEAD 4
#define SOUND_LOSE 5

#define MODE_PREGAME 0
#define MODE_GAME 1
#define MODE_LULL 2
#define MODE_DEAD 3
#define MODE_POSTDEAD 4

#define TARGET_SPEED 3

#define LAUNCHER_ONE 1
#define LAUNCHER_TWO 2
#define MAX_PMISSILES 10
#define PSPEED 4
#define PRADIUS 7
#define EXPAND 0
#define SHRINK 1

#define MAX_EMISSILES 10
#define MAX_CHANCE 50

// State variables
uint8_t mode = 0;
uint8_t counter = 0;
uint8_t flash = 0;
uint8_t stage = 0; //Maximum of 255 stages
uint32_t score = 0; //Score needs more space than other vars

uint8_t lullMissiles = 0;
uint8_t lullCities[8] = {0,0,0,0,0,0,0,0};

uint8_t cities[8] = {1,1,1,1,1,1,1,1}; //Whether the cities or launchers are alive

uint8_t targetX = 84/2;
uint8_t targetY = 48/2;
uint8_t pammo[2] = {10,10};
uint8_t pDests[MAX_PMISSILES][2] = {{100,100},{100,100},{100,100},{100,100},{100,100},{100,100},{100,100},{100,100},{100,100},{100,100}};
float pMissiles[MAX_PMISSILES][3] = {{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0},{100,100,0}};
uint8_t pDetonations[MAX_PMISSILES][4] = {{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0},{100,100,0,0}};

uint8_t etotal = 5;
uint8_t echance = 1;
float espeed = 0.2;
uint8_t eDests[MAX_EMISSILES] = {100,100,100,100,100,100,100,100,100,100};
float eMissiles[MAX_EMISSILES][4] = {{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100},{100,100,100,100}};

void setup() {
  gb.begin();
  loadHighscores();
  gb.titleScreen(armageddon);
  gb.battery.show = false;
  gb.pickRandomSeed();
}

void nextStage(){
  stage++;
  //Reset cities (since we cleared them for the visual effect
  for( uint8_t i = 0; i < 8; i++ ){
    cities[i] = lullCities[i];
  }
  //Reset launchers
  cities[2] = 1;
  cities[5] = 1;
  //Reset missiles
  pammo[0] = 10;
  pammo[1] = 10;
  //Reset in-flight missiles
  for( uint8_t i = 0; i < 10; i++ ){
    pDests[i][0] = 100;
    pDetonations[i][0] = 100;
    eDests[i] = 100;
  }

  etotal = stage > 10 ? 20 : 10+stage; //Max of 20 missiles per stage, start at 10
  //echance = stage > 5 ? 5 : stage; //Max of 5/100 chance per frame
  espeed = stage > 18 ? 2 : 0.2+(stage*0.1); //Max speed of 2, up 0.1 per stage, starts at 0.2
}

void nextLull(){
  //Reset lullMissiles
  lullMissiles = 0;
  //Reset lullCities
  for( uint8_t i = 0; i < 8; i++ ){
    lullCities[i] = 0;
  }
}

void drawScore(){
  gb.display.cursorX = 84/2 - 4*3;
  gb.display.cursorY = 0;

  if( score < 100000 ){
    gb.display.print(0);
  }
  if( score < 10000 ){
    gb.display.print(0);
  }
  if( score < 1000 ){
    gb.display.print(0);
  }
  if( score < 100 ){
    gb.display.print(0);
  }
  if( score < 10 ){
    gb.display.print(0);
  }
  gb.display.print(score);
}

void drawTargets(){
  gb.display.drawFastHLine(targetX-1,targetY,3);
  gb.display.drawFastVLine(targetX,targetY-1,3);

  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
    //Check for a valid destination without a current detonation
    if( pDests[i][0] <= 84 && pDetonations[i][0] > 84 ){
      gb.display.drawPixel(pDests[i][0], pDests[i][1]);
    }
  }
}

void drawCities(){
  //uint8_t alldead = 1;
  for(uint8_t i = 0; i < 8; i++){
      if( i == 2 || i == 5 ){
        if( cities[i] ){
          gb.display.drawBitmap(i*10+2,40,launcher);
        }else{
          gb.display.drawBitmap(i*10+2,40,deadlauncher);
        }
      }else{
        if( cities[i] ){
          //alldead = 0;
          gb.display.drawBitmap(i*10+2,40,city);
        }else{
          gb.display.drawBitmap(i*10+2,40,deadcity);
        }
      }
    }

    /*
    if( alldead ){
      gb.display.cursorX = 84/2 - 5*3;
      gb.display.cursorY = 48/2 - 5;
      gb.display.print("THE END");
    }
    */
}

void drawAmmo(){
  gb.display.setColor(2);
  for( uint8_t i = 0; i < 2; i++ ){
    uint8_t xcoord = i == 0 ? 25 : 55;
    uint8_t ycoord = 47;
    if( cities[i*3+2] ){ //Is launcher alive?
      for( uint8_t j = 0; j < pammo[i]; j++ ){
        gb.display.drawPixel(xcoord,ycoord);
        if( xcoord % 2 == 0 ){
          xcoord--;
          ycoord--;
        }else{
          xcoord++;
        }
      }
    }
  }
  gb.display.setColor(1);
}

void drawMissiles(){
  //Player Missiles
  gb.display.setColor(2);
  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
    //Check for a valid destination without a current detonation
    if( pDests[i][0] <= 84 && pDetonations[i][0] > 84 ){
      if(pMissiles[i][2] == LAUNCHER_ONE){
        gb.display.drawLine(25,40,pMissiles[i][0], pMissiles[i][1]);
      }else{
        gb.display.drawLine(56,40,pMissiles[i][0], pMissiles[i][1]);
      }
    }
  }

  //Enemy Missiles
  gb.display.setColor(3);
  for(uint8_t i = 0; i < MAX_EMISSILES; i++){
    //Check for a valid destination
    if( eDests[i] <= 84 ){
        gb.display.drawLine(eMissiles[i][0],eMissiles[i][1],eMissiles[i][2], eMissiles[i][3]);
    }
  }
  gb.display.setColor(1);
}

void drawDetonations(){
  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
    if( pDetonations[i][0] <= 84 ){
      gb.display.drawCircle(pDetonations[i][0],pDetonations[i][1],pDetonations[i][2]);
    }
  }
}

void launchMissile(uint8_t launcher){
  //If there is no free slot in pDests, do not launch
  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
    if( pDests[i][0] > 84 ){
      // Which launcher?             Alive?       Has ammo?
      if(launcher == LAUNCHER_ONE && cities[2] && pammo[0]){
        pDests[i][0] = targetX;
        pDests[i][1] = targetY;
        pMissiles[i][0] = 25; //X-coord of left launcher
        pMissiles[i][2] = LAUNCHER_ONE; //Launched from launcher one
        pammo[0]--;
        playSound(SOUND_PLAUNCH);
      }else if(launcher == LAUNCHER_TWO && cities[5] && pammo[1]){
        pDests[i][0] = targetX;
        pDests[i][1] = targetY;
        pMissiles[i][0] = 56; //X-coord of right launcher
        pMissiles[i][2] = LAUNCHER_TWO; //Launched from launcher two
        pammo[1]--;
        playSound(SOUND_PLAUNCH);
      }
      pMissiles[i][1] = 40; //Y-coord of both launchers
      break;
    }
  }
}

void tryLaunchEnemy(){
  uint8_t someActive = 0;

  if( etotal > 0 ){

    // Check whether there are any active missiles
    // If none are active, always spawn one to avoid
    // long pauses without any enemy missiles
    for(uint8_t i = 0; i < MAX_EMISSILES; i++){
      if( eDests[i] <= 84 ){
        someActive = 1;
        break;
      }
    }

    if( (!someActive || echance >= random(100)) ){ //echance of 100
      for(uint8_t i = 0; i < MAX_EMISSILES; i++){
        if( eDests[i] > 84 ){
          etotal--;
          eDests[i] = random(8); //Target one of the 6 cities or 2 launch sites
          eMissiles[i][0] = random(84); //Screen width
          eMissiles[i][1] = 0; //Top of screen
          eMissiles[i][2] = eMissiles[i][0]; //Start and end are same
          eMissiles[i][3] = 0; //Top of screen
          playSound(SOUND_ELAUNCH);
          break; //Only spawn one
        }
      }
    }

  }
}

void stepMissiles(){
  //Player Missiles
  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
    //Check for a valid destination without a current detonation
    if( pDests[i][0] <= 84 && pDetonations[i][0] > 84 ){
      //If the missile is close enough to the destination, detonate
      if( abs( pDests[i][0] - pMissiles[i][0] ) < PSPEED && abs( pDests[i][1] - pMissiles[i][1] ) < PSPEED ){
        pDetonations[i][0] = pDests[i][0];
        pDetonations[i][1] = pDests[i][1];
        pDetonations[i][2] = 0; //Start detonation at radius of 0
        pDetonations[i][3] = EXPAND; //Detonation is increasing in size
      //Otherwise, keep moving towards destination
      }else{
        float dir = atan2(pDests[i][1]-pMissiles[i][1], pDests[i][0]-pMissiles[i][0]);
        pMissiles[i][0] += PSPEED * cos(dir);
        pMissiles[i][1] += PSPEED * sin(dir);
      }
    }
  }

  //Enemy Missiles
  for(uint8_t i = 0; i < MAX_EMISSILES; i++){
    //Check for a valid destination
    if( eDests[i] <= 84 ){
       //If enemy missile is close enough to the destination, detonate
      if( abs( (eDests[i]*10+6) - eMissiles[i][2] ) < PSPEED && abs( 44 - eMissiles[i][3] ) < PSPEED ){
        cities[eDests[i]] = 0; //Destroy city/launcher

        //If launcher, remove its ammo
        if( eDests[i] == 2 ){
          pammo[0] = 0;
        }
        if( eDests[i] == 5 ){
          pammo[1] = 0;
        }

        eDests[i] = 100; //Reset enemy missile
        playSound(SOUND_DEAD);
      //Otherwise, keep moving towards destination
      }else{
        float dir = atan2( 44-eMissiles[i][3], (eDests[i]*10+6)-eMissiles[i][2] );
        eMissiles[i][2] += espeed * cos(dir);
        eMissiles[i][3] += espeed * sin(dir);
      }
    }
  }
}

void stepDetonations(){
  if( counter%2 == 0 ){
    for(uint8_t i = 0; i < MAX_PMISSILES; i++){
      if( pDetonations[i][0] <= 84 ){
        if( pDetonations[i][3] == EXPAND ){ //If detonation is expanding
          if( pDetonations[i][2] < PRADIUS ){
            pDetonations[i][2]++;
          }else{
            pDetonations[i][3] = SHRINK; //Start shrinking
          }
        }
        //Check this now instead of using else because it may have just
        //set to SHRINK; immediately checking will remove a delay at full
        //size.  If a delay is desired, this if can be switched to an else.
        if( pDetonations[i][3] == SHRINK ){ //If detonation is shrinking
          if( pDetonations[i][2] > 0 ){
            pDetonations[i][2]--;
          }else{
            pDetonations[i][0] = 100; //Detonation is complete, remove it
            pDests[i][0] = 100; //Remove this destination
          }
        }
      }
    }
  }
}

void stepCollision(){
  //Player Detonations with Enemy Missiles
  for(uint8_t i = 0; i < MAX_PMISSILES; i++){
      if( pDetonations[i][0] <= 84 ){
        for(uint8_t j = 0; j < MAX_EMISSILES; j++){
          if( eDests[j] <= 84 && pDetonations[i][2] >= sqrt( (eMissiles[j][2]-pDetonations[i][0])*(eMissiles[j][2]-pDetonations[i][0]) + (eMissiles[j][3]-pDetonations[i][1])*(eMissiles[j][3]-pDetonations[i][1]) ) ){
            eDests[j] = 100; //Remove enemy missile
            score+=25;
            playSound(SOUND_DETONATE);
          }
        }
      }
  }
}


void checkMenu(){
  if( gb.buttons.pressed(BTN_C) ){
    gb.titleScreen(armageddon);
    gb.battery.show = false;
  }
}

void checkWin(){
  if( etotal == 0 ){
    for(uint8_t i = 0; i < MAX_EMISSILES; i++){
      //Check for a valid destination
      if( eDests[i] <= 84 ){
        return;
      }
    }
    //If we get here, all enemy missiles are destroyed and they have no more
    nextLull();
    mode = MODE_LULL;
  }
}

void checkLose(){
  for(uint8_t i = 0; i < 8; i++){
    if( i != 2 && i != 5 ){
      if( cities[i] ){
        return; // A city remains alive
      }
    }
  }
  //If we get here, all cities are dead.  It is the end of days.
  counter = 0;
  mode = MODE_DEAD;
  playSound(SOUND_LOSE);
}

void stepGame(){
  //Player input
  if( gb.buttons.pressed(BTN_A) ){
    launchMissile(LAUNCHER_TWO);
  }
  if( gb.buttons.pressed(BTN_B) ){
    launchMissile(LAUNCHER_ONE);
  }

  if( gb.buttons.repeat(BTN_LEFT,1) ){
    targetX = targetX-TARGET_SPEED > 0 ? targetX-TARGET_SPEED : 0;
  }
  if( gb.buttons.repeat(BTN_RIGHT,1) ){
    targetX = targetX+TARGET_SPEED < 84 ? targetX+TARGET_SPEED : 84;
  }
  if( gb.buttons.repeat(BTN_UP,1) ){
    targetY = targetY-TARGET_SPEED > 0 ? targetY-TARGET_SPEED : 0;
  }
  if( gb.buttons.repeat(BTN_DOWN,1) ){
    targetY = targetY+TARGET_SPEED < 48 ? targetY+TARGET_SPEED : 48;
  }

  //Game logic
  tryLaunchEnemy();
  stepMissiles();
  stepDetonations();
  stepCollision();

  //Drawing
  drawScore();
  drawTargets();
  drawCities();
  drawAmmo();
  drawMissiles();
  drawDetonations();

  checkWin();
  checkLose();
}

void drawLull(){
  uint8_t cityCount = 0;
  gb.display.cursorX = 84/2 - 4*6;
  gb.display.cursorY = 48/2 - 5*3;
  gb.display.print(("BONUS POINTS"));

  gb.display.cursorX = 84/2 - 4*8;
  gb.display.cursorY += 5*2;
  gb.display.print(lullMissiles);

  for(uint8_t i = 0; i < lullMissiles; i++){
    gb.display.drawPixel(84/2 - 4*6 + i*2,48/2 - 3);
  }

  gb.display.cursorX = 84/2 - 4*8;
  gb.display.cursorY += 5*2;
  for( uint8_t i; i < 8; i++ ){
    if( lullCities[i] ) cityCount++;
  }
  gb.display.print(cityCount);

  for(uint8_t i = 0; i < cityCount; i++){
    gb.display.drawBitmap(84/2 - 4*6 + i*9,48/2+2, city);
  }

  drawScore();
  drawCities();
  drawAmmo();
}

void stepLull(){

  if( counter % 4 == 0 && (pammo[0] > 0 || pammo[1] > 0) ){
    lullMissiles++;
    score+=10;
    if( pammo[0] > 0 ) pammo[0]--;
    else pammo[1]--;
    playSound(SOUND_SCORE);
  }

  //If we have already iterated through the missiles
  if( counter % 8 == 0 && pammo[0] == 0 && pammo[1] == 0 ){
    for( uint8_t i = 0; i < 9; i++ ){
      if( i == 8 ){ //We have iterated through all live cities
        nextStage();
        mode = MODE_GAME;
        return;
      }
      //If not a launcher and the city is alive
      if( i != 2 && i != 5 && cities[i] != 0 ){
        lullCities[i] = 1;
        score+=100;
        cities[i] = 0;
        playSound(SOUND_SCORE);
        break;
      }
    }
  }

  drawLull();
}

void stepDead(){
  gb.display.cursorX = 84/2 - 5*3;
  gb.display.cursorY = 48/2 - 5;
  gb.display.print(("THE END"));

  if( mode == MODE_DEAD && counter%20 == 0 ){
    mode = MODE_POSTDEAD;
  }else if( mode == MODE_POSTDEAD ){
    if( counter%8 == 0 ){
      flash ^= 255;
    }
    if( flash ){
      gb.display.cursorX = 84/2 - 5*3;
      gb.display.cursorY = 48 - 9;
      gb.display.print(("PRESS \25"));

      if( isHighscore(score) ){
        gb.display.cursorX = 84/2 - 5*5 - 2;
        gb.display.cursorY = 48 - 15;
        gb.display.print(("NEW HIGHSCORE"));
      }
    }

    if( gb.buttons.pressed(BTN_A) ){
      if( isHighscore(score) ){
        char tmp_name[11];
        //gb.getDefaultName(tmp_name);
        gb.keyboard(tmp_name, 11);
        //saveHighscore(score,tmp_name);
      }
      score = 0;
      mode = MODE_PREGAME;
    }
  }
}

void stepPregame(){
  drawHighscores();

  if( counter%8 == 0 ){
    flash ^= 255;
  }
  if( flash ){
    gb.display.cursorX = 84/2 - 5*3;
    gb.display.cursorY = 48 - 9;
    gb.display.print(("PRESS \25"));
  }

  if( gb.buttons.pressed(BTN_A) ){
    stage = 255;
    for( uint8_t i = 0; i < 8; i++ ){
      lullCities[i] = 1;
    }
    nextStage(); //Reset to stage 0
    mode = MODE_GAME;
  }
}

void loop() {
  if(gb.update()){

    switch( mode ){
      case MODE_GAME:
        stepGame();
        break;

      case MODE_LULL:
        stepLull();
        break;

      case MODE_DEAD:
      case MODE_POSTDEAD:
        stepDead();
        break;

      case MODE_PREGAME:
        stepPregame();
        break;
    }

    checkMenu();

    counter++;
  }
}
#define NUM_HIGHSCORES 5
#define NAME_SIZE 10
#define ENTRY_SIZE 15

uint32_t highscores[NUM_HIGHSCORES];
char names[NUM_HIGHSCORES][NAME_SIZE+1];

void loadHighscores(){
  for( uint8_t entry = 0; entry < NUM_HIGHSCORES; entry++ ){
    for( uint8_t offset = 0; offset < ENTRY_SIZE; offset++ ){
      if( offset < NAME_SIZE ){
        //names[entry][offset] = EEPROM.read( ENTRY_SIZE * entry + offset );
      }else{
        uint8_t* addr = (uint8_t*) &highscores[entry];
        addr+=offset-NAME_SIZE;
        //*addr = EEPROM.read( ENTRY_SIZE * entry + offset );
      }
    }
  }
}

uint8_t isHighscore(uint32_t score){
  if( score > highscores[NUM_HIGHSCORES-1] ){
    return 1;
  }
  return 0;
}

void saveHighscore(uint32_t score, char* who){
  uint8_t found = 0;
  uint32_t tmp_score = 0;
  char tmp_name[10];
  for( uint8_t entry = 0; entry < NUM_HIGHSCORES; entry++ ){
    if( score > highscores[entry] ){
      found = 1;
    }
    if( found ){
      tmp_score = highscores[entry];
      strcpy(tmp_name,names[entry]);

      highscores[entry] = score;
      strcpy(names[entry], who);

      score = tmp_score;
      strcpy(who, tmp_name);
    }
  }
  for( uint8_t entry = 0; entry < NUM_HIGHSCORES; entry++ ){
    for( uint8_t offset = 0; offset < ENTRY_SIZE; offset++ ){
      if( offset < NAME_SIZE ){
        //EEPROM.write( ENTRY_SIZE * entry + offset, names[entry][offset] );
      }else{
        uint8_t* addr = (uint8_t*) &highscores[entry];
        addr+=offset-NAME_SIZE;
        //EEPROM.write( ENTRY_SIZE * entry + offset, *addr );
      }
    }
  }
}

void drawHighscores(){
  gb.display.cursorX = 84/2 - 5*4;
  gb.display.cursorY = 5;
  gb.display.print(("HIGHSCORES"));

  for( uint8_t entry = 0; entry < NUM_HIGHSCORES; entry++ ){
    gb.display.cursorX = 5;
    gb.display.cursorY = 12 + 5*entry;
    gb.display.print(names[entry]);
    gb.display.print((" "));
    gb.display.cursorX = 84 - 5*6;
    if( highscores[entry] < 100000 ){
      gb.display.print(0);
    }
    if( highscores[entry] < 10000 ){
      gb.display.print(0);
    }
    if( highscores[entry] < 1000 ){
      gb.display.print(0);
    }
    if( highscores[entry] < 100 ){
      gb.display.print(0);
    }
    if( highscores[entry] < 10 ){
      gb.display.print(0);
    }
    gb.display.print(highscores[entry]);
  }
}

// Wave, pitch, duration, arpeggio step duration, arpeggio step size
const int8_t sounds[][5] = {
  { 0, 20, 5, 1, 1 }, //Player launch
  { 0, 25, 5, 1, -1 }, //Enemy launch
  { 1, 10, 5, 1, -1 }, //Detonating enemy missile
  { 1, 10, 2, 0, 0 }, //Score pips
  { 1, 2, 10, 1, -1 }, //A city dies
  { 0, 20, 14, 3, -1 }, //Lose
};

void initSound(){
  gb.sound.command(CMD_VOLUME, 5, 0, 0);
  gb.sound.command(CMD_SLIDE, 0, 0, 0);
}

void playSound(uint8_t i){
  gb.sound.command(CMD_VOLUME, 5, 0, 0);
  gb.sound.command(CMD_SLIDE, 0, 0, 0);
  gb.sound.command(CMD_ARPEGGIO, sounds[i][3], sounds[i][4], 0);
  gb.sound.command(CMD_INSTRUMENT, sounds[i][0], 0, 0);
  gb.sound.playNote(sounds[i][1], sounds[i][2], 0);

  //gb.sound.playNote(20, 5, 0);
}