unofficial version 0.7.1: ui improvements
[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 static int shadowy;
37
38
39 ExtFunc void ClearField(int scr)
40 {
41         int y, x;
42
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;
46                 }
47 } //ClearField
48
49 ExtFunc BlockType GetBlock(int scr, int y, int x)
50 {
51         if (y < 0 || x < 0 || x >= Players[scr].boardWidth)
52                 return BT_wall;
53         else if (y >= Players[scr].boardHeight)
54                 return BT_none;
55         else
56                 return abs(board[scr][y][x]);
57 } //GetBlock
58
59 ExtFunc void SetBlock(int scr, int y, int x, BlockType type)
60 {
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;
67         }
68 } //SetBlock
69
70 ExtFunc int RefreshBoard(int scr)
71 { //draw changes to screen
72         int y, x, any = 0;
73         unsigned int c;
74         BlockType b;
75
76         for (y = Players[scr].boardVisible - 1; y >= 0; --y)
77                 if ((c = changed[scr][y])) {
78                         if (robotEnable) {
79                                 RobotCmd(0, "RowUpdate %d %d", scr, y);
80                                 for (x = 0; x < Players[scr].boardWidth; ++x) {
81                                         b = board[scr][y][x];
82                                         if (fairRobot)
83                                                 b = abs(b);
84                                         RobotCmd(0, " %d", b);
85                                 }
86                                 RobotCmd(0, "\n");
87                         } //robot
88                         changed[scr][y] = 0;
89                         any = 1;
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]);
94                                 }
95                 } //changed row
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]);
101                         any = 1;
102                 }
103         return any;
104 } //RefreshBoard
105
106 ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data)
107 {
108         PlotBlock1(scr, 20 - y, x * 2, type);
109         return 0;
110 } //GlanceFunc
111
112 ExtFunc int ShadowFunc(int scr, int y, int x, BlockType type, void *data)
113 { //draw shadow
114         SetBlock(scr, y, x, BT_shadow);
115         return 0;
116 } //ShadowFunc
117
118 ExtFunc int PlotFunc(int scr, int y, int x, BlockType type, void *data)
119 {
120         SetBlock(scr, y, x, type);
121         return 0;
122 }
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))
128                                 break;
129                 ShapeIterate(shape, scr, shadowy + 1, x, falling, ShadowFunc, NULL);
130         } //draw shadow
131         ShapeIterate(shape, scr, y, x, falling, PlotFunc, NULL);
132 } //PlotShape
133
134 ExtFunc int EraseFunc(int scr, int y, int x, BlockType type, void *data)
135 {
136         SetBlock(scr, y, x, BT_none);
137         return 0;
138 }
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);
144 } //EraseShape
145
146 ExtFunc int CollisionFunc(int scr, int y, int x, BlockType type, void *data)
147 {
148         return GetBlock(scr, y, x) > BT_none;
149 }
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);
153 } //ShapeFits
154
155 ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data)
156 {
157         return (y >= 0 && y < Players[scr].boardVisible &&
158                         x >= 0 && x < Players[scr].boardWidth);
159 }
160 ExtFunc int ShapeVisible(Shape *shape, int scr, int y, int x)
161 {
162         return ShapeIterate(shape, scr, y, x, 0, VisibleFunc, NULL);
163 } //ShapeVisible
164
165 ExtFunc int MovePiece(int scr, int deltaY, int deltaX)
166 {
167         int result;
168
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);
173         if (result) {
174                 Players[scr].curY += deltaY;
175                 Players[scr].curX += deltaX;
176         }
177         PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,
178                 1, 1);
179         return result;
180 } //MovePiece
181
182 ExtFunc int RotatePiece(int scr, int dir)
183 {
184         int result;
185
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);
191         if (result)
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);
196         return result;
197 } //RotatePiece
198
199 ExtFunc int DropPiece(int scr)
200 {
201         int count = 0;
202
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)) {
207                 --Players[scr].curY;
208                 ++count;
209         }
210         PlotShape(Players[scr].curShape, scr,
211                 Players[scr].curY, Players[scr].curX, 1, 0);
212         return count;
213 } //DropPiece
214
215 ExtFunc int LineIsFull(int scr, int y)
216 {
217         int x;
218
219         for (x = 0; x < Players[scr].boardWidth; ++x)
220                 if (GetBlock(scr, y, x) <= BT_none)
221                         return 0;
222         return 1;
223 }
224
225 ExtFunc void CopyLine(int scr, int from, int to)
226 {
227         int x;
228
229         if (from != to)
230                 for (x = 0; x < Players[scr].boardWidth; ++x)
231                         SetBlock(scr, to, x, GetBlock(scr, from, x));
232 }
233
234 ExtFunc int ClearFullLines(int scr)
235 {
236         int from, to;
237
238         from = to = 0;
239         while (to < Players[scr].boardHeight) {
240                 while (LineIsFull(scr, from))
241                         ++from;
242                 CopyLine(scr, from++, to++);
243         }
244         return from - to;
245 }
246
247 ExtFunc void FreezePiece(int scr)
248 {
249         int y, x;
250         BlockType type;
251
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);
256 }
257
258 ExtFunc void InsertJunk(int scr, int count, int column)
259 {
260         int y, x;
261
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
273                 else break;
274         PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,
275                 1, 1);
276 } //InoertJunk
277
278 /*
279  * vi: ts=4 ai
280  * vim: noai si
281  */