8524cc5b7adeceff018baa0c2b8df445fca8880a
[netris.git] / board.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>
4  * 
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.
9  * 
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.
14  * 
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.
18  *
19  * $Id: board.c,v 1.15 1999/05/16 06:56:24 mhw Exp $
20  */
21
22 #include "netris.h"
23 #include <stdlib.h>
24
25 #ifdef DEBUG_FALLING
26 # define B_OLD
27 #else
28 # define B_OLD abs
29 #endif
30
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];
36
37 ExtFunc void CleanupBoard(int scr)
38 {
39         CleanupScreen(scr);
40 }
41
42 ExtFunc BlockType GetBlock(int scr, int y, int x)
43 {
44         if (y < 0 || x < 0 || x >= Players[scr].boardWidth)
45                 return BT_wall;
46         else if (y >= Players[scr].boardHeight)
47                 return BT_none;
48         else
49                 return abs(board[scr][y][x]);
50 }
51
52 ExtFunc void SetBlock(int scr, int y, int x, BlockType type)
53 {
54         if (y >= 0 && y < Players[scr].boardHeight &&
55                 x >= 0 && x < Players[scr].boardWidth) {
56                 if (y < Players[scr].boardVisible)
57                         falling[scr][x] += (type < 0) - (board[scr][y][x] < 0);
58                 board[scr][y][x] = type;
59                 changed[scr][y] |= 1 << x;
60         }
61 }
62
63 ExtFunc int RefreshBoard(int scr)
64 {
65         int y, x, any = 0;
66         unsigned int c;
67         BlockType b;
68
69         for (y = Players[scr].boardVisible - 1; y >= 0; --y)
70                 if ((c = changed[scr][y])) {
71                         if (robotEnable) {
72                                 RobotCmd(0, "RowUpdate %d %d", scr, y);
73                                 for (x = 0; x < Players[scr].boardWidth; ++x) {
74                                         b = board[scr][y][x];
75                                         if (fairRobot)
76                                                 b = abs(b);
77                                         RobotCmd(0, " %d", b);
78                                 }
79                                 RobotCmd(0, "\n");
80                         }
81                         changed[scr][y] = 0;
82                         any = 1;
83                         for (x = 0; c; (c >>= 1), (++x))
84                                 if ((c & 1) && B_OLD(board[scr][y][x])!=oldBoard[scr][y][x]) {
85                                         PlotBlock(scr, y, x, B_OLD(board[scr][y][x]));
86                                         oldBoard[scr][y][x] = B_OLD(board[scr][y][x]);
87                                 }
88                 }
89         if (robotEnable)
90                 RobotTimeStamp();
91         for (x = 0; x < Players[scr].boardWidth; ++x)
92                 if (oldFalling[scr][x] != !!falling[scr][x]) {
93                         oldFalling[scr][x] = !!falling[scr][x];
94                         PlotUnderline(scr, x, oldFalling[scr][x]);
95                         any = 1;
96                 }
97         return any;
98 }
99
100 ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data)
101 {
102         PlotBlock1(scr, 20 - y, x * 2, type);
103         return 0;
104 }
105
106 ExtFunc int PlotFunc(int scr, int y, int x, BlockType type, void *data)
107 {
108         SetBlock(scr, y, x, type);
109         return 0;
110 }
111
112 ExtFunc int EraseFunc(int scr, int y, int x, BlockType type, void *data)
113 {
114         SetBlock(scr, y, x, BT_none);
115         return 0;
116 }
117
118 ExtFunc int CollisionFunc(int scr, int y, int x, BlockType type, void *data)
119 {
120         return GetBlock(scr, y, x) != BT_none;
121 }
122
123 ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data)
124 {
125         return (y >= 0 && y < Players[scr].boardVisible &&
126                         x >= 0 && x < Players[scr].boardWidth);
127 }
128
129 ExtFunc void PlotShape(Shape *shape, int scr, int y, int x, int falling)
130 {
131         ShapeIterate(shape, scr, y, x, falling, PlotFunc, NULL);
132 }
133
134 ExtFunc void EraseShape(Shape *shape, int scr, int y, int x)
135 {
136         ShapeIterate(shape, scr, y, x, 0, EraseFunc, NULL);
137 }
138
139 ExtFunc int ShapeFits(Shape *shape, int scr, int y, int x)
140 {
141         return !ShapeIterate(shape, scr, y, x, 0, CollisionFunc, NULL);
142 }
143
144 ExtFunc int ShapeVisible(Shape *shape, int scr, int y, int x)
145 {
146         return ShapeIterate(shape, scr, y, x, 0, VisibleFunc, NULL);
147 }
148
149 ExtFunc int MovePiece(int scr, int deltaY, int deltaX)
150 {
151         int result;
152
153         EraseShape(Players[scr].curShape, scr,
154                 Players[scr].curY, Players[scr].curX);
155         result = ShapeFits(Players[scr].curShape, scr, Players[scr].curY + deltaY,
156                                 Players[scr].curX + deltaX);
157         if (result) {
158                 Players[scr].curY += deltaY;
159                 Players[scr].curX += deltaX;
160         }
161         PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, 1);
162         return result;
163 }
164
165 ExtFunc int RotatePiece(int scr, int dir)
166 {
167         int result;
168
169         EraseShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX);
170         result = ShapeFits(dir ? Players[scr].curShape->rotateTo
171                                                    : Players[scr].curShape->rotateFrom,
172                 scr, Players[scr].curY, Players[scr].curX);
173         if (result)
174                 Players[scr].curShape = dir ? Players[scr].curShape->rotateTo
175                                                                         : Players[scr].curShape->rotateFrom;
176         PlotShape(Players[scr].curShape, scr,
177                         Players[scr].curY, Players[scr].curX, 1);
178         return result;
179 }
180
181 ExtFunc int DropPiece(int scr)
182 {
183         int count = 0;
184
185         EraseShape(Players[scr].curShape, scr,
186                 Players[scr].curY, Players[scr].curX);
187         while (ShapeFits(Players[scr].curShape, scr,
188                         Players[scr].curY - 1, Players[scr].curX)) {
189                 --Players[scr].curY;
190                 ++count;
191         }
192         PlotShape(Players[scr].curShape, scr,
193                 Players[scr].curY, Players[scr].curX, 1);
194         return count;
195 }
196
197 ExtFunc int LineIsFull(int scr, int y)
198 {
199         int x;
200
201         for (x = 0; x < Players[scr].boardWidth; ++x)
202                 if (GetBlock(scr, y, x) == BT_none)
203                         return 0;
204         return 1;
205 }
206
207 ExtFunc void CopyLine(int scr, int from, int to)
208 {
209         int x;
210
211         if (from != to)
212                 for (x = 0; x < Players[scr].boardWidth; ++x)
213                         SetBlock(scr, to, x, GetBlock(scr, from, x));
214 }
215
216 ExtFunc int ClearFullLines(int scr)
217 {
218         int from, to;
219
220         from = to = 0;
221         while (to < Players[scr].boardHeight) {
222                 while (LineIsFull(scr, from))
223                         ++from;
224                 CopyLine(scr, from++, to++);
225         }
226         return from - to;
227 }
228
229 ExtFunc void FreezePiece(int scr)
230 {
231         int y, x;
232         BlockType type;
233
234         for (y = 0; y < Players[scr].boardHeight; ++y)
235                 for (x = 0; x < Players[scr].boardWidth; ++x)
236                         if ((type = board[scr][y][x]) < 0)
237                                 SetBlock(scr, y, x, -type);
238 }
239
240 ExtFunc void InsertJunk(int scr, int count, int column)
241 {
242         int y, x;
243
244         EraseShape(Players[scr].curShape, scr,
245                 Players[scr].curY, Players[scr].curX);
246         for (y = Players[scr].boardHeight - count - 1; y >= 0; --y)
247                 CopyLine(scr, y, y + count);
248         for (y = 0; y < count; ++y)
249                 for (x = 0; x < Players[scr].boardWidth; ++x)
250                         SetBlock(scr, y, x, (x == column) ? BT_none : BT_white);
251         Players[scr].curY += count; //move piece up..
252         for (y = 0; y < count; ++y)
253                 if (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX))
254                         Players[scr].curY--; //..and down as far as possible
255                 else break;
256         PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, 1);
257 }
258
259 /*
260  * vi: ts=4 ai
261  * vim: noai si
262  */