  // copyright (c) 2009, keith drakard
  // this program is distributed under the terms of the creative commons
  // license at http://creativecommons.org/licenses/by-nc-sa/2.0/

  var IMAGESBEFORE= 1; // no of images in html page before the game
  

  // ############### init functions ###################################
  // globals
  var running= 0; var paused= 0;             // game state
  var width= 10; var height= 21;             // board shape 10x21
  var tilex= tiley= 18;                      // tile size
  var color;                                 // the colour of the current piece
  var nextp; var nextc;                      // next piece and colour (used for preview)
  var heap= new Array(width*height);         // the big stack of pieces we all end up with...
  var id;                                    // timeout id (used for pausing/continuing)

  var DOWN= 98; var LEFT= 100; var RIGHT= 102; // key definitions - so if you want to use
  var ROTATE_C= 104; var ROTATE_A= 101;        // different keys, replace these with other
                                               // ASCII values - see play() for more
											   
  var interval;                              // the rate at which pieces fall
  var level= 1;                              // current level and score needed for next level
  var lev= new Array(0,25,60,110,180,280,430,670,970,1340,1760,2290,3000,4000,5000);

  function preload() {
    if (document.images) {
      colour= new makeArray(8);
      colour[0].src= "/wp-content/scripts/images/common/blank.gif";
      colour[1].src= "/wp-content/scripts/images/tetris/grey.gif";
      colour[2].src= "/wp-content/scripts/images/tetris/red.gif";
      colour[3].src= "/wp-content/scripts/images/tetris/orange.gif";
      colour[4].src= "/wp-content/scripts/images/tetris/green.gif";
      colour[5].src= "/wp-content/scripts/images/tetris/purple.gif";
      colour[6].src= "/wp-content/scripts/images/tetris/lblue.gif";
      colour[7].src= "/wp-content/scripts/images/tetris/yellow.gif";  // feel free to make your own colour scheme ;)

    } else {
      alert("Sorry, this game needs to run on a browser\nwhich supports JavaScript 1.2\neg. MSIE4+ or NS4+");
    }
  }


  // ############### movement functions ###############################
  function handleKeyPress(evt) { // written by Eric Pascarello
    nbr = (window.Event) ? evt.which : event.keyCode;
    play(nbr);
    return true;
  }
  document.onkeydown= handleKeyPress;

  function play(key) {
    // if you want to redefine the controls and don't know the
    // keycodes of the new keys, uncomment the line below:
    // alert(key);

    switch(key) {
        case LEFT : move(-1); break;
        case RIGHT : move(1); break;
        case DOWN : move_down(); break;
        case ROTATE_C : rotate(1); break;
        case ROTATE_A : rotate(-1); 
     }

    return(0);
  }

  function rotate(dir) {
    if (block[0]== -1) return(0);

    // to rotate the piece, we need to work out a pivot point
    // in terms of x,y co-ords and swing the piece around this
    // point by applying a transformation to each x,y pair of
    // the piece

    var x= new Array(3); var y= new Array(3);
    var xt= 0; var xp; var xn;
    var yt= 0; var yp; var yn;
    var pos; var newpos= new Array(3);

    // work out the x,y pairs of the piece (4 tiles = 4 pairs...)
    // and sum all the x's together and all the y's together:
    for (var i=0; i<4; i++) {
      x[i]= (block[i]% width);           xt+= x[i];
      y[i]= Math.floor(block[i]/ width); yt+= y[i];
    }

    // now we can work out the average x,y co-ord of the piece:
    xp= Math.floor((xt/ 4)+ 0.5);
    yp= Math.floor((yt/ 4)+ 0.5);

    // and based on this average x,y (the pivot point) we can mess
    // about with the difference between the pivot and the current
    // co-ord of each tile and make it rotate clockwise or anticlockwise:
    for (i=0; i<4; i++) {
      xn= (dir==1) ? (xp- (y[i]-yp)) : (xp+ (y[i]-yp))
      yn= (dir==1) ? (yp+ (x[i]-xp)) : (yp- (x[i]-xp));
      pos= (yn* width)+ xn;

      // and we check if this rotation has brought it outside the
      // bounds of the playing area or into another piece:
      if ((xn<0 || xn>=width) || (yn<0 || yn>=height) || heap[pos]) return(0);

      // if not, we record the new position in terms of board
      // position (not x,y):
      newpos[i]= pos;
    }

    // and if everything's okay, delete the piece from the old position:
    for (var i=0; i<4; i++) {
      document.images["t"+block[i]].src= colour[0].src;
    }
    // and re-display it at the new:
    for (i=0; i<4; i++) {
      block[i]= newpos[i];
      document.images["t"+newpos[i]].src= colour[color].src;
    }    
    return(1);
  }

  function move(dir) {
    if (block[0]== -1) return(0);

    // check if moving in dir would hit the edge or another block:
    for (var i=0; i<4; i++) {
      edge= (dir==1) ? ((block[i]% width)== width-1) : ((block[i]% width)== 0)
      if (edge || heap[block[i]+dir]) return(0);
    }

    // nope, it's safe to re-display the piece:
    display(dir);
    return(1);
  }

  function move_down() {
    if (block[0]== -1) return(0);

    // check if the piece has hit the bottom row or
    // if it now intersects with the heap of old pieces:
    for (var i=0; i<4; i++) {
      if ((block[i]>= (height-1)*width) || (heap[block[i]+width])) {
        // yep, that's it for this piece:
        if (document.user.scoring.checked) {
          document.user.score.value= document.user.score.value*1 +level;
        }
        merge(); return(0);
      }
    }

    // nope, it's safe to re-display the piece:
    display(width);
    return(1);
  }


  // ############### display function #################################
  function display(modifier) {
    // this is done in two steps for a reason... if you're curious,
    // edit this to do it in one loop and watch the effect :)

    // delete the piece from old position:
    for (var i=0; i<4; i++) {
      document.images["t"+block[i]].src= colour[0].src;
    }

    // and re-display it at the new:
    for (i=0; i<4; i++) {
      block[i]+= modifier;
      document.images["t"+block[i]].src= colour[color].src;
    }
  }


  // ############### heap functions ###################################
  function merge() {
    var count; var x = 0;
  
    for (i = 0; i < 4; i++) {
      heap[block[i]] = 1; block[i] = -1;
    }
  
    for (y = 0; y < height; y++) {
      count = 0;
      while (heap[(y * width) + x]) { count++; x++; }
  
      if (count >= width) {
        for (x = (y * width); x < (y * width) + width; x++) {
          document.images["t"+x].src = colour[color].src;
        }
        score(height - y);
        setTimeout('del('+y+')', 50);
      }
      x = 0;
    }
  }


  function del(y) {
    var ymod;
    
    // remove the row:
    for (var x= (y*width); x< (y*width)+width; x++) {
      document.images["t"+x].src= colour[0].src;
      heap[x]= 0;
    }

    // and, starting from the row above, see if we need
    // to drop tiles down into gaps:
    for (var c=(width*y)-1; c>=0; c--) {
      if (heap[c]) {
        // okay, we know we're on a tile - is there room below?

        while (!heap[c+width]) {
          // yes - move the tile down:
          document.images["t"+(c+width)].src= document.images["t"+c].src;
          document.images["t"+c].src= colour[0].src;
          heap[c+width]= 1; heap[c]= 0;
        }
      }
    }
  }


  // ############### scoring functions ################################
  function score(modifier) {
    // add some points to the score, depending on:
    // the height of the row, the current level,
    // whether we're previewing the next piece _and_
    // whether we're just counting rows completed...

    var cs= (document.user.score.value)* 1;

    if (document.user.scoring.checked) {
      // fancy scoring :)

      var score= (Math.floor(modifier/ 5)+ 1)* level;
      if (document.user.preview.checked) score= Math.floor(score/2 +0.5);
      cs+= score; if (cs> lev[level] && level<15) level++;

    } else {
      // just rows completed      
      cs+= 1; if (cs> ((lev[level]/10) * 3) && level<15) level++;
    }

    // update score and level:
    document.user.score.value= cs;
    document.user.level.value= level;

    // gives about 10-14 levels before it becomes too quick...
    interval= 300- (20*level);

  }


  // ############### main loop ########################################
  function step() {
    // main loop - if a piece is in play, move it down
    // otherwise, try to make a new one...

    if (block[0]!= -1) {
      // piece in play, so move it down and do this again:
      move_down();
      id= setTimeout('step()', interval);

    } else {
      // no piece in play atm, so see if we can make one:

      if (newpiece(nextp)) {
        // new piece has been created, so display it:
        nextp= rand(7); nextc= rand(7); preview();
        id= setTimeout('step()', interval);

      } else {
        // can't create new piece, so that's it for this game:
        color= rand(7);
        for (var c=0; c<(width*height); c++) {
          if (heap[c]) document.images["t"+c].src= colour[color].src;
        }
        for (var i=0; i<8; i++) {
          document.images["preview"+i].src= colour[0].src;
        }
        document.user.b.value= " New Game "; running= 0;
        // without setting block to null, we're unable to reset it after the first game...
        block= null;
      }
    }
  }


  // ############### miscellaneous stuff ##########################
  function newpiece(flag) {
    var w= (flag) ? flag : rand(7)
    var m= rand(width-3);

    // what piece have we got?
    switch (w) {
      case 1 : block[0]=  8; block[1]= 18;
               block[2]= 28; block[3]= 38;
               break;
      case 2 : block[0]=  7; block[1]=  8;
               block[2]=  9; block[3]= 17;
               break;
      case 3 : block[0]=  7; block[1]=  8;
               block[2]=  9; block[3]= 19;
               break;
      case 4 : block[0]=  8; block[1]= 17;
               block[2]= 18; block[3]= 28;
               break;
      case 5 : block[0]=  7; block[1]= 17;
               block[2]= 18; block[3]= 28;
               break;
      case 6 : block[0]=  8; block[1]= 17;
               block[2]= 18; block[3]= 27;
               break;
      case 7 : block[0]=  7; block[1]=  8;
               block[2]= 17; block[3]= 18;
    }

    for (var i=0; i<4; i++) {
      // move piece's starting position by the random modifier:
      block[i]-= m;

      // and check if we've hit another piece:
      if (heap[block[i]]) return(0);
    }

    // otherwise, we've successfully created a new piece:
    if (flag) {
      color= nextc;
      for (var i=0; i<4; i++) {
        document.images["t"+block[i]].src= colour[color].src;
      }
    }

    return(w); 
  }

  function preview() {
    var c= colour[nextc].src;
    for (var i=0; i<8; i++) { document.images["preview"+i].src= colour[0].src; }

    if (!document.user.preview.checked) return(0);

    // note that this preview bit does rely on the pieces being
    // defined in a particular order...
    if (nextp!= 5)   document.images["preview0"].src= c;
                     document.images["preview1"].src= c;
    if (nextp< 6)    document.images["preview2"].src= c;
    if (nextp== 1)   document.images["preview3"].src= c;
    if (nextp== 2 || nextp== 5 || nextp== 7) document.images["preview4"].src= c;
    if (nextp> 3)    document.images["preview5"].src= c;
    if (nextp%3== 0) document.images["preview6"].src= c;

    return(1);
  }

  function newgame() {
    if (!running) {
      if (!paused) {

        // same options so just reset the board
        document.user.score.value= 0;
        document.user.level.value= 1;
        block= new Array(3); // holds position info for piece in play
        for (var i=0; i<4; i++) { block[i]= -1; }
        for (var c=0; c<(width*height); c++) {
          document.images["t"+c].src= colour[0].src;
          heap[c]= 0;
        }
        nextc= rand(7); newpiece(rand(7));
        nextp= rand(7); nextc= rand(7); preview(nextp);
        level= 1; interval= 300;
      }
      // unpause game (even if it wasn't paused before)
      running= 1; paused= 0;
      document.user.b.value= " Pause ";
      id= setTimeout('step()', interval*2);

    } else {
      // pause game:
      running= 0; paused= 1;
      document.user.b.value= " Continue ";
      clearTimeout(id);
    }
  }

  function help() {
    alert("Tetris v0.40 by Keith Drakard (kif@irt.org) 27/11/98\n\nKeys:\tUse the keypad (make sure the 'Num Lock' is on) -\n\tMove left= 4, right= 6, down= 2\n\tRotate clockwise= 8, anticlockwise= 5\n\nScoring:\tIf 'Scoring' is on, then you get points for each piece\n\tand each row that you fill, depending on the height\n\tof that row and your current level.\n\tIf 'Scoring' is off, then you just score 1 point for each\n\trow filled.\n\nTo Play:\tFill as many rows as you can by guiding the various\n\tpieces falling from the top into suitable positions at\n\tthe bottom.\n\tAs your score increases, so does the rate at which\n\tthe pieces fall...\n\n\tTo quit a game, simply press the down key for a\n\twhile.\n");
  }

  // The Central Randomizer 1.3 (C) 1997 by Paul Houle (houle@msc.cornell.edu)
  // See:  http://www.msc.cornell.edu/~houle/javascript/randomizer.html
  // NOTE:- this example is set up to produce integers between 1-limit
  rnd.today=new Date(); rnd.seed=rnd.today.getTime();
  function rnd() {
    rnd.seed = (rnd.seed*9301+49297) % 233280;
    return rnd.seed/(233280.0);
  }
  function rand(limit) {
    return Math.ceil(rnd()*limit);
  }

  // The following functions were written by Martin Webb at http://www.irt.org/
  function makeArray(n) {
    this.length= n; for (i=0; i<n; i++) { this[i]= new Image(); }
    return this;
  }

  
  
  function initialise() {
  var output= '';
  output+= '<form name="user">';
  output+= '<table align=center cellspacing=0 cellpadding=0 border=0>\n';

  // create the board
  output+= '<tr bgcolor="#333300"><td rowspan=7><table cellpadding=8 cellspacing=0 border=0>\n';
  output+= '<tr bgcolor="#000055"><td><table cellspacing=0 cellpadding=0 border=0>\n';
  for (y=0; y<height; y++) {
    for (x=0; x<width; x++) {
      if (x== 0) output+= '<tr>';
      output+= '<td><img src="/wp-content/scripts/images/common/blank.gif"';
      output+= ' name="t'+((y*width)+x)+'" width='+tilex+' height='+tiley+' alt="" border=0></td>';
      if (x== width-1) output+= '</tr>\n';
    }
  }
  output+= '</table></td></tr></table></td><td rowspan=7>&nbsp;&nbsp;&nbsp;</td>\n';

  // create the ui
  output+= '<td bgcolor="#333300" valign=middle align=center>';
  output+= '<table bgcolor="#000033" cellspacing=0 cellpadding=0 border=0>\n';
  output+= '<tr><td>&nbsp;</td>'
  for (var i=0; i<8; i++) {
    output+= '<td><img src="/wp-content/scripts/images/common/blank.gif" name="preview'+i+'" ';
    output+= 'width='+tilex+' height='+tiley+' alt="" border=0></td>';
    if (i==3) output+= '<td>&nbsp;</td></tr>\n<tr><td>&nbsp;</td>';
  }
  output+= '<td>&nbsp;</td></tr>\n';
  output+= '</table></td></tr>\n';

  // note you need to blur() these otherwise netscape won't detect key presses...
  output+= '<tr bgcolor="#333300"><td align=center>score: <input type="text" size="4" name="score" value=0 onFocus="blur()"></td></tr>\n';
  output+= '<tr bgcolor="#333300"><td align=center>level: <input type="text" size="2" name="level" value=1 onFocus="blur()"></td></tr>\n';
  output+= '<tr bgcolor="#333300"><td align=center><input type="button" name="b" value=" new game " onClick="newgame()" onFocus="blur()"></td></tr>\n';
  output+= '<tr bgcolor="#333300"><td align=center>preview? <input type="checkbox" size=2 name="preview" checked onFocus="blur()"></td></tr>\n';
  output+= '<tr bgcolor="#333300"><td align=center>scoring? <input type="checkbox" size=2 name="scoring" checked onFocus="blur()"></td></tr>\n';
  output+= '<tr bgcolor="#333300"><td><img src="/wp-content/scripts/images/common/blank.gif" alt="" width=120 height=1></td></tr>\n';

  output+= '</table></form>\n';

  document.write(output);
  preload();
}