1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* tetris --- autoplaying tetris game */
3 
4 #if 0
5 static const char sccsid[] = "@(#)tetris.c	5.01 2000/12/19 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1998 by Jouk Jansen <joukj AT hrem.nano.tudelft.nl>
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * The author should like to be notified if changes have been made to the
25  * routine.  Response will only be guaranteed when a VMS version of the
26  * program is available.
27  *
28  * An autoplaying tetris mode for xlockmore
29  * David Bagley changed much of it to look more like altetris code...
30  * which a significant portion belongs to Q. Alex Zhao.
31  *
32  * Copyright (c) 1992 - 95    Q. Alex Zhao, azhao AT cc.gatech.edu
33  *
34  *     All Rights Reserved
35  *
36  * Permission to use, copy, modify, and distribute this software and
37  * its documentation for any purpose and without fee is hereby granted,
38  * provided that the above copyright notice appear in all copies and
39  * that both that copyright notice and this permission notice appear in
40  * supporting documentation, and that the name of the author not be
41  * used in advertising or publicity pertaining to distribution of the
42  * software without specific, written prior permission.
43  *
44  * This program is distributed in the hope that it will be "playable",
45  * but WITHOUT ANY WARRANTY; without even the implied warranty of
46  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
47  *
48  * Todo list:
49  *  -Add option for the level of thinking the computer should perform
50  *     (i.e. dummy = do nothing ..... genius = do always the best move
51  *     possible)
52  *  -Get welltris option to work better.
53  *     draw more sophisticated squares (i.e. something like the bitmaps
54  *       on tetris)
55  *
56  * Revision History:
57  * 01-Dec-2000: Lifted code from polyominoes for variable size pieces
58  *              Copyright (c) 2000 by Stephen Montgomery-Smith
59  * 01-Nov-2000: Allocation checks
60  * 02-Aug-2000: alwelltris trackmouse implemented
61  * 27-Jul-2000: alwelltris all but trackmouse
62  * 22-Jun-2000: trackmouse added, row clearing fixed, bonus pieces,
63  * 01-Nov-1998: altetris additions by David Bagley
64  * 01-Oct-1998: Created
65  */
66 
67 #ifdef STANDALONE
68 #define MODE_tetris
69 #define DEFAULTS "*delay: 600000 \n" \
70 	"*count: -500 \n" \
71 	"*cycles: 200 \n" \
72 	"*size: 0 \n" \
73 	"*ncolors: 200 \n" \
74 	"*fullrandom: True \n" \
75 	"*verbose: False \n" \
76 
77 # define free_tetris 0
78 # define reshape_tetris 0
79 # define tetris_handle_event 0
80 #include "xlockmore.h"    /* in xscreensaver distribution */
81 #else /* STANDALONE */
82 #include "xlock.h"    /* in xlockmore distribution */
83 #include "color.h"
84 #endif /* STANDALONE */
85 
86 #ifdef MODE_tetris
87 
88 #define DEF_BONUS "False"
89 #define DEF_CYCLE "True"
90 #define DEF_PLAIN "False"
91 #define DEF_TRACKMOUSE  "False"
92 #define DEF_WELL "False"
93 
94 static Bool bonus;
95 static Bool cycle_p;
96 static Bool plain;
97 static Bool trackmouse;
98 static Bool well;
99 
100 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
101 
102 static XrmOptionDescRec opts[] =
103 {
104   {(char *) "-bonus", (char *) ".tetris.bonus", XrmoptionNoArg, (caddr_t) "on"},
105   {(char *) "+bonus", (char *) ".tetris.bonus", XrmoptionNoArg, (caddr_t) "off"},
106   {(char *) "-cycle", (char *) ".tetris.cycle", XrmoptionNoArg, (caddr_t) "on"},
107   {(char *) "+cycle", (char *) ".tetris.cycle", XrmoptionNoArg, (caddr_t) "off"},
108   {(char *) "-plain", (char *) ".tetris.plain", XrmoptionNoArg, (caddr_t) "on"},
109   {(char *) "+plain", (char *) ".tetris.plain", XrmoptionNoArg, (caddr_t) "off"},
110 #ifndef DISABLE_INTERACTIVE
111   {(char *) "-trackmouse", (char *) ".tetris.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
112   {(char *) "+trackmouse", (char *) ".tetris.trackmouse", XrmoptionNoArg, (caddr_t) "off"},
113 #endif
114   {(char *) "-well", (char *) ".tetris.well", XrmoptionNoArg, (caddr_t) "on"},
115   {(char *) "+well", (char *) ".tetris.well", XrmoptionNoArg, (caddr_t) "off"}
116 };
117 
118 static argtype vars[] =
119 {
120   {(void *) & bonus, (char *) "bonus", (char *) "Bonus", (char *) DEF_BONUS, t_Bool},
121   {(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool},
122   {(void *) & plain, (char *) "plain", (char *) "Plain", (char *) DEF_PLAIN, t_Bool},
123 #ifndef DISABLE_INTERACTIVE
124   {(void *) & trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool},
125 #endif
126   {(void *) & well, (char *) "well", (char *) "Well", (char *) DEF_WELL, t_Bool}
127 };
128 static OptionStruct desc[] =
129 {
130   {(char *) "-/+bonus", (char *) "turn on/off larger bonus pieces"},
131   {(char *) "-/+cycle", (char *) "turn on/off colour cycling"},
132   {(char *) "-/+plain", (char *) "turn on/off plain pieces"},
133 #ifndef DISABLE_INTERACTIVE
134   {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"},
135 #endif
136   {(char *) "-/+well", (char *) "turn on/off the welltris mode"}
137 };
138 
139 ENTRYPOINT ModeSpecOpt tetris_opts =
140 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
141 
142 #ifdef USE_MODULES
143 ModStruct   tetris_description =
144 {"tetris", "init_tetris", "draw_tetris", "release_tetris",
145  "refresh_tetris", "change_tetris", (char *) NULL, &tetris_opts,
146  600000, -40, 200, -100, 64, 1.0, "",
147  "Shows an autoplaying tetris game", 0, NULL};
148 
149 #endif
150 
151 #include "bitmaps/gray1.xbm"
152 
153 #define MINGRIDSIZE 10
154 #define MAXPIXELSIZE 12
155 #define MINSIZE 6
156 #define MAX_SIDES 4
157 
158 #define NUM_FLASHES 16
159 #define BITMAPS 256
160 
161 #define DELTA 1
162 #define WELL_WIDTH 8
163 #define WELL_DEPTH 12
164 #define WELL_PERIMETER (MAX_SIDES*WELL_WIDTH)
165 #define BASE_WIDTH (WELL_WIDTH*tp->xs+DELTA)
166 #define ENDPT (3*BASE_WIDTH)
167 
168 #define THRESHOLD(x) ((x+1)*10)
169 #define EMPTY (-1)
170 
171 typedef enum {FALL, DROP, MOVE_LEFT, MOVE_RIGHT, ROTATE, REFLECT} move_t;
172 
173 typedef struct {
174   int  squares, polyomino_number;
175   int  xpos, ypos;
176   int  size, color_number;
177   int  random_rotation;
178   int  random_reflection;  /* not used */
179   long  random_number;
180 } thing_t;
181 
182 typedef struct {
183   int  rotation;
184   int  reflection;  /* not used */
185   int  leadingEmptyWidth, leadingEmptyHeight;
186   int  *shape;
187   int  size;
188 } Polyominoes;
189 
190 typedef struct {
191   int  number;
192   int  *start;
193 } Mode;
194 
195 typedef struct {
196   Polyominoes *polyomino;
197   Mode  mode;
198 } Polytris;
199 
200 static Polytris polytris[2];
201 
202 typedef struct {
203   int pmid, cid;
204 } fieldstruct;
205 
206 typedef struct {
207   Bool   painted;
208   int   object, orient;
209   GC   gc;
210   Colormap cmap;
211   Bool   cycle_p, mono_p, no_colors, use3D;
212   unsigned long blackpixel, whitepixel, fg, bg;
213   int   direction;
214   unsigned long colour;
215   int   p_type;
216   int   sidemoves;
217 
218   int   xb, yb;
219   int   xs, ys;
220   int   width, height;
221   int   pixelmode;
222   XImage *images[BITMAPS];
223   XColor     *colors;
224   int   ncolors;
225   int   ncols, nrows;
226   int   rows, level;
227   Bool    bonus, bonusNow;
228   thing_t     curPolyomino;
229 
230   /* tetris */
231   fieldstruct *field;
232 
233   /* welltris */
234   Bool well;
235   int frozen_wall[MAX_SIDES];
236   fieldstruct wall[WELL_DEPTH+WELL_WIDTH][WELL_PERIMETER];
237   fieldstruct base[WELL_WIDTH][WELL_WIDTH];
238   Pixmap graypix;
239 } trisstruct;
240 
241 #define ARR(i,j) (((i)<0||(i)>=tp->curPolyomino.size||\
242 (j)<0||(j)>=tp->curPolyomino.size)?-2:\
243 (polytris[(int) tp->bonusNow].polyomino[tp->curPolyomino.polyomino_number].shape[(j) * tp->curPolyomino.size + (i)]>0))
244 
245 #define ROUND8(n) ((((n)+7)/8)*8)
246 
247 /* Defines to index the bitmaps.  A set bit indicates that an edge or
248    corner is required. */
249 #define LEFT 1 /* (1<<0) */
250 #define DOWN 2 /* (1<<1) */
251 #define RIGHT 4 /* (1<<2) */
252 #define UP 8 /* (1<<3) */
253 #define LEFT_DOWN 16 /* (1<<4) */
254 #define RIGHT_DOWN 32 /* (1<<5) */
255 #define RIGHT_UP 64 /* (1<<6) */
256 #define LEFT_UP 128 /* (1<<7) */
257 #define IS_LEFT(n) ((n)&LEFT)
258 #define IS_DOWN(n) ((n)&DOWN)
259 #define IS_RIGHT(n) ((n)&RIGHT)
260 #define IS_UP(n) ((n)&UP)
261 #define IS_LEFT_DOWN(n) ((n)&LEFT_DOWN)
262 #define IS_RIGHT_DOWN(n) ((n)&RIGHT_DOWN)
263 #define IS_RIGHT_UP(n) ((n)&RIGHT_UP)
264 #define IS_LEFT_UP(n) ((n)&LEFT_UP)
265 
266 #define CHECKLEFT(x) ((x)|LEFT)
267 #define CHECKDOWN(x) ((x)|DOWN)
268 #define CHECKRIGHT(x) ((x)|RIGHT)
269 #define CHECKUP(x) ((x)|UP)
270 
271 /* Defines to access the bitmaps. */
272 #define BITNO(x,y) ((x)+(y)*ROUND8(tp->ys))
273 #define SETBIT(x,y) {data[BITNO(x,y)/8] |= 1<<(BITNO(x,y)%8);}
274 #define RESBIT(x,y) {data[BITNO(x,y)/8] &= ~(1<<(BITNO(x,y)%8));}
275 #define TWOTHIRDSBIT(x,y) {if ((x+y-1)%3) SETBIT(x,y) else RESBIT(x,y)}
276 #define HALFBIT(x,y) {if ((x-y)%2) SETBIT(x,y) else RESBIT(x,y)}
277 #define THIRDBIT(x,y) {if (!((x-y-1)%3)) SETBIT(x,y) else RESBIT(x,y)}
278 #define THREEQUARTERSBIT(x,y) \
279   {if ((y%2)||((x+2+y/2+1)%2)) SETBIT(x,y) else RESBIT(x,y)}
280 #define NOTHALFBIT(x,y) {if ((x-y)%2) RESBIT(x,y) else SETBIT(x,y)}
281 
282 /* Parameters for bitmaps. */
283 #define G ((tp->ys/45)+1)         /* 1/2 of gap between pentominoes. */
284 #define T ((tp->ys<=12)?1:(G*2))  /* Thickness of walls of pentominoes. */
285 #define R ((tp->ys<=12)?1:(G*6))  /* Amount of rounding. */
286 #define RT ((tp->ys<=12)?1:(G*3)) /* Thickness of wall of rounded parts.
287                                   Here 3 is an approximation to 2 sqrt(2).  */
288 #define RR 0   /* Roof ridge thickness */
289 
290 /* A list of those bitmaps we need to create to display any polyomino. */
291 static int images_needed[] =
292 {
293 /* This needed for mononimo*/
294  LEFT|RIGHT|UP|DOWN|LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
295 
296  LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
297 
298  LEFT|RIGHT_UP|RIGHT_DOWN,
299  RIGHT|LEFT_UP|LEFT_DOWN,
300  UP|LEFT_DOWN|RIGHT_DOWN,
301  DOWN|LEFT_UP|RIGHT_UP,
302  LEFT|RIGHT_UP,
303  RIGHT|LEFT_UP,
304  UP|LEFT_DOWN,
305  DOWN|LEFT_UP,
306  LEFT|RIGHT_DOWN,
307  RIGHT|LEFT_DOWN,
308  UP|RIGHT_DOWN,
309  DOWN|RIGHT_UP,
310 
311 #if 0
312 /* These needed for hexonimoes*/
313  LEFT,
314  RIGHT,
315  UP,
316  DOWN,
317  LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
318  LEFT_UP|RIGHT_UP|RIGHT_DOWN,
319  LEFT_UP|LEFT_DOWN|RIGHT_DOWN,
320  LEFT_UP|LEFT_DOWN|RIGHT_UP,
321 #endif
322 
323  LEFT|UP|RIGHT_DOWN,
324  LEFT|DOWN|RIGHT_UP,
325  RIGHT|UP|LEFT_DOWN,
326  RIGHT|DOWN|LEFT_UP,
327  LEFT|UP,
328  LEFT|DOWN,
329  RIGHT|UP,
330  RIGHT|DOWN,
331 
332  LEFT|RIGHT,
333  UP|DOWN,
334 
335  RIGHT|UP|DOWN,
336  LEFT|UP|DOWN,
337  LEFT|RIGHT|DOWN,
338  LEFT|RIGHT|UP,
339 
340  -1
341 };
342 
343 static trisstruct *triss = (trisstruct *) NULL;
344 
345 /* Setup: Normal, Bonus */
346 static int area_kinds[] = {3, 3};
347 static int omino_squares[] = {4, 5};
348 static int start_ominoes[] = {7, 18};
349 static int max_ominoes[] = {19, 63};
350 
351 static int
352 ominos[] =
353 {
354   /* Side of smallest square that contains shape */
355   /* Number of orientations */
356   /* Position, Next Position, (not used yet),
357      number_down, used_for_start?
358      Polyomino (side^2 values) */
359 
360   /* Normal pieces  4 squares */
361   2,
362   1,
363   0, 0, 0,   2,   6, 3,  12, 9,
364 
365   3,
366   16,
367   0, 1, 4,     2,   0, 0, 0,  6, 5, 1,   8, 0, 0,
368   1, 2, 7,     0,   0, 2, 0,  0, 10, 0,  0, 12, 1,
369   2, 3, 6,     0,   0, 0, 0,  0, 0, 2,   4, 5, 9,
370   3, 0, 5,     0,   0, 4, 3,  0, 0, 10,  0, 0, 8,
371   4, 5, 0,     1,   0, 0, 0,  4, 5, 3,   0, 0, 8,
372   5, 6, 3,     0,   0, 6, 1,  0, 10, 0,  0, 8, 0,
373   6, 7, 2,     0,   0, 0, 0,  2, 0, 0,   12, 5, 1,
374   7, 4, 1,     0,   0, 0, 2,  0, 0, 10,  0, 4, 9,
375   8, 9, 8,     2,   0, 0, 0,  4, 7, 1,   0, 8, 0,
376   9, 10, 11,   0,   0, 2, 0,  0, 14, 1,  0, 8, 0,
377   10, 11, 10,  0,   0, 0, 0,  0, 2, 0,   4, 13, 1,
378   11, 8, 9,    0,   0, 0, 2,  0, 4, 11,  0, 0, 8,
379   12, 13, 14,  2,   0, 0, 0,  4, 3, 0,   0, 12, 1,
380   13, 12, 15,  0,   0, 0, 2,  0, 6, 9,   0, 8, 0,
381   14, 15, 12,  1,   0, 0, 0,  0, 6, 1,   4, 9, 0,
382   15, 14, 13,  0,   0, 2, 0,  0, 12, 3,  0, 0, 8,
383 
384   4,
385   2,
386   0, 1, 0,  2,   0, 0, 0, 0,  0, 0, 0, 0,   4, 5, 5, 1,   0, 0, 0, 0,
387   1, 0, 1,  0,   0, 0, 2, 0,  0, 0, 10, 0,  0, 0, 10, 0,  0, 0, 8, 0,
388 
389   /* Bonus pieces  5 squares */
390   3,
391   37,
392   0, 1, 0,     2,   0, 0, 0,  6, 5, 3,    8, 0, 8,
393   1, 2, 3,     0,   0, 6, 1,  0, 10, 0,   0, 12, 1,
394   2, 3, 2,     0,   0, 0, 0,  2, 0, 2,    12, 5, 9,
395   3, 0, 1,     0,   0, 4, 3,  0, 0, 10,   0, 4, 9,
396   4, 5, 8,     2,   0, 0, 0,  6, 7, 1,    12, 9, 0,
397   5, 6, 11,    0,   0, 2, 0,  0, 14, 3,   0, 12, 9,
398   6, 7, 10,    0,   0, 0, 0,  0, 6, 3,    4, 13, 9,
399   7, 4, 9,     0,   0, 6, 3,  0, 12, 11,  0, 0, 8,
400   8, 9, 4,     1,   0, 0, 0,  4, 7, 3,    0, 12, 9,
401   9, 10, 7,    0,   0, 6, 3,  0, 14, 9,   0, 8, 0,
402   10, 11, 6,   0,   0, 0, 0,  6, 3, 0,    12, 13, 1,
403   11, 8, 5,    0,   0, 0, 2,  0, 6, 11,   0, 12, 9,
404   12, 13, 12,  2,   4, 7, 1,  0, 10, 0,   0, 8, 0,
405   13, 14, 15,  0,   2, 0, 0,  14, 5, 1,   8, 0, 0,
406   14, 15, 14,  0,   0, 2, 0,  0, 10, 0,   4, 13, 1,
407   15, 12, 13,  0,   0, 0, 2,  4,  5, 11,  0, 0, 8,
408   16, 17, 19,  2,   6, 5, 1,  10, 0, 0,   8, 0, 0,
409   17, 18, 18,  0,   2, 0, 0,  10, 0, 0,   12, 5, 1,
410   18, 19, 17,  0,   0, 0, 2,  0, 0, 10,   4, 5, 9,
411   19, 16, 16,  0,   4, 5, 3,  0, 0, 10,   0, 0, 8,
412   20, 21, 22,  2,   2, 0, 0,  12, 5, 3,   0, 0, 8,
413   21, 20, 23,  0,   0, 6, 1,  0, 10, 0,   4, 9, 0,
414   22, 23, 20,  1,   0, 0, 2,  6, 5, 9,    8, 0, 0,
415   23, 22, 21,  0,   4, 3, 0,  0, 10, 0,   0, 12, 1,
416   24, 25, 25,  2,   4, 3, 0,  0, 12, 3,   0, 0, 8,
417   25, 26, 24,  0,   0, 6, 1,  6, 9, 0,    8, 0, 0,
418   26, 27, 27,  0,   2, 0, 0,  12, 3, 0,   0, 12, 1,
419   27, 24, 26,  0,   0, 0, 2,  0, 6, 9,    4, 9, 0,
420   28, 29, 32,  2,   0, 2, 0,  6, 13, 1,   8, 0, 0,
421   29, 30, 35,  0,   0, 2, 0,  4, 11, 0,   0, 12, 1,
422   30, 31, 34,  0,   0, 0, 2,  4, 7, 9,    0, 8, 0,
423   31, 28, 33,  0,   4, 3, 0,  0, 14, 1,   0, 8, 0,
424   32, 33, 28,  1,   0, 2, 0,  4, 13, 3,   0, 0, 8,
425   33, 34, 31,  0,   0, 6, 1,  4, 11, 0,   0, 8, 0,
426   34, 35, 30,  0,   2, 0, 0,  12, 7, 1,   0, 8, 0,
427   35, 32, 29,  0,   0, 2, 0,  0, 14, 1,   4, 9, 0,
428   36, 36, 36,  2,   0, 2, 0,  4, 15, 1,   0, 8, 0,
429 
430   4,
431   24,
432   0, 1, 4,     2,   0, 0, 0, 0,  6, 5, 5, 1,   8, 0, 0, 0,   0, 0, 0, 0,
433   1, 2, 7,     0,   0, 2, 0, 0,  0, 10, 0, 0,  0, 10, 0, 0,  0, 12, 1, 0,
434   2, 3, 6,     0,   0, 0, 0, 0,  0, 0, 0, 2,   4, 5, 5, 9,   0, 0, 0, 0,
435   3, 0, 5,     0,   0, 4, 3, 0,  0, 0, 10, 0,  0, 0, 10, 0,  0, 0, 8, 0,
436   4, 5, 0,     1,   0, 0, 0, 0,  4, 5, 5, 3,   0, 0, 0, 8,   0, 0, 0, 0,
437   5, 6, 3,     0,   0, 6, 1, 0,  0, 10, 0, 0,  0, 10, 0, 0,  0, 8, 0, 0,
438   6, 7, 2,     0,   0, 0, 0, 0,  2, 0, 0, 0,   12, 5, 5, 1,  0, 0, 0, 0,
439   7, 4, 1,     0,   0, 0, 2, 0,  0, 0, 10, 0,  0, 0, 10, 0,  0, 4, 9, 0,
440   8, 9, 12,    2,   0, 0, 0, 0,  4, 7, 5, 1,   0, 8, 0, 0,   0, 0, 0, 0,
441   9, 10, 15,   0,   0, 2, 0, 0,  0, 10, 0, 0,  0, 14, 1, 0,  0, 8, 0, 0,
442   10, 11, 14,  0,   0, 0, 0, 0,  0, 0, 2, 0,   4, 5, 13, 1,  0, 0, 0, 0,
443   11, 8, 13,   0,   0, 0, 2, 0,  0, 4, 11, 0,  0, 0, 10, 0,  0, 0, 8, 0,
444   12, 13, 8,   1,   0, 0, 0, 0,  4, 5, 7, 1,   0, 0, 8, 0,   0, 0, 0, 0,
445   13, 14, 11,  0,   0, 2, 0, 0,  0, 14, 1, 0,  0, 10, 0, 0,  0, 8, 0, 0,
446   14, 15, 10,  0,   0, 0, 0, 0,  0, 2, 0, 0,   4, 13, 5, 1,  0, 0, 0, 0,
447   15, 12, 9,   0,   0, 0, 2, 0,  0, 0, 10, 0,  0, 4, 11, 0,  0, 0, 8, 0,
448   16, 17, 20,  2,   0, 0, 0, 0,  4, 5, 3, 0,   0, 0, 12, 1,  0, 0, 0, 0,
449   17, 18, 23,  0,   0, 0, 2, 0,  0, 6, 9, 0,   0, 10, 0, 0,  0, 8, 0, 0,
450   18, 19, 22,  0,   0, 0, 0, 0,  4, 3, 0, 0,   0, 12, 5, 1,  0, 0, 0, 0,
451   19, 16, 21,  0,   0, 0, 2, 0,  0, 0, 10, 0,  0, 6, 9, 0,   0, 8, 0, 0,
452   20, 21, 16,  1,   0, 0, 0, 0,  0, 6, 5, 1,   4, 9, 0, 0,   0, 0, 0, 0,
453   21, 22, 19,  0,   0, 2, 0, 0,  0, 10, 0, 0,  0, 12, 3, 0,  0, 0, 8, 0,
454   22, 23, 18,  0,   0, 0, 0, 0,  0, 0, 6, 1,   4, 5, 9, 0,   0, 0, 0, 0,
455   23, 20, 17,  0,   0, 2, 0, 0,  0, 12, 3, 0,  0, 0, 10, 0,  0, 0, 8, 0,
456 
457   5,
458   2,
459   0, 1, 0,  2,   0, 0, 0, 0, 0,  0, 0, 0, 0, 0,   4, 5, 5, 5, 1,   0, 0, 0, 0, 0,   0, 0, 0, 0, 0,
460   1, 0, 1,  0,   0, 0, 2, 0, 0,  0, 0, 10, 0, 0,  0, 0, 10, 0, 0,  0, 0, 10, 0, 0,  0, 0, 8, 0, 0,
461 };
462 
463 static int
image_needed(int n)464 image_needed(int n) {
465   int i;
466 
467   for (i=0;images_needed[i]!=-1;i++)
468     if (n == images_needed[i])
469       return 1;
470   return 0;
471 }
472 
473 static void
leadingEmptyWidth(Polyominoes * polyo)474 leadingEmptyWidth(Polyominoes * polyo)
475 {
476   int i, j;
477 
478   for (i = 0; i < polyo->size; i++) {
479     for (j = 0; j < polyo->size; j++) {
480       if (polyo->shape[j * polyo->size + i]) {
481         polyo->leadingEmptyWidth = i;
482         return;
483       }
484     }
485   }
486   polyo->leadingEmptyWidth = polyo->size;
487 }
488 
489 static void
leadingEmptyHeight(Polyominoes * polyo)490 leadingEmptyHeight(Polyominoes * polyo)
491 {
492   int i, j;
493 
494   for (j = 0; j < polyo->size; j++) {
495     for (i = 0; i < polyo->size; i++) {
496       if (polyo->shape[j * polyo->size + i]) {
497         polyo->leadingEmptyHeight = j;
498         return;
499       }
500     }
501   }
502   polyo->leadingEmptyHeight = polyo->size;
503 }
504 
505 static Bool
readPolyominoes(void)506 readPolyominoes(void)
507 {
508   int   size, n, polyindex = 0, sum = 0;
509   int   counter, start_counter;
510   int   polyomino, kinds, i, j, bonustype;
511 
512   for (bonustype = 0; bonustype < 2; bonustype++) {
513     counter = 0, start_counter = 0;
514     polytris[bonustype].mode.number = start_ominoes[bonustype];
515     for (kinds = 0; kinds < area_kinds[bonustype]; kinds++) {
516       size = ominos[polyindex++];
517       if (size > omino_squares[bonustype]) {
518         (void) printf("tetris corruption: size %d\n", size);
519         return False;
520       }
521       n = ominos[polyindex++];
522       if (sum > max_ominoes[bonustype]) {
523         (void) printf("tetris corruption: n %d\n", n);
524         return False;
525       }
526       for (polyomino = 0; polyomino < n; polyomino++) {
527         if (polyomino + counter < max_ominoes[bonustype]) {
528           sum = polyomino + counter;
529         } else {
530           (void) printf("tetris corruption: bonustype %d, polyomino %d, counter %d\n",
531             bonustype, polyomino, counter);
532           return False;
533         }
534         if (polyomino != ominos[polyindex]) {
535           (void) printf("tetris corruption: polyomino %d, ominos[polyindex] %d\n",
536             polyomino, ominos[polyindex]);
537           return False;
538         }
539         polyindex++;  /* This is only there to "read" it */
540         polytris[bonustype].polyomino[sum].rotation =
541           ominos[polyindex++] + counter;
542         polytris[bonustype].polyomino[sum].reflection =
543           ominos[polyindex++] + counter; /* not used */
544 
545         if (ominos[polyindex++]) {
546           if (start_counter < start_ominoes[bonustype]) {
547             polytris[bonustype].mode.start[start_counter++] = sum;
548           } else {
549             (void) printf("tetris corruption: bonustype %d, polyomino %d, start_counter %d\n",
550               bonustype, polyomino, start_counter);
551             return False;
552           }
553         }
554         polytris[bonustype].polyomino[sum].size = size;
555         if ((polytris[bonustype].polyomino[sum].shape = (int *) malloc(size *
556             size * sizeof(int))) == NULL) {
557           (void) printf("tetris out of memory\n");
558           return False;
559 	}
560         for (j = 0; j < size; j++) {
561           for (i = 0; i < size; i++) {
562             polytris[bonustype].polyomino[sum].shape[j * size + i] =
563         ominos[polyindex++];
564           }
565         }
566         leadingEmptyWidth(&(polytris[bonustype].polyomino[sum]));
567         leadingEmptyHeight(&(polytris[bonustype].polyomino[sum]));
568       }
569       counter += n;
570     }
571   }
572   return True;
573 }
574 
575 #ifdef DEBUG
576 static void
writePolyominoes(trisstruct * tp)577 writePolyominoes(trisstruct * tp)
578 {
579   int   size = 0;
580   int   polyomino, i, j, bonustype;
581 
582   for (bonustype = 0; bonustype < 2; bonustype++) {
583     for (polyomino = 0; polyomino < max_ominoes[bonustype]; polyomino++) {
584       (void) printf("polyomino %d, rotation %d, reflection %d, size %d\n",
585         polyomino, polytris[bonustype].polyomino[polyomino].rotation,
586         polytris[bonustype].polyomino[polyomino].reflection,
587         polytris[bonustype].polyomino[polyomino].size);
588       size = polytris[bonustype].polyomino[polyomino].size;
589       for (j = 0; j < size; j++) {
590         (void) printf(" ");
591         for (i = 0; i < size; i++) {
592           (void) printf(" %d", polytris[bonustype].polyomino[polyomino].shape[j * size + i]);
593         }
594       }
595       (void) printf("\n");
596     }
597     (void) printf("Starts:");
598     for (polyomino = 0; polyomino < start_ominoes[bonustype]; polyomino++) {
599       (void) printf(" %d", polytris[bonustype].mode.start[polyomino]);
600     }
601     (void) printf("\n");
602   }
603 }
604 #endif
605 
606 static void
setColour(ModeInfo * mi,int cid)607 setColour(ModeInfo * mi, int cid /* , int exor */)
608 {
609   Display    *display = MI_DISPLAY(mi);
610   trisstruct *tp = &triss[MI_SCREEN(mi)];
611   long colour;
612 
613   if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
614     if (tp->ncolors >= start_ominoes[(int) tp->bonusNow] + 2)
615       colour = cid + 2;
616     else
617       colour = 1; /* Just in case */
618     XSetBackground(display, tp->gc, tp->blackpixel);
619     XSetForeground(display, tp->gc, tp->colors[colour].pixel);
620   } else {
621     if (MI_NPIXELS(mi) > start_ominoes[(int) tp->bonusNow])
622       colour = MI_PIXEL(mi, cid * MI_NPIXELS(mi) / start_ominoes[(int) tp->bonusNow]);
623     else
624       colour = MI_WHITE_PIXEL(mi);
625     XSetForeground(display, tp->gc, colour);
626     XSetBackground(display, tp->gc, MI_BLACK_PIXEL(mi));
627   }
628 }
629 
630 static void
drawSquare(ModeInfo * mi,int pmid,int cid,int col,int row)631 drawSquare(ModeInfo * mi, int pmid, int cid, int col, int row)
632 {
633   Display    *display = MI_DISPLAY(mi);
634   Window      window = MI_WINDOW(mi);
635   trisstruct *tp = &triss[MI_SCREEN(mi)];
636 
637   setColour(mi, cid /* , 0 */);
638   if (tp->pixelmode)
639     XFillRectangle(display, window, tp->gc,
640       tp->xb + col * tp->xs, tp->yb + row * tp->ys, tp->xs, tp->ys);
641   else {
642     if (pmid < 0 || pmid >= 256)
643       (void) printf("pmid = %d\n", pmid);
644 /*-
645  * PURIFY on SunOS4 and on Solaris 2 reports a 120 byte memory leak on
646  * the next line */
647     (void) XPutImage(display, window, tp->gc, tp->images[pmid], 0, 0,
648       tp->xb + col * tp->xs, tp->yb + row * tp->ys,
649       tp->xs, tp->ys);
650   }
651 }
652 
653 static void
xorSquare(ModeInfo * mi,int i,int j)654 xorSquare(ModeInfo * mi, int i, int j)
655 {
656   Display    *display = MI_DISPLAY(mi);
657   Window      window = MI_WINDOW(mi);
658   trisstruct *tp = &triss[MI_SCREEN(mi)];
659 
660   XSetFunction(display, tp->gc, GXxor);
661   XSetBackground(display, tp->gc, 0);
662   XSetForeground(display, tp->gc, 0xFFFFFF);
663   XFillRectangle(display, window, tp->gc,
664     tp->xb + i * tp->xs, tp->yb + j * tp->ys,
665     tp->xs, tp->ys);
666   XSetFunction(display, tp->gc, GXcopy);
667   XSetBackground(display, tp->gc, tp->blackpixel);
668   XSetForeground(display, tp->gc, tp->whitepixel);
669 }
670 
671 static void
XFillTrapazoid(Display * display,Window window,GC gc,int ulx,int uly,int base_x,int base_y,int lrx,int lry,int plateau_x,int plateau_y)672 XFillTrapazoid(Display *display, Window window, GC gc,
673   int ulx, int uly, int base_x, int base_y, int lrx, int lry,
674   int plateau_x, int plateau_y)
675 {
676   XPoint trapazoid_list[MAX_SIDES];
677 
678   trapazoid_list[0].x = ulx;
679   trapazoid_list[0].y = uly;
680   trapazoid_list[1].x = base_x;
681   trapazoid_list[1].y = base_y;
682   trapazoid_list[2].x = lrx - base_x - ulx;
683   trapazoid_list[2].y = lry - base_y - uly;
684   trapazoid_list[3].x = -plateau_x;
685   trapazoid_list[3].y = -plateau_y;
686   XFillPolygon(display, window, gc, trapazoid_list, MAX_SIDES,
687     Convex, CoordModePrevious);
688 }
689 
690 static void
drawWallSquare(ModeInfo * mi,GC gc,int i,int j)691 drawWallSquare(ModeInfo * mi, GC gc, int i, int j)
692 {
693   Display    *display = MI_DISPLAY(mi);
694   Window      window = MI_WINDOW(mi);
695   trisstruct *tp = &triss[MI_SCREEN(mi)];
696   int ulx, uly, lrx, lry, base_x, plateau_x, w, offsetx, offsety;
697 
698   offsetx = tp->width / 2 - 3 * (WELL_WIDTH * tp->xs) / 2 - DELTA;
699   offsety = tp->height / 2 - 3 * (WELL_WIDTH * tp->xs) / 2 - DELTA;
700   w = i / WELL_WIDTH;
701   i -= (w * WELL_WIDTH);
702   ulx = 3 * BASE_WIDTH / 2 + (i - (WELL_WIDTH / 2)) *
703     (2 * tp->xs * (WELL_DEPTH - j) / WELL_DEPTH + tp->xs) +
704     2 * DELTA;
705   uly = j * WELL_WIDTH * tp->xs / WELL_DEPTH + 2 * DELTA;
706   lrx = 3 * BASE_WIDTH / 2 + (i + 1 - (WELL_WIDTH / 2)) *
707     (2 * tp->xs * (WELL_DEPTH - j - 1) / WELL_DEPTH + tp->xs) +
708     DELTA * (i / 4) - 3 * DELTA;
709   lry = (j + 1) * WELL_WIDTH * tp->xs / WELL_DEPTH - DELTA;
710   base_x = tp->xs + (WELL_DEPTH - j) * 2 * tp->xs / WELL_DEPTH -
711     5 * DELTA;
712   plateau_x = tp->xs + (WELL_DEPTH - j - 1) * 2 *
713     tp->xs / WELL_DEPTH - 5 * DELTA;
714   {
715     XSetFillStyle(display, gc, FillOpaqueStippled);
716     XSetStipple(display, gc, tp->graypix);
717   }
718   switch (w) {
719   case 0:
720     XFillTrapazoid(display, window, gc,
721       ulx + offsetx, uly + offsety, base_x, 0,
722       lrx + offsetx, lry + offsety, plateau_x, 0);
723     break;
724   case 1:
725     XFillTrapazoid(display, window, gc,
726       ENDPT - uly + offsetx, ulx + offsety, 0, base_x,
727       ENDPT - lry + offsetx, lrx + offsety, 0, plateau_x);
728     break;
729   case 2:
730     XFillTrapazoid(display, window, gc,
731       ENDPT - 1 - ulx + offsetx, ENDPT - uly + offsety, -base_x, 0,
732       ENDPT - 1 - lrx + offsetx, ENDPT - lry + offsety, -plateau_x, 0);
733     break;
734   case 3:
735     XFillTrapazoid(display, window, gc,
736       uly + offsetx, ENDPT - 1 - ulx + offsety, 0, -base_x,
737       lry + offsetx, ENDPT - 1 - lrx + offsety, 0, -plateau_x);
738     break;
739   default:
740     (void) fprintf (stderr, "trapazoid kinds range 0-3, got %d.\n", w);
741   }
742   {
743     XSetFillStyle(display, gc, FillSolid);
744   }
745 }
746 
747 static void
clearTrapazoid(ModeInfo * mi,int i,int j)748 clearTrapazoid(ModeInfo * mi, int i, int j)
749 {
750   Display    *display = MI_DISPLAY(mi);
751   trisstruct *tp = &triss[MI_SCREEN(mi)];
752 
753   XSetForeground(display, tp->gc, tp->blackpixel);
754   drawWallSquare(mi, tp->gc, i, j); /* pmid not used yet */
755 }
756 
757 static void
drawTrapazoid(ModeInfo * mi,int cid,int i,int j)758 drawTrapazoid(ModeInfo * mi, /* int pmid, */ int cid, int i, int j)
759 {
760   trisstruct *tp = &triss[MI_SCREEN(mi)];
761 
762   setColour(mi, cid /* , 0 */ );
763   drawWallSquare(mi, tp->gc, i, j); /* pmid not used yet */
764 }
765 
766 static void
freezeTrapazoid(ModeInfo * mi,int i,int j)767 freezeTrapazoid(ModeInfo * mi, int i, int j)
768 {
769   Display    *display = MI_DISPLAY(mi);
770   trisstruct *tp = &triss[MI_SCREEN(mi)];
771 
772   XSetFunction(display, tp->gc, GXxor);
773   XSetBackground(display, tp->gc, 0);
774   XSetForeground(display, tp->gc, 0xFFFFFF);
775   drawWallSquare(mi, tp->gc, i, j); /* pmid not used yet */
776   XSetFunction(display, tp->gc, GXcopy);
777   XSetBackground(display, tp->gc, tp->blackpixel);
778   XSetForeground(display, tp->gc, tp->whitepixel);
779 }
780 
781 static int
checkWall(int pmid,int base_i,int base_j)782 checkWall(int pmid, int base_i, int base_j)
783 {
784   if (pmid < 0)
785     return pmid;
786   /* Check if next to well wall */
787   if (base_i == 0)
788     pmid = CHECKLEFT((unsigned int) pmid);
789   if (base_j == 0)
790     pmid = CHECKUP((unsigned int) pmid);
791   if (base_i == WELL_WIDTH - 1)
792     pmid = CHECKRIGHT((unsigned int) pmid);
793   if (base_j == WELL_WIDTH - 1)
794     pmid = CHECKDOWN((unsigned int) pmid);
795   return pmid;
796 }
797 
798 static int
checkSides(int pmid,int i)799 checkSides(int pmid, int i)
800 {
801   if (pmid < 0)
802     return pmid;
803   if (i == 0 || i == 3 * WELL_WIDTH - 1)
804     pmid = CHECKLEFT((unsigned int) pmid);
805   else if (i == WELL_WIDTH - 1 || i == 2 * WELL_WIDTH)
806     pmid = CHECKRIGHT((unsigned int) pmid);
807   else if (i == WELL_WIDTH || i == 4 * WELL_WIDTH - 1)
808     pmid = CHECKUP((unsigned int) pmid);
809   else if (i == 2 * WELL_WIDTH - 1 || i == 3 * WELL_WIDTH)
810     pmid = CHECKDOWN((unsigned int) pmid);
811   return pmid;
812 }
813 
814 static int
checkBottom(int pmid,int i,int j)815 checkBottom(int pmid, int i, int j)
816 {
817   if (pmid < 0 || j != WELL_DEPTH - 1)
818     return pmid;
819   switch (i / WELL_WIDTH) {
820   case 0:
821     return CHECKDOWN((unsigned int) pmid);
822   case 1:
823     return CHECKLEFT((unsigned int) pmid);
824   case 2:
825     return CHECKUP((unsigned int) pmid);
826   case 3:
827     return CHECKRIGHT((unsigned int) pmid);
828   }
829   return EMPTY;
830 }
831 
832 /* Wall number ... imagine a 4 hour clock...
833      0
834     3+1
835      2
836  */
837 static void
wall_to_base(int * base_x,int * base_y,int wall_x,int wall_y)838 wall_to_base(int *base_x, int *base_y, int wall_x, int wall_y)
839 {
840   switch (wall_x / WELL_WIDTH)
841   {
842   case 0:
843     *base_x = wall_x;
844     *base_y = wall_y - WELL_DEPTH;
845     break;
846   case 1:
847     *base_x = WELL_WIDTH - 1 + WELL_DEPTH - wall_y;
848     *base_y = wall_x - WELL_WIDTH;
849     break;
850   case 2:
851     *base_x = WELL_PERIMETER - 1 - WELL_WIDTH - wall_x;
852     *base_y = WELL_WIDTH - 1 + WELL_DEPTH - wall_y;
853     break;
854   case 3:
855     *base_x = wall_y - WELL_DEPTH;
856     *base_y = WELL_PERIMETER - 1 - wall_x;
857     break;
858   default:
859    (void) fprintf (stderr, "wall_to_base kinds range 0-3, got %d.\n",
860                wall_x / WELL_WIDTH);
861   }
862 }
863 
864 static void
dropWall(ModeInfo * mi,int w)865 dropWall(ModeInfo *mi, int w)
866 {
867   Display    *display = MI_DISPLAY(mi);
868   trisstruct *tp = &triss[MI_SCREEN(mi)];
869   int i, j, k, l, lines, base_x, base_y;
870   Bool fits;
871 
872   lines = 0;
873   for (j = WELL_DEPTH - 1; j >= 0 && lines == 0; j--)
874     for (i = 0; i < WELL_WIDTH; i++)
875       if (tp->wall[j][w * WELL_WIDTH + i].pmid != EMPTY)
876         lines = WELL_DEPTH - j;
877   if (lines > 0) {
878     fits = True;
879     j = 0;
880     while (j < (WELL_WIDTH / 2 + lines - 1) && fits) {
881       j++;
882       for (l = WELL_DEPTH - j; l < WELL_DEPTH; l++)
883         for (i = 0; i < WELL_WIDTH; i++)
884           if (tp->wall[l][w * WELL_WIDTH + i].pmid != EMPTY) {
885             wall_to_base(&base_x, &base_y,
886               w * WELL_WIDTH + i, l + j);
887             if (tp->base[base_y][base_x].pmid != EMPTY)
888               fits = False;
889           }
890     }
891     if (!fits)
892       j--;
893     if (j > 0)
894     {
895       for (l = WELL_DEPTH - 1; l >= 0; l--)
896         for (i = 0; i < WELL_WIDTH; i++)
897           if (tp->wall[l][w * WELL_WIDTH + i].pmid != EMPTY) {
898             k = w * WELL_WIDTH + i;
899             if (l + j >= WELL_DEPTH) {
900               wall_to_base(&base_x, &base_y, k, l + j);
901               tp->base[base_y][base_x] = tp->wall[l][k];
902               tp->base[base_y][base_x].pmid =
903                 checkWall(tp->base[base_y][base_x].pmid, base_x, base_y);
904               tp->wall[l][k].pmid = EMPTY;
905               clearTrapazoid(mi, k, l);
906               drawSquare(mi, tp->base[base_y][base_x].pmid,
907                 tp->base[base_y][base_x].cid, base_x, base_y);
908             } else {
909               tp->wall[l + j][k] = tp->wall[l][k];
910               tp->wall[l + j][k].pmid =
911                 checkBottom(tp->wall[l + j][k].pmid, k, l + j);
912               tp->wall[l][k].pmid = EMPTY;
913               clearTrapazoid(mi, k, l);
914               drawTrapazoid(mi, /* tp->wall[l][k].pmid, */ tp->wall[l][k].cid,
915                 k, l + j);
916             }
917             XFlush(display);
918           }
919     }
920   }
921 }
922 
923 static void
freezeWall(ModeInfo * mi,int w)924 freezeWall(ModeInfo * mi, int w)
925 {
926   int i, j;
927 
928   for (j = 0; j < WELL_DEPTH; j++)
929     for (i = 0; i < WELL_WIDTH; i++) {
930       freezeTrapazoid(mi, w * WELL_WIDTH + i, j);
931     }
932   XFlush(MI_DISPLAY(mi));
933 }
934 
935 static Bool
allFrozen(ModeInfo * mi)936 allFrozen(ModeInfo * mi)
937 {
938   trisstruct *tp = &triss[MI_SCREEN(mi)];
939   int w;
940 
941   for (w = 0; w < MAX_SIDES; w++)
942     if (tp->frozen_wall[w] == MAX_SIDES) {
943       freezeWall(mi, w);
944       XFlush(MI_DISPLAY(mi));
945     }
946   for (w = 0; w < MAX_SIDES; w++)
947     if (!tp->frozen_wall[w])
948       return False;
949   return True;
950 }
951 
952 static void
checkFreeze(ModeInfo * mi)953 checkFreeze(ModeInfo *mi)
954 {
955   trisstruct *tp = &triss[MI_SCREEN(mi)];
956   int w;
957 
958   for (w = 0; w < MAX_SIDES; w++) {
959     if (!tp->frozen_wall[w]) {
960       dropWall(mi, w);
961     } else {
962       tp->frozen_wall[w]--;
963       if (!tp->frozen_wall[w]) {
964         freezeWall(mi, w);
965         dropWall(mi, w);
966       }
967     }
968   }
969 }
970 
971 static int
curPixmap(trisstruct * tp,int i,int j)972 curPixmap(trisstruct *tp, int i, int j)
973 {
974   int pmid = 0;
975 
976   if (ARR(i,j) != ARR(i-1,j))
977     pmid |= LEFT;
978   if (ARR(i,j) != ARR(i,j+1))
979     pmid |= DOWN;
980   if (ARR(i,j) != ARR(i+1,j))
981     pmid |= RIGHT;
982   if (ARR(i,j) != ARR(i,j-1))
983     pmid |= UP;
984   if (ARR(i,j) != ARR(i-1,j+1))
985     pmid |= LEFT_DOWN;
986   if (ARR(i,j) != ARR(i+1,j+1))
987     pmid |= RIGHT_DOWN;
988   if (ARR(i,j) != ARR(i+1,j-1))
989     pmid |= RIGHT_UP;
990   if (ARR(i,j) != ARR(i-1,j-1))
991     pmid |= LEFT_UP;
992   return pmid;
993 }
994 
995 static int
rotateIndex(int pmid,int i)996 rotateIndex(int pmid, int i)
997 {
998   int wallRotation, pm1, pm0;
999 
1000   if (pmid == EMPTY)
1001     return EMPTY;
1002   wallRotation = (MAX_SIDES - i / WELL_WIDTH) % MAX_SIDES;
1003   pm1 = (0xF0 & pmid) << wallRotation;
1004   pm0 = (0xF & pmid) << wallRotation;
1005   pm1 = (0xF0 & pm1) | ((pm1 & 0xF00) >> MAX_SIDES);
1006   pm0 = (0xF & pm0) | ((pm0 & 0xF0) >> MAX_SIDES);
1007   return (pm1 | pm0);
1008 }
1009 
1010 static void
drawBox(ModeInfo * mi,int pmid,int cid,int i,int j)1011 drawBox(ModeInfo * mi, int pmid, int cid, int i, int j)
1012 {
1013   if (j < WELL_DEPTH) {
1014     drawTrapazoid(mi, /* pmid, */ cid, i, j);
1015   } else {
1016     int base_i, base_j;
1017 
1018     wall_to_base(&base_i, &base_j, i, j);
1019     drawSquare(mi, pmid, cid, base_i, base_j);
1020   }
1021 }
1022 
1023 static void
clearSquare(ModeInfo * mi,int col,int row)1024 clearSquare(ModeInfo * mi, int col, int row)
1025 {
1026   Display    *display = MI_DISPLAY(mi);
1027   Window      window = MI_WINDOW(mi);
1028   trisstruct *tp = &triss[MI_SCREEN(mi)];
1029 
1030   XSetForeground(display, tp->gc, tp->blackpixel);
1031   XFillRectangle(display, window, tp->gc,
1032     tp->xb + col * tp->xs, tp->yb + row * tp->ys, tp->xs, tp->ys);
1033 }
1034 
1035 static void
drawPolyomino(ModeInfo * mi)1036 drawPolyomino(ModeInfo * mi)
1037 {
1038   trisstruct *tp = &triss[MI_SCREEN(mi)];
1039   int   i, j;
1040 
1041   if (tp->well) {
1042     int xi, yj, base_i, base_j;
1043     int temp_base[WELL_WIDTH][WELL_WIDTH];
1044 
1045     /* Initialize */
1046     for (i = 0; i < WELL_WIDTH; i++)
1047       for (j = 0; j < WELL_WIDTH; j++)
1048         temp_base[j][i] = 0;
1049     /* Find pieces and overlap them if necessary */
1050     for (i = 0; i < tp->curPolyomino.size; i++) {
1051       for (j = 0; j < tp->curPolyomino.size; j++) {
1052         if (polytris[(int) tp->bonusNow].polyomino
1053                     [tp->curPolyomino.polyomino_number].shape
1054                     [j * tp->curPolyomino.size + i]) {
1055           xi = (tp->curPolyomino.xpos + i) % WELL_PERIMETER;
1056           yj = tp->curPolyomino.ypos + j;
1057           if (yj >= WELL_DEPTH) {
1058             wall_to_base(&base_i, &base_j, xi, yj);
1059             xi = checkWall(rotateIndex(curPixmap(tp, i, j), xi),
1060               base_i, base_j);
1061             if (!temp_base[base_j][base_i])
1062               temp_base[base_j][base_i] = xi;
1063             else
1064               temp_base[base_j][base_i] &= xi;
1065           }
1066         }
1067       }
1068       /* Now draw */
1069       for (i = 0; i < tp->curPolyomino.size; i++)
1070         for (j = 0; j < tp->curPolyomino.size; j++)
1071           if (polytris[(int) tp->bonusNow].polyomino
1072                       [tp->curPolyomino.polyomino_number].shape
1073                       [j * tp->curPolyomino.size + i]) {
1074             xi = (tp->curPolyomino.xpos + i) % WELL_PERIMETER;
1075             yj = tp->curPolyomino.ypos + j;
1076             if (yj >= WELL_DEPTH) {
1077               wall_to_base(&base_i, &base_j, xi, yj);
1078               if (temp_base[base_j][base_i]) {
1079                 drawSquare(mi, temp_base[base_j][base_i],
1080                   tp->curPolyomino.color_number, base_i, base_j);
1081                 temp_base[base_j][base_i] = 0;
1082               }
1083             } else if (yj >= 0) {
1084               drawTrapazoid(mi, /* tp->curPolyomino.pmid, */
1085                 tp->curPolyomino.color_number, xi, yj);
1086             }
1087           }
1088     }
1089   } else {
1090     for (i = 0; i < tp->curPolyomino.size; i++) {
1091       for (j = 0; j < tp->curPolyomino.size; j++) {
1092         if (polytris[(int) tp->bonusNow].polyomino
1093                     [tp->curPolyomino.polyomino_number].shape
1094                     [j * tp->curPolyomino.size + i]) {
1095           drawSquare(mi, curPixmap(tp, i, j),
1096             tp->curPolyomino.color_number,
1097             tp->curPolyomino.xpos + i, tp->curPolyomino.ypos + j);
1098         }
1099       }
1100     }
1101   }
1102 }
1103 
1104 static void
drawPolyominoDiff(ModeInfo * mi,thing_t * old)1105 drawPolyominoDiff(ModeInfo *mi, thing_t * old)
1106 {
1107   trisstruct *tp = &triss[MI_SCREEN(mi)];
1108   int   i, j, ox, oy;
1109 
1110   if (tp->well) {
1111     int xi, yj, base_i, base_j;
1112     int temp_base[WELL_WIDTH][WELL_WIDTH];
1113 
1114     /* Initialize */
1115     for (i = 0; i < WELL_WIDTH; i++)
1116       for (j = 0; j < WELL_WIDTH; j++)
1117         temp_base[j][i] = 0;
1118     /* Find pieces and overlap them if necessary */
1119     for (i = 0; i < tp->curPolyomino.size; i++)
1120       for (j = 0; j < tp->curPolyomino.size; j++)
1121         if (polytris[(int) tp->bonusNow].polyomino
1122                     [tp->curPolyomino.polyomino_number].shape
1123                     [j * tp->curPolyomino.size + i]) {
1124           xi = (tp->curPolyomino.xpos + i) % WELL_PERIMETER;
1125           yj = tp->curPolyomino.ypos + j;
1126           if (yj >= WELL_DEPTH) {
1127             wall_to_base(&base_i, &base_j, xi, yj);
1128             xi = checkWall(rotateIndex(curPixmap(tp, i, j), xi),
1129               base_i, base_j);
1130             if (!temp_base[base_j][base_i])
1131               temp_base[base_j][base_i] = xi;
1132             else
1133               temp_base[base_j][base_i] &= xi;
1134            }
1135           }
1136     /* Now draw */
1137     for (i = 0; i < tp->curPolyomino.size; i++)
1138       for (j = 0; j < tp->curPolyomino.size; j++)
1139         if (polytris[(int) tp->bonusNow].polyomino
1140                     [tp->curPolyomino.polyomino_number].shape
1141                     [j * tp->curPolyomino.size + i]) {
1142           xi = (tp->curPolyomino.xpos + i) % WELL_PERIMETER;
1143           yj = tp->curPolyomino.ypos + j;
1144           if (yj >= WELL_DEPTH) {
1145             wall_to_base(&base_i, &base_j, xi, yj);
1146             if (temp_base[base_j][base_i] > 0) {
1147               drawSquare(mi, temp_base[base_j][base_i],
1148                 tp->curPolyomino.color_number, base_i, base_j);
1149                /* negate for erase */
1150                temp_base[base_j][base_i] = -temp_base[base_j][base_i];
1151              }
1152            } else if (yj >= 0) {
1153               drawTrapazoid(mi, /* tp->curPolyomino.pmid, */
1154                 tp->curPolyomino.color_number, xi, yj);
1155             }
1156           }
1157     /* Erase */
1158     for (i = 0; i < old->size; i++)
1159       for (j = 0; j < old->size; j++) {
1160         xi = (old->xpos + i) % WELL_PERIMETER;
1161         yj = old->ypos + j;
1162         ox = (xi - tp->curPolyomino.xpos + WELL_PERIMETER) % WELL_PERIMETER;
1163         oy = yj - tp->curPolyomino.ypos;
1164         if (yj >= WELL_DEPTH) {
1165           wall_to_base(&base_i, &base_j, xi, yj);
1166           if (polytris[(int) tp->bonusNow].polyomino
1167                       [old->polyomino_number].shape
1168                       [j * old->size + i] &&
1169             ((ox >= tp->curPolyomino.size) || (oy < 0) ||
1170              (oy >= tp->curPolyomino.size) || !temp_base[base_j][base_i]))
1171             clearSquare(mi, base_i, base_j);
1172         } else if (yj >= 0) {
1173            if (polytris[(int) tp->bonusNow].polyomino
1174                        [old->polyomino_number].shape
1175                        [j * old->size + i] &&
1176              ((ox >= tp->curPolyomino.size) || (oy < 0) ||
1177               (oy >= tp->curPolyomino.size) || !polytris
1178 		[(int) tp->bonusNow].polyomino
1179                 [tp->curPolyomino.polyomino_number].shape
1180                 [oy * tp->curPolyomino.size + ox]))
1181               clearTrapazoid(mi, xi, yj);
1182           }
1183         }
1184   } else {
1185     for (i = 0; i < tp->curPolyomino.size; i++)
1186       for (j = 0; j < tp->curPolyomino.size; j++)
1187         if ((tp->curPolyomino.ypos + j >= 0) &&
1188           polytris[(int) tp->bonusNow].polyomino
1189             [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1190           drawSquare(mi, curPixmap(tp, i, j),
1191             tp->curPolyomino.color_number,
1192             tp->curPolyomino.xpos + i, tp->curPolyomino.ypos + j);
1193         }
1194     for (i = 0; i < tp->curPolyomino.size; i++)
1195       for (j = 0; j < tp->curPolyomino.size; j++) {
1196         ox = old->xpos + i - tp->curPolyomino.xpos;
1197         oy = old->ypos + j - tp->curPolyomino.ypos;
1198         if (polytris[(int) tp->bonusNow].polyomino[old->polyomino_number].shape[j * tp->curPolyomino.size + i] &&
1199           ((ox < 0) || (ox >= tp->curPolyomino.size) ||
1200           (oy < 0) || (oy >= tp->curPolyomino.size) ||
1201           !polytris[(int) tp->bonusNow].polyomino
1202             [tp->curPolyomino.polyomino_number].shape[oy * tp->curPolyomino.size + ox])) {
1203           clearSquare(mi, (old->xpos + i), (old->ypos + j));
1204         }
1205       }
1206   }
1207 }
1208 
1209 static void
redoNext(ModeInfo * mi)1210 redoNext(ModeInfo * mi)
1211 {
1212   trisstruct *tp = &triss[MI_SCREEN(mi)];
1213   int next_start, i;
1214 
1215   next_start = (int) (tp->curPolyomino.random_number % polytris[(int) tp->bonusNow].mode.number);
1216   tp->curPolyomino.color_number = next_start;
1217 
1218   tp->curPolyomino.polyomino_number = polytris[(int) tp->bonusNow].mode.start[next_start];
1219   for (i = 0; i < tp->curPolyomino.random_rotation; i++)
1220     tp->curPolyomino.polyomino_number = polytris[(int) tp->bonusNow].polyomino
1221       [tp->curPolyomino.polyomino_number].rotation;
1222   tp->curPolyomino.size = polytris[(int) tp->bonusNow].polyomino[tp->curPolyomino.polyomino_number].size;
1223   tp->curPolyomino.ypos = -polytris[(int) tp->bonusNow].polyomino
1224     [tp->curPolyomino.polyomino_number].leadingEmptyHeight;
1225 }
1226 
1227 static void
newPolyomino(ModeInfo * mi)1228 newPolyomino(ModeInfo * mi) {
1229   trisstruct *tp = &triss[MI_SCREEN(mi)];
1230 
1231   tp->curPolyomino.random_number = LRAND();
1232   tp->curPolyomino.random_rotation = NRAND(MAX_SIDES);
1233 #if 0
1234   tp->curPolyomino.random_reflection = NRAND(2);  /* Future? */
1235 #endif
1236   if (tp->bonus) {
1237     if (trackmouse) {
1238       tp->bonusNow = 0;
1239     } else {
1240       /* Unlikely to finish rows, so show bonus pieces this way */
1241       tp->bonusNow = !NRAND(16);
1242     }
1243   }
1244   redoNext(mi);
1245   if (tp->well) {
1246     int w;
1247 
1248     /* pick a free spot on the rim, not all frozen else this is an infinite
1249        loop */
1250     /* tp->curPolyomino.xpos = (WELL_WIDTH - tp->curPolyomino.size) / 2; */
1251     tp->curPolyomino.xpos = NRAND(WELL_WIDTH - tp->curPolyomino.size + 1);
1252     do {
1253       w = NRAND(MAX_SIDES);
1254     } while (tp->frozen_wall[w]);
1255     tp->curPolyomino.xpos += w * WELL_WIDTH;
1256   } else {
1257     tp->curPolyomino.xpos = NRAND(tp->ncols - tp->curPolyomino.size + 1);
1258     /* tp->curPolyomino.xpos = (tp->ncols - tp->curPolyomino.size) / 2; */
1259   }
1260 }
1261 
1262 static void
putBox(ModeInfo * mi)1263 putBox(ModeInfo * mi)
1264 {
1265   trisstruct *tp = &triss[MI_SCREEN(mi)];
1266   int   i, j;
1267   int   x = tp->curPolyomino.xpos, y = tp->curPolyomino.ypos, pos;
1268 
1269   for (i = 0; i < tp->curPolyomino.size; i++)
1270     for (j = 0; j < tp->curPolyomino.size; j++)
1271       if ((y + j >= 0) && polytris[(int) tp->bonusNow].polyomino
1272         [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1273         if (tp->well) {
1274           /* Set pieces and overlap them if necessary */
1275           int xi, yj;
1276 
1277           xi = (x + i) % WELL_PERIMETER;
1278           yj = y + j;
1279           if (yj >= WELL_DEPTH) {
1280             int base_i, base_j;
1281 
1282             wall_to_base(&base_i, &base_j, xi, yj);
1283             xi = checkWall(rotateIndex(curPixmap(tp, i, j), xi),
1284               base_i, base_j);
1285             if (!tp->base[base_j][base_i].pmid)
1286               tp->base[base_j][base_i].pmid = xi;
1287             else
1288               tp->base[base_j][base_i].pmid &= xi;
1289             tp->base[base_j][base_i].cid = tp->curPolyomino.color_number;
1290           } else {
1291             tp->wall[yj][xi].pmid =
1292               checkSides(checkBottom(rotateIndex(curPixmap(tp, i,
1293               j), xi), xi, yj), xi);
1294             tp->wall[yj][xi].cid = tp->curPolyomino.color_number;
1295             tp->frozen_wall[xi / WELL_WIDTH] = MAX_SIDES;
1296           }
1297         } else {
1298           pos = (y + j) * tp->ncols + x + i;
1299           tp->field[pos].pmid = curPixmap(tp, i, j);
1300           tp->field[pos].cid = tp->curPolyomino.color_number;
1301         }
1302       }
1303 }
1304 
1305 static Bool
overlapping(ModeInfo * mi)1306 overlapping(ModeInfo * mi)
1307 {
1308   trisstruct *tp = &triss[MI_SCREEN(mi)];
1309   int       i, j;
1310   int       x = tp->curPolyomino.xpos, y = tp->curPolyomino.ypos;
1311   Bool gradualAppear = tp->well;
1312 
1313   if (tp->well) {
1314     for (i = 0; i < tp->curPolyomino.size; i++)
1315       for (j = 0; j < tp->curPolyomino.size; j++)
1316         if (polytris[(int) tp->bonusNow].polyomino
1317                 [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1318           int xi, yj;
1319 
1320           xi = (x + i) % WELL_PERIMETER;
1321           yj = y + j;
1322           if (yj < WELL_DEPTH) {
1323             if (tp->frozen_wall[xi / WELL_WIDTH])
1324               return True;
1325             if (gradualAppear) {
1326 /* This method one can turn polyomino to an area above of screen, also
1327    part of the polyomino may not be visible initially */
1328               if ((yj >= 0) && (tp->wall[yj][xi].pmid >= 0))
1329                 return True;
1330             } else {
1331 /* This method does not allow turning polyomino to an area above screen */
1332               if ((yj < 0) || (tp->wall[yj][xi].pmid >= 0))
1333                 return True;
1334             }
1335           }
1336           else if (yj < WELL_DEPTH + WELL_WIDTH) {
1337             int base_i, base_j;
1338 
1339             wall_to_base(&base_i, &base_j, xi, yj);
1340             if (tp->base[base_j][base_i].pmid >= 0)
1341               return True;
1342           }
1343           else
1344             return True;
1345         }
1346   } else {
1347     for (i = 0; i < tp->curPolyomino.size; i++)
1348       for (j = 0; j < tp->curPolyomino.size; j++)
1349         if (polytris[(int) tp->bonusNow].polyomino
1350             [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1351           if ((y + j >= tp->nrows) || (x + i < 0) || (x + i >= tp->ncols))
1352             return True;
1353           if (gradualAppear) {
1354 /* This method one can turn polyomino to an area above of screen, also
1355    part of the polyomino may not be visible initially */
1356             if ((y + j >= 0) &&
1357                 (tp->field[(y + j) * tp->ncols + x + i].pmid >= 0))
1358               return True;
1359           } else {
1360 /* This method does not allow turning polyomino to an area above screen */
1361             if ((y + j < 0) ||
1362                 (tp->field[(y + j) * tp->ncols + x + i].pmid >= 0))
1363               return True;
1364           }
1365         }
1366   }
1367   return False;
1368 }
1369 
1370 static Bool
atBottom(ModeInfo * mi)1371 atBottom(ModeInfo * mi)
1372 {
1373   trisstruct *tp = &triss[MI_SCREEN(mi)];
1374   int       i, j;
1375   int       x = tp->curPolyomino.xpos, y = tp->curPolyomino.ypos;
1376 
1377   if (tp->well) {
1378     for (i = 0; i < tp->curPolyomino.size; i++)
1379       for (j = 0; j < tp->curPolyomino.size; j++)
1380         if (polytris[(int) tp->bonusNow].polyomino
1381             [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1382           int xi, yj;
1383 
1384           xi = (x + i) % WELL_PERIMETER;
1385           yj = y + j;
1386           if (yj < -1)
1387             return False;
1388           if (yj < WELL_DEPTH - 1) {
1389             if (tp->frozen_wall[xi / WELL_WIDTH])
1390               return True;
1391             if (tp->wall[yj + 1][xi].pmid >= 0)
1392               return True;
1393           } else if (yj < WELL_DEPTH + WELL_WIDTH - 1) {
1394             int base_i, base_j;
1395 
1396             wall_to_base(&base_i, &base_j, xi, yj + 1);
1397             if (tp->base[base_j][base_i].pmid >= 0)
1398               return True;
1399           } else
1400             return True;
1401         }
1402   } else {
1403     for (i = 0; i < tp->curPolyomino.size; i++)
1404       for (j = 0; j < tp->curPolyomino.size; j++)
1405         if ((y + j >= -1) && polytris[(int) tp->bonusNow].polyomino
1406           [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i])
1407           if ((y + j >= tp->nrows - 1) || (x + i < 0) || (x + i >= tp->ncols) ||
1408               (tp->field[(y + j + 1) * tp->ncols + x + i].pmid >= 0))
1409             return True;
1410   }
1411   return False;
1412 }
1413 
1414 static Bool
atBaseFully(ModeInfo * mi)1415 atBaseFully(ModeInfo * mi)
1416 {
1417   trisstruct *tp = &triss[MI_SCREEN(mi)];
1418   int i, j;
1419 
1420   for (i = 0; i < tp->curPolyomino.size; i++)
1421     for (j = 0; j < tp->curPolyomino.size; j++)
1422       if (tp->curPolyomino.ypos + j < WELL_DEPTH &&
1423           polytris[(int) tp->bonusNow].polyomino
1424            [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i])
1425     return False;
1426   return True;
1427 }
1428 
1429 static Bool
atBasePartially(ModeInfo * mi)1430 atBasePartially(ModeInfo * mi)
1431 {
1432   trisstruct *tp = &triss[MI_SCREEN(mi)];
1433   int i, j;
1434 
1435   for (i = 0; i < tp->curPolyomino.size; i++)
1436     for (j = 0; j < tp->curPolyomino.size; j++)
1437         if ((tp->curPolyomino.ypos + j >= WELL_DEPTH) &&
1438             polytris[(int) tp->bonusNow].polyomino
1439               [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i])
1440           return True;
1441   return False;
1442 }
1443 
1444 static Bool
wallChange(ModeInfo * mi,thing_t oldthing,thing_t newthing)1445 wallChange(ModeInfo *mi, thing_t oldthing, thing_t newthing)
1446 {
1447   trisstruct *tp = &triss[MI_SCREEN(mi)];
1448   int             w = -1, i, j;
1449   int             x = tp->curPolyomino.xpos;
1450 
1451   for (i = 0; i < oldthing.size; i++)
1452     for (j = 0; j < oldthing.size; j++)
1453       if (polytris[(int) tp->bonusNow].polyomino[oldthing.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1454         if (w == -1)
1455           w = ((x + i) % WELL_PERIMETER) / WELL_WIDTH;
1456         else if (w != ((x + i) % WELL_PERIMETER) / WELL_WIDTH)
1457           return True;
1458       }
1459   for (i = 0; i < newthing.size; i++)
1460     for (j = 0; j < newthing.size; j++)
1461       if (polytris[(int) tp->bonusNow].polyomino
1462                 [tp->curPolyomino.polyomino_number].shape[j * tp->curPolyomino.size + i]) {
1463           if (w != ((x + i) % WELL_PERIMETER) / WELL_WIDTH)
1464             return True;
1465       }
1466   return False;
1467 }
1468 
1469 static void
tryMove(ModeInfo * mi,move_t move)1470 tryMove(ModeInfo * mi, move_t move)
1471 {
1472   trisstruct *tp = &triss[MI_SCREEN(mi)];
1473   thing_t   old;
1474   int       i;
1475   int       skip = False;
1476   int       cw = False; /* I am not sure if this is the original */
1477 
1478   old = tp->curPolyomino;
1479   switch (move) {
1480     case FALL:
1481       tp->curPolyomino.ypos++;
1482       break;
1483 
1484     case DROP:
1485       do { /* so fast you can not see it ;) */
1486         tp->curPolyomino.ypos ++;
1487       } while (!overlapping(mi));
1488       tp->curPolyomino.ypos--;
1489       break;
1490 
1491     case MOVE_LEFT:
1492       if (tp->well) {
1493         tp->curPolyomino.xpos = (tp->curPolyomino.xpos + WELL_PERIMETER - 1) % WELL_PERIMETER;
1494         if (atBaseFully(mi) || (atBasePartially(mi) && wallChange(mi, old, tp->curPolyomino)))
1495           skip = True;
1496       } else
1497         tp->curPolyomino.xpos--;
1498       break;
1499 
1500     case MOVE_RIGHT:
1501       if (tp->well) {
1502         tp->curPolyomino.xpos = (tp->curPolyomino.xpos + WELL_PERIMETER + 1) % WELL_PERIMETER;
1503         if (atBaseFully(mi) || (atBasePartially(mi) && wallChange(mi, old, tp->curPolyomino)))
1504           skip = True;
1505       } else
1506         tp->curPolyomino.xpos++;
1507       break;
1508 
1509     case ROTATE:
1510         if (cw)
1511           for (i = 0; i < MAX_SIDES - 1; i++)
1512             tp->curPolyomino.polyomino_number = polytris[(int) tp->bonusNow].polyomino
1513               [tp->curPolyomino.polyomino_number].rotation;
1514         else /* ccw */
1515           tp->curPolyomino.polyomino_number = polytris[(int) tp->bonusNow].polyomino
1516             [tp->curPolyomino.polyomino_number].rotation;
1517       tp->curPolyomino.xpos = old.xpos;
1518       tp->curPolyomino.ypos = old.ypos;
1519       if (tp->well && atBasePartially(mi) && wallChange(mi, old, tp->curPolyomino))
1520           skip = True;
1521       break;
1522 
1523     case REFLECT: /* reflect on y axis */
1524       tp->curPolyomino.polyomino_number = polytris[(int) tp->bonusNow].polyomino
1525         [tp->curPolyomino.polyomino_number].reflection;
1526       tp->curPolyomino.xpos = old.xpos;
1527       tp->curPolyomino.ypos = old.ypos;
1528       if (tp->well && atBasePartially(mi) && wallChange(mi, old, tp->curPolyomino))
1529           skip = True;
1530       break;
1531   }
1532 
1533   if (!skip && !overlapping(mi)) {
1534     drawPolyominoDiff(mi, &old);
1535   } else {
1536     tp->curPolyomino = old;
1537     tp->sidemoves = tp->ncols / 2;
1538   }
1539 }
1540 
1541 static void
fillLines(ModeInfo * mi)1542 fillLines(ModeInfo *mi)
1543 {
1544   Display    *display = MI_DISPLAY(mi);
1545   trisstruct *tp = &triss[MI_SCREEN(mi)];
1546   int             i, j;
1547 
1548   XFlush(display);
1549   if (tp->well) {
1550     for (j = 0; j < WELL_DEPTH + WELL_WIDTH; j++)
1551       for (i = 0; i < WELL_PERIMETER; i++) {
1552          drawBox(mi, BITMAPS - 1,
1553            LRAND() % polytris[(int) tp->bonusNow].mode.number,
1554                  i, j);
1555          XFlush(display);
1556       }
1557   } else {
1558     for (j = 0; j <= tp->nrows / 2; j++) {
1559       for (i = 0; i < tp->ncols; i++) {
1560          drawSquare(mi, BITMAPS - 1,
1561            LRAND() % polytris[(int) tp->bonusNow].mode.number,
1562                  i, j);
1563          drawSquare(mi, BITMAPS - 1,
1564            LRAND() % polytris[(int) tp->bonusNow].mode.number,
1565                  i, tp->nrows - j - 1);
1566       }
1567       XFlush(display);
1568     }
1569   }
1570 }
1571 
1572 static void
free_images(trisstruct * tp)1573 free_images(trisstruct *tp)
1574 {
1575   int n;
1576 
1577   if (tp->images[BITMAPS - 1] != None) {
1578     (void) XDestroyImage(tp->images[BITMAPS - 1]);
1579     tp->images[BITMAPS - 1] = None;
1580   }
1581   for (n = 0; n < BITMAPS - 1; n++) {
1582     /* Don't bother to free duplicates */
1583     if (IS_UP(n) && IS_DOWN(n) && IS_LEFT(n) && IS_RIGHT(n))
1584       tp->images[n] = None;
1585     else if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
1586       tp->images[n] = None;
1587     else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
1588       tp->images[n] = None;
1589     else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
1590       tp->images[n] = None;
1591     else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
1592       tp->images[n] = None;
1593     else if (tp->images[n] != None) {
1594       (void) XDestroyImage(tp->images[n]);
1595       tp->images[n] = None;
1596     }
1597   }
1598 }
1599 
1600 static void
free_tetris_screen(ModeInfo * mi,trisstruct * tp)1601 free_tetris_screen(ModeInfo *mi, trisstruct *tp)
1602 {
1603   Display *display = MI_DISPLAY(mi);
1604 
1605   if (tp == NULL) {
1606     return;
1607   }
1608   if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1609     MI_WHITE_PIXEL(mi) = tp->whitepixel;
1610     MI_BLACK_PIXEL(mi) = tp->blackpixel;
1611 #ifndef STANDALONE
1612     MI_FG_PIXEL(mi) = tp->fg;
1613     MI_BG_PIXEL(mi) = tp->bg;
1614 #endif
1615     if (tp->colors != NULL) {
1616 #ifdef STANDALONE
1617 	Screen *screen = MI_SCREENPTR(mi);
1618 #endif
1619       if (tp->ncolors && !tp->no_colors)
1620 	free_colors(
1621 #ifdef STANDALONE
1622 		screen,
1623 #else
1624 		display,
1625 #endif
1626 		tp->cmap, tp->colors, tp->ncolors);
1627       free(tp->colors);
1628       tp->colors = (XColor *) NULL;
1629     }
1630     if (tp->cmap != None) {
1631       XFreeColormap(display, tp->cmap);
1632       tp->cmap = None;
1633     }
1634   }
1635   if (tp->gc != None) {
1636      XFreeGC(display, tp->gc);
1637      tp->gc = None;
1638   }
1639   if (tp->graypix != None) {
1640     XFreePixmap(display, tp->graypix);
1641     tp->graypix = None;
1642   }
1643   if (tp->field != NULL) {
1644      free(tp->field);
1645      tp->field = (fieldstruct *) NULL;
1646   }
1647   free_images(tp);
1648   tp = NULL;
1649 }
1650 
1651 static int
checkLines(ModeInfo * mi)1652 checkLines(ModeInfo *mi)
1653 {
1654   trisstruct *tp = &triss[MI_SCREEN(mi)];
1655   Display    *display = MI_DISPLAY(mi);
1656   Window      window = MI_WINDOW(mi);
1657 
1658   if (tp->well) {
1659     int             lSet[2][WELL_WIDTH], nset[2];
1660     int             i, j, k, *tmp;
1661 
1662     nset[0] = nset[1] = 0;
1663 
1664     /* Find filled rows */
1665     for (j = 0; j < WELL_WIDTH; j++) {
1666       lSet[0][j] = 0;
1667       for (i = 0; i < WELL_WIDTH; i++)
1668         if (tp->base[j][i].pmid >= 0)
1669           lSet[0][j] ++;
1670       if (lSet[0][j] == WELL_WIDTH)
1671         nset[0] ++;
1672     }
1673     /* Find filled columns */
1674     for (i = 0; i < WELL_WIDTH; i++) {
1675       lSet[1][i] = 0;
1676       for (j = 0; j < WELL_WIDTH; j++)
1677         if (tp->base[j][i].pmid >= 0)
1678           lSet[1][i] ++;
1679       if (lSet[1][i] == WELL_WIDTH)
1680         nset[1] ++;
1681     }
1682 
1683     if (nset[0] || nset[1]) {
1684         fieldstruct temp_base[WELL_WIDTH][WELL_WIDTH];
1685         for (k = 0; k < ((NUM_FLASHES / (nset[0] + nset[1])) / 2) * 2; k++) {
1686             for (j = 0; j < WELL_WIDTH; j++) {
1687                 if (lSet[0][j] == WELL_WIDTH)
1688                   for (i = 0; i < WELL_WIDTH; i++)
1689                     xorSquare(mi, i, j);
1690                 if (lSet[1][j] == WELL_WIDTH)
1691                   for (i = 0; i < WELL_WIDTH; i++)
1692                     xorSquare(mi, j, i);
1693             }
1694             XFlush(display);
1695         }
1696 
1697         for (j = 0; j < WELL_WIDTH; j++)
1698           for (i = 0; i < WELL_WIDTH; i++)
1699             temp_base[j][i] = tp->base[j][i];
1700         if (nset[0]) {
1701           for (j = 0; j < WELL_WIDTH / 2; j++)
1702             if (lSet[0][j] == WELL_WIDTH)
1703               for (i = 0; i < WELL_WIDTH; i++) {
1704                 for (k = j; k > 0; k--)
1705                   temp_base[k][i] = temp_base[k - 1][i];
1706                 temp_base[0][i].pmid = EMPTY;
1707                 if (j > 0) {
1708                   tmp = &temp_base[j][i].pmid;
1709                   if (*tmp >= 0)
1710                      *tmp = CHECKDOWN((unsigned int) *tmp);
1711                 }
1712                 tmp = &temp_base[j + 1][i].pmid;
1713                 if (*tmp >= 0)
1714                    *tmp = CHECKUP((unsigned int) *tmp);
1715               }
1716           for (j = WELL_WIDTH - 1; j >= WELL_WIDTH / 2; j--)
1717             if (lSet[0][j] == WELL_WIDTH)
1718               for (i = 0; i < WELL_WIDTH; i++) {
1719                 for (k = j; k < WELL_WIDTH - 1; k++)
1720                   temp_base[k][i] = temp_base[k + 1][i];
1721                 temp_base[WELL_WIDTH - 1][i].pmid = EMPTY;
1722                 if (j < WELL_WIDTH - 1) {
1723                   tmp = &temp_base[j][i].pmid;
1724                   if (*tmp >= 0)
1725                      *tmp = CHECKUP((unsigned int) *tmp);
1726                 }
1727                 tmp = &temp_base[j - 1][i].pmid;
1728                 if (*tmp >= 0)
1729                    *tmp = CHECKDOWN((unsigned int) *tmp);
1730               }
1731         }
1732         if (nset[1]) {
1733           for (i = 0; i < WELL_WIDTH / 2; i++)
1734             if (lSet[1][i] == WELL_WIDTH)
1735               for (j = 0; j < WELL_WIDTH; j++) {
1736                 for (k = i; k > 0; k--)
1737                   temp_base[j][k] = temp_base[j][k - 1];
1738                 temp_base[j][0].pmid = EMPTY;
1739                 if (i > 0) {
1740                   tmp = &temp_base[j][i].pmid;
1741                   if (*tmp >= 0)
1742                      *tmp = CHECKRIGHT((unsigned int) *tmp);
1743                 }
1744                 tmp = &temp_base[j][i + 1].pmid;
1745                 if (*tmp >= 0)
1746                    *tmp = CHECKLEFT((unsigned int) *tmp);
1747               }
1748           for (i = WELL_WIDTH - 1; i >= WELL_WIDTH / 2; i--)
1749             if (lSet[1][i] == WELL_WIDTH)
1750               for (j = 0; j < WELL_WIDTH; j++) {
1751                 for (k = i; k < WELL_WIDTH - 1; k++)
1752                   temp_base[j][k] = temp_base[j][k + 1];
1753                 temp_base[j][WELL_WIDTH - 1].pmid = EMPTY;
1754                 if (i < WELL_WIDTH - 1) {
1755                   tmp = &temp_base[j][i].pmid;
1756                   if (*tmp >= 0)
1757                      *tmp = CHECKLEFT((unsigned int) *tmp);
1758                 }
1759                 tmp = &temp_base[j][i - 1].pmid;
1760                 if (*tmp >= 0)
1761                    *tmp = CHECKRIGHT((unsigned int) *tmp);
1762               }
1763         }
1764         for (j = 0; j < WELL_WIDTH; j++)
1765           for (i = 0; i < WELL_WIDTH; i++)
1766             if ((temp_base[j][i].cid != tp->base[j][i].cid) ||
1767                 (temp_base[j][i].pmid != tp->base[j][i].pmid))
1768             {
1769               tp->base[j][i] = temp_base[j][i];
1770               if (tp->base[j][i].pmid >= 0)
1771                 drawSquare(mi, tp->base[j][i].pmid, tp->base[j][i].cid, i, j);
1772               else
1773                 clearSquare(mi, i, j);
1774             }
1775        XFlush(display);
1776     }
1777 
1778     return (nset[0] + nset[1]);
1779   } else {
1780     int      *lSet, nset = 0;
1781     int       i, j, y;
1782 
1783     if ((lSet = (int *) calloc(tp->nrows, sizeof (int))) == NULL) {
1784         free_tetris_screen(mi, tp);
1785         return -1; /* error */
1786     }
1787     for (j = 0; j < tp->nrows; j++) {
1788       for (i = 0; i < tp->ncols; i++)
1789         if (tp->field[j * tp-> ncols + i].pmid >= 0)
1790           lSet[j]++;
1791       if (lSet[j] == tp->ncols)
1792         nset++;
1793     }
1794     if (nset) {
1795       for (i = 0; i < ((NUM_FLASHES / nset) % 2) * 2; i++) {
1796         for (j = 0; j < tp->nrows; j++) {
1797           if (lSet[j] == tp->ncols)
1798             for (i = 0; i < tp->ncols; i++)
1799               xorSquare(mi, i, j);
1800         }
1801         XFlush(display);
1802       }
1803 
1804       for (j = tp->nrows - 1; j >= 0; j--) {
1805         if (lSet[j] == tp->ncols) {
1806           for (y = j; y > 0; y--)
1807             for (i = 0; i < tp->ncols; i++)
1808               tp->field[y * tp->ncols + i] =
1809                  tp->field[(y - 1) * tp->ncols + i];
1810           for (i = 0; i < tp->ncols; i++)
1811             tp->field[i].pmid = EMPTY;
1812 
1813           XCopyArea(display, window, window, tp->gc,
1814             tp->xb, tp->yb,
1815             tp->xs * tp->ncols, j * tp->ys,
1816             tp->xb, tp->yb + tp->ys);
1817           XSetForeground(display, tp->gc, tp->blackpixel);
1818           XFillRectangle(display, window, tp->gc,
1819             tp->xb, tp->yb, tp->xs * tp->ncols, tp->ys);
1820 
1821           for (i = j; i > 0; i--)
1822             lSet[i] = lSet[i - 1];
1823           lSet[0] = 0;
1824 
1825           if (j > 0)
1826             for (i = 0; i < tp->ncols; i++) {
1827               int       tmp = tp->field[j * tp->ncols + i].pmid;
1828 
1829               if ((tmp >= 0) && (tmp != CHECKDOWN(tmp))) {
1830                 tp->field[j * tp->ncols + i].pmid = CHECKDOWN(tmp);
1831                   drawSquare(mi,
1832                     tp->field[j * tp->ncols + i].pmid, tp->field[j * tp->ncols + i].cid,
1833                     i, j);
1834               }
1835             }
1836 
1837           j++;
1838 
1839           if (j < tp->nrows)
1840             for (i = 0; i < tp->ncols; i++) {
1841               int       tmp = tp->field[j * tp->ncols + i].pmid;
1842 
1843               if ((tmp >= 0) && (tmp != CHECKUP(tmp))) {
1844                 tp->field[j * tp->ncols + i].pmid = CHECKUP(tmp);
1845                 drawSquare(mi,
1846                   tp->field[j * tp->ncols + i].pmid, tp->field[j * tp->ncols + i].cid,
1847                   i, j);
1848               }
1849             }
1850 
1851           XFlush(display);
1852         }
1853       }
1854     }
1855 
1856     if (lSet)
1857       free(lSet);
1858     return nset;
1859   }
1860 }
1861 
1862 static void
gameOver(ModeInfo * mi)1863 gameOver(ModeInfo *mi)
1864 {
1865   /* maybe more stuff later */
1866   fillLines(mi);
1867 }
1868 
1869 static Bool
create_an_image(ModeInfo * mi,trisstruct * tp,int n)1870 create_an_image(ModeInfo *mi, trisstruct *tp, int n)
1871 {
1872   int x, y;
1873   unsigned char * data;
1874 
1875   if ((data = (unsigned char *) malloc(sizeof(char)*(tp->ys*ROUND8(tp->ys)/8))) == NULL) {
1876     return False;  /* no biggie, will not use images */
1877   }
1878 
1879   for (y=0;y<tp->ys;y++) for (x=0;x<tp->ys;x++) {
1880      if (!tp->use3D) {
1881 #ifdef SMALL_BELLYBUTTON
1882         if (x >= tp->ys / 2 && x <= tp->ys / 2 + 1 &&
1883             y >= tp->ys / 2 && y <= tp->ys / 2 + 1)
1884           NOTHALFBIT(x,y)
1885         else
1886 #endif
1887           HALFBIT(x,y)
1888       } else if ((x>=y && x<=tp->ys-y-1 && IS_UP(n))
1889           || (x<=y && x<=tp->ys-y-1 && y<tp->ys/2 && !IS_LEFT(n))
1890           || (x>=y && x>=tp->ys-y-1 && y<tp->ys/2 && !IS_RIGHT(n)))
1891         SETBIT(x,y)
1892       else if ((x<=y && x<=tp->ys-y-1 && IS_LEFT(n))
1893           || (x>=y && x<=tp->ys-y-1 && x<tp->ys/2 && !IS_UP(n))
1894           || (x<=y && x>=tp->ys-y-1 && x<tp->ys/2 && !IS_DOWN(n)))
1895         TWOTHIRDSBIT(x,y)
1896       else if ((x>=y && x>=tp->ys-y-1 && IS_RIGHT(n))
1897           || (x>=y && x<=tp->ys-y-1 && x>=tp->ys/2 && !IS_UP(n))
1898           || (x<=y && x>=tp->ys-y-1 && x>=tp->ys/2 && !IS_DOWN(n)))
1899         HALFBIT(x,y)
1900       else if ((x<=y && x>=tp->ys-y-1 && IS_DOWN(n))
1901           || (x<=y && x<=tp->ys-y-1 && y>=tp->ys/2 && !IS_LEFT(n))
1902           || (x>=y && x>=tp->ys-y-1 && y>=tp->ys/2 && !IS_RIGHT(n)))
1903         THIRDBIT(x,y)
1904   }
1905 
1906   if (IS_LEFT(n))
1907     for (y=0;y<tp->ys;y++)
1908       for (x=G;x<G+T;x++)
1909         SETBIT(x,y)
1910   if (IS_RIGHT(n))
1911     for (y=0;y<tp->ys;y++)
1912       for (x=G;x<G+T;x++)
1913         SETBIT(tp->ys-1-x,y)
1914   if (IS_UP(n))
1915     for (x=0;x<tp->ys;x++)
1916       for (y=G;y<G+T;y++)
1917         SETBIT(x,y)
1918   if (IS_DOWN(n))
1919     for (x=0;x<tp->ys;x++)
1920       for (y=G;y<G+T;y++)
1921         SETBIT(x,tp->ys-1-y)
1922   if (IS_LEFT(n))
1923     for (y=0;y<tp->ys;y++)
1924       for (x=0;x<G;x++)
1925         RESBIT(x,y)
1926   if (IS_RIGHT(n))
1927     for (y=0;y<tp->ys;y++)
1928       for (x=0;x<G;x++)
1929         RESBIT(tp->ys-1-x,y)
1930   if (IS_UP(n))
1931     for (x=0;x<tp->ys;x++)
1932       for (y=0;y<G;y++)
1933         RESBIT(x,y)
1934   if (IS_DOWN(n))
1935     for (x=0;x<tp->ys;x++)
1936       for (y=0;y<G;y++)
1937         RESBIT(x,tp->ys-1-y)
1938 
1939   if (IS_LEFT(n) && IS_UP(n))
1940     for (x=G;x<=G+R;x++)
1941       for (y=G;y<=R+2*G-x;y++) {
1942         if (x+y>R+2*G-RT)
1943           SETBIT(x,y)
1944         else
1945           RESBIT(x,y)
1946       }
1947   if (IS_LEFT(n) && IS_DOWN(n))
1948     for (x=G;x<=G+R;x++)
1949       for (y=G;y<=R+2*G-x;y++) {
1950         if (x+y>R+2*G-RT)
1951           SETBIT(x,tp->ys-1-y)
1952         else
1953           RESBIT(x,tp->ys-1-y)
1954       }
1955   if (IS_RIGHT(n) && IS_UP(n))
1956     for (x=G;x<=G+R;x++)
1957       for (y=G;y<=R+2*G-x;y++) {
1958         if (x+y>R+2*G-RT)
1959           SETBIT(tp->ys-1-x,y)
1960         else
1961           RESBIT(tp->ys-1-x,y)
1962       }
1963   if (IS_RIGHT(n) && IS_DOWN(n))
1964     for (x=G;x<=G+R;x++)
1965       for (y=G;y<=R+2*G-x;y++) {
1966         if (x+y>R+2*G-RT)
1967           SETBIT(tp->ys-1-x,tp->ys-1-y)
1968         else
1969           RESBIT(tp->ys-1-x,tp->ys-1-y)
1970       }
1971 
1972   if (!IS_LEFT(n) && !IS_UP(n) && IS_LEFT_UP(n)) {
1973     for (x=0;x<G;x++)
1974       for(y=0;y<G;y++)
1975         RESBIT(x,y)
1976     for (x=G;x<G+T;x++)
1977       for(y=0;y<G;y++)
1978         SETBIT(x,y)
1979     for (x=0;x<G+T;x++)
1980       for(y=G;y<G+T;y++)
1981         SETBIT(x,y)
1982   }
1983   if (!IS_LEFT(n) && !IS_DOWN(n) && IS_LEFT_DOWN(n)) {
1984     for (x=0;x<G;x++)
1985       for(y=0;y<G;y++)
1986         RESBIT(x,tp->ys-1-y)
1987     for (x=G;x<G+T;x++)
1988       for(y=0;y<G;y++)
1989         SETBIT(x,tp->ys-1-y)
1990     for (x=0;x<G+T;x++)
1991       for(y=G;y<G+T;y++)
1992         SETBIT(x,tp->ys-1-y)
1993   }
1994   if (!IS_RIGHT(n) && !IS_UP(n) && IS_RIGHT_UP(n)) {
1995     for (x=0;x<G;x++)
1996       for(y=0;y<G;y++)
1997         RESBIT(tp->ys-1-x,y)
1998     for (x=G;x<G+T;x++)
1999       for(y=0;y<G;y++)
2000         SETBIT(tp->ys-1-x,y)
2001     for (x=0;x<G+T;x++)
2002       for(y=G;y<G+T;y++)
2003         SETBIT(tp->ys-1-x,y)
2004   }
2005   if (!IS_RIGHT(n) && !IS_DOWN(n) && IS_RIGHT_DOWN(n)) {
2006     for (x=0;x<G;x++)
2007       for(y=0;y<G;y++)
2008         RESBIT(tp->ys-1-x,tp->ys-1-y)
2009     for (x=G;x<G+T;x++)
2010       for(y=0;y<G;y++)
2011         SETBIT(tp->ys-1-x,tp->ys-1-y)
2012     for (x=0;x<G+T;x++)
2013       for(y=G;y<G+T;y++)
2014         SETBIT(tp->ys-1-x,tp->ys-1-y)
2015   }
2016 #ifdef LARGE_BELLYBUTTON
2017   if (!tp->use3D) {
2018     if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
2019       for (x=0;x<G+T;x++)
2020         for(y=0;y<G+T;y++)
2021           SETBIT(x,y)
2022     if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
2023       for (x=0;x<G+T;x++)
2024         for(y=tp->ys-G-T;y<tp->ys;y++)
2025           SETBIT(x,y)
2026     if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
2027       for (x=tp->ys-G-T;x<tp->ys;x++)
2028         for(y=0;y<G+T;y++)
2029           SETBIT(x,y)
2030     if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
2031       for (x=tp->ys-G-T;x<tp->ys;x++)
2032         for(y=tp->ys-G-T;y<tp->ys;y++)
2033           SETBIT(x,y)
2034   } else
2035 #else
2036   if (tp->use3D)
2037 #endif
2038   {
2039     if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
2040       for (x=0;x<tp->ys/2-RR;x++)
2041         for(y=0;y<tp->ys/2-RR;y++)
2042           THREEQUARTERSBIT(x,y)
2043     if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
2044       for (x=0;x<tp->ys/2-RR;x++)
2045         for(y=tp->ys/2+RR;y<tp->ys;y++)
2046           THREEQUARTERSBIT(x,y)
2047     if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
2048       for (x=tp->ys/2+RR;x<tp->ys;x++)
2049         for(y=0;y<tp->ys/2-RR;y++)
2050           THREEQUARTERSBIT(x,y)
2051     if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
2052       for (x=tp->ys/2+RR;x<tp->ys;x++)
2053         for(y=tp->ys/2+RR;y<tp->ys;y++)
2054           THREEQUARTERSBIT(x,y)
2055   }
2056 
2057   if ((tp->images[n] = XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi),
2058            1, XYBitmap, 0, (char *) data, tp->xs, tp->ys, 8, 0)) == None) {
2059      free(data);
2060      return False;
2061   }
2062   tp->images[n]->byte_order = MSBFirst;
2063   tp->images[n]->bitmap_unit = 8;
2064   tp->images[n]->bitmap_bit_order = LSBFirst;
2065   return True;
2066 }
2067 
2068 static Bool
create_images(ModeInfo * mi,trisstruct * tp)2069 create_images(ModeInfo *mi, trisstruct *tp)
2070 {
2071   int n;
2072 
2073   (void) create_an_image(mi, tp, BITMAPS - 1);
2074   for (n = 0; n < BITMAPS - 1; n++) {
2075     /* Avoid duplication of identical images. */
2076     if (IS_UP(n) && IS_DOWN(n) && IS_LEFT(n) && IS_RIGHT(n))
2077       tp->images[n] = tp->images[BITMAPS - 1];
2078     else if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
2079       tp->images[n] = tp->images[n & ~LEFT_UP];
2080     else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
2081       tp->images[n] = tp->images[n & ~LEFT_DOWN];
2082     else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
2083       tp->images[n] = tp->images[n & ~RIGHT_UP];
2084     else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
2085       tp->images[n] = tp->images[n & ~RIGHT_DOWN];
2086     else if (image_needed(n)) {
2087       if (!create_an_image(mi, tp, n))
2088         return False;
2089     }
2090   }
2091   return True;
2092 }
2093 
2094 #ifndef STANDALONE
2095 ENTRYPOINT void
refresh_tetris(ModeInfo * mi)2096 refresh_tetris(ModeInfo * mi)
2097 {
2098   trisstruct *tp;
2099 
2100   if (triss == NULL)
2101     return;
2102   tp = &triss[MI_SCREEN(mi)];
2103   if (!tp->well && tp->field == NULL)
2104     return;
2105 
2106   if (!tp->painted)
2107     return;
2108   MI_CLEARWINDOW(mi);
2109   if (tp->well) {
2110     int i, j;
2111 
2112     for (i = 0; i < WELL_PERIMETER; i++) {
2113       for (j = 0; j < WELL_DEPTH; j++) {
2114         if (tp->wall[j][i].pmid >= 0) {
2115           drawTrapazoid(mi, /*  tp->wall[j][i].pmid, */ tp->wall[j][i].cid, i, j);
2116         }
2117         if (tp->frozen_wall[i / WELL_WIDTH]) {
2118           freezeTrapazoid(mi, i, j);
2119         }
2120       }
2121     }
2122     for (i = 0; i < WELL_WIDTH; i++)
2123       for (j = 0; j < WELL_WIDTH; j++)
2124         if (tp->base[j][i].pmid >= 0)
2125           drawSquare(mi, tp->base[j][i].pmid, tp->base[j][i].cid, i, j);
2126   } else {
2127     int col, row, pos;
2128 
2129     for (col = 0; col < tp->ncols; col++)
2130       for (row = 0; row < tp->nrows; row++) {
2131         pos = row * tp->ncols + col;
2132 #ifdef DEBUG
2133         (void) printf("pmid %d, cid %d, %d %d\n",
2134           tp->field[pos].pmid, tp->field[pos].cid, col, row);
2135 #endif
2136         if (tp->field[pos].pmid != EMPTY)
2137           drawSquare(mi, tp->field[pos].pmid, tp->field[pos].cid, col, row);
2138     }
2139   }
2140   drawPolyomino(mi);
2141 }
2142 
2143 ENTRYPOINT void
change_tetris(ModeInfo * mi)2144 change_tetris(ModeInfo * mi) {
2145   trisstruct *tp;
2146 
2147   if (triss == NULL)
2148     return;
2149   tp = &triss[MI_SCREEN(mi)];
2150   if (!tp->well && tp->field == NULL)
2151     return;
2152 
2153   tryMove(mi, ROTATE);
2154 }
2155 #endif
2156 
2157 ENTRYPOINT void
release_tetris(ModeInfo * mi)2158 release_tetris(ModeInfo * mi) {
2159   int bonustype, number;
2160 
2161   if (triss != NULL) {
2162     int   screen;
2163 
2164     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
2165        free_tetris_screen(mi, &triss[screen]);
2166     free(triss);
2167     triss = (trisstruct *) NULL;
2168     for (bonustype = 0; bonustype < 2; bonustype++) {
2169       if (polytris[bonustype].polyomino != NULL) {
2170         for (number = 0; number < max_ominoes[bonustype]; number++) {
2171           if (polytris[bonustype].polyomino[number].shape != NULL)
2172             free(polytris[bonustype].polyomino[number].shape);
2173         }
2174         free(polytris[bonustype].polyomino);
2175         polytris[bonustype].polyomino = (Polyominoes *) NULL;
2176       }
2177       if (polytris[bonustype].mode.start != NULL) {
2178         free(polytris[bonustype].mode.start);
2179         polytris[bonustype].mode.start = (int *) NULL;
2180       }
2181     }
2182   }
2183 }
2184 
2185 #ifndef STANDALONE
2186 extern char *background;
2187 extern char *foreground;
2188 #endif
2189 
2190 ENTRYPOINT void
init_tetris(ModeInfo * mi)2191 init_tetris(ModeInfo * mi) {
2192   Display *   display = MI_DISPLAY(mi);
2193   Window      window = MI_WINDOW(mi);
2194   int size = MI_SIZE(mi);
2195   int   i, j, bonustype;
2196   trisstruct *tp;
2197 
2198   if (triss == NULL) {
2199     MI_INIT(mi, triss);
2200     for (bonustype = 0; bonustype < 2; bonustype++) {
2201       if (((polytris[bonustype].mode.start = (int *) malloc(start_ominoes[bonustype] *
2202             sizeof(int))) == NULL) ||
2203           ((polytris[bonustype].polyomino = (Polyominoes *) malloc(max_ominoes[bonustype] *
2204             sizeof(Polyominoes))) == NULL)) {
2205         release_tetris(mi);
2206         return;
2207       }
2208     }
2209     if (!readPolyominoes()) {
2210       release_tetris(mi);
2211       return;
2212     }
2213 #ifdef DEBUG
2214     writePolyominoes(tp);
2215 #endif
2216   }
2217    tp = &triss[MI_SCREEN(mi)];
2218 
2219   if (MI_IS_FULLRANDOM(mi)) {
2220     tp->bonus = (Bool) (LRAND() & 1);
2221     tp->well = !(NRAND(3));
2222     tp->use3D = (Bool) (NRAND(4));
2223   } else {
2224     tp->bonus = bonus;
2225     tp->well = well;
2226     tp->use3D = !plain;
2227   }
2228 
2229   if (tp->gc == None) {
2230     tp->blackpixel = MI_BLACK_PIXEL(mi);
2231     if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
2232       XColor      color;
2233 
2234 #ifndef STANDALONE
2235       tp->fg = MI_FG_PIXEL(mi);
2236       tp->bg = MI_BG_PIXEL(mi);
2237 #endif
2238       tp->whitepixel = MI_WHITE_PIXEL(mi);
2239       if ((tp->cmap = XCreateColormap(display, window,
2240           MI_VISUAL(mi), AllocNone)) == None) {
2241         free_tetris_screen(mi, tp);
2242         return;
2243       }
2244       XSetWindowColormap(display, window, tp->cmap);
2245       (void) XParseColor(display, tp->cmap, "black", &color);
2246       (void) XAllocColor(display, tp->cmap, &color);
2247       MI_BLACK_PIXEL(mi) = color.pixel;
2248       (void) XParseColor(display, tp->cmap, "white", &color);
2249       (void) XAllocColor(display, tp->cmap, &color);
2250       MI_WHITE_PIXEL(mi) = color.pixel;
2251 #ifndef STANDALONE
2252       (void) XParseColor(display, tp->cmap, background, &color);
2253       (void) XAllocColor(display, tp->cmap, &color);
2254       MI_BG_PIXEL(mi) = color.pixel;
2255       (void) XParseColor(display, tp->cmap, foreground, &color);
2256       (void) XAllocColor(display, tp->cmap, &color);
2257       MI_FG_PIXEL(mi) = color.pixel;
2258 #endif
2259       tp->colors = (XColor *) NULL;
2260       tp->ncolors = 0;
2261     }
2262     if ((tp->gc = XCreateGC(display, MI_WINDOW(mi),
2263         (unsigned long) 0, (XGCValues *) NULL)) == None) {
2264       free_tetris_screen(mi, tp);
2265       return;
2266     }
2267 #if 0
2268     {
2269       XGCValues       gcv;
2270       gcv.function = GXxor;
2271       gcv.foreground = tp->fg;
2272       gcv.background = tp->bg;
2273     }
2274 #endif
2275   }
2276   MI_CLEARWINDOW(mi);
2277   tp->painted = False;
2278 
2279   tp->width = MI_WIDTH(mi);
2280   tp->height = MI_HEIGHT(mi);
2281 
2282   free_images(tp);
2283   if (tp->width < 2 + 2 * tp->well)
2284     tp->width = 2 + 2 * tp->well;
2285   if (tp->height < 2 + 2 * tp->well)
2286     tp->height = 2 + 2 * tp->well;
2287   if (size >= MAXPIXELSIZE  &&
2288         (MINGRIDSIZE * size < tp->width && MINGRIDSIZE * size < tp->height)) {
2289       if (!tp->well) {
2290         tp->xs = size;
2291         tp->ys = size;
2292       } else {
2293         tp->xs = tp->ys = MAX(MINSIZE, MIN(tp->width, tp->height) /
2294             ((tp->well) ? 3 * MINGRIDSIZE : MINGRIDSIZE));
2295       }
2296   } else {
2297     if (size < -MINSIZE)
2298       tp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(tp->width, tp->height) /
2299         ((tp->well) ? 3 * MINGRIDSIZE : MINGRIDSIZE))) - MINSIZE + 1) + MINSIZE;
2300     else if (size < MINSIZE)
2301       tp->ys = MINSIZE;
2302     else
2303       tp->ys = MIN(size, MAX(MINSIZE, MIN(tp->width, tp->height) /
2304         ((tp->well) ? 3 * MINGRIDSIZE : MINGRIDSIZE)));
2305     tp->xs = tp->ys;
2306   }
2307   if (tp->ys >= MAXPIXELSIZE) {
2308     tp->xs = tp->ys = (tp->ys / 12) * 12;
2309     if (!create_images(mi, tp)) {
2310       free_images(tp);
2311       tp->pixelmode = True;
2312     } else
2313       tp->pixelmode = False;
2314   } else
2315     tp->pixelmode = True;
2316   if (tp->well) {
2317     if ((tp->graypix = XCreateBitmapFromData(display, window,
2318          (char *) gray1_bits, gray1_width, gray1_height)) == None) {
2319       free_tetris_screen(mi, tp);
2320       return;
2321     }
2322     tp->ncols = MAX_SIDES * WELL_WIDTH;
2323     tp->nrows = WELL_DEPTH;
2324     tp->xb = tp->width / 2 - tp->xs * WELL_WIDTH / 2;
2325     tp->yb = tp->height / 2 - tp->ys * WELL_WIDTH / 2;
2326     for (i = 0; i < WELL_PERIMETER; i++) {
2327       for (j = 0; j < WELL_DEPTH + WELL_WIDTH; j++) {
2328         tp->wall[j][i].pmid = EMPTY;
2329         tp->wall[j][i].cid = 0;
2330       }
2331     }
2332     for (i = 0; i < WELL_WIDTH; i++) {
2333       for (j = 0; j < WELL_WIDTH; j++) {
2334         tp->base[j][i].pmid = EMPTY;
2335         tp->base[j][i].cid = BITMAPS - 1;
2336       }
2337     }
2338     for (i = 0; i < MAX_SIDES; i++) {
2339       tp->frozen_wall[i] = 0;
2340     }
2341   } else {
2342     tp->ncols = MAX(tp->width / tp->xs, 5);
2343     tp->nrows = MAX(tp->height / tp->ys, 5);
2344     tp->xb = (tp->width - tp->xs * tp->ncols) / 2;
2345     tp->yb = (tp->height - tp->ys * tp->nrows) / 2;
2346     if (tp->field != NULL)
2347       free(tp->field);
2348     if ((tp->field = (fieldstruct *) malloc(tp->ncols * tp->nrows *
2349         sizeof (fieldstruct))) == NULL) {
2350       free_tetris_screen(mi, tp);
2351       return;
2352     }
2353     for (i = 0; i < tp->ncols * tp->nrows; i++) {
2354       tp->field[i].pmid = EMPTY;
2355       tp->field[i].cid = 0;
2356     }
2357   }
2358   tp->rows = 0;
2359   tp->level = 0;
2360   tp->bonusNow = False;
2361 
2362   /* Set up colour map */
2363   tp->direction = (LRAND() & 1) ? 1 : -1;
2364   if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
2365 #ifdef STANDALONE
2366 	Screen *screen = MI_SCREENPTR(mi);
2367 #endif
2368     if (tp->colors != NULL) {
2369       if (tp->ncolors && !tp->no_colors)
2370 	free_colors(
2371 #ifdef STANDALONE
2372 		screen,
2373 #else
2374 		display,
2375 #endif
2376 		tp->cmap, tp->colors, tp->ncolors);
2377       free(tp->colors);
2378       tp->colors = (XColor *) NULL;
2379     }
2380     tp->ncolors = MI_NCOLORS(mi);
2381     if (tp->ncolors < 2)
2382       tp->ncolors = 2;
2383     if (tp->ncolors <= 2)
2384       tp->mono_p = True;
2385     else
2386       tp->mono_p = False;
2387 
2388     if (tp->mono_p)
2389       tp->colors = (XColor *) NULL;
2390     else
2391       if ((tp->colors = (XColor *) malloc(sizeof (*tp->colors) *
2392           (tp->ncolors + 1))) == NULL) {
2393         free_tetris_screen(mi, tp);
2394         return;
2395       }
2396     tp->cycle_p = has_writable_cells(
2397 #ifdef STANDALONE
2398 	screen, MI_VISUAL(mi)
2399 #else
2400 	mi
2401 #endif
2402 	);
2403     if (tp->cycle_p) {
2404       if (MI_IS_FULLRANDOM(mi)) {
2405         if (!NRAND(8))
2406           tp->cycle_p = False;
2407         else
2408           tp->cycle_p = True;
2409       } else {
2410         tp->cycle_p = cycle_p;
2411       }
2412     }
2413     if (!tp->mono_p) {
2414       if (!(LRAND() % 10))
2415         make_random_colormap(
2416 #ifdef STANDALONE
2417 		screen, MI_VISUAL(mi),
2418 		tp->cmap, tp->colors, &tp->ncolors,
2419 		True, True, &tp->cycle_p, True
2420 #else
2421 		mi,
2422 		tp->cmap, tp->colors, &tp->ncolors,
2423 		True, True, &tp->cycle_p
2424 #endif
2425 		);
2426       else if (!(LRAND() % 2))
2427         make_uniform_colormap(
2428 #ifdef STANDALONE
2429 		screen, MI_VISUAL(mi),
2430 		tp->cmap, tp->colors, &tp->ncolors,
2431 		True, &tp->cycle_p, True
2432 #else
2433 		mi,
2434 		tp->cmap, tp->colors, &tp->ncolors,
2435 		True, &tp->cycle_p
2436 #endif
2437 		);
2438       else
2439         make_smooth_colormap(
2440 #ifdef STANDALONE
2441 		screen, MI_VISUAL(mi),
2442 		tp->cmap, tp->colors, &tp->ncolors,
2443 		True, &tp->cycle_p, True
2444 #else
2445 		mi,
2446 		tp->cmap, tp->colors, &tp->ncolors,
2447 		True, &tp->cycle_p
2448 #endif
2449 		);
2450     }
2451     XInstallColormap(display, tp->cmap);
2452     if (tp->ncolors < 2) {
2453       tp->ncolors = 2;
2454       tp->no_colors = True;
2455     } else
2456       tp->no_colors = False;
2457     if (tp->ncolors <= 2)
2458       tp->mono_p = True;
2459 
2460     if (tp->mono_p)
2461       tp->cycle_p = False;
2462 
2463   }
2464   /* initialize object */
2465   newPolyomino(mi);
2466 }
2467 
2468 static Bool
moveOne(ModeInfo * mi,move_t move)2469 moveOne(ModeInfo *mi, move_t move)
2470 {
2471   Display    *display = MI_DISPLAY(mi);
2472   trisstruct *tp = &triss[MI_SCREEN(mi)];
2473 
2474   if (move == FALL) {
2475     if (trackmouse) {
2476       tp->sidemoves = tp->sidemoves + 1;
2477       if (tp->sidemoves < tp->ncols / 2) {
2478         Window      r, c;
2479         int         rx, ry, cx, cy;
2480         unsigned int m;
2481 
2482         (void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
2483           &r, &c, &rx, &ry, &cx, &cy, &m);
2484         if (tp->well) {
2485           cx = cx - tp->width / 2;
2486           cy = cy - tp->height / 2;
2487           if (ABS(cx) <= tp->xs * tp->ncols / 2 ||
2488               ABS(cy) <= tp->ys * tp->nrows / 2) {
2489             int ominopos, mousepos, diff;
2490             double wall;
2491 
2492             /* Avoid atan2: DOMAIN error message */
2493             if (cy == 0 && cx == 0)
2494               wall = 0.0;
2495             else
2496               wall = 2.0 * (atan2((double) cy, (double) cx) + 3 * M_PI / 4) / M_PI;
2497             if (wall < 0.0)
2498               wall += 4.0;
2499             mousepos = (int) (wall * WELL_WIDTH);
2500             ominopos = tp->curPolyomino.xpos;
2501             diff = mousepos - ominopos;
2502             if (diff < 0)
2503               diff += WELL_WIDTH * MAX_SIDES;
2504             if (diff > WELL_WIDTH * (MAX_SIDES / 2))
2505               move = MOVE_LEFT;
2506             else if (diff > 0)
2507               move = MOVE_RIGHT;
2508           }
2509         } else {
2510           cx = (cx - tp->xb) / tp->xs;
2511           cy = (cy - tp->yb) / tp->ys;
2512           if (!(cx < 0 || cy < 1 || cx >= tp->ncols || cy > tp->nrows)) {
2513             if (cx > tp->curPolyomino.xpos +
2514   polytris[(int) tp->bonusNow].polyomino[tp->curPolyomino.polyomino_number].leadingEmptyWidth) {
2515               move = MOVE_RIGHT;
2516             } else if (cx < tp->curPolyomino.xpos +
2517   polytris[(int) tp->bonusNow].polyomino[tp->curPolyomino.polyomino_number].leadingEmptyWidth) {
2518               move = MOVE_LEFT;
2519             }
2520           }
2521         }
2522       } else {
2523         tp->sidemoves = 0;
2524       }
2525     } else if (!NRAND(4)) {
2526       if (LRAND() & 1)
2527         move = ROTATE;
2528       else if (LRAND() & 1)
2529         move = MOVE_LEFT;
2530       else
2531         move = MOVE_RIGHT;
2532     }
2533   }
2534   if ((move == DROP) || ((move == FALL) && atBottom(mi))) {
2535     putBox(mi);
2536     {
2537       int       lines;
2538 
2539       if ((lines = checkLines(mi)) < 0) {
2540         return False;
2541       }
2542       tp->rows += lines;
2543       if (tp->rows > THRESHOLD(tp->level)) {
2544         tp->level++;
2545         if (tp->bonus) {
2546           tp->bonusNow = True; /* No good deed goes unpunished */
2547         }
2548       }
2549     }
2550     XFlush(display);
2551     if (tp->well) {
2552       if (allFrozen(mi)) {
2553         gameOver(mi);
2554         init_tetris(mi);
2555         return False;
2556       }
2557     }
2558     newPolyomino(mi);
2559     if (tp->well) {
2560       checkFreeze(mi);
2561     }
2562     if (overlapping(mi)) {
2563       gameOver(mi);
2564       init_tetris(mi);
2565       return False;
2566     }
2567     drawPolyomino(mi);
2568     return True;
2569   } else {
2570     tryMove(mi, move);
2571     if (tp->rows > THRESHOLD(tp->level)) {
2572       tp->level++;
2573       if (tp->bonus) {
2574         tp->bonusNow = True;
2575       }
2576     }
2577     return False;
2578   }
2579 }
2580 
2581 ENTRYPOINT void
draw_tetris(ModeInfo * mi)2582 draw_tetris(ModeInfo * mi)
2583 {
2584   trisstruct *tp;
2585 
2586   if (triss == NULL)
2587     return;
2588   tp = &triss[MI_SCREEN(mi)];
2589   if (!tp->well && tp->field == NULL)
2590     return;
2591 
2592   if (tp->no_colors) {
2593     init_tetris(mi);
2594     return;
2595   }
2596   tp->painted = True;
2597   MI_IS_DRAWN(mi) = True;
2598 
2599   /* Rotate colours */
2600   if (tp->cycle_p) {
2601     rotate_colors(
2602 #ifdef STANDALONE
2603 		MI_SCREENPTR(mi),
2604 #else
2605 		MI_DISPLAY(mi),
2606 #endif
2607 		tp->cmap, tp->colors, tp->ncolors, tp->direction);
2608     if (!(LRAND() % 1000))
2609       tp->direction = -tp->direction;
2610   }
2611 
2612   (void) moveOne(mi, FALL);
2613 }
2614 
2615 XSCREENSAVER_MODULE ("Tetris", tetris)
2616 
2617 #endif /* MODE_tetris */
2618