c33f28e969245b7bb363134071cd7ff3c2ebd037
[xscreensaver] / hacks / pacman_level.h
1 /*-
2  * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>.
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted,
6  * provided that the above copyright notice appear in all copies and that
7  * both that copyright notice and this permission notice appear in
8  * supporting documentation.
9  *
10  * This file is provided AS IS with no warranties of any kind.  The author
11  * shall have no liability with respect to the infringement of copyrights,
12  * trade secrets or any patents by this file or any part thereof.  In no
13  * event will the author be liable for any lost revenue or profits or
14  * other special, indirect and consequential damages.
15  */
16
17 #define NONE 0x0000
18 #define LT   0x1000
19 #define RT   0x0001
20 #define RB   0x0010
21 #define LB   0x0100
22 #define ALL  0x1111
23
24 #define BLOCK_EMPTY     ' '
25 #define BLOCK_DOT_1     '`'
26 #define BLOCK_DOT_2     '.'
27 #define BLOCK_WALL      '#'
28 #define BLOCK_GHOST_ONLY        '='
29 #define BLOCK_WALL_TL   '\''
30 #define BLOCK_WALL_TR   '`'
31 #define BLOCK_WALL_BR   ','
32 #define BLOCK_WALL_BL   '_'
33 #define BLOCK_WALL_HO   '-'
34 #define BLOCK_WALL_VE   '|'
35
36 /* This is more or less the standard pacman level (without the left-right
37    tunnel. */
38 static const lev_t stdlevel = {
39         "########################################",
40         "########################################",
41         "#######````````````##````````````#######",
42         "#######`####`#####`##`#####`####`#######",
43         "#######`####`#####`##`#####`####`#######",
44         "#######`####`#####`##`#####`####`#######",
45         "#######``````````````````````````#######",
46         "#######`####`##`########`##`####`#######",
47         "#######`####`##`########`##`####`#######",
48         "#######``````##````##````##``````#######",
49         "############`#####`##`#####`############",
50         "############`#####`##`#####`############",
51         "############`##``````````##`############",
52         "############`##`###==###`##`############",
53         "############`##`########`##`############",
54         "############````########````############",
55         "############`##`########`##`############",
56         "############`##`########`##`############",
57         "############`##``````````##`############",
58         "############`##`########`##`############",
59         "############`##`########`##`############",
60         "#######````````````##````````````#######",
61         "#######`####`#####`##`#####`####`#######",
62         "#######`####`#####`##`#####`####`#######",
63         "#######```##````````````````##```#######",
64         "#########`##`##`########`##`##`#########",
65         "#########`##`##`########`##`##`#########",
66         "#######``````##````##````##``````#######",
67         "#######`##########`##`##########`#######",
68         "#######`##########`##`##########`#######",
69         "#######``````````````````````````#######",
70         "########################################"};
71
72 #define TILEWIDTH 5U
73 #define TILEHEIGHT 5U
74 #define TILES_COUNT 11U
75
76 #define GO_UP 0x0001U
77 #define GO_LEFT 0x0002U
78 #define GO_RIGHT 0x0004U
79 #define GO_DOWN 0x0008U
80
81 /* This are tiles which can be places to create a level. */
82 static struct {
83         char block[TILEWIDTH * TILEHEIGHT + 1];
84         unsigned dirvec[4];
85         unsigned ndirs;
86         unsigned simular_to;
87 } tiles[TILES_COUNT] = { 
88 /*   
89  *   ' ' == dont care == BLOCK_EMPTY
90  *   '#' == set wall, and not clear == BLOCK_WALL
91  *   '`' == clear == BLOCK_DOT_1
92  *   middle position is always set as cleardef
93  */
94   {     "  #  "
95         "  #  "
96         " ``` "
97         "  #  "
98         "  #  ", 
99         { GO_LEFT, GO_RIGHT, 0, 0 }, 2,
100         (unsigned) (1 << 0 | 1 << 6 | 1 << 8 | 1 << 10) },
101   {     "     "
102         "  `  "
103         "##`##"
104         "  `  "
105         "     ", 
106         { GO_UP, GO_DOWN, 0, 0 }, 2,
107         (unsigned) (1 << 1 | 1 << 7 | 1 << 9 | 1 << 10) },
108   {     "   ##"
109         "##`##"
110         "##`` "
111         "#### "
112         "#### ", 
113         { GO_UP, GO_RIGHT, 0, 0 }, 2,
114         (unsigned) (1 << 2 | 1 << 6 | 1 << 7 | 1 << 10) },
115   {     "#### "
116         "#### "
117         "##`` "
118         "##`##"
119         "   ##", 
120         { GO_RIGHT, GO_DOWN, 0, 0 }, 2,
121         (unsigned) (1 << 3 | 1 << 7 | 1 << 8 | 1 << 10) },
122   {     "  ###"
123         "  ###"
124         " ``##"
125         "##`  "
126         "##   ",
127         { GO_LEFT, GO_DOWN, 0, 0 }, 2,
128         (unsigned) (1 << 4 | 1 << 8 | 1 << 9 | 1 << 10) },
129   {     "##   "
130         "##`##"
131         " ``##"
132         " ####"
133         " ####",
134         { GO_LEFT, GO_UP, 0, 0 }, 2,
135         (unsigned) (1 << 5 | 1 << 6 | 1 << 9 | 1 << 10) },
136   {     "##`##"
137         "##`##"
138         "`````"
139         " ### "
140         " ### ",
141         { GO_LEFT, GO_UP, GO_RIGHT, 0 }, 3,
142         (unsigned) 1 << 6 },
143   {     "  `##"
144         "##`##"
145         "##```"
146         "##`##"
147         "  `##",
148         { GO_UP, GO_RIGHT, GO_DOWN, 0}, 3,
149         (unsigned) (1 << 7) },
150   {     " ### "
151         " ### "
152         "`````"
153         "##`##"
154         "##`##",
155         { GO_LEFT, GO_RIGHT, GO_DOWN, 0}, 3, 
156         (unsigned) (1 << 8) },
157   {     "##`  "
158         "##`##"
159         "```##"
160         "##`##"
161         "##`  ",
162         { GO_UP, GO_DOWN, GO_LEFT, 0 }, 3,
163         (unsigned) (1 << 9) },
164   {     "##`##"
165         "##`##"
166         "`````"
167         "##`##"
168         "##`##",
169         { GO_UP, GO_DOWN, GO_LEFT, GO_RIGHT }, 4,
170         (unsigned) (1 << 10) }
171 };
172
173 /* probability array for each of the tiles */
174 #define MAXTILEPROB 22
175 static const unsigned tileprob[MAXTILEPROB] =
176         { 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10 };
177
178 /* Sets a block in the level to a certain state. */
179 static void 
180 setblockto(lev_t *level, const unsigned x, const unsigned y, 
181                 const char c) 
182 {
183         if (!(x < LEVWIDTH && y < LEVHEIGHT)) return;
184         (*level)[y][x] = c;
185 }
186
187 /* check if a block is set */
188 static int 
189 checkset(lev_t *level, const unsigned x, const unsigned y) 
190 {
191         if (!(x < LEVWIDTH && y < LEVHEIGHT) ||
192                         (*level)[y][x] == BLOCK_WALL || 
193                         (*level)[y][x] == BLOCK_GHOST_ONLY)
194                 return True;
195         return False;
196 }
197
198 /* Check if a block is not set */
199 static int 
200 checksetout(lev_t *level, const unsigned x, const unsigned y) 
201 {
202         if (!(x < LEVWIDTH && y < LEVHEIGHT) ||
203                         checkset(level, x, y) != 0)
204                 return True;
205
206         return False;
207 }
208
209 /* Check if a block cannot be set */
210 static int 
211 checkunsetdef(lev_t *level, const unsigned x, const unsigned y) 
212 {
213         if (!(x < LEVWIDTH && y < LEVHEIGHT))
214                 return False;
215         if ((*level)[y][x] == BLOCK_DOT_1) return True;
216         return False;
217 }
218
219 /* Initializes a level to empty state. */
220 static void 
221 clearlevel(lev_t *level) 
222 {
223         unsigned x, y;
224
225         for (y = 0; y < LEVHEIGHT ; y++)
226                 for (x = 0 ; x < LEVWIDTH ; x++)
227                         (*level)[y][x] = BLOCK_EMPTY;
228 }
229
230 /* Changes a level from the level creation structure ((array to array) to
231    array. */
232 static void
233 copylevel(char *dest, lev_t *level) 
234 {
235         unsigned x, y;
236
237         for (y = 0; y < LEVHEIGHT ; y++)
238                 for (x = 0; x < LEVWIDTH ; x++)
239                         dest[y * LEVWIDTH + x] = (*level)[y][x];
240 }
241
242 /* Creates a jail to work around, so we can finish it later. */
243 static void 
244 createjail(lev_t *level, const unsigned width, 
245                 const unsigned height) 
246 {
247         unsigned x, y, xstart, xend, ystart, yend;
248
249         if (LEVWIDTH < width || LEVHEIGHT < height) return;
250
251         xstart = LEVWIDTH/2 - width/2;
252         xend = LEVWIDTH/2 + width/2;
253         ystart = LEVHEIGHT/2 - height/2;
254         yend = LEVHEIGHT/2 + height/2;
255
256         for (y = ystart - 1; y < yend + 1; y++)
257                 for (x = xstart - 1; x < xend + 1; x++)
258                         setblockto(level, x, y, BLOCK_DOT_1);
259
260         for (y = ystart; y < yend; y++)
261                 for (x = xstart; x < xend; x++)
262                         setblockto(level, x, y, BLOCK_WALL);
263 }
264
265 /* Finishes a jail so it is empty and the ghostpass is on top. */
266 static void 
267 finishjail(lev_t *level, const unsigned width, 
268                 const unsigned height) 
269 {
270         unsigned x, y, xstart, xend, ystart, yend;
271
272         xstart = LEVWIDTH/2 - width/2;
273         xend = LEVWIDTH/2 + width/2;
274         ystart = LEVHEIGHT/2 - height/2;
275         yend = LEVHEIGHT/2 + height/2;
276
277         for (y = ystart + 1; y < yend - 1 ; y++)
278                 for (x = xstart + 1; x < xend - 1; x++)
279                         setblockto(level, x, y, BLOCK_EMPTY);
280
281         for (x = xstart - 1; x < xend + 1; x++) {
282                 setblockto(level, x, ystart - 1, BLOCK_EMPTY);
283                 setblockto(level, x, yend, BLOCK_EMPTY);
284         }
285
286         for (y = ystart - 1; y < yend + 1; y++) {
287                 setblockto(level, xstart - 1, y, BLOCK_EMPTY);
288                 setblockto(level, xend, y, BLOCK_EMPTY);
289         }
290
291         setblockto(level, xstart + width/2 - 1, ystart, BLOCK_GHOST_ONLY);
292         setblockto(level, xstart + width/2, ystart, BLOCK_GHOST_ONLY);
293 }
294
295 /* Tries to set a block at a certain position. Returns true if possible,
296     and leaves level in new state (plus block), or False if not possible,
297     and leaves level in unpredictable state. */
298 static int 
299 tryset(lev_t *level, const unsigned xpos, const unsigned ypos, 
300                 const char *block) 
301 {
302         register unsigned x, y;
303         register char locchar;
304         int xstart, ystart;
305         unsigned xend, yend;
306
307         if ((*level)[ypos][xpos] == BLOCK_DOT_1) return False;
308
309         xstart = xpos - 2;
310         ystart = ypos - 2;
311
312         for (y = 0 ; y < TILEHEIGHT ; y++)
313                 for (x = 0 ; x < TILEWIDTH ; x++) {
314                         locchar = block[y * TILEWIDTH + x];
315                         if (locchar == BLOCK_EMPTY)
316                                 continue;
317                         if (locchar == BLOCK_DOT_1 &&
318                              (xstart + x < 1 ||
319                               xstart + x >= LEVWIDTH - 1 ||
320                               ystart + y < 1 ||
321                               ystart + y >= LEVHEIGHT - 1 ||
322                               checkset(level, xstart + x, ystart + y) != 0))
323                                 return False;
324                         else if (locchar == BLOCK_WALL &&
325                                 (xstart + x > 1 &&
326                                  xstart + x < LEVWIDTH &&
327                                  ystart + y > 1 &&
328                                  ystart + y < LEVHEIGHT - 1) &&
329                                  checkunsetdef(level, 
330                                          (unsigned)(xstart + x), 
331                                          (unsigned)(ystart + y)) != 0)
332                                 return False;
333                 }
334
335         /* and set the block in place */
336
337         xend = (xstart + TILEWIDTH < LEVWIDTH - 1) ? 
338                 TILEWIDTH : LEVWIDTH - xstart - 2;
339         yend = (ystart + TILEHEIGHT < LEVHEIGHT - 1) ?
340                 TILEHEIGHT : LEVHEIGHT - ystart - 2;
341
342         for (y = (ystart < 1) ? (unsigned)(1 - ystart) : 0U ; 
343                         y < yend ; y++)
344                 for (x = (xstart < 1) ? 
345                                 (unsigned)(1 - xstart) : 0U ; 
346                        x < xend ; x++) {
347                         locchar = block[y * TILEWIDTH + x];
348                         if ((locchar == BLOCK_WALL) &&
349                             ((*level)[ystart + y][xstart + x] == BLOCK_EMPTY)) {
350                                 (*level)[ystart + y][xstart + x] = BLOCK_WALL;
351                                 (*level)[ystart + y]
352                                         [LEVWIDTH - (xstart + x + 1)] = 
353                                                 BLOCK_WALL;
354                         }
355                 }
356
357         (*level)[ypos][xpos] = BLOCK_DOT_1;
358         (*level)[ypos][LEVWIDTH-xpos-1] = BLOCK_DOT_1;
359
360         return True;
361 }
362
363 /* Tries certain combinations of blocks in the level recursively. */
364 static unsigned
365 nextstep(lev_t *level, const unsigned x, const unsigned y, 
366                 unsigned dirvec[], unsigned ndirs) 
367 {
368         unsigned dirpos, curdir, inc = 0;
369         int ret = 0;
370
371         while (ndirs > 0) {
372                 ndirs--;
373                 if (ndirs == 0) {
374                         curdir = dirvec[0];
375                 }
376                 else {
377                         dirpos = NRAND(ndirs);
378                         curdir = dirvec[dirpos];
379                         /* nope, no bufoverflow, but ndirs - 1 + 1 */
380                         dirvec[dirpos] = dirvec[ndirs];
381                         dirvec[ndirs] = curdir;
382                 }
383
384                 switch (curdir) {
385                    case GO_UP:
386                         if (y < 1 || 
387                                 (ret = creatlevelblock(level, x, y - 1)) 
388                                         == 0)
389                                 return 0;
390                         break;
391                    case GO_RIGHT:
392                         if (x > LEVWIDTH - 2 || 
393                                 (ret = creatlevelblock(level, x + 1, y))
394                                         == 0)
395                                 return 0;
396                         break;
397                    case GO_DOWN:
398                         if (y > LEVHEIGHT - 2 ||
399                                 (ret = creatlevelblock(level, x, y + 1))
400                                         == 0)
401                                 return 0;
402                         break;
403                    case GO_LEFT:
404                         if (x < 1 || 
405                                 (ret = creatlevelblock(level, x - 1, y))
406                                         == 0)
407                                 return 0;
408                 }
409                 if (ret != -1)
410                         inc += (unsigned)ret;
411         }
412         if (inc == 0) inc = 1;
413         return inc; 
414 }
415
416 static int 
417 creatlevelblock(lev_t *level, const unsigned x, const unsigned y) 
418 {
419         unsigned tried = GETNB(TILES_COUNT);
420         unsigned tilenr;
421         unsigned ret;
422         lev_t savedlev;
423
424         if (!((x < LEVWIDTH) && (y < LEVHEIGHT)))
425                 return 0;
426
427         if (checkunsetdef(level, x, y) != 0)
428                 return -1;
429
430         if (x == 0)
431                 tried &= ~(1<<0);
432         else if (x == 1)
433                 tried &= ~(1<<4 | 1<<5 | 1<<6 | 1<<8 | 1<<9 | 1<<10);
434         else if (x == LEVWIDTH-1)
435                 tried &= ~(1<<0);
436         else if (x == LEVWIDTH-2)
437                 tried &= ~(1<<2 | 1<<3 | 1<<6 | 1<<7 | 1<<8 | 1<<10);
438
439         if (y == 1) 
440                 tried &= ~(1<<2 | 1<<5 | 1<<6 | 1<<7 | 1<<9 | 1<<10);
441         else if (y == 0)
442                 tried &= ~(1<<1);
443         else if (y == LEVHEIGHT-1)
444                 tried &= ~(1<<1);
445         else if (y == LEVHEIGHT-2)
446                 tried &= ~(1<<3 | 1<<4 | 1<<7 | 1<<8 | 1<<9 | 1<<10);
447
448         /* make a copy of the current level, so we can go back on the stack */
449         (void) memcpy(&savedlev, level, sizeof(lev_t));
450
451         /* while there are still some blocks left to try */
452         while (tried != 0x00) {
453                 tilenr = tileprob[NRAND(MAXTILEPROB)];
454
455                 if (!TESTNB(tried, tilenr))
456                         continue;
457
458                 if (tryset(level, x, y, tiles[tilenr].block) != 0) {
459                         if ((ret = nextstep(level, x, y, tiles[tilenr].dirvec,
460                                         tiles[tilenr].ndirs)) != 0) {
461                                 return ret + 1;
462                         }
463                         (void) memcpy(level, &savedlev, sizeof(lev_t));
464                 }
465                 tried &= ~(tiles[tilenr].simular_to);
466         }
467         return 0;
468 }
469
470 /* Fills up all empty space so there is wall everywhere. */
471 static void 
472 filllevel(lev_t *level) 
473 {
474         unsigned x, y;
475
476         for (y = 0; y < LEVHEIGHT; y++)
477                 for (x = 0; x < LEVWIDTH; x++)
478                         if ((*level)[y][x] == BLOCK_EMPTY) 
479                                 (*level)[y][x] = BLOCK_WALL;
480 }
481
482 /* Changes a level from a simple wall/nowall to a wall with rounded corners
483    and such.  Stupid algorithm, could be done better! */
484 static void 
485 frmtlevel(lev_t *level) 
486 {
487         lev_t frmtlev;
488         register unsigned x, y;
489         register unsigned poscond;
490         register unsigned poscond2;
491
492         clearlevel(&frmtlev);
493
494         for (y = 0; y < LEVHEIGHT; y++)
495                 for (x = 0; x < LEVWIDTH; x++) {
496
497                         if (checkset(level, x, y) == 0) {
498                                 frmtlev[y][x] = BLOCK_DOT_2;
499                                 continue;
500                         }
501
502                         if ((*level)[y][x] == BLOCK_GHOST_ONLY) {
503                                 frmtlev[y][x] = BLOCK_GHOST_ONLY;       
504                                 continue;
505                         }
506
507                         poscond = 
508                                  (checksetout(level, x - 1, y - 1) != 0 ? 
509                                          0x01U : 0U) |
510                                  (checksetout(level, x + 1, y - 1) != 0 ?
511                                          0x02U : 0U) |
512                                  (checksetout(level, x + 1, y + 1) != 0 ?
513                                          0x04U : 0U) |
514                                  (checksetout(level, x - 1, y + 1) != 0 ?
515                                          0x08U : 0U);
516
517                         poscond2 = 
518                                 (checksetout(level, x - 1, y) != 0 ?
519                                         0x01U : 0) |
520                                 (checksetout(level, x, y - 1) != 0 ?
521                                         0x02U : 0) |
522                                 (checksetout(level, x + 1, y) != 0 ?
523                                         0x04U : 0) |
524                                 (checksetout(level, x, y + 1) != 0 ?
525                                         0x08U : 0);
526
527                         switch (poscond) {
528                                 /* completely filled */
529                                 case 0x01U | 0x02U | 0x04U | 0x08U:
530                                         frmtlev[y][x] = BLOCK_EMPTY; continue;
531
532                                 /* left to top corner */
533                                 case 0x01U:
534                                         frmtlev[y][x] = BLOCK_WALL_TL; continue;
535                                 /* top to right corner */
536                                 case 0x02U:
537                                         frmtlev[y][x] = BLOCK_WALL_TR; continue;
538                                 /* right to bottom corner */
539                                 case 0x04U:
540                                         frmtlev[y][x] = BLOCK_WALL_BR; continue;
541                                 /* bottom to left corner */
542                                 case 0x08U:
543                                         frmtlev[y][x] = BLOCK_WALL_BL; continue;
544                         }
545
546                         switch (poscond2) {
547                                 case 0x01U | 0x04U:
548                                 case 0x01U | 0x04U | 0x08U:
549                                 case 0x01U | 0x04U | 0x02U:
550                                         frmtlev[y][x] = BLOCK_WALL_HO; continue;
551                                 case 0x02U | 0x08U:
552                                 case 0x02U | 0x08U | 0x01U:
553                                 case 0x02U | 0x08U | 0x04U:
554                                         frmtlev[y][x] = BLOCK_WALL_VE; continue;
555                                 case 0x01U | 0x02U:
556                                         frmtlev[y][x] = BLOCK_WALL_TL; continue;
557                                 case 0x02U | 0x04U:
558                                         frmtlev[y][x] = BLOCK_WALL_TR; continue;
559                                 case 0x04U | 0x08U:
560                                         frmtlev[y][x] = BLOCK_WALL_BR; continue;
561                                 case 0x08U | 0x01U:
562                                         frmtlev[y][x] = BLOCK_WALL_BL; continue;
563                         }
564                         switch (poscond) {
565                                 case 0x02U | 0x04U | 0x08U:
566                                         frmtlev[y][x] = BLOCK_WALL_TL; continue;
567                                 case 0x01U | 0x04U | 0x08U:
568                                         frmtlev[y][x] = BLOCK_WALL_TR; continue;
569                                 case 0x01U | 0x02U | 0x08U:
570                                         frmtlev[y][x] = BLOCK_WALL_BR; continue;
571                                 case 0x01U | 0x02U | 0x04U:
572                                         frmtlev[y][x] = BLOCK_WALL_BL; continue;
573                         }
574                         frmtlev[y][x] = BLOCK_EMPTY;
575                 }
576         (void) memcpy((lev_t *)level, (lev_t *)&frmtlev, sizeof(lev_t));
577 }
578
579 /* Counts the number of dots in the level, and returns that number. */
580 static unsigned
581 countdots(ModeInfo * mi)
582 {
583         pacmangamestruct *pp = &pacmangames[MI_SCREEN(mi)];
584         unsigned i, count = 0;
585
586         for (i = 0 ; i < LEVWIDTH*LEVHEIGHT ; i++)
587                 if (pp->level[i] == BLOCK_DOT_2) count++;
588
589         return count;
590 }
591
592 /* Creates a new level, and places that in the pacmangamestruct. */
593 static int
594 createnewlevel(ModeInfo * mi)
595 {
596         pacmangamestruct *pp = &pacmangames[MI_SCREEN(mi)];
597         lev_t *level;
598         unsigned dirvec[1] = { GO_UP };
599         unsigned ret = 0, i = 0;
600
601         if ((level = (lev_t *)calloc(1, sizeof(lev_t))) == NULL)
602                 return i;
603
604         if (NRAND(2) == 0) {
605
606                 do {
607                         clearlevel(level);
608                         createjail(level, JAILWIDTH, JAILHEIGHT);
609                         if ((ret = nextstep(level, LEVWIDTH/2 - 1,
610                                             LEVHEIGHT/2 - JAILHEIGHT/2 - 3, 
611                                             dirvec, 1)) == 0) {
612                                 (void) free((void *) level);
613                                 return i;
614                         }
615                 } while (ret * 100 < (LEVWIDTH * LEVHEIGHT * MINDOTPERC));
616
617                 filllevel(level);
618                 frmtlevel(level);
619                 finishjail(level, JAILWIDTH, JAILHEIGHT);
620         } else {
621                 (void) memcpy(level, stdlevel, sizeof(lev_t));
622                 frmtlevel(level);
623                 i = 1;
624         }
625         copylevel(pp->level, level);
626         pp->dotsleft = countdots(mi);
627
628         (void) free((void *) level);
629         return i;
630 }
631
632 /* Checks if a position is allowable for ghosts/pacs to enter. */
633 static int
634 check_pos(pacmangamestruct *pp, int y, int x, int ghostpass) 
635 {
636         if ((pp->level[y*LEVWIDTH + x] == BLOCK_DOT_2) ||
637             (pp->level[y*LEVWIDTH + x] == BLOCK_EMPTY) ||
638            ((pp->level[y*LEVWIDTH + x] == BLOCK_GHOST_ONLY) && ghostpass)) {
639                 return 1;
640         }
641         return 0;
642 }
643
644 /* Checks if there is a dot on the specified position in the level. */
645 static int 
646 check_dot(pacmangamestruct *pp, unsigned int x, unsigned int y) 
647 {
648         if (x >= LEVWIDTH || y >= LEVHEIGHT) return 0;
649         if (pp->level[y * LEVWIDTH + x] == BLOCK_DOT_2) return 1;
650         return 0;
651 }