1 /*
2 * Alizarin Tetris
3 * Functions relating to the game board.
4 *
5 * Copyright 2000, Kiri Wagstaff & Westley Weimer
6 */
7
8 #include <config.h> /* go autoconf! */
9
10 #include "atris.h"
11 #include "display.h"
12 #include "grid.h"
13 #include "options.h"
14 #include "piece.h"
15
16 /***************************************************************************
17 * cleanup_grid()
18 * Removes all of the REMOVE_ME's in a grid. Normally one uses draw_grid
19 * for this purpose, but you might have a personal testing grid or
20 * something that you're not displaying.
21 *********************************************************************PROTO*/
22 void
cleanup_grid(Grid * g)23 cleanup_grid(Grid *g)
24 {
25 int x,y;
26 for (y=g->h-1;y>=0;y--)
27 for (x=g->w-1;x>=0;x--)
28 if (GRID_CONTENT(*g,x,y) == REMOVE_ME)
29 GRID_SET(*g,x,y,0);
30 }
31
32 /***************************************************************************
33 * generate_board()
34 * Creates a new board at the given level.
35 *********************************************************************PROTO*/
36 Grid
generate_board(int w,int h,int level)37 generate_board(int w, int h, int level)
38 {
39 int i,j,r;
40
41 Grid retval;
42
43 retval.w = w;
44 retval.h = h;
45
46 Calloc(retval.contents,unsigned char *,(w*h*sizeof(*retval.contents)));
47 Calloc(retval.fall,unsigned char *,(w*h*sizeof(*retval.fall)));
48 Calloc(retval.changed,unsigned char *,(w*h*sizeof(*retval.changed)));
49 Calloc(retval.temp,unsigned char *,(w*h*sizeof(*retval.temp)));
50
51 if (level) {
52 int start_garbage;
53 level = GARBAGE_LEVEL(level);
54 start_garbage = (h-level) - 2;
55
56 if (start_garbage < 2) start_garbage = 2;
57 else if (start_garbage >= h) start_garbage = h - 1;
58
59 for (j=start_garbage;j<h;j++)
60 for (r=0;r<w/2;r++) {
61 do {
62 i = ZEROTO(w);
63 } while (GRID_CONTENT(retval,i,j) == 1);
64 GRID_SET(retval,i,j,1);
65 }
66 }
67 return retval;
68 }
69
70 /***************************************************************************
71 * add_garbage()
72 * Adds garbage to the given board. Pushes all of the lines up, adds the
73 * garbage to the bottom.
74 *********************************************************************PROTO*/
75 void
add_garbage(Grid * g)76 add_garbage(Grid *g)
77 {
78 int i,j;
79 for (j=0;j<g->h-1;j++)
80 for (i=0;i<g->w;i++) {
81 GRID_SET(*g,i,j, GRID_CONTENT(*g,i,j+1));
82 FALL_SET(*g,i,j, NOT_FALLING);
83 if (GRID_CONTENT(*g,i,j) == 0)
84 GRID_SET(*g,i,j,REMOVE_ME);
85 GRID_CHANGED(*g,i,j) = 1;
86 }
87
88 j = g->h - 1;
89 for (i=0; i<g->w; i++) {
90 if (ZEROTO(100) < 50) {
91 GRID_SET(*g,i,j,1);
92 if (GRID_CONTENT(*g,i,j-1) &&
93 GRID_CONTENT(*g,i,j-1) != REMOVE_ME)
94 GRID_SET(*g,i,j-1,1);
95 } else {
96 GRID_SET(*g,i,j,REMOVE_ME);
97 }
98 FALL_SET(*g,i,j, NOT_FALLING);
99 GRID_CHANGED(*g,i,j) = 1;
100 }
101
102 for (j=0;j<g->h;j++)
103 for (i=0;i<g->w;i++) {
104 Assert(GRID_CHANGED(*g,i,j));
105 Assert(FALL_CONTENT(*g,i,j) == NOT_FALLING);
106 }
107
108 return;
109 }
110
111 /***************************************************************************
112 * draw_grid()
113 * Draws the main grid board. This involves drawing all of the pieces (and
114 * garbage) currently pasted on to it. This is the function that actually
115 * clears out grid pieces marked with "REMOVE_ME". The main bit of work
116 * here is calculating the shadows.
117 *
118 * Uses the color style to actually draw the right picture on the screen.
119 *********************************************************************PROTO*/
120 void
draw_grid(SDL_Surface * screen,color_style * cs,Grid * g,int draw)121 draw_grid(SDL_Surface *screen, color_style *cs, Grid *g, int draw)
122 {
123 SDL_Rect r,s;
124 int i,j;
125 int mini=20, minj=20, maxi=-1, maxj=-1;
126 for (j=g->h-1;j>=0;j--) {
127 for (i=g->w-1;i>=0;i--) {
128 int c = GRID_CONTENT(*g,i,j);
129 if (draw && c && c != REMOVE_ME && GRID_CHANGED(*g,i,j)) {
130 if (i < mini) mini = i; if (j < minj) minj = j;
131 if (i > maxi) maxi = i; if (j > maxj) maxj = j;
132
133
134 s.x = g->board.x + (i * cs->w);
135 s.y = g->board.y + (j * cs->h);
136 s.w = cs->w;
137 s.h = cs->h;
138
139 SDL_BlitSafe(cs->color[c], NULL, screen, &s);
140
141 {
142 int fall = FALL_CONTENT(*g,i,j);
143
144 int that_precolor = (j == 0) ? 0 :
145 GRID_CONTENT(*g,i,j-1);
146 int that_fall = (j == 0) ? -1 :
147 FALL_CONTENT(*g,i,j-1);
148 /* light up */
149 if (that_precolor != c || that_fall != fall) {
150 r.x = g->board.x + i * cs->w;
151 r.y = g->board.y + j * cs->h;
152 r.h = edge[HORIZ_LIGHT]->h;
153 r.w = edge[HORIZ_LIGHT]->w;
154 SDL_BlitSafe(edge[HORIZ_LIGHT],NULL,
155 screen, &r);
156 }
157
158 /* light left */
159 that_precolor = (i == 0) ? 0 :
160 GRID_CONTENT(*g,i-1,j);
161 that_fall = (i == 0) ? -1 :
162 FALL_CONTENT(*g,i-1,j);
163 if (that_precolor != c || that_fall != fall) {
164 r.x = g->board.x + i * cs->w;
165 r.y = g->board.y + j * cs->h;
166 r.h = edge[VERT_LIGHT]->h;
167 r.w = edge[VERT_LIGHT]->w;
168 SDL_BlitSafe(edge[VERT_LIGHT],NULL,
169 screen,&r);
170 }
171
172 /* shadow down */
173 that_precolor = (j == g->h-1) ? 0 :
174 GRID_CONTENT(*g,i,j+1);
175 that_fall = (j == g->h-1) ? -1 :
176 FALL_CONTENT(*g,i,j+1);
177 if (that_precolor != c || that_fall != fall) {
178 r.x = g->board.x + i * cs->w;
179 r.y = (g->board.y + (j+1) * cs->h)
180 - edge[HORIZ_DARK]->h;
181 r.h = edge[HORIZ_DARK]->h;
182 r.w = edge[HORIZ_DARK]->w;
183 SDL_BlitSafe(edge[HORIZ_DARK],NULL,
184 screen,&r);
185 }
186
187 /* shadow right */
188 that_precolor = (i == g->w-1) ? 0 :
189 GRID_CONTENT(*g,i+1,j);
190 that_fall = (i == g->w-1) ? -1 :
191 FALL_CONTENT(*g,i+1,j);
192 if (that_precolor != c || that_fall != fall) {
193 r.x = (g->board.x + (i+1) * cs->w)
194 - edge[VERT_DARK]->w;
195 r.y = (g->board.y + (j) * cs->h);
196 r.h = edge[VERT_DARK]->h;
197 r.w = edge[VERT_DARK]->w;
198 SDL_BlitSafe(edge[VERT_DARK],NULL,
199 screen,&r);
200 }
201 } /* endof: hikari to kage */
202 /* SDL_UpdateSafe(screen, 1, &s); */
203 GRID_CHANGED(*g,i,j) = 0;
204 } else if (c == REMOVE_ME) {
205 if (i < mini) mini = i; if (j < minj) minj = j;
206 if (i > maxi) maxi = i; if (j > maxj) maxj = j;
207 if (draw) {
208 s.x = g->board.x + (i * cs->w);
209 s.y = g->board.y + (j * cs->h);
210 s.w = cs->w;
211 s.h = cs->h;
212 SDL_FillRect(screen, &s, int_solid_black);
213 GRID_SET(*g,i,j,0);
214 GRID_CHANGED(*g,i,j) = 0;
215 } else {
216 GRID_SET(*g,i,j,0);
217 }
218 }
219 }
220 }
221 s.x = g->board.x + mini * cs->w;
222 s.y = g->board.y + minj * cs->h;
223 s.w = (maxi - mini + 1) * cs->w;
224 s.h = (maxj - minj + 1) * cs->h;
225 if (draw && maxi > -1) SDL_UpdateSafe(screen,1,&s);
226 return;
227 }
228
229 /***************************************************************************
230 * draw_falling()
231 * Draws the falling pieces on the main grid. Offset should range from 1 to
232 * the size of the color tiles -- the falling pieces are drawn that far
233 * down out of their "real" places. This gives a smooth animation effect.
234 *********************************************************************PROTO*/
235 void
draw_falling(SDL_Surface * screen,int blockWidth,Grid * g,int offset)236 draw_falling(SDL_Surface *screen, int blockWidth, Grid *g, int offset)
237 {
238 SDL_Rect s;
239 SDL_Rect r;
240 int i,j;
241 int mini=100000, minj=100000, maxi=-1, maxj=-1;
242
243 int cj; /* cluster right, cluster bottom */
244
245 memset(g->temp, 0, sizeof(*g->temp)*g->w*g->h);
246
247 for (j=0;j<g->h;j++) {
248 for (i=0;i<g->w;i++) {
249 int c = GRID_CONTENT(*g,i,j);
250 if (c && FALL_CONTENT(*g,i,j) == FALLING &&
251 TEMP_CONTENT(*g,i,j) == 0) {
252
253 for (cj = j; GRID_CONTENT(*g,i,cj) &&
254 FALL_CONTENT(*g,i,cj) &&
255 TEMP_CONTENT(*g,i,cj) == 0 &&
256 cj < g->h; cj++)
257 TEMP_CONTENT(*g,i,cj) = 1;
258
259 /* source == up */
260 s.x = g->board.x + (i * blockWidth);
261 s.y = g->board.y + (j * blockWidth) + offset - 1;
262 s.w = blockWidth;
263 s.h = blockWidth * (cj - j + 1);
264
265 /* dest == down */
266 r.x = g->board.x + (i * blockWidth);
267 r.y = g->board.y + (j * blockWidth) + offset;
268 r.w = blockWidth;
269 r.h = blockWidth * (cj - j + 1);
270
271 /* just blit the screen down a notch */
272 SDL_BlitSafe(screen, &s, screen, &r);
273
274 if (s.x < mini) mini = s.x;
275 if (s.y < minj) minj = s.y;
276 if (s.x+s.w > maxi) maxi = s.x+s.w;
277 if (s.y+s.h > maxj) maxj = s.y+s.h;
278
279 /* clear! */
280 if (j == 0 || FALL_CONTENT(*g,i,j-1) == NOT_FALLING ||
281 GRID_CONTENT(*g,i,j-1) == 0) {
282 s.h = 1;
283 SDL_BlitSafe(widget_layer, &s, screen, &s);
284 /* SDL_UpdateSafe(screen, 1, &s); */
285 }
286 }
287 }
288 }
289
290 s.x = mini;
291 s.y = minj;
292 s.w = maxi - mini + 1;
293 s.h = maxj - minj + 1;
294 if (maxi > -1) SDL_UpdateSafe(screen,1,&s);
295 return;
296 }
297
298 /***************************************************************************
299 * fall_down()
300 * Move all of the fallen pieces down a notch.
301 *********************************************************************PROTO*/
302 void
fall_down(Grid * g)303 fall_down(Grid *g)
304 {
305 int x,y;
306 for (y=g->h-1;y>=1;y--) {
307 for (x=0;x<g->w;x++) {
308 if (FALL_CONTENT(*g,x,y-1) == FALLING &&
309 GRID_CONTENT(*g,x,y-1)) {
310 Assert(GRID_CONTENT(*g,x,y) == 0 ||
311 GRID_CONTENT(*g,x,y) == REMOVE_ME);
312 GRID_SET(*g,x,y, GRID_CONTENT(*g,x,y-1));
313 GRID_SET(*g,x,y-1,REMOVE_ME);
314 FALL_SET(*g,x,y, FALLING);
315 /* FALL_SET(*g,x,y-1,UNKNOWN); */
316 }
317 }
318 }
319 return;
320 }
321
322 /***************************************************************************
323 * determine_falling()
324 * Determines if anything can fall.
325 *********************************************************************PROTO*/
326 int
determine_falling(Grid * g)327 determine_falling(Grid *g)
328 {
329 int x,y;
330 #ifdef DEBUG
331 {
332 int retval=0;
333 for (y=0;y<g->h;y++) {
334 for (x=0;x<g->w;x++) {
335 if (GRID_CONTENT(*g,x,y) && FALL_CONTENT(*g,x,y) == FALLING) {
336 printf("X");
337 retval= 1;
338 } else printf(".");
339 }
340 printf("\n");
341 }
342 printf("--\n");
343 return retval;
344 }
345 #else
346 for (y=0;y<g->h;y++)
347 for (x=0;x<g->w;x++)
348 if (GRID_CONTENT(*g,x,y) && FALL_CONTENT(*g,x,y) == FALLING)
349 return 1;
350 return 0;
351 #endif
352 }
353
354 /***************************************************************************
355 * run_gravity()
356 * Applies gravity: pieces with no support change to "FALLING". After this,
357 * "determine_falling" can be used to determine if anything should be
358 * falling.
359 *
360 * Returns 1 if any pieces that were FALLING settled down.
361 *
362 * This is the Mark II iterative version. Heavy-sigh!
363 *********************************************************************PROTO*/
364 int
run_gravity(Grid * g)365 run_gravity(Grid *g)
366 {
367 int falling_pieces_settled;
368 int x,y,c,f, X,Y, YY;
369 int S;
370 int lowest_y = 0;
371 int garbage_on_row[21] ; /* FIXME! */
372 /* 6.68 5.20 0.38 16769 0.02 0.02 run_gravity */
373
374 char UP_QUEUE[2000], UP_POS=0;
375
376 #define UP_X(P) UP_QUEUE[(P)*3]
377 #define UP_Y(P) UP_QUEUE[(P)*3 + 1]
378 #define UP_S(P) UP_QUEUE[(P)*3 + 2]
379
380 falling_pieces_settled = 0;
381 for (y=0; y<g->h; y++) {
382 garbage_on_row[y] = 0;
383 for (x=0;x<g->w;x++) {
384 int c = GRID_CONTENT(*g,x,y);
385 if (!lowest_y && c)
386 lowest_y = y;
387 if (c == 1)
388 garbage_on_row[y] = 1;
389 if (FALL_CONTENT(*g,x,y) == NOT_FALLING)
390 FALL_SET(*g,x,y,UNKNOWN);
391 }
392 }
393 garbage_on_row[20] = 1;
394
395 for (y=g->h-1;y>=lowest_y;y--)
396 for (x=0;x<g->w;x++) {
397 c = GRID_CONTENT(*g,x,y);
398 if (!c) continue;
399 else if (c != 1 && y < g->h-1) continue;
400 else if (c == 1 && !garbage_on_row[y+1]) {
401 /* if we do not set this, garbage from above us will appear
402 * to be supported and it will reach down and support us!
403 * scary! */
404 garbage_on_row[y] = 0;
405 continue;
406 }
407 f = FALL_CONTENT(*g,x,y);
408 if (f == NOT_FALLING) continue;
409 else if (f == FALLING) {
410 falling_pieces_settled = 1;
411 }
412
413 /* now, run up as far as we can ... */
414 if (y >= 1) {
415 Y = y;
416 while ((c = GRID_CONTENT(*g,x,Y)) &&
417 FALL_CONTENT(*g,x,Y) != NOT_FALLING) {
418 /* mark stable */
419 f = FALL_CONTENT(*g,x,Y);
420 if (f == FALLING) {
421 falling_pieces_settled = 1;
422 }
423 FALL_SET(*g,x,Y,NOT_FALLING);
424 /* promise to get to our same-color buddies later */
425 if (x >= 1 && GRID_CONTENT(*g,x-1,Y) == c &&
426 FALL_CONTENT(*g,x-1,Y) != NOT_FALLING) {
427 UP_X(UP_POS) = x-1 ; UP_Y(UP_POS) = Y;
428 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
429 }
430 if (x < g->w-1 && GRID_CONTENT(*g,x+1,Y) == c &&
431 FALL_CONTENT(*g,x+1,Y) != NOT_FALLING) {
432 UP_X(UP_POS) = x+1 ; UP_Y(UP_POS) = Y;
433 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
434 }
435 if (Y < g->h-1 && GRID_CONTENT(*g,x,Y+1) == c &&
436 FALL_CONTENT(*g,x,Y+1) != NOT_FALLING) {
437 UP_X(UP_POS) = x ; UP_Y(UP_POS) = Y+1;
438 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
439 }
440 Y--;
441 }
442 } else {
443 /* Debug("2 (%2d,%2d)\n",x,y); */
444 FALL_SET(*g,x,y,NOT_FALLING);
445 }
446
447 /* now burn down the queue */
448 while (UP_POS > 0) {
449 UP_POS--;
450 X = UP_X(UP_POS);
451 Y = UP_Y(UP_POS);
452 S = UP_S(UP_POS);
453 c = GRID_CONTENT(*g,X,Y);
454 Assert(c);
455 f = FALL_CONTENT(*g,X,Y);
456 if (f == NOT_FALLING) continue;
457 else if (f == FALLING && !S) continue;
458
459 if (Y >= 1) {
460 YY = Y;
461 while ((c = GRID_CONTENT(*g,X,YY)) &&
462 FALL_CONTENT(*g,X,YY) != NOT_FALLING) {
463 /* mark stable */
464 f = FALL_CONTENT(*g,X,YY);
465 if (f == FALLING) falling_pieces_settled = 1;
466 FALL_SET(*g,X,YY,NOT_FALLING);
467 /* promise to get to our same-color buddies later */
468 if (X >= 1 && GRID_CONTENT(*g,X-1,YY) == c &&
469 FALL_CONTENT(*g,X-1,YY) != NOT_FALLING) {
470 UP_X(UP_POS) = X-1 ; UP_Y(UP_POS) = YY;
471 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
472 }
473 if (X < g->w-1 && GRID_CONTENT(*g,X+1,YY) == c &&
474 FALL_CONTENT(*g,X+1,YY) != NOT_FALLING) {
475 UP_X(UP_POS) = X+1 ; UP_Y(UP_POS) = YY;
476 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
477 }
478 if (YY < g->h-1 && GRID_CONTENT(*g,X,YY+1) == c &&
479 FALL_CONTENT(*g,X,YY+1) != NOT_FALLING) {
480 UP_X(UP_POS) = X ; UP_Y(UP_POS) = YY+1;
481 UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
482 }
483 YY--;
484 }
485 } else {
486 FALL_SET(*g,X,Y,NOT_FALLING);
487 }
488 }
489 }
490
491 for (y=g->h-1;y>=0;y--)
492 for (x=0;x<g->w;x++)
493 if (FALL_CONTENT(*g,x,y) == UNKNOWN)
494 FALL_CONTENT(*g,x,y) = FALLING;
495
496 return falling_pieces_settled;
497 }
498
499
500 /***************************************************************************
501 * check_tetris()
502 * Checks to see if any rows have been completely filled. Returns the
503 * number of such rows. Such rows are cleared.
504 *********************************************************************PROTO*/
505 int
check_tetris(Grid * g)506 check_tetris(Grid *g)
507 {
508 int tetris_count = 0;
509 int x,y;
510 for (y=g->h-1;y>=0;y--) {
511 int c = 0;
512 for (x=0;x<g->w;x++)
513 if (GRID_CONTENT(*g,x,y))
514 c++;
515 if (c == g->w) {
516 tetris_count++;
517 for (x=0;x<g->w;x++)
518 GRID_SET(*g,x,y,REMOVE_ME);
519 }
520 }
521 return tetris_count;
522 }
523
524 /*
525 * $Log: grid.c,v $
526 * Revision 1.24 2000/11/10 18:16:48 weimer
527 * changes for Atris 1.0.4 - three new special options
528 *
529 * Revision 1.23 2000/11/06 04:06:44 weimer
530 * option menu
531 *
532 * Revision 1.22 2000/11/03 04:25:58 weimer
533 * add some optimizations to run_gravity to make it just a bit faster (down
534 * to 0.01 ms/call from 0.02), sleep a bit more in event-loop: generally
535 * trying to make us more CPU friendly ...
536 *
537 * Revision 1.21 2000/11/03 03:41:35 weimer
538 * made the light and dark "edges" of pieces global, rather than part of a
539 * specific color style. also fixed a bug where we were updating too much
540 * when drawing falling pieces (bad min() code on my part)
541 *
542 * Revision 1.20 2000/10/29 21:23:28 weimer
543 * One last round of header-file changes to reflect my newest and greatest
544 * knowledge of autoconf/automake. Now if you fail to have some bizarro
545 * function, we try to go on anyway unless it is vastly needed.
546 *
547 * Revision 1.19 2000/10/29 17:23:13 weimer
548 * incorporate "xflame" flaming background for added spiffiness ...
549 *
550 * Revision 1.18 2000/10/26 22:23:07 weimer
551 * double the effective number of levels
552 *
553 * Revision 1.17 2000/10/21 01:14:42 weimer
554 * massic autoconf/automake restructure ...
555 *
556 * Revision 1.16 2000/10/18 23:57:49 weimer
557 * general fixup, color changes, display changes.
558 * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
559 * we hope!
560 *
561 * Revision 1.15 2000/10/18 03:29:56 weimer
562 * fixed problem with "machine-gun" sounds caused by "run_gravity()" returning
563 * 1 too often
564 *
565 * Revision 1.14 2000/10/14 02:52:44 weimer
566 * fixed a memory corruption problem in display (a use after a free)
567 *
568 * Revision 1.13 2000/10/14 00:31:53 weimer
569 * non-recursive run-gravity ...
570 *
571 * Revision 1.12 2000/10/13 15:41:53 weimer
572 * revamped AI support, now you can pick your AI and have AI duels (such fun!)
573 * the mighty Aliz AI still crashes a bit, though ... :-)
574 *
575 * Revision 1.11 2000/10/12 22:21:25 weimer
576 * display changes, more multi-local-play threading (e.g., myScore ->
577 * Score[0]), that sort of thing ...
578 *
579 * Revision 1.10 2000/10/12 19:17:08 weimer
580 * Further support for AI players and multiple game types.
581 *
582 * Revision 1.9 2000/10/12 00:49:08 weimer
583 * added "AI" support and walking radio menus for initial game configuration
584 *
585 * Revision 1.8 2000/09/09 17:05:35 wkiri
586 * Hideous log changes (Wes: how dare you include a comment character!)
587 *
588 * Revision 1.7 2000/09/09 16:58:27 weimer
589 * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
590 * main(), isolate the behavior of the three game types. Move graphic files
591 * into graphics/-, style files into styles/-, remove some unused files,
592 * add game flow support (breaks between games, remembering your level within
593 * this game), multiplayer support for the event loop, some global variable
594 * cleanup. All that and a bag of chips!
595 *
596 * Revision 1.6 2000/09/05 22:10:46 weimer
597 * fixed initial garbage generation strangeness
598 *
599 * Revision 1.5 2000/09/05 20:22:12 weimer
600 * native video mode selection, timing investigation
601 *
602 * Revision 1.4 2000/09/04 21:02:18 weimer
603 * Added some addition piece layout code, garbage now falls unless the row
604 * below it features some non-falling garbage
605 *
606 * Revision 1.3 2000/09/04 15:20:21 weimer
607 * faster blitting algorithms for drawing the grid and drawing falling pieces
608 * (when you eliminate a line)
609 *
610 * Revision 1.2 2000/09/03 18:26:10 weimer
611 * major header file and automatic prototype generation changes, restructuring
612 *
613 * Revision 1.1 2000/09/03 17:56:36 wkiri
614 * Reorganization of files (display.[ch], event.c are new).
615 *
616 * Revision 1.9 2000/08/26 02:28:55 weimer
617 * now you can see the other player!
618 *
619 * Revision 1.8 2000/08/26 01:36:25 weimer
620 * fixed a long-running update bug: the grid changed field was being reset to
621 * 0 when falling states or content were set to the same thing, even if they
622 * had actually previously changed ...
623 *
624 * Revision 1.7 2000/08/26 01:03:11 weimer
625 * remove keyboard repeat when you enter high scores
626 *
627 * Revision 1.6 2000/08/24 02:32:18 weimer
628 * gameplay changes (key repeats) and speed modifications (falling pieces,
629 * redraws, etc.)
630 *
631 * Revision 1.5 2000/08/22 15:13:53 weimer
632 * added a garbage-generation routine
633 *
634 * Revision 1.4 2000/08/21 00:04:56 weimer
635 * minor text placement changes, falling speed, etc.
636 *
637 * Revision 1.3 2000/08/15 00:59:41 weimer
638 * a few more sound things
639 *
640 * Revision 1.2 2000/08/13 19:27:20 weimer
641 * added file changelogs
642 *
643 */
644