//// Quiz 71t example.
//// B.A.Martin

String author=  "B.A.Martin";
String title=  "Quiz example:  Under the Sea (with bombs)";
String news="";

int score=0;
float rate, oldrate;
boolean debug=false;
boolean pause=false;

int wide=800, high=600;
float surface=  high/4;
float cloudX=20, cloudY=20, cloudDX=0.4, cloudDY=0.2;

float boatX=0, boatY=surface, boatDX=0.5;
float fish1X,fish1Y, fish2X,fish2Y, fish3X,fish3Y, fish4X,fish4Y;
float fish1DX, fish2DX, fish3DX, fish4DX;
float fish1M=1, fish2M=0.8, fish3M=1.2, fish4M=2;
String name1=  "Charlie";
String name2=  "Oscar";
String name3=  "Nemo";
String name4=  "MEGALODON";

float bombX=wide/2, bombY=high-80, bombDY=0;
int bombLaunch=0,bombCount=0;



String button1String="  GO"; 
String button2String="CATCH"; 
String button3String="RESET"; 
String button4String="BOMB"; 

float button1X=50, button1Y=40;
float button2X=150, button2Y=40;
float button3X=250, button3Y=40;
float button4X=550, button4Y=80;

//// SETUP: screen size
void setup() {
  size( 800, 600 );
  oldrate=  rate=  frameRate;
  surface=  height/4;
  reset();
  key=  '=';
}
void reset() {
  score=0;
  resetFish1();
  resetFish2();
  resetFish3();
  resetFish4();
}


//// NEXT FRAME ////
void draw() {
  if (key=='=') { showQuiz(); return; }
  //
  scene();
  if (keyPressed && key=='?') help();
  else 
  {
    if ( pause) {
      fill(0);
      textSize(20);
      text( "PAUSED.", wide/2, high/2 ); 
      textSize(12);
      text( "(Press 'p' key again to continue", wide/2, 24+high/2 ); 
    }
    else {
      show();
      action();
      buttons();
    }
  }
  dialog();
}

//// SCENE:  sky & sea.
void scene() {
  background( 150, 200, 250 );
  fill( 0, 150, 50 );
  rectMode( CORNERS );
  rect( 0,surface, width, height );
  showCloud( cloudX, cloudY );
}
void showCloud( float x, float y ) {
  fill( 220,220,220, 200 );
  noStroke();
  ellipse( cloudX,cloudY, 100, 50 );
  ellipse( cloudX-30,cloudY-20, 60, 30 );
  ellipse( cloudX+30,cloudY+20, 60, 30 );
  stroke(0);
}


//// SHOW:  Display boat & fishes (and bomb).
void show() {
  showBoat( boatX, surface, boatDX );  
  //
  fill( 255, 200, 200 );            // Pink fish
  showFish( name1, fish1X, fish1Y, fish1M );
  fill( 150, 150, 50 );            // Yellow fish
  showFish( name2, fish2X, fish2Y, fish2M );  
  fill( 100, 100, 200 );           // Blue fish
  showFish( name3, fish3X, fish3Y, fish3M );  
  fill( 50, 100, 150, 127 );        // Huge, gray, transparent fish
  showFish( name4, fish4X, fish4Y, -fish4M );  
  //
  showBomb( bombX, bombY );
}
void showBoat( float x, float y, float speed ) {
  // There is no boat unless it is moving!
  if (speed == 0) return;
  fill( 0,0,255 );
  rectMode(CORNER );
  rect( x, y, 100, -30 );
  rect( x+30, y-30, 40, -15 );    // cabin
  // Now, draw the pointy bow.
  if (speed>0) {
    triangle( x+100,surface, x+140,surface-30, x+100,surface-30 );
    line( x+50,surface-45, x+30,surface-80 );
  }
  if (speed<0) {
    triangle( x,surface, x,surface-30, x-30,surface-30 );
    line( x+50,surface-45, x+70,surface-80 );
  }
}
//// Draw one fish.
void showFish( String name, float x, float y, float m ) {
  triangle( x-m*30,y, x-m*50,y-m*15, x-m*50,y+m*15 );       // Tail
  ellipse( x,y, m*80,m*30 );                          // Body (on top of tail
  // flipper
  int position=  int(x) / 100;
  if ( position % 2 == 0) {               // Even or odd 100s for x.
    triangle( x,y, x+20,y, x+10,y-m*20 );   // Flipper is up
  }else{
    triangle( x,y, x+20,y, x+10,y+m*20 );   // Flipper is up
  }
  //// Name of fish
  fill(0);
  text( name, x-35, y+5 );
  // Eye.
  fill(255);
  ellipse( x+(m*30),y-6, 8,8 );
}
void showBomb( float x, float y )
{
  fill( 250,100,0);
  if (bombDY != 0) fill( 150+random(100), 50+random(100), random(50) );      // Flicker while moving
  triangle( x,y-20, x-30,y+35, x+30,y+35 );
  ellipse( x,y, 40,80 );
  fill(0);
  textSize(20);
  if (bombCount>0) text( bombCount, x-15, y+5 );
  textSize(12);
  if (bombLaunch>0) text( "/" + bombLaunch, x-10, y+20 );
}  

//// Display the buttons;  GO and CATCH.
void buttons() 
{
  fill( 0, 255, 0 );
  showButton( button1String, button1X, button1Y );
  fill( 255, 0, 255 );
  showButton( button2String, button2X, button2Y );  
  fill( 255, 255, 0 );
  showButton( button3String, button3X, button3Y );  
  fill( 250, 100, 0 );
  showButton( button4String, button4X, button4Y );  
}
void showButton( String s, float x, float y ) {
  strokeWeight(3);
  rectMode(CORNER);
  rect( x,y, 80, 30, 30 );
  strokeWeight(1);
  fill(0);
  text( s, x+10, y+20 );
}


//// ACTION:  Move boat & fish.  Check for hits. ////
void action() {
  // Move the cloud; bounce off surface, top, and sides;
  moveCloud();
  // Move the boat (if DX <> 0)
  moveBoat();
  // Make fish swim; reset fish when it reaches right side.
  fish1X += fish1DX;
  fish2X += fish2DX;
  fish3X += fish3DX;
  fish4X += fish4DX;
  if (fish1X>width) resetFish1();
  if (fish2X>width) resetFish2();
  if (fish3X>width) resetFish3();
  if (fish4X<0) {  resetFish4();  }
  //// Bomb. ////
  if (bombDY<0) {
    bombY +=  bombDY;
    bombDY = bombDY - 0.5;              // Acceleration.
    stroke(0,200,150);
    line(bombX,bombY, boatX+50,surface);
    stroke(0);
  }
  if (bombY<surface) {
    // Did it hit the boat?
    strokeWeight(6);
    if (abs(bombX-50-boatX)<100) {
      resetBoat();
      score -= 50;
      ++bombCount;
    }
    // New bomb at bottom.
    bombX=  random( 50, wide-50 );
    bombY=  high-80;
    bombDY=0;
  }   
}
void moveCloud() {
  cloudX=  cloudX + cloudDX;
  if (cloudX<0) cloudDX *= -1;
  if (cloudX>wide) cloudDX *= -1;
  cloudY=  cloudY + cloudDY;
  if (cloudY<0) cloudDY *= -1;
  if (cloudY>surface) cloudDY *= -1;
}
void moveBoat() {
  boatX=  boatX + boatDX;
  if (boatX>width) {
    // Turn boat around, when at right side.
    boatDX=  -boatDX; 
    news="(BOAT is now heading BACK.)"; 
  }
  if (boatX<0) {
    // Stop the boat when it reaches left side.
    boatDX= 0;
    news=""; 
  }
}
void resetBoat() {
    boatX=  5;
    boatDX=  random( 0.1, 0.8 );
    int knots= int(boatDX*10);
    news="(BOAT is heading out (at "+ knots +" knots)\nClick CATCH button to catch fish below.)"; 
    score = score -knots;
}


//// Reset fish to left, with random height and speed.
void resetFish1() {
  fish1X=  0;
  fish1Y=  random( surface+30, height-30 );
  fish1DX=  random( 1, 5 );
  if (debug) println( "fish1:  " + fish1Y +"  speed="+ fish1DX );
  fish1M=  random(0.6,1.2 );
}
void resetFish2() {
  fish2X=  0;
  fish2Y=  random( surface+30, height-30 );
  fish2DX=  random( 1, 5 );
  if (debug) println( "fish2:  " + fish2Y +"  speed="+ fish2DX );
  fish3M=  random(0.6,1.2 );
}
void resetFish3() {
  fish3X=  0;
  fish3Y=  random( surface+30, height-30 );
  fish3DX=  random( 1, 5 );
  if (debug) println( "fish3:  " + fish3Y +"  speed="+ fish3DX +"\n" );
  fish3M=  random(0.6,1.2 );
}
void resetFish4() {
  fish4X=  wide+200;
  fish4Y=  random( surface+30, height-30 );
  fish4DX=  - random( 0.5, 3 );
  if (debug) println( "fish4:  " + fish4Y +"  speed="+ fish4DX +"\n" );
  fish4M=  random(1.5, 3.0 );
}


//// Put some text on the screen..
void dialog() {
  fill( 0 );
  text( title, width/3, 20 );
  text( title, width/3, 20 );
  if (score<0) fill( 255,0,0 );
  if (score != 0) text( "SCORE:  " + score, width*3/4, 40 );
  fill(255,255,0);
  text( news, width/4, surface+12 );
  //
  fill(150,0,0);
  text( author, 20, height-20 );
  fill(150,0,0);
  text( "Press 'q' key to quit.", width*2/3, height-40 );
  text( "Hold '?' key for help.", width*2/3, height-25 );
  text( "    Press = key to see quiz instructions.", width*2/3, height-10 );
}
void help() {
  float x=50, y=height-200, dy=18, n=0;
  fill(250,200,250);
  textSize(16);
  String s;
  s=  "Click GO button to start ship moving.";
  text( s, x, y+dy*n++ );
  s=  "Click CATCH button to catch fish below the boat.";
  text( s, x, y+dy*n++ );
  textSize(12);
  s=  "  (Score 10 points per fish; -1 per attempt, -1 per knot.)";
  text( s, x, y+dy*n++ );
  //
  textSize(12);
  ++n;
  s=  "  d for debug";
  text( s, x, y+dy*n++ );
  s=  "frameRate="+ int(frameRate+0.5);
  s +=  "    +/-/0 for faster/slower/reset";
  text( s, x, y+dy*n++ );
}


//// EVENT HANDLERS ////
void mousePressed() {
  if (overButton( button1X, button1Y )) {  resetBoat();  }        // GO BUTTON (1) //
  if (overButton( button2X, button2Y )) {  catchFish(boatX+50); } // CATCH BUTTON (2) //
  if (overButton( button3X, button3Y )) {  reset();      }        // RESET BUTTON (3) //
  if (overButton( button4X, button4Y )) {  bombStart();  }        // BOMB BUTTON (3) //
  //   Also accept clicks on boat or bomb.
  if (dist(mouseX,mouseY, boatX+50,boatY)<30) {  catchFish(boatX+50);  }
  if (dist(mouseX,mouseY, bombX,bombY)<30) {  bombStart();  }
  //
  if (dist(mouseX,mouseY, fish1X,fish1Y)<30) {  resetFish1();  }
  if (dist(mouseX,mouseY, fish2X,fish3Y)<30) {  resetFish2();  }
  if (dist(mouseX,mouseY, fish3X,fish3Y)<30) {  resetFish3();  }
  if (dist(mouseX,mouseY, fish4X,fish4Y)<30) {  resetFish4();  }
}
//// Return true if mouse is over button.
boolean overButton( float x, float y ) {
  return(  mouseX>x && mouseX<x+80
        && mouseY>y && mouseY<y+30 );
}  


//// CATCH:  Try to catch each fish.
void catchFish(float x) {
    news+= "\nCATCH:  ";
    score = score - 1;        // Deduct one per click.
    ray( x );                 // Draw a ray (from surface to bottom );   
    //
    if ( boatDX==0) {
      news=  "*** You can't catch fish when there is no BOAT! ***\n     (-25 points.)";
      score=  score - 25;
      return;  // (Boat must be moving to catch fish.)
    }
    // Check each fish:  catch & reset if boatX is near it!
    if ( abs(x-fish1X) < 30) { 
      news +=  name1 +" was caught!  ";
      resetFish1();
      score+=10; 
    }
    if ( abs(x-fish2X) < 30) { 
      news +=  name2 +" was caught!  ";
      resetFish2(); 
      score+=10;
    }
    if ( abs(x+50-fish3X) < 30) { 
      news +=  name3 +" was caught!  ";
      resetFish3(); 
      score+=10; 
    }
    if ( abs(x+50-fish4X) < 30) { 
      news +=  name4 +" was caught!  ";
      resetFish4(); 
      score+=20; 
    }
}
void ray( float x ) {
    // Draw a ray downward!
    strokeWeight(5);
    stroke(255,255,0);
    line( x,surface, x,height );
    strokeWeight(1);
    stroke(100,255,100);
    line( x+30,surface, x+30,height );
    line( x-30,surface, x-30,height );
    stroke(0);    
}
void bombStart() {
    bombDY=  -4;    // Bomb starts moving upward.
    ++bombLaunch;
}  
void keyPressed() {
  if (key == 'q') {  exit();  }
  if (key == 'd') {  debug=  ! debug;  }
  if (key == 'p') {  pause=  ! pause;  }
  //
  // Buttons:  GO, CATCH, RESET, BOMB.
  if (key == 'g') { resetBoat();  }        // GO
  if (key == 'c') { catchFish(boatX+50); } // CATCH
  if (key == 'r') { reset();      }        // RESET
  if (key == 'b') { bombStart();  }        // BOMB
  //
  if (key == '+') {  rate=rate*2; frameRate(rate); }
  if (key == '-') {  rate=rate/2; frameRate(rate); }
  if (key == '0') {  rate=oldrate; frameRate(rate); }
}



/*********************/
String NL="\n";
float quizX,quizY, quizH=16;
void showQuiz() {
  background(255);
  quizX=10;
  quizY=50;
  textSize(24);
  fill(0,0,255);
  text( "INSTRUCTIONS FOR QUIZ:", width/6, 25 );
  textSize(20);
  qq("Start with a copy of your Project 2 code, then add new code for these features.");
  textSize(quizH);
  fill(0,150,150);
  qq("NOTE:  [[ Features already in Project 2 are noted in Double-brackets. ]]");
  q();
  q();
  //
  fill(100,0,0);
  qqq();            // Display instructions for quiz.
  {
    textSize(16);
    fill( 255,0,0 );
    text( "UPLOAD YOUR IN-CLASS CODE AS:  XYquiz.pde   ", wide/8, high-35 );
    textSize(12);
    text( "UPLOAD YOUR TAKEHOME CODE AS:  XYtakehome.pde   ", wide/8, high-20 );
    text( "    (where X and Y are YOUR first and last initials.)", wide/8, high-5 );
  }
 textSize(12);
 fill( 255,0,255 );
  text( "(Press another key to resume.)", wide-250, high-5 );
}
void qq( String s ) {
  text( s, quizX, quizY );
  quizY += quizH+2;
}
void q() {
  quizY += quizH/2;
}  
void qqq() {
  int n=0;
  qq(++n+".  ANTENNA:  Add an antenna at the top of the boat's cabin:  just a black line, leaning backward.");
  qq("     Make the antenna lean to the left as the boat moves right, and lean right as boat moves left.");
  q();
  qq(++n+".  CLOUD:  Add a slowly moving cloud, bouncing around in the sky.");
  qq("     Reverse vertical direction when cloud hits surface or top; reverse horizontal at left or right side.");
  fill(0);
  qq("           Suggested declaration:  float cloudX=20, cloudY=20, cloudDX=0.4, cloudDY=0.2;");
  fill(100,0,0);
  q();
  qq(++n+".  ANIMATE FISH:  Triangular flipper flaps UP or DOWN every 100 pixels, as fish swims to the right.");
  qq("     [[ Each fish has a different color and a different name displayed on it. ]]");
  q();
  qq(++n+".  NEW BUTTONS:   RESET  and  BOMB  [[in addition to your GO and CATCH buttons]].");
  qq("     You may also use keys (r, b, g, and c) to do the same thing as the buttons.");
  q();
  qq(++n+".  RESET:  Reset all 3 fish to left side, at random height, with random speed,");
  qq("     when RESET button is clicked (or when 'r' key is pressed).");
  q();
  qq(++n+".  BOMB:  Draw an orange bomb sitting near the bottom, at a random x value.");
  qq("     Bomb starts accelerating upward when BOMB button is clicked (or 'b' key is pressed),");
  q();
  qq(++n+".  When bomb reaches surface, check if boat was hit (then place new bomb near bottom, random x).");
  qq("     If bomb hits the boat, deduct 50 points from score and reset the boat.");
  qq("     [[ Boat starts from left, with random speed, when GO is clicked (or 'g' key pressed). ]]");
  q();
  qq(++n+".  Count number of bomb launches & bomb hits (on the boat; display both numbers on the bomb.");
  q();
  qq(++n+".  OPTIONAL (extra credit):");
  qq("     Add a fourth fish, much larger, and swimming right to left.");
  qq("     Click boat to catch fish; click any fish to reset that fish (only); click bomb to start it.");
  q();
  q();
  fill(0,0,250);
  qq("SUGGESTION:  Write a separate function for each new feature, then call it from your existing code.");
  fill(0);
}

