//------------------------------------------------------------------------------ // Tetris //------------------------------------------------------------------------------ Program tetris; const HIGH = 20; WIDE = 10; global //GP Keys __A = _control; __B = _alt; __SELECT = _space; __R = _tab; __L = _backspace; __START = _enter; //High scores for all 3 difficulties highscore[2]; //Current difficulty difficulty; graad[2]; BLOKSPEED = 15; drawmode = 1; blok[10][5][5]; //Available //upcoming block type next = 0; //Current block type nu = 1; //position of the current block nux = 6; nuy = 7; //which way it is rotated kant; //Scoring: ScoreVolleRij = 100; ScoreZomaar = 2; //declare the playfield steen[HIGH][WIDE]; //Statistics: score; level; //Loading stuff fpg; music; n; begin //Set the text color set_text_color(rgb(0,0,255)); //initialize screen full_screen = false; set_mode(m320x240); fill_map(); //Load graphics fpg = load_fpg("tetris.fpg"); //Start up: //Scorelist //Load highscores from file: if there is no such file create one: if(!file_exists("scores.dat")); save("scores.dat",highscore); end load("scores.dat",highscore); //Create the blocks: n = 0; // OO // OO // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 1; blok[n][1][3] = 1; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 0; blok[n][2][2] = 1; blok[n][2][3] = 1; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 0; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; n++; //Blokkie 1: // O // O // OO // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 0; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 1; blok[n][2][2] = 1; blok[n][2][3] = 1; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 0; blok[n][3][3] = 1; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; // O // OOO n++; // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 1; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 1; blok[n][2][2] = 1; blok[n][2][3] = 1; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 0; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; n++; // OOOO // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 1; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 1; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 0; blok[n][2][2] = 1; blok[n][2][3] = 0; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 1; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; n++; // OO // OO // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 1; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 1; blok[n][2][2] = 1; blok[n][2][3] = 0; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 1; blok[n][3][2] = 0; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; //End easy difficulty, coming blocks are for medium graad[0] = n+1; n++; // O O // OOO // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 1; blok[n][1][2] = 0; blok[n][1][3] = 1; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 1; blok[n][2][2] = 1; blok[n][2][3] = 1; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 0; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; n++; // O // OOO // O // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 0; blok[n][1][2] = 1; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 1; blok[n][2][2] = 1; blok[n][2][3] = 1; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 1; blok[n][3][3] = 0; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; //End of medium, upcoming are for hard graad[1] = n+1; n++; // O // O // O // H V blok[n][0][0] = 0; blok[n][0][1] = 0; blok[n][0][2] = 0; blok[n][0][3] = 0; blok[n][0][4] = 0; blok[n][1][0] = 0; blok[n][1][1] = 1; blok[n][1][2] = 0; blok[n][1][3] = 0; blok[n][1][4] = 0; blok[n][2][0] = 0; blok[n][2][1] = 0; blok[n][2][2] = 1; blok[n][2][3] = 0; blok[n][2][4] = 0; blok[n][3][0] = 0; blok[n][3][1] = 0; blok[n][3][2] = 0; blok[n][3][3] = 1; blok[n][3][4] = 0; blok[n][4][0] = 0; blok[n][4][1] = 0; blok[n][4][2] = 0; blok[n][4][3] = 0; blok[n][4][4] = 0; //End of hard difficulty graad[2] = n+1; //initialize score = 0; level = 0; //Fire up the menu Menu(); end /* basic menu, option to select difficulty and view the corresponding highscore */ Process Menu() private i; String graden[2] = "Easy","Medium","Hard"; text,tex2; begin //Empty playfield for(x=0;x1) difficulty--; delete_text(text); delete_text(tex2); text = write(0,220,190,5,graden[difficulty-1]); tex2 = write_int(0,220,210,5,&highscore[difficulty-1]); while(key(_left))frame;end end //Switch difficulty and fix variables according to that if(key(_right) and difficulty<3) difficulty++; delete_text(text); delete_text(tex2); text = write(0,220,190,5,graden[difficulty-1]); tex2 = write_int(0,220,210,5,&highscore[difficulty-1]); while(key(_right))frame;end end //break out of the loop if the game is started if(key(__START)) break; end //and exit if select is pressed if(key(__SELECT)) exit("",0); end frame; end //START GAME //============ //Limit the frames per second related to the difficulty, to make the game faster //for higher and slower for lower difficulty set_fps(20+difficulty*7,0); //delete all menu text delete_text(all_text); //process to render playfield to the screen Render(); //write game texts write_int(0,280,100,4,&score); write(0,280,90,4,"Score:"); write(0,280,130,4,"Level:"); write_int(0,280,140,4,&level); //and fire up the game logic game(); end /* Renders the level/next-block-preview/current block to the screen every frame. */ process Render(); private i,j,k,l,block; begin //nux = 5;nuy=7; loop //select key to exit to the main menu, exit everything and start the menu. if(key(__SELECT)) while(key(__SELECT))frame;end clear_screen(); delete_text(all_text); score = 0; difficulty = 0; let_me_alone(); menu(); return; end //Rendering level: for(i = 0;i < HIGH+2;i++) for(j = 0;j < WIDE+2;j++) block = 0; if(i == 0 or i == HIGH+1 or j == 0 or j == WIDE+1) block = 1; else block = steen[i-1][j-1]; end if(block == 0) block = 10; end put(fpg,block,80+((j-WIDE/2)*8),120+((i-HIGH/2)*8)-8); end end if(drawmode) for(i = 0;i < 5+2;i++) for(j = 0;j < 5+2;j++) block = 0; if(i == 0 or i == 5+1 or j == 0 or j == 5+1) block = 1; else if(blok[next][i-1][j-1]) block = next+1; end end if(block == 0) block=10; end put(fpg,block,100+(WIDE*8)+((j-5/2)*8),80+((i-5/2)*8)-8); end end for(i = 0;i < 5;i++) for(j = 0;j < 5;j++) switch(kant) case 0: k = i; l = j; end case 1: k = 4-j; l = i; end case 2: k = 4-i; l = 4-j; end case 3: k = j; l = 4-i; end end block = blok[nu][i][j]; if(block != 0) put(fpg,nu+1,80+(((nux+k-1)-WIDE/2)*8),120+(((nuy+l-1)-HIGH/2)*8)-8); end end end end//drawmode frame; end end /* Detects horizontal lines and handles accordingly */ Process Detect(); private i,j,k; rij[HIGH]; begin loop //add up how many positions are taken for every horizontal rule for(i = HIGH-1;i >= 0;i--) rij[i] = 0; for(j = 0;j < WIDE;j++) if(steen[i][j] > 0) rij[i]++; end end //if the amount of blocks on a line the same is as the amount of positions if(rij[i] == WIDE) //line detected! //Add the points for a line to the total score score+=ScoreVolleRij; //move the rest of the lines one position down for(k = i;k>0;k--) for(j = 0;j < WIDE;j++) steen[k][j] = steen[k-1][j]; end end i++; end end frame; end end /* Returns whether or not block type(blocknumber given in 'blokje' with rotation 'gekant') can fit on block position x,y in the playing field. Returns true or false */ Process KanNaar(blokje,gekant,x,y) private i,j,k,l; begin for(i=0;i<5;i++) for(j=0;j<5;j++) switch(gekant) case 0: k = i; l = j; end case 1: k = 4-j; l = i; end case 2: k = 4-i; l = 4-j; end case 3: k = j; l = 4-i; end end if(blok[blokje][i][j]) k = x+k-2; l = y+l-2; if(k < 0 or k>WIDE-1 or l<0 or l>HIGH-1) return false; else if(steen[l][k]>0) return false; end end end end end return true; end /* Deprecated process to test out if stuff was working correctly, skip! */ Process Test(); private i,j,k,l; begin write(0,0,0,0,"Coords:"); write_int(0,20,10,0,&nux); write_int(0,40,10,0,&nuy); //write(0, loop if(key(_left)) if(!kannaar(nu,kant,--nux,nuy)) nux++; end while(key(_left))frame;end end if(key(_right)) if(!kannaar(nu,kant,++nux,nuy)) nux--; end while(key(_right))frame;end end if(key(_up)) if(!kannaar(nu,kant,nux,--nuy)) nuy++; end while(key(_up))frame;end end if(key(_down)) if(!kannaar(nu,kant,nux,++nuy)) nuy--; end while(key(_down))frame;end end if(key(_control)) kant = (kant+1)%4; while(key(_control))frame;end end if(key(_enter)) while(key(_enter))frame;end for(i=0;i<5;i++) for(j=0;j<5;j++) switch(kant) case 0: k = i; l = j; end case 1: k = 4-j; l = i; end case 2: k = 4-i; l = 4-j; end case 3: k = j; l = 4-i; end end if(blok[nu][i][j] > 0) steen[l+nuy-2][k+nux-2] = 1; end end end //Volgend blokje nu = next; next = rand(0,graad[difficulty-1]-1); nux = WIDE/2; nuy = -1; kant = 0; while(!kannaar(nu,kant,nux,nuy)) nuy++; end end frame; end end /* Game logic! holds track of variables, game over, playing block descendance, block picking, etc. */ Process game() private //if zero the playblock is ready to go down a line neer=1; //Helping variables i,j,k,l; li,r,d; ct; begin //Launch the process that autodetects if lines are filled Detect(); //determines which blocks are being played with(nu = current, next = next block) nu = rand(0,graad[difficulty-1]-1); next = rand(0,graad[difficulty-1]-1); //set the render process to render the preview field too drawmode = 1; //set current block position(x -> nux, y -> nuy) nux = WIDE / 2; nuy = -1; //set current block rotation kant = 0; //reset score and level score = 0; level = 1; //descent the current block untill it is fully in the playfield. while(!kannaar(nu,kant,nux,nuy)) nuy++; end //ready to go! loop //which level is based on the score level = 1+(score / 5000); //can't go higher than level 10 if(level > 10) level = 10;end //blocks descent faster for higher levels BLOKSPEED = 16 - level; //decrease time(in frames) before the current block can go down one line neer--; //if time to go down a line: if(neer == 0) if(!kannaar(nu,kant,nux,nuy+1)) //if it can't descent a line, set y to true so the process knows it's time //for the next block y = 1; else //else go down and add the basic score addition to the total score nuy++; score += ScoreZomaar; end //time to the next descent of a block is BLOKSPEED neer = BLOKSPEED; else //not time to go down a line, so no new block. y = 0; end //signal that user wants to move the block to left/right/down direction if(key(_left)) li++; else li = 0; end if(key(_right)) r++; else r = 0; end //fast down: if(key(_down) or key(__B)) d++; else d = 0; end //act on those signals by moving if possible: if(d == 1 or ((d%(BLOKSPEED/5)==BLOKSPEED/5-1) and d > 5)) if(!kannaar(nu,kant,nux,++nuy)) nuy--; end end if(li == 1 or ((li%(BLOKSPEED/5)==BLOKSPEED/5-1) and li > 5)) if(!kannaar(nu,kant,--nux,nuy)) nux++; end end if(r == 1 or ((r%(BLOKSPEED/5)==BLOKSPEED/5-1) and r > 5)) if(!kannaar(nu,kant,++nux,nuy)) nux--; end end //signal that the user wants to rotate the block if(key(__A)) ct++; else ct=0; end //act on that signal if(ct == 1 and kannaar(nu,(kant+1)%4,nux,nuy)) kant = (kant+1)%4; end //if y is true it's time for a new block if(y) for(i=0;i<5;i++) for(j=0;j<5;j++) switch(kant) case 0: k = i; l = j; end case 1: k = 4-j; l = i; end case 2: k = 4-i; l = 4-j; end case 3: k = j; l = 4-i; end end if(blok[nu][i][j] > 0) steen[l+nuy-2][k+nux-2] = nu+1; end end end //next block! current block 'nu' is assigned next block 'next' nu = next; //and choose a new block type for 'next' next = rand(0,graad[difficulty-1]-1); //reset variables to signal with li = -300; r = -300; d = -300; //reset position of the new block nux = WIDE/2; nuy = -1; kant = 0; //descent untill fully in the playground while(!kannaar(nu,kant,nux,nuy)) nuy++; //if descendance takes long, it means the new block can't be placed, //playfield is full and player is game over if(nuy >= 4) gameover(); return; end end end frame; end end /* Process to handle game over by player */ Process gameover() private t; begin //if the reached score is bigger than the highscore on the current difficulty //change the highscore and save it if(score > highscore[difficulty-1]) highscore[difficulty-1] = score; t = write(0,80,70,4,"New Highscore!"); save("scores.dat",highscore); end //write game over text x = write(0,80,120,4,"Game Over"); y = write(0,80,140,4,""); //end all processes except for the current one let_me_alone(); //and restart the render process render(); //signal render() process not to draw the preview next block part drawmode = 0; loop //if key start, start over after fancy filling effect if(key(__START)) //delete game over text delete_text(x); delete_text(y); //if highscore, delete New Highscore text too if(t != 0) delete_text(t); end //working upwards, fill the playfield for(x=HIGH;x>=0;x--) for(y=0;y