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