// Bop It - Play - by Hari Wiguna - March 2000
// Load this as program 2
// It starts playing a rhythmn beat, then plays the "command" that you need to repeat.
// You'd have to repeat it quickly.
// After game ends, you can press the bop it button to start a new game.
#define BOP_IT    SENSOR_1
#define PULL_IT   SENSOR_2
#define TWIST_IT  SENSOR_3

#define BOPPED   1
#define PULLED   0
#define TWISTED  49

#define BOP       2
#define TWIST     3
#define PULL      1

#define __NOTETIME   5
#define __WAITTIME   3

#define INITIAL_SPEED 50
#define THRESHOLD_TIME 10


//=== Globals ===
int gGoal;
int gEndGame;


//=== Functions ===
void PlayBop()
{
  PlayTone(392,1*__NOTETIME); Wait(3*__WAITTIME);
  PlayTone(392,1*__NOTETIME); Wait(3*__WAITTIME);
  PlayTone(392,1*__NOTETIME); Wait(3*__WAITTIME);
}


sub PlayPull()
{
  PlayTone(622,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(587,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(554,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(523,1*__NOTETIME); Wait(1*__WAITTIME);
}


void PlayTwist()
{
  PlayTone(2*523,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(2*554,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(2*587,1*__NOTETIME); Wait(1*__WAITTIME);
  PlayTone(2*622,1*__NOTETIME); Wait(1*__WAITTIME);
}


// Plays one bar of the rhythm
void PlayRhythm(int inSpeed)
{
  #define LEN 4

  PlayTone(31,LEN);  Wait(inSpeed);
  PlayTone(62,LEN);  Wait(inSpeed);

  PlayTone(31,LEN);  Wait(inSpeed/2);  
  PlayTone(31,LEN);  Wait(inSpeed/2);
  
  PlayTone(62,LEN);  Wait(inSpeed);
}


// Plays the rhythm, goal sounds,
// and starts the sensor watch task
task Rhythm()
{
  int tSpeed, i;
  tSpeed = INITIAL_SPEED;
  
  while (true) {
    // Play two bars of the rhythm
    repeat (2) {
      PlayRhythm(tSpeed);
    }
    
    // If by time we're about to play next goal sound
    // player still has not pressed button, it's end of game!
    if ( gGoal != -1 ) {
       EndGame();
    }
    
    // Pick a goal, then play its sound
    gGoal = 1+ Random(2);
    if (gGoal==BOP) {
       PlayBop();
    }
    else {
      if (gGoal==TWIST) {
         PlayTwist();
      }
      else {
        PlayPull();
      }
    }

    // Start timer
    ClearTimer(0);
        
    tSpeed = tSpeed - 1;
  }
}


task ButtonWatcher()
{
  while (true)
  {
    if (BOP_IT == BOPPED)
    {
      PlayBop();
      if ( (gGoal != BOP) || (Timer(0) > THRESHOLD_TIME) ) {
         gEndGame=1;
      }
      else {
        gGoal = -1;
      }
      until (BOP_IT != BOPPED);
    }
    
    if (TWIST_IT > TWISTED)
    {
      PlayTwist();
      if ( (gGoal != TWIST) || (Timer(0) > THRESHOLD_TIME) ) {
         gEndGame=1;
      }
      else {
        gGoal = -1;
      }
      until (TWIST_IT < TWISTED);
    }
    
    if (PULL_IT == PULLED)
    {
      PlayPull();
      if ( (gGoal != PULL) || (Timer(0) > THRESHOLD_TIME) ) {
         gEndGame=1;
      }
      else {
        gGoal = -1;
      }
      until (PULL_IT != PULLED);
    }
  }
}


void StartGame()
{
  // Reset "Score" (number of minutes user lasted in game)
  SetWatch(0,0);

  gEndGame=0;
  gGoal = -1;
  start Rhythm;
  start ButtonWatcher;
}


void EndGame()
{
  // Play end of game sound
  PlaySound(SOUND_DOWN);
  
  // Stop the game
  stop Rhythm;
  stop ButtonWatcher;
}


task main()
{
  SetSensor(BOP_IT,SENSOR_TOUCH);
  SetSensor(PULL_IT,SENSOR_TOUCH);
  SetSensor(TWIST_IT,SENSOR_LIGHT);
 
  while (true)
  {
    StartGame();
  
    // Wait until game over
    until (gEndGame==1);

    EndGame();

    // Wait until user presses and releases start game button
    until (BOP_IT == BOPPED);
    until (BOP_IT != BOPPED);
  }
}