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