880 lines
16 KiB
C
880 lines
16 KiB
C
/* BLOCKS!
|
|
|
|
Game from Floppy Software for MESCC - Mike's Enhanced Small C Compiler.
|
|
|
|
Copyright (c) 2012 Miguel I. Garcia Lopez, Valencia, Spain.
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
Revisions:
|
|
|
|
02 Jul 2012 : Generic CP/M version 1.0 for 24x80 VT52 screen.
|
|
11 Mar 2020 : modified to VT100 version by acn@acn.wtf
|
|
*/
|
|
|
|
#include <mescc.h> /* MESCC header & runtime */
|
|
#include <string.h> /* We need strlen() */
|
|
#include <ctype.h> /* We need toupper() */
|
|
#include <sprintf.h> /* We need sprintf() */
|
|
|
|
#ifndef NULL
|
|
#define NULL 0
|
|
#endif
|
|
|
|
#ifndef WORD
|
|
#define WORD unsigned int
|
|
#endif
|
|
|
|
#include <kslib.h> /* Screen output for CP/M */
|
|
#include <kslibfun.h> /* More functions for kslib */
|
|
|
|
/* GAME DEFS
|
|
*/
|
|
|
|
#define BOARD_ROW 6 /* Screen position for board */
|
|
#define BOARD_COL 25 /* id */
|
|
|
|
#define BORDER_ROW 5 /* Screen position for border */
|
|
#define BORDER_COL 24 /* id */
|
|
|
|
#define BOARD_ROWS 10 /* Board rows */
|
|
#define BOARD_COLS 10 /* Board columns */
|
|
|
|
#define BLOCK_COLS 3 /* Block size */
|
|
#define BLOCK_ROWS 1 /* id */
|
|
|
|
#define BLOCK_EMPTY ' ' /* Value if block is empty */
|
|
|
|
#define LEVEL_ROW 2 /* Screen position for level info - used to show blocks killed */
|
|
#define LEVEL_COL 2 /* id */
|
|
|
|
#define SCORE_ROW 2 /* Screen position for score info */
|
|
#define SCORE_COL 73 /* id */
|
|
|
|
#define K_UP '8' /* Key up */
|
|
#define K_DOWN '2' /* Key down */
|
|
#define K_LEFT '4' /* Key left */
|
|
#define K_RIGHT '6' /* Key right */
|
|
#define K_EXIT 'Q' /* Key exit */
|
|
#define K_SELECT '7' /* Key select */
|
|
#define K_KILL '9' /* Key kill */
|
|
#define K_GRAV_UP 'E' /* Key gravity up */
|
|
#define K_GRAV_LEFT 'S' /* Key gravity left */
|
|
#define K_GRAV_RIGHT 'D' /* Key gravity right */
|
|
#define K_GRAV_DOWN 'X' /* Key gravity down */
|
|
|
|
#define RESET "\e[0m" /* reset all attributes */
|
|
#define RED "\e[31m"
|
|
#define GREEN "\e[32m"
|
|
#define YELLOW "\e[33m"
|
|
#define BLUE "\e[34;1m"
|
|
#define MAGENTA "\e[35m"
|
|
#define CYAN "\e[36m"
|
|
#define WHITE "\e[37m"
|
|
|
|
/* VARIABLES
|
|
*/
|
|
|
|
WORD board[BOARD_ROWS]; /* Array for blocks values <<char *board[] -- MESCC things>> */
|
|
WORD board_sel[BOARD_ROWS]; /* Array for blocks selections <<id>> */
|
|
|
|
int score, /* Score */
|
|
blocks, /* Blocks remaining */
|
|
randindex, /* Random number used for generate blocks values */
|
|
selected, /* Number of blocks selected */
|
|
add_to_score, /* How much can I add to score if I kill selected blocks */
|
|
automode, /* Non zero if automode is selected */
|
|
ChkPlsCtr, /* CheckPlease variable */
|
|
ChkPlsMul, /* id */
|
|
ChkPlsVal; /* id */
|
|
|
|
/* MAIN FUNCTION
|
|
*/
|
|
|
|
main(argc, argv)
|
|
int argc, argv[];
|
|
{
|
|
int opt;
|
|
|
|
/* SETUP KSLIB ENVIRONMENT
|
|
*/
|
|
|
|
KbdScrStart();
|
|
|
|
/* SETUP SOME THINGS
|
|
*/
|
|
|
|
board[0]="1234567890"; board_sel[0]="1234567890";
|
|
board[1]="1234567890"; board_sel[1]="1234567890";
|
|
board[2]="1234567890"; board_sel[2]="1234567890";
|
|
board[3]="1234567890"; board_sel[3]="1234567890";
|
|
board[4]="1234567890"; board_sel[4]="1234567890";
|
|
board[5]="1234567890"; board_sel[5]="1234567890";
|
|
board[6]="1234567890"; board_sel[6]="1234567890";
|
|
board[7]="1234567890"; board_sel[7]="1234567890";
|
|
board[8]="1234567890"; board_sel[8]="1234567890";
|
|
board[9]="1234567890"; board_sel[9]="1234567890";
|
|
|
|
/* PLAY THE GAME, PLEASE
|
|
*/
|
|
|
|
while((opt=Menu()))
|
|
{
|
|
if(opt==1)
|
|
Play();
|
|
}
|
|
|
|
/* GAME IS OVER - BEST TO CLEAN THE SCREEN
|
|
*/
|
|
|
|
ScrClr(); ScrCurOn();
|
|
|
|
/* WE SAY GOOD BYE TO KSLIB ENVIRONMENT & WE SAY HELLO TO CP/M
|
|
*/
|
|
|
|
KbdScrEnd();
|
|
}
|
|
|
|
/* MENU - RETURN 0 IF WE WANT TO END GAME, 1 IF WE WANT TO PLAY GAME, OR 2 IF WE WANT TO RETURN TO MENU
|
|
*/
|
|
|
|
Menu()
|
|
{
|
|
char str[80];
|
|
|
|
ScrClr(); ScrCurOff();
|
|
|
|
sprintf(str, "%sB%sl%so%sc%sk%ss%s", RED, GREEN, BLUE, CYAN, MAGENTA, WHITE, RESET); ScrOutStrRC(1, 37, str);
|
|
ScrTitle(3, "v1.1");
|
|
ScrTitle(5, "(c) 2012 Floppy Software");
|
|
ScrTitle(6, "VT-100 version (c) 2020 acn128");
|
|
|
|
ScrOutStrRC(10, 25, "1 : Play game in normal mode");
|
|
ScrOutStrRC(12, 25, "2 : Play game in automatic mode");
|
|
ScrOutStrRC(14, 25, "3 : Show help");
|
|
|
|
ScrOutStrRC(18, 25, "Q : Quit game");
|
|
|
|
ScrTitle(SCR_ROWS-2, "Select your choice");
|
|
|
|
randindex=0; /* This is used to generate a random number */
|
|
|
|
while(1)
|
|
{
|
|
while(!KbdChk())
|
|
{
|
|
if(++randindex==BOARD_ROWS*BOARD_COLS)
|
|
randindex=0;
|
|
}
|
|
|
|
switch(toupper(KbdIn()))
|
|
{
|
|
case '1' : automode=0; return 1;
|
|
case '2' : automode=1; return 1;
|
|
case '3' : Help(); return 2;
|
|
case K_EXIT : return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* HELP -- SHOW HELP
|
|
*/
|
|
|
|
Help()
|
|
{
|
|
ScrClr();
|
|
|
|
ScrTitle( 0, "Blocks");
|
|
ScrTitle( 1, "------");
|
|
|
|
ScrTitle( 3, "The object of the game is to remove all the");
|
|
ScrTitle( 4, "blocks of the board.");
|
|
ScrTitle( 6, "You can select just one block, or a group of");
|
|
ScrTitle( 7, "blocks of the same type.");
|
|
ScrTitle( 9, "Then, if you are in the normal mode, you can place all");
|
|
ScrTitle(10, "the blocks against a side (top, bottom, left or right).");
|
|
ScrTitle(12, "If you are in the automatic mode, the blocks rows will be");
|
|
ScrTitle(13, "placed on the bottom side of the board, and the columns");
|
|
ScrTitle(14, "will be placed on the middle of the board.");
|
|
ScrTitle(16, "The partial score is the square of the number of");
|
|
ScrTitle(17, "blocks selected.");
|
|
ScrTitle(19, "The special block 'X', multiplies that result by 10.");
|
|
ScrTitle(21, "Good luck!");
|
|
ScrTitle(23, "PRESS ANY KEY");
|
|
|
|
KbdIn();
|
|
}
|
|
|
|
/* PLAY THE GAME, PLEASE
|
|
*/
|
|
|
|
Play()
|
|
{
|
|
int row, col, run, val, key;
|
|
char str[80];
|
|
|
|
/* SETUP VARIABLES & BOARD
|
|
*/
|
|
|
|
row=col=selected=score=0; run=1;
|
|
|
|
blocks=BOARD_ROWS*BOARD_COLS;
|
|
|
|
SetupBoard();
|
|
|
|
/* DRAW SCREEN
|
|
*/
|
|
|
|
ScrClr();
|
|
|
|
ScrBox(0, 0, SCR_ROWS-1, SCR_COLS, NULL);
|
|
sprintf(str, "| %sB%sL%sO%sC%sK%sS%s |", RED, GREEN, BLUE, CYAN, MAGENTA, WHITE, RESET); ScrOutStrRC(0, 35, str);
|
|
|
|
ScrOutStrRC(LEVEL_ROW, LEVEL_COL, "Blocks"); PrintBlocks();
|
|
|
|
ScrOutStrRC(SCORE_ROW, SCORE_COL, "Score"); PrintScore();
|
|
|
|
|
|
ScrBox(BORDER_ROW, BORDER_COL, BOARD_ROWS*BLOCK_ROWS+2, BOARD_COLS*BLOCK_COLS+2, NULL);
|
|
|
|
|
|
PaintBoard();
|
|
|
|
|
|
if(!automode)
|
|
{
|
|
sprintf(str, "%c", K_GRAV_UP); ScrTitle(BORDER_ROW-1, str);
|
|
sprintf(str, "%c", K_GRAV_DOWN); ScrTitle(BORDER_ROW+BOARD_ROWS+2, str);
|
|
sprintf(str, "%c", K_GRAV_LEFT); ScrOutStrRC(BORDER_ROW+5, BORDER_COL-2, str);
|
|
sprintf(str, "%c", K_GRAV_RIGHT); ScrOutStrRC(BORDER_ROW+5, BORDER_COL+BOARD_COLS*BLOCK_COLS+3, str);
|
|
}
|
|
|
|
sprintf(str, " %c", K_UP); ScrOutStrRC(BORDER_ROW+3, 7, str);
|
|
ScrOutStrRC(BORDER_ROW+4, 7, " |");
|
|
sprintf(str, "%c --+-- %c", K_LEFT, K_RIGHT); ScrOutStrRC(BORDER_ROW+5, 7, str);
|
|
ScrOutStrRC(BORDER_ROW+6, 7, " |");
|
|
sprintf(str, " %c", K_DOWN); ScrOutStrRC(BORDER_ROW+7, 7, str);
|
|
|
|
sprintf(str, "%c> Select blocks", K_SELECT); ScrOutStrRC(BORDER_ROW+4, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, str);
|
|
sprintf(str, "%c> Kill blocks", K_KILL); ScrOutStrRC(BORDER_ROW+5, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, str);
|
|
sprintf(str, "%c> Quit", K_EXIT); ScrOutStrRC(BORDER_ROW+6, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, str);
|
|
|
|
/* PLAY GAME
|
|
*/
|
|
|
|
while(run)
|
|
{
|
|
/* DRAW CURSOR
|
|
*/
|
|
|
|
ScrSetRC(BOARD_ROW+row*BLOCK_ROWS, BOARD_COL+col*BLOCK_COLS+1); ScrCurOn();
|
|
|
|
/* USER ACTION
|
|
*/
|
|
|
|
key=toupper(KbdIn());
|
|
|
|
ScrCurOff();
|
|
|
|
switch(key)
|
|
{
|
|
case K_UP: if(row) --row;
|
|
break;
|
|
|
|
case K_DOWN: if(++row==BOARD_ROWS) --row;
|
|
break;
|
|
|
|
case K_LEFT: if(col) --col;
|
|
break;
|
|
|
|
case K_RIGHT: if(++col==BOARD_COLS) -- col;
|
|
break;
|
|
|
|
case K_SELECT: /* CHECK FOR VALID BLOCKS
|
|
*/
|
|
|
|
val=GetBlock(row, col);
|
|
|
|
if(val==BLOCK_EMPTY || val=='X')
|
|
break;
|
|
|
|
/* CHECK IF ALREADY SELECTED
|
|
*/
|
|
|
|
if(TstSelBlock(row, col))
|
|
break;
|
|
|
|
/* UNSELECT PREVIOUS SELECTION
|
|
*/
|
|
|
|
if(selected)
|
|
{
|
|
/* HEY! TOO MUCH WORK IF ONLY 1 SELECTED */
|
|
|
|
UnSelAllBlocks();
|
|
PaintBoard();
|
|
}
|
|
|
|
/* SELECT
|
|
*/
|
|
|
|
selected=CheckPlease(row, col);
|
|
|
|
add_to_score=selected*selected*ChkPlsMul;
|
|
|
|
PrintSelec();
|
|
|
|
break;
|
|
|
|
case K_KILL: if(selected)
|
|
{
|
|
/* HEY! TOO MUCH WORK IF ONLY 1 SELECTED */
|
|
|
|
KillSelBlocks();
|
|
|
|
score+=add_to_score;
|
|
|
|
PrintScore();
|
|
|
|
blocks-=selected; PrintBlocks();
|
|
|
|
selected=add_to_score=0;
|
|
|
|
PrintSelec();
|
|
|
|
if(!blocks)
|
|
{
|
|
GameOver(); run=0;
|
|
}
|
|
else if(automode)
|
|
{
|
|
DoAutoMode(); PaintBoard();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case K_GRAV_UP: if(automode)
|
|
break;
|
|
|
|
GravityUp();
|
|
|
|
if(selected)
|
|
{
|
|
UnSelAllBlocks(); selected=0;
|
|
}
|
|
|
|
PaintBoard();
|
|
|
|
break;
|
|
|
|
case K_GRAV_DOWN:
|
|
if(automode)
|
|
break;
|
|
|
|
GravityDown();
|
|
|
|
if(selected)
|
|
{
|
|
UnSelAllBlocks(); selected=0;
|
|
}
|
|
|
|
PaintBoard();
|
|
|
|
break;
|
|
|
|
case K_GRAV_LEFT:
|
|
if(automode)
|
|
break;
|
|
|
|
GravityLeft();
|
|
|
|
if(selected)
|
|
{
|
|
UnSelAllBlocks(); selected=0;
|
|
}
|
|
|
|
PaintBoard();
|
|
|
|
break;
|
|
|
|
case K_GRAV_RIGHT:
|
|
if(automode)
|
|
break;
|
|
|
|
GravityRight();
|
|
|
|
if(selected)
|
|
{
|
|
UnSelAllBlocks(); selected=0;
|
|
}
|
|
|
|
PaintBoard();
|
|
|
|
break;
|
|
|
|
case K_EXIT :
|
|
PrintMsg("ARE YOU SURE Y/N?");
|
|
|
|
if(toupper(KbdIn())=='Y')
|
|
run=0;
|
|
else
|
|
PrintMsg("");
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* GAME IS OVER
|
|
*/
|
|
|
|
GameOver()
|
|
{
|
|
ScrTitle(BORDER_ROW+4, "*** GAME OVER ***");
|
|
|
|
PrintMsg("PRESS ANY KEY");
|
|
|
|
KbdIn();
|
|
}
|
|
|
|
/* SETUP BOARD
|
|
*/
|
|
|
|
SetupBoard()
|
|
{
|
|
int r, c; unsigned char *values;
|
|
|
|
/* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (width 100) */
|
|
values="4321242333123432411123443444432111234332222343331214422444441243444132222311114242423111133222441111";
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
{
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
{
|
|
SetBlock(r, c, values[randindex]);
|
|
|
|
UnSelBlock(r, c);
|
|
|
|
if(++randindex==BOARD_ROWS*BOARD_COLS)
|
|
randindex=0;
|
|
}
|
|
}
|
|
|
|
if(randindex<25)
|
|
SetBlock(2, 5, 'X');
|
|
else if(randindex<50)
|
|
SetBlock(9, 4, 'X');
|
|
else if(randindex<75)
|
|
SetBlock(4, 8, 'X');
|
|
else
|
|
SetBlock(7, 3, 'X');
|
|
}
|
|
|
|
/* SET BLOCK WITH VALUE
|
|
*/
|
|
|
|
SetBlock(row, col, value)
|
|
int row, col, value;
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=board[row];
|
|
|
|
ptr[col]=value;
|
|
}
|
|
|
|
/* GET BLOCK VALUE
|
|
*/
|
|
|
|
GetBlock(row, col)
|
|
int row, col;
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=board[row];
|
|
|
|
return ptr[col];
|
|
}
|
|
|
|
/* SELECT BLOCK
|
|
*/
|
|
|
|
SelBlock(row, col)
|
|
int row, col;
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=board_sel[row];
|
|
|
|
ptr[col]=1;
|
|
}
|
|
|
|
/* UNSELECT BLOCK
|
|
*/
|
|
|
|
UnSelBlock(row, col)
|
|
int row, col;
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=board_sel[row];
|
|
|
|
ptr[col]=0;
|
|
}
|
|
|
|
/* UNSELECT ALL BLOCKS
|
|
*/
|
|
|
|
UnSelAllBlocks()
|
|
{
|
|
int r, c;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
UnSelBlock(r, c);
|
|
}
|
|
|
|
/* TEST IF A BLOCK IS SELECTED
|
|
*/
|
|
|
|
TstSelBlock(row, col)
|
|
int row, col;
|
|
{
|
|
char *ptr;
|
|
|
|
ptr=board_sel[row];
|
|
|
|
return ptr[col];
|
|
}
|
|
|
|
/* KILL SELECTED BLOCKS
|
|
*/
|
|
|
|
KillSelBlocks()
|
|
{
|
|
int r, c;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
{
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
{
|
|
if(TstSelBlock(r, c))
|
|
{
|
|
SetBlock(r, c, BLOCK_EMPTY);
|
|
UnSelBlock(r, c);
|
|
PaintBlock(r, c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* PAINT BLOCK
|
|
*/
|
|
|
|
PaintBlock(row, col)
|
|
int row, col;
|
|
{
|
|
int selected;
|
|
|
|
ScrSetRC(BOARD_ROW+row*BLOCK_ROWS, BOARD_COL+col*BLOCK_COLS);
|
|
|
|
ScrOut((selected=TstSelBlock(row, col)) ? ':' : ' ');
|
|
|
|
switch(GetBlock(row, col))
|
|
{
|
|
case '1' : ScrOutStr(RED); ScrOut('$'); ScrOutStr(RESET); break;
|
|
case '2' : ScrOutStr(GREEN); ScrOut('O'); ScrOutStr(RESET); break;
|
|
case '3' : ScrOutStr(BLUE); ScrOut('+'); ScrOutStr(RESET); break;
|
|
case '4' : ScrOutStr(MAGENTA); ScrOut('#'); ScrOutStr(RESET); break;
|
|
case 'X' : ScrOutStr(WHITE); ScrOut('X'); ScrOutStr(RESET); break;
|
|
case BLOCK_EMPTY : ScrOutStr(RESET); ScrOut(' '); break;
|
|
default : ScrOutStr(RESET); ScrOut('?'); break;
|
|
}
|
|
|
|
ScrOut(selected ? ':' : ' ');
|
|
}
|
|
|
|
/* PAINT ALL BLOCKS
|
|
*/
|
|
|
|
PaintBoard()
|
|
{
|
|
int r, c;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
PaintBlock(r, c);
|
|
}
|
|
|
|
/* CHECK WHAT BLOCKS CAN BE SELECTED - SETUP THREE VARIABLES
|
|
*/
|
|
|
|
CheckPlease(row, col)
|
|
int row, col;
|
|
{
|
|
ChkPlsCtr=0; ChkPlsMul=1; ChkPlsVal=GetBlock(row, col);
|
|
|
|
ChkPls2(row, col);
|
|
|
|
return ChkPlsCtr;
|
|
}
|
|
|
|
ChkPls2(row, col)
|
|
int row, col;
|
|
{
|
|
int val;
|
|
|
|
SelBlock(row, col); PaintBlock(row, col);
|
|
|
|
if(GetBlock(row, col)=='X')
|
|
ChkPlsMul=10;
|
|
|
|
if(row)
|
|
{
|
|
if(((val=GetBlock(row-1, col))==ChkPlsVal || val=='X') && (!TstSelBlock(row-1, col)))
|
|
ChkPls2(row-1, col);
|
|
}
|
|
|
|
if(col<(BOARD_COLS-1))
|
|
{
|
|
if(((val=GetBlock(row, col+1))==ChkPlsVal || val=='X') && (!TstSelBlock(row, col+1)))
|
|
ChkPls2(row, col+1);
|
|
}
|
|
|
|
if(row<(BOARD_ROWS-1))
|
|
{
|
|
if(((val=GetBlock(row+1, col))==ChkPlsVal || val=='X') && (!TstSelBlock(row+1, col)))
|
|
ChkPls2(row+1, col);
|
|
}
|
|
|
|
if(col)
|
|
{
|
|
if(((val=GetBlock(row, col-1))==ChkPlsVal || val=='X') && (!TstSelBlock(row, col-1)))
|
|
ChkPls2(row, col-1);
|
|
}
|
|
|
|
++ChkPlsCtr;
|
|
}
|
|
|
|
/* GRAVITY DOWN (BOARD BOTTOM)
|
|
*/
|
|
|
|
GravityDown()
|
|
{
|
|
int r, c, i, blk, row[BOARD_ROWS];
|
|
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
{
|
|
for((r=i=BOARD_ROWS-1); r!=-1; --r)
|
|
{
|
|
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
|
row[i--]=blk;
|
|
}
|
|
|
|
while(i!=-1)
|
|
row[i--]=BLOCK_EMPTY;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, c, row[r]);
|
|
}
|
|
}
|
|
|
|
/* GRAVITY UP (WE PUT BLOCKS ON BOARD TOP)
|
|
*/
|
|
|
|
GravityUp()
|
|
{
|
|
int r, c, i, blk, row[BOARD_ROWS];
|
|
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
{
|
|
for((r=i=0); r!=BOARD_ROWS; ++r)
|
|
{
|
|
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
|
row[i++]=blk;
|
|
}
|
|
|
|
while(i!=BOARD_ROWS)
|
|
row[i++]=BLOCK_EMPTY;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, c, row[r]);
|
|
}
|
|
}
|
|
|
|
/* GRAVITY LEFT (WE PUT BLOCKS ON BOARD LEFT)
|
|
*/
|
|
|
|
GravityLeft()
|
|
{
|
|
int r, c, i, blk, col[BOARD_ROWS];
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
{
|
|
for((c=i=0); c!=BOARD_COLS; ++c)
|
|
{
|
|
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
|
col[i++]=blk;
|
|
}
|
|
|
|
while(i!=BOARD_COLS)
|
|
col[i++]=BLOCK_EMPTY;
|
|
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
SetBlock(r, c, col[c]);
|
|
}
|
|
}
|
|
|
|
/* GRAVITY RIGHT (WE PUT BLOCKS ON BOARD RIGHT)
|
|
*/
|
|
|
|
GravityRight()
|
|
{
|
|
int r, c, i, blk, col[BOARD_ROWS];
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
{
|
|
for((c=i=BOARD_COLS-1); c!=-1; --c)
|
|
{
|
|
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
|
col[i--]=blk;
|
|
}
|
|
|
|
while(i!=-1)
|
|
col[i--]=BLOCK_EMPTY;
|
|
|
|
for(c=0; c!=BOARD_COLS; ++c)
|
|
SetBlock(r, c, col[c]);
|
|
}
|
|
}
|
|
|
|
/* AUTOMATIC MODE (WE PUT BLOKS FIRST ON BOARD BOTTOM, THEN WE CENTER THE COLUMNS)
|
|
*/
|
|
|
|
DoAutoMode()
|
|
{
|
|
int r, c, i, pos, cols;
|
|
|
|
GravityDown();
|
|
|
|
/* COPY NON EMPTY COLUMNS TO THE LEFT
|
|
*/
|
|
|
|
for(i=c=0; c!=BOARD_COLS; ++c)
|
|
{
|
|
if(GetBlock(BOARD_ROWS-1, c) != BLOCK_EMPTY)
|
|
{
|
|
if(i!=c)
|
|
{
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, i, GetBlock(r, c));
|
|
}
|
|
|
|
++i;
|
|
}
|
|
}
|
|
|
|
/* DO NOTHING IF ALL COLUMNS ARE NON EMPTY
|
|
*/
|
|
|
|
if(i==BOARD_COLS)
|
|
return;
|
|
|
|
/* CALCULATE WHERE TO PUT THE COLUMNS
|
|
*/
|
|
|
|
pos=(BOARD_COLS-i)/2;
|
|
|
|
/* COPY COLUMNS WITHOUT OVERLAP
|
|
*/
|
|
|
|
cols=i;
|
|
|
|
for(c=pos+i-1; i!=-1; --c)
|
|
{
|
|
--i;
|
|
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, c, GetBlock(r, i));
|
|
}
|
|
|
|
/* EMPTY COLUMNS TO THE LEFT
|
|
*/
|
|
|
|
for(c=0; c!=pos; ++c)
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, c, BLOCK_EMPTY);
|
|
|
|
/* EMPTY COLUMNS TO THE RIGHT
|
|
*/
|
|
|
|
for(c=pos+cols; c!=BOARD_COLS; ++c)
|
|
for(r=0; r!=BOARD_ROWS; ++r)
|
|
SetBlock(r, c, BLOCK_EMPTY);
|
|
}
|
|
|
|
/* PRINT HOW MANY BLOCKS ARE REMAINING
|
|
*/
|
|
|
|
PrintBlocks()
|
|
{
|
|
char str[6];
|
|
|
|
sprintf(str, "%d ", blocks);
|
|
|
|
ScrOutStrRC(LEVEL_ROW+1, LEVEL_COL, str);
|
|
}
|
|
|
|
/* PRINT SCORE
|
|
*/
|
|
|
|
PrintScore()
|
|
{
|
|
char str[6];
|
|
|
|
sprintf(str, "%5d", score);
|
|
|
|
ScrOutStrRC(SCORE_ROW+1, SCORE_COL, str);
|
|
}
|
|
|
|
/* PRINT SELECTION INFO.
|
|
*/
|
|
|
|
PrintSelec()
|
|
{
|
|
char str[7];
|
|
|
|
sprintf(str, "x%d ", selected);
|
|
|
|
ScrOutStrRC(LEVEL_ROW+3, LEVEL_COL, str);
|
|
|
|
sprintf(str, "%5d+", add_to_score);
|
|
|
|
ScrOutStrRC(SCORE_ROW+3, SCORE_COL-1, str);
|
|
}
|
|
|
|
/* PRINT TEXT STRING (MESSAGE)
|
|
*/
|
|
|
|
PrintMsg(str)
|
|
char *str;
|
|
{
|
|
ScrSetRC(SCR_ROWS-4, 2);
|
|
ScrOutRpt(' ', SCR_COLS-4);
|
|
|
|
ScrTitle(SCR_ROWS-4, str);
|
|
}
|