2 * Netris -- A free networked version of T*tris
3 * Copyright (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: board.c,v 1.15 1999/05/16 06:56:24 mhw Exp $
31 static BlockType board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
32 static BlockType oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
33 static unsigned int changed[MAX_SCREENS][MAX_BOARD_HEIGHT];
34 static int falling[MAX_SCREENS][MAX_BOARD_WIDTH];
35 static int oldFalling[MAX_SCREENS][MAX_BOARD_WIDTH];
39 ExtFunc void ClearField(int scr)
43 for (y = Players[scr].boardHeight - 1; y >= 0; --y)
44 for (x = 0; x < Players[scr].boardWidth; ++x) {
45 oldBoard[scr][y][x] = board[scr][y][x] = BT_none;
49 ExtFunc BlockType GetBlock(int scr, int y, int x)
51 if (y < 0 || x < 0 || x >= Players[scr].boardWidth)
53 else if (y >= Players[scr].boardHeight)
56 return abs(board[scr][y][x]);
59 ExtFunc void SetBlock(int scr, int y, int x, BlockType type)
61 if (y >= 0 && y < Players[scr].boardHeight &&
62 x >= 0 && x < Players[scr].boardWidth) {
63 if (y < Players[scr].boardVisible)
64 falling[scr][x] += (type < 0) - (board[scr][y][x] < 0);
65 board[scr][y][x] = type;
66 changed[scr][y] |= 1 << x;
70 ExtFunc int RefreshBoard(int scr)
71 { //draw changes to screen
76 for (y = Players[scr].boardVisible - 1; y >= 0; --y)
77 if ((c = changed[scr][y])) {
79 RobotCmd(0, "RowUpdate %d %d", scr, y);
80 for (x = 0; x < Players[scr].boardWidth; ++x) {
84 RobotCmd(0, " %d", b);
90 for (x = 0; c; (c >>= 1), (++x))
91 if ((c & 1) && B_OLD(board[scr][y][x])!=oldBoard[scr][y][x]) {
92 PlotBlock(scr, y, x, B_OLD(board[scr][y][x]));
93 oldBoard[scr][y][x] = B_OLD(board[scr][y][x]);
96 if (robotEnable) RobotTimeStamp();
97 for (x = 0; x < Players[scr].boardWidth; ++x)
98 if (oldFalling[scr][x] != !!falling[scr][x]) {
99 oldFalling[scr][x] = !!falling[scr][x];
100 PlotUnderline(scr, x, oldFalling[scr][x]);
106 ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data)
108 PlotBlock1(scr, 20 - y, x * 2, type);
112 ExtFunc int ShadowFunc(int scr, int y, int x, BlockType type, void *data)
114 SetBlock(scr, y, x, BT_shadow);
118 ExtFunc int PlotFunc(int scr, int y, int x, BlockType type, void *data)
120 SetBlock(scr, y, x, type);
123 ExtFunc void PlotShape(Shape *shape, int scr, int y, int x, int falling, int shadow)
124 { //put shape on field
125 if (shadow && scr == me) {
126 for (shadowy = y - 1; shadowy >= 0; shadowy--)
127 if (!ShapeFits(shape, scr, shadowy, x))
129 ShapeIterate(shape, scr, shadowy + 1, x, falling, ShadowFunc, NULL);
131 ShapeIterate(shape, scr, y, x, falling, PlotFunc, NULL);
134 ExtFunc int EraseFunc(int scr, int y, int x, BlockType type, void *data)
136 SetBlock(scr, y, x, BT_none);
139 ExtFunc void EraseShape(Shape *shape, int scr, int y, int x, int shadow)
140 { //remove block from field
141 ShapeIterate(shape, scr, y, x, 0, EraseFunc, NULL);
142 if (shadow && scr == me) //draw shadow
143 ShapeIterate(shape, scr, shadowy + 1, x, 0, EraseFunc, NULL);
146 ExtFunc int CollisionFunc(int scr, int y, int x, BlockType type, void *data)
148 return GetBlock(scr, y, x) > BT_none;
150 ExtFunc int ShapeFits(Shape *shape, int scr, int y, int x)
151 { //check if there's nothing in the way
152 return !ShapeIterate(shape, scr, y, x, 0, CollisionFunc, NULL);
155 ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data)
157 return (y >= 0 && y < Players[scr].boardVisible &&
158 x >= 0 && x < Players[scr].boardWidth);
160 ExtFunc int ShapeVisible(Shape *shape, int scr, int y, int x)
162 return ShapeIterate(shape, scr, y, x, 0, VisibleFunc, NULL);
165 ExtFunc int MovePiece(int scr, int deltaY, int deltaX)
169 EraseShape(Players[scr].curShape, scr,
170 Players[scr].curY, Players[scr].curX, 1);
171 result = ShapeFits(Players[scr].curShape, scr, Players[scr].curY + deltaY,
172 Players[scr].curX + deltaX);
174 Players[scr].curY += deltaY;
175 Players[scr].curX += deltaX;
177 PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,
182 ExtFunc int RotatePiece(int scr, int dir)
186 EraseShape(Players[scr].curShape, scr, Players[scr].curY,
187 Players[scr].curX, 1);
188 result = ShapeFits(dir ? Players[scr].curShape->rotateTo
189 : Players[scr].curShape->rotateFrom,
190 scr, Players[scr].curY, Players[scr].curX);
192 Players[scr].curShape = dir ? Players[scr].curShape->rotateTo
193 : Players[scr].curShape->rotateFrom;
194 PlotShape(Players[scr].curShape, scr,
195 Players[scr].curY, Players[scr].curX, 1, 1);
199 ExtFunc int DropPiece(int scr)
203 EraseShape(Players[scr].curShape, scr,
204 Players[scr].curY, Players[scr].curX, 1);
205 while (ShapeFits(Players[scr].curShape, scr,
206 Players[scr].curY - 1, Players[scr].curX)) {
210 PlotShape(Players[scr].curShape, scr,
211 Players[scr].curY, Players[scr].curX, 1, 0);
215 ExtFunc int LineIsFull(int scr, int y)
219 for (x = 0; x < Players[scr].boardWidth; ++x)
220 if (GetBlock(scr, y, x) <= BT_none)
225 ExtFunc void CopyLine(int scr, int from, int to)
230 for (x = 0; x < Players[scr].boardWidth; ++x)
231 SetBlock(scr, to, x, GetBlock(scr, from, x));
234 ExtFunc int ClearFullLines(int scr)
239 while (to < Players[scr].boardHeight) {
240 while (LineIsFull(scr, from))
242 CopyLine(scr, from++, to++);
247 ExtFunc void FreezePiece(int scr)
252 for (y = 0; y < Players[scr].boardHeight; ++y)
253 for (x = 0; x < Players[scr].boardWidth; ++x)
254 if ((type = board[scr][y][x]) < 0)
255 SetBlock(scr, y, x, -type);
258 ExtFunc void InsertJunk(int scr, int count, int column)
262 EraseShape(Players[scr].curShape, scr,
263 Players[scr].curY, Players[scr].curX, 1);
264 for (y = Players[scr].boardHeight - count - 1; y >= 0; --y)
265 CopyLine(scr, y, y + count);
266 for (y = 0; y < count; ++y)
267 for (x = 0; x < Players[scr].boardWidth; ++x)
268 SetBlock(scr, y, x, (x == column) ? BT_none : BT_white);
269 Players[scr].curY += count; //move piece up..
270 for (y = 0; y < count; ++y)
271 if (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX))
272 Players[scr].curY--; //..and down again as far as possible
274 PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,