X-Git-Url: http://git.shiar.net/netris.git/blobdiff_plain/45dc9d995860486f1758dcf79fd2d8cd8dfb210a..0e779d807aa1830dde2f4a75117fd16f5627dc76:/board.c diff --git a/board.c b/board.c index 55983b4..c3a8d5c 100644 --- a/board.c +++ b/board.c @@ -22,22 +22,110 @@ #include "netris.h" #include -#ifdef DEBUG_FALLING -# define B_OLD -#else -# define B_OLD abs -#endif - -static BlockType board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH]; -static BlockType oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH]; +#include "board.h" + +static const char shapes[7][4][4][4] = { + { { {0x00, 0x00, 0x00, 0x00}, {0x47, 0xC7, 0x97, 0x00}, + {0x00, 0x00, 0x27, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal + { {0x00, 0x17, 0x00, 0x00}, {0x00, 0x37, 0x00, 0x00}, + {0x47, 0xA7, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt vertical J + { {0x17, 0x00, 0x00, 0x00}, {0x67, 0xC7, 0x87, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal + { {0x00, 0x57, 0x87, 0x00}, {0x00, 0x37, 0x00, 0x00}, + {0x00, 0x27, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //J (yellow) + + { { {0x00, 0x00, 0x00, 0x00}, {0x53, 0xC3, 0x83, 0x00}, + {0x23, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal + { {0x43, 0x93, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00}, + {0x00, 0x23, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp vertical + { {0x00, 0x00, 0x13, 0x00}, {0x43, 0xC3, 0xA3, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal + { {0x00, 0x13, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00}, + {0x00, 0x63, 0x83, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //L (cyan) + + { { {0x00, 0x00, 0x00, 0x00}, {0x48, 0xD8, 0x88, 0x00}, + {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing down + { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xB8, 0x00, 0x00}, + {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing left + { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xE8, 0x88, 0x00}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing up + { {0x00, 0x18, 0x00, 0x00}, {0x00, 0x78, 0x88, 0x00}, + {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //T (white) + + { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00}, + {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, + { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00}, + {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, + { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00}, + {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep + { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00}, + {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //S (green) + + { { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00}, + {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} }, + { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00}, + {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, + { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00}, + {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep + { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00}, + {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //Z (red) + + { { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //lieing + { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00}, + {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} }, //standing + { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84}, + {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep + { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00}, + {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} } }, //stick (blue) + + { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00}, + {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, + { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00}, + {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep + { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00}, + {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep + { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00}, + {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} } } //square (purple) +}; + +int ShapeIterate(char s, int scr, int y, int x, ShapeDrawFunc func) +{ //Draw a certain shape using + int i, j, result; + char type, rotation; + + type = s/4; + rotation = s&3; + for (i = 0; i<4; i++) + for (j = 0; j<4; j++) + if (shapes[type][rotation][i][j]) + if (result = func(scr, y-i, x+j, shapes[type][rotation][i][j])) + return result; + return 0; +} + + +float stdOptions[7] = {1, 1, 1, 1, 1, 1, 1}; //stdOptions + +char ChooseOption(float options[7]) +{ //Return a random piece with given piece weight + int i; + float total = 0, val; + + for (i = 0; i<7; i++) total += options[i]; + val = Random(0, 32767)/32768.0*total; + for (i = 0; i<7; i++) if ((val -= options[i])<0) return i<<2; + return 0; +} + + +static unsigned char board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH]; +static unsigned char oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH]; static unsigned int changed[MAX_SCREENS][MAX_BOARD_HEIGHT]; -static int falling[MAX_SCREENS][MAX_BOARD_WIDTH]; -static int oldFalling[MAX_SCREENS][MAX_BOARD_WIDTH]; static int shadowy; - -ExtFunc void ClearField(int scr) -{ +void ClearField(int scr) +{ //Empty the whole field (all blocks BT_none) int y, x; for (y = Players[scr].boardHeight - 1; y >= 0; --y) @@ -46,123 +134,103 @@ ExtFunc void ClearField(int scr) } } //ClearField -ExtFunc BlockType GetBlock(int scr, int y, int x) -{ +unsigned char GetBlock(int scr, int y, int x) +{ //Returns the block on field at position (x,y) if (y < 0 || x < 0 || x >= Players[scr].boardWidth) return BT_wall; else if (y >= Players[scr].boardHeight) return BT_none; else - return abs(board[scr][y][x]); + return board[scr][y][x]; } //GetBlock -ExtFunc void SetBlock(int scr, int y, int x, BlockType type) +void SetBlock(int scr, int y, int x, unsigned char type) { if (y >= 0 && y < Players[scr].boardHeight && x >= 0 && x < Players[scr].boardWidth) { - if (y < Players[scr].boardVisible) - falling[scr][x] += (type < 0) - (board[scr][y][x] < 0); board[scr][y][x] = type; changed[scr][y] |= 1 << x; } } //SetBlock -ExtFunc int RefreshBoard(int scr) +int RefreshBoard(int scr) { //draw changes to screen int y, x, any = 0; unsigned int c; - BlockType b; - - for (y = Players[scr].boardVisible - 1; y >= 0; --y) - if ((c = changed[scr][y])) { - if (robotEnable) { - RobotCmd(0, "RowUpdate %d %d", scr, y); - for (x = 0; x < Players[scr].boardWidth; ++x) { - b = board[scr][y][x]; - if (fairRobot) - b = abs(b); - RobotCmd(0, " %d", b); + + for (y = Players[scr].boardVisible - 1; y >= 0; y--) + if ((c = changed[scr][y])) { //line changed + for (x = 0; c; (c >>= 1), x++) + if ((c & 1) && board[scr][y][x] != oldBoard[scr][y][x]) { + PlotBlock(scr, y, x, board[scr][y][x]); + oldBoard[scr][y][x] = board[scr][y][x]; } - RobotCmd(0, "\n"); - } //robot - changed[scr][y] = 0; + changed[scr][y] = 0; //reset any = 1; - for (x = 0; c; (c >>= 1), (++x)) - if ((c & 1) && B_OLD(board[scr][y][x])!=oldBoard[scr][y][x]) { - PlotBlock(scr, y, x, B_OLD(board[scr][y][x])); - oldBoard[scr][y][x] = B_OLD(board[scr][y][x]); - } } //changed row - if (robotEnable) RobotTimeStamp(); - for (x = 0; x < Players[scr].boardWidth; ++x) - if (oldFalling[scr][x] != !!falling[scr][x]) { - oldFalling[scr][x] = !!falling[scr][x]; - PlotUnderline(scr, x, oldFalling[scr][x]); - any = 1; - } return any; } //RefreshBoard -ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data) +int GlanceFunc(int scr, int y, int x, unsigned char type) { - PlotBlock1(scr, 20 - y, x * 2, type); + PlotBlockXY(y, x, type); return 0; } //GlanceFunc -ExtFunc int ShadowFunc(int scr, int y, int x, BlockType type, void *data) +int ShadowFunc(int scr, int y, int x, unsigned char type) { //draw shadow SetBlock(scr, y, x, BT_shadow); return 0; } //ShadowFunc -ExtFunc int PlotFunc(int scr, int y, int x, BlockType type, void *data) +int PlotFunc(int scr, int y, int x, unsigned char type) { SetBlock(scr, y, x, type); return 0; } -ExtFunc void PlotShape(Shape *shape, int scr, int y, int x, int falling, int shadow) +void PlotShape(char shape, int scr, int y, int x, int shadow) { //put shape on field - if (shadow && scr == me) { + if (shadow) { for (shadowy = y - 1; shadowy >= 0; shadowy--) if (!ShapeFits(shape, scr, shadowy, x)) break; - ShapeIterate(shape, scr, shadowy + 1, x, falling, ShadowFunc, NULL); + ShapeIterate(shape, scr, shadowy + 1, x, ShadowFunc); } //draw shadow - ShapeIterate(shape, scr, y, x, falling, PlotFunc, NULL); + ShapeIterate(shape, scr, y, x, PlotFunc); } //PlotShape -ExtFunc int EraseFunc(int scr, int y, int x, BlockType type, void *data) +int EraseFunc(int scr, int y, int x, unsigned char type) { SetBlock(scr, y, x, BT_none); return 0; } -ExtFunc void EraseShape(Shape *shape, int scr, int y, int x, int shadow) +void EraseShape(char shape, int scr, int y, int x, int shadow) { //remove block from field - ShapeIterate(shape, scr, y, x, 0, EraseFunc, NULL); + ShapeIterate(shape, scr, y, x, EraseFunc); if (shadow && scr == me) //draw shadow - ShapeIterate(shape, scr, shadowy + 1, x, 0, EraseFunc, NULL); + ShapeIterate(shape, scr, shadowy + 1, x, EraseFunc); } //EraseShape -ExtFunc int CollisionFunc(int scr, int y, int x, BlockType type, void *data) +int CollisionFunc(int scr, int y, int x, unsigned char type) { return GetBlock(scr, y, x) > BT_none; } -ExtFunc int ShapeFits(Shape *shape, int scr, int y, int x) +int ShapeFits(char shape, int scr, int y, int x) { //check if there's nothing in the way - return !ShapeIterate(shape, scr, y, x, 0, CollisionFunc, NULL); + return !ShapeIterate(shape, scr, y, x, CollisionFunc); } //ShapeFits -ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data) +int VisibleFunc(int scr, int y, int x, unsigned char type) { return (y >= 0 && y < Players[scr].boardVisible && x >= 0 && x < Players[scr].boardWidth); } -ExtFunc int ShapeVisible(Shape *shape, int scr, int y, int x) +int ShapeVisible(char shape, int scr, int y, int x) { - return ShapeIterate(shape, scr, y, x, 0, VisibleFunc, NULL); + return ShapeIterate(shape, scr, y, x, VisibleFunc); } //ShapeVisible -ExtFunc int MovePiece(int scr, int deltaY, int deltaX) +int MovePiece(int scr, int deltaY, int deltaX) { int result; @@ -175,28 +243,36 @@ ExtFunc int MovePiece(int scr, int deltaY, int deltaX) Players[scr].curX += deltaX; } PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, - 1, 1); + scr == me); return result; } //MovePiece -ExtFunc int RotatePiece(int scr, int dir) +int RotatePiece(int scr, int dir) { + char newshape; int result; EraseShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, 1); - result = ShapeFits(dir ? Players[scr].curShape->rotateTo - : Players[scr].curShape->rotateFrom, - scr, Players[scr].curY, Players[scr].curX); - if (result) - Players[scr].curShape = dir ? Players[scr].curShape->rotateTo - : Players[scr].curShape->rotateFrom; + /* (inc|dec)rement only 3 least significant bits which indicate rotation */ + newshape = (Players[scr].curShape & 252) + (((Players[scr].curShape & 3) + dir) & 3); + result = ShapeFits(newshape, scr, Players[scr].curY, Players[scr].curX); + if (!result) { + short int slideX; + for (slideX = 0; slideX < 2; slideX = -slideX) { + if (slideX >= 0) slideX++; //slide more + if (result = ShapeFits(newshape, scr, Players[scr].curY, + Players[scr].curX+slideX)) break; + } //slide left and right + if (result) Players[scr].curX += slideX; + } //try to fit if it doesn't + if (result) Players[scr].curShape = newshape; PlotShape(Players[scr].curShape, scr, - Players[scr].curY, Players[scr].curX, 1, 1); + Players[scr].curY, Players[scr].curX, scr == me); return result; } //RotatePiece -ExtFunc int DropPiece(int scr) +int DropPiece(int scr) { int count = 0; @@ -204,26 +280,70 @@ ExtFunc int DropPiece(int scr) Players[scr].curY, Players[scr].curX, 1); while (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX)) { - --Players[scr].curY; - ++count; + Players[scr].curY--; + count++; } PlotShape(Players[scr].curShape, scr, - Players[scr].curY, Players[scr].curX, 1, 0); + Players[scr].curY, Players[scr].curX, 0); return count; } //DropPiece -ExtFunc int LineIsFull(int scr, int y) -{ +int BlockFree(int scr, int x, int y, unsigned char z) +{ //Check if blocks are empty below block (x,y) and sticking to (x,y) mask + unsigned char curblock; + + if (y == 0) return 0; //at bottom + curblock = GetBlock(scr, y, x) & z; + if (curblock & 16 && !BlockFree(scr, x, y-1, z & 208)) return 0; + if (curblock & 32 && !BlockFree(scr, x, y+1, z & 224)) return 0; + if (curblock & 64 && !BlockFree(scr, x+1, y, z & 112)) return 0; + if (curblock & 128 && !BlockFree(scr, x-1, y, z & 176)) return 0; + if ((z = GetBlock(scr, y-1, x)) & 32) return 1; //stuck to block below + if (z > BT_none) return 0; //some other piece below + return 1; //nothing below +} + +int BlockFall(int scr, int x, int y, unsigned char z) +{ //Drop down block (x,y) and those sticking to it mask + if (GetBlock(scr, y, x) & z & 16) BlockFall(scr, x, y-1, z & 208); + if (GetBlock(scr, y, x) & z & 32) BlockFall(scr, x, y+1, z & 224); + if (GetBlock(scr, y, x) & z & 64) BlockFall(scr, x+1, y, z & 112); + if (GetBlock(scr, y, x) & z & 128) BlockFall(scr, x-1, y, z & 174); + SetBlock(scr, y-1, x, GetBlock(scr, y, x)); + SetBlock(scr, y, x, BT_none); +} + +int CheckFall(int scr) +{ //Drop any free blocks on field + int xloop, x, x2, y, fallen = 0; + unsigned char z; + + if (!Game.gravity) return 0; + for (y = Players[scr].boardHeight-1; y > 0; y--) + for (x = 0; x < Players[scr].boardWidth; x++) { + if (((z = GetBlock(scr, y, x)) > BT_none) && ((z & 160) == 0)) { + //doesn't stick left/up => topleft block + if (BlockFree(scr, x, y, 240)) { + BlockFall(scr, x, y, 240); + fallen++; + } //move blocks down + } //block present + } //handle line + return fallen; +} + +int LineIsFull(int scr, int y) +{ //return 0 if any blocks present on line int x; - for (x = 0; x < Players[scr].boardWidth; ++x) + for (x = 0; x < Players[scr].boardWidth; x++) if (GetBlock(scr, y, x) <= BT_none) return 0; return 1; } -ExtFunc void CopyLine(int scr, int from, int to) -{ +void CopyLine(int scr, int from, int to) +{ //move blocks on line to line int x; if (from != to) @@ -231,32 +351,35 @@ ExtFunc void CopyLine(int scr, int from, int to) SetBlock(scr, to, x, GetBlock(scr, from, x)); } -ExtFunc int ClearFullLines(int scr) -{ - int from, to; +int ClearFullLines(int scr) +{ //remove full lines, return lines cleared + int from, to, x, linescleared = 0; + do { from = to = 0; while (to < Players[scr].boardHeight) { - while (LineIsFull(scr, from)) - ++from; + while (LineIsFull(scr, from)) { + from++; //skip + for (x = 0; x1) + SetBlock(scr, from-2, x, GetBlock(scr, from-2, x)&223); + } //don't stick blocks to line which we'll remove + } //full lines CopyLine(scr, from++, to++); } - return from - to; + linescleared += from - to; + } while (CheckFall(scr)); + return linescleared; } -ExtFunc void FreezePiece(int scr) +void FreezePiece(int scr) { - int y, x; - BlockType type; - - for (y = 0; y < Players[scr].boardHeight; ++y) - for (x = 0; x < Players[scr].boardWidth; ++x) - if ((type = board[scr][y][x]) < 0) - SetBlock(scr, y, x, -type); + // remove me! :) } -ExtFunc void InsertJunk(int scr, int count, int column) -{ +void InsertJunk(int scr, int color, int count, int column) +{ //add junklines with hole at to by team int y, x; EraseShape(Players[scr].curShape, scr, @@ -265,14 +388,16 @@ ExtFunc void InsertJunk(int scr, int count, int column) CopyLine(scr, y, y + count); for (y = 0; y < count; ++y) for (x = 0; x < Players[scr].boardWidth; ++x) - SetBlock(scr, y, x, (x == column) ? BT_none : BT_white); + SetBlock(scr, y, x, (x == column) ? BT_none : color + 1 + + 64 * (x != column-1 && x < Players[scr].boardWidth-1) + + 128 * (x != column+1 && x > 0)); Players[scr].curY += count; //move piece up.. for (y = 0; y < count; ++y) if (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX)) Players[scr].curY--; //..and down again as far as possible else break; PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, - 1, 1); + scr == me); } //InoertJunk /*