d617942cf4613c057aa03164052e9a7f5a79ebe7
[xscreensaver] / hacks / pacman_level.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*-
3  * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation for any purpose and without fee is hereby granted,
7  * provided that the above copyright notice appear in all copies and that
8  * both that copyright notice and this permission notice appear in
9  * supporting documentation.
10  *
11  * This file is provided AS IS with no warranties of any kind.  The author
12  * shall have no liability with respect to the infringement of copyrights,
13  * trade secrets or any patents by this file or any part thereof.  In no
14  * event will the author be liable for any lost revenue or profits or
15  * other special, indirect and consequential damages.
16  */
17
18 #include <assert.h>
19 #include "pacman.h"
20 #include "pacman_level.h"
21
22
23 #define NONE 0x0000
24 #define LT   0x1000
25 #define RT   0x0001
26 #define RB   0x0010
27 #define LB   0x0100
28 #define ALL  0x1111
29
30 #define BLOCK_EMPTY     ' '
31 #define BLOCK_DOT_1     '`'
32 #define BLOCK_DOT_2     '.'
33 #define BLOCK_WALL      '#'
34 #define BLOCK_GHOST_ONLY        '='
35 #define BLOCK_WALL_TL   '\''
36 #define BLOCK_WALL_TR   '`'
37 #define BLOCK_WALL_BR   ','
38 #define BLOCK_WALL_BL   '_'
39 #define BLOCK_WALL_HO   '-'
40 #define BLOCK_WALL_VE   '|'
41 #define BLOCK_DOT_BONUS 'o'
42
43 /* This is more or less the standard pacman level (without the left-right
44    tunnel. */
45 static const lev_t stdlevel = {
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     "########################################"
78 };
79
80 #define TILES_COUNT 11U
81
82 #define GO_UP 0x0001U
83 #define GO_LEFT 0x0002U
84 #define GO_RIGHT 0x0004U
85 #define GO_DOWN 0x0008U
86
87 static const struct tiles def_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     GO_LEFT, GO_RIGHT, 0, 0}, 2,
97             (unsigned) (1 << 0 | 1 << 6 | 1 << 8 | 1 << 10)}, {
98         "     " "  `  " "##`##" "  `  " "     ", {
99     GO_UP, GO_DOWN, 0, 0}, 2,
100             (unsigned) (1 << 1 | 1 << 7 | 1 << 9 | 1 << 10)}, {
101         "   ##" "##`##" "##`` " "#### " "#### ", {
102     GO_UP, GO_RIGHT, 0, 0}, 2,
103             (unsigned) (1 << 2 | 1 << 6 | 1 << 7 | 1 << 10)}, {
104         "#### " "#### " "##`` " "##`##" "   ##", {
105     GO_RIGHT, GO_DOWN, 0, 0}, 2,
106             (unsigned) (1 << 3 | 1 << 7 | 1 << 8 | 1 << 10)}, {
107         "  ###" "  ###" " ``##" "##`  " "##   ", {
108     GO_LEFT, GO_DOWN, 0, 0}, 2,
109             (unsigned) (1 << 4 | 1 << 8 | 1 << 9 | 1 << 10)}, {
110         "##   " "##`##" " ``##" " ####" " ####", {
111     GO_LEFT, GO_UP, 0, 0}, 2,
112             (unsigned) (1 << 5 | 1 << 6 | 1 << 9 | 1 << 10)}, {
113         "##`##" "##`##" "`````" " ### " " ### ", {
114     GO_LEFT, GO_UP, GO_RIGHT, 0}, 3, (unsigned) 1 << 6}, {
115         "  `##" "##`##" "##```" "##`##" "  `##", {
116     GO_UP, GO_RIGHT, GO_DOWN, 0}, 3, (unsigned) (1 << 7)}, {
117         " ### " " ### " "`````" "##`##" "##`##", {
118     GO_LEFT, GO_RIGHT, GO_DOWN, 0}, 3, (unsigned) (1 << 8)}, {
119         "##`  " "##`##" "```##" "##`##" "##`  ", {
120     GO_UP, GO_DOWN, GO_LEFT, 0}, 3, (unsigned) (1 << 9)}, {
121         "##`##" "##`##" "`````" "##`##" "##`##", {
122     GO_UP, GO_DOWN, GO_LEFT, GO_RIGHT}, 4, (unsigned) (1 << 10)}
123 };
124
125 /* probability array for each of the tiles */
126 #define MAXTILEPROB 22
127 static const unsigned tileprob[MAXTILEPROB] =
128     { 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10 };
129
130
131 static int creatlevelblock (pacmangamestruct *pp, 
132                             lev_t * level, const unsigned x,
133                             const unsigned y);
134
135
136 enum
137 { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
138
139 /* Sets a block in the level to a certain state. */
140 static void
141 setblockto (lev_t * level, const unsigned x, const unsigned y, const char c)
142 {
143     if (!(x < LEVWIDTH && y < LEVHEIGHT))
144         return;
145     (*level)[y][x] = c;
146 }
147
148 /* check if a block is set */
149 static int
150 checkset (lev_t * level, const unsigned x, const unsigned y)
151 {
152     if (!(x < LEVWIDTH && y < LEVHEIGHT) ||
153         (*level)[y][x] == BLOCK_WALL || (*level)[y][x] == BLOCK_GHOST_ONLY)
154         return True;
155     return False;
156 }
157
158 /* Check if a block is not set */
159 static int
160 checksetout (lev_t * level, const unsigned x, const unsigned y)
161 {
162     if (!(x < LEVWIDTH && y < LEVHEIGHT) || checkset (level, x, y) != 0)
163         return True;
164
165     return False;
166 }
167
168 /* Check if a block cannot be set */
169 static int
170 checkunsetdef (lev_t * level, const unsigned x, const unsigned y)
171 {
172     if (!(x < LEVWIDTH && y < LEVHEIGHT))
173         return False;
174     if ((*level)[y][x] == BLOCK_DOT_1)
175         return True;
176     return False;
177 }
178
179 /* Initializes a level to empty state. */
180 static void
181 clearlevel (lev_t * level)
182 {
183     unsigned x, y;
184
185     for (y = 0; y < LEVHEIGHT; y++)
186         for (x = 0; x < LEVWIDTH; x++)
187             (*level)[y][x] = BLOCK_EMPTY;
188 }
189
190 /* Changes a level from the level creation structure ((array to array) to
191    array. */
192 static void
193 copylevel (char *dest, lev_t * level)
194 {
195     unsigned x, y;
196
197     for (y = 0; y < LEVHEIGHT; y++)
198         for (x = 0; x < LEVWIDTH; x++)
199             dest[y * LEVWIDTH + x] = (*level)[y][x];
200 }
201
202 /* Creates a jail to work around, so we can finish it later. */
203 static void
204 createjail (lev_t * level, const unsigned width, const unsigned height)
205 {
206     unsigned x, y, xstart, xend, ystart, yend;
207
208     if (LEVWIDTH < width || LEVHEIGHT < height)
209         return;
210
211     xstart = LEVWIDTH / 2 - width / 2;
212     xend = LEVWIDTH / 2 + width / 2;
213     ystart = LEVHEIGHT / 2 - height / 2;
214     yend = LEVHEIGHT / 2 + height / 2;
215
216     for (y = ystart - 1; y < yend + 1; y++)
217         for (x = xstart - 1; x < xend + 1; x++)
218             setblockto (level, x, y, BLOCK_DOT_1);
219
220     for (y = ystart; y < yend; y++)
221         for (x = xstart; x < xend; x++)
222             setblockto (level, x, y, BLOCK_WALL);
223 }
224
225 void
226 pacman_get_jail_opening ( int *x, int *y)
227 {
228     int xstart = LEVWIDTH / 2  - JAILWIDTH / 2;
229     int ystart = LEVHEIGHT / 2 - JAILHEIGHT / 2;
230     *x = xstart + JAILWIDTH / 2;
231     *y = ystart;
232 }
233
234 /* Finishes a jail so it is empty and the ghostpass is on top. */
235 static void
236 finishjail (lev_t * level, const unsigned width, const unsigned height)
237 {
238     unsigned x, y, xstart, xend, ystart, yend;
239
240     xstart = LEVWIDTH / 2 - width / 2;
241     xend = LEVWIDTH / 2 + width / 2;
242     ystart = LEVHEIGHT / 2 - height / 2;
243     yend = LEVHEIGHT / 2 + height / 2;
244
245     for (y = ystart + 1; y < yend - 1; y++)
246         for (x = xstart + 1; x < xend - 1; x++)
247             setblockto (level, x, y, BLOCK_EMPTY);
248
249     for (x = xstart - 1; x < xend + 1; x++) {
250         setblockto (level, x, ystart - 1, BLOCK_EMPTY);
251         setblockto (level, x, yend, BLOCK_EMPTY);
252     }
253
254     for (y = ystart - 1; y < yend + 1; y++) {
255         setblockto (level, xstart - 1, y, BLOCK_EMPTY);
256         setblockto (level, xend, y, BLOCK_EMPTY);
257     }
258
259     setblockto (level, xstart + width / 2 - 1, ystart, BLOCK_GHOST_ONLY);
260     setblockto (level, xstart + width / 2, ystart, BLOCK_GHOST_ONLY);
261 }
262
263 /* Tries to set a block at a certain position. Returns true if possible,
264     and leaves level in new state (plus block), or False if not possible,
265     and leaves level in unpredictable state. */
266 static int
267 tryset (lev_t * level, const unsigned xpos, const unsigned ypos,
268         const char *block)
269 {
270     register unsigned x, y;
271     register char locchar;
272     int xstart, ystart;
273     unsigned xend, yend;
274
275     if ((*level)[ypos][xpos] == BLOCK_DOT_1)
276         return False;
277
278     xstart = xpos - 2;
279     ystart = ypos - 2;
280
281     for (y = 0; y < TILEHEIGHT; y++)
282         for (x = 0; x < TILEWIDTH; x++) {
283             locchar = block[y * TILEWIDTH + x];
284             if (locchar == BLOCK_EMPTY)
285                 continue;
286             if (locchar == BLOCK_DOT_1 &&
287                 (xstart + x < 1 ||
288                  xstart + x >= LEVWIDTH - 1 ||
289                  ystart + y < 1 ||
290                  ystart + y >= LEVHEIGHT - 1 ||
291                  checkset (level, xstart + x, ystart + y) != 0))
292                 return False;
293             else if (locchar == BLOCK_WALL &&
294                      (xstart + x > 1 &&
295                       xstart + x < LEVWIDTH &&
296                       ystart + y > 1 &&
297                       ystart + y < LEVHEIGHT - 1) &&
298                      checkunsetdef (level,
299                                     (unsigned) (xstart + x),
300                                     (unsigned) (ystart + y)) != 0)
301                 return False;
302         }
303
304     /* and set the block in place */
305
306     xend = (xstart + TILEWIDTH < LEVWIDTH - 1) ?
307         TILEWIDTH : LEVWIDTH - xstart - 2;
308     yend = (ystart + TILEHEIGHT < LEVHEIGHT - 1) ?
309         TILEHEIGHT : LEVHEIGHT - ystart - 2;
310
311     for (y = (ystart < 1) ? (unsigned) (1 - ystart) : 0U; y < yend; y++)
312         for (x = (xstart < 1) ? (unsigned) (1 - xstart) : 0U; x < xend; x++) {
313             locchar = block[y * TILEWIDTH + x];
314             if ((locchar == BLOCK_WALL) &&
315                 ((*level)[ystart + y][xstart + x] == BLOCK_EMPTY)) {
316                 (*level)[ystart + y][xstart + x] = BLOCK_WALL;
317                 (*level)[ystart + y]
318                     [LEVWIDTH - (xstart + x + 1)] = BLOCK_WALL;
319             }
320         }
321
322     (*level)[ypos][xpos] = BLOCK_DOT_1;
323     (*level)[ypos][LEVWIDTH - xpos - 1] = BLOCK_DOT_1;
324
325     return True;
326 }
327
328 /* Tries certain combinations of blocks in the level recursively. */
329 static unsigned
330 nextstep (pacmangamestruct *pp, 
331           lev_t * level, const unsigned x, const unsigned y,
332           unsigned dirvec[], unsigned ndirs)
333 {
334     unsigned dirpos, curdir, inc = 0;
335     int ret = 0;
336
337     while (ndirs > 0) {
338         ndirs--;
339         if (ndirs == 0) {
340             curdir = dirvec[0];
341         }
342         else {
343             dirpos = NRAND (ndirs);
344             curdir = dirvec[dirpos];
345             /* nope, no bufoverflow, but ndirs - 1 + 1 */
346             dirvec[dirpos] = dirvec[ndirs];
347             dirvec[ndirs] = curdir;
348         }
349
350         switch (curdir) {
351         case GO_UP:
352             if (y < 1 || (ret = creatlevelblock (pp, level, x, y - 1))
353                 == 0)
354                 return 0;
355             break;
356         case GO_RIGHT:
357             if (x > LEVWIDTH - 2 || (ret = creatlevelblock (pp, level, x + 1, y))
358                 == 0)
359                 return 0;
360             break;
361         case GO_DOWN:
362             if (y > LEVHEIGHT - 2 || (ret = creatlevelblock (pp, level, x, y + 1))
363                 == 0)
364                 return 0;
365             break;
366         case GO_LEFT:
367             if (x < 1 || (ret = creatlevelblock (pp, level, x - 1, y))
368                 == 0)
369                 return 0;
370         }
371         if (ret != -1)
372             inc += (unsigned) ret;
373     }
374     if (inc == 0)
375         inc = 1;
376     return inc;
377 }
378
379 static int
380 creatlevelblock (pacmangamestruct *pp, 
381                  lev_t * level, const unsigned x, const unsigned y)
382 {
383     unsigned tried = GETNB (TILES_COUNT);
384     unsigned tilenr;
385     unsigned ret;
386     lev_t savedlev;
387
388     if (!pp->tiles) {
389         pp->tiles = (struct tiles *) malloc (sizeof (def_tiles));
390         memcpy (pp->tiles, def_tiles, sizeof (def_tiles));
391     }
392
393     if (!((x < LEVWIDTH) && (y < LEVHEIGHT)))
394         return 0;
395
396     if (checkunsetdef (level, x, y) != 0)
397         return -1;
398
399     if (x == 0)
400         tried &= ~(1 << 0);
401     else if (x == 1)
402         tried &= ~(1 << 4 | 1 << 5 | 1 << 6 | 1 << 8 | 1 << 9 | 1 << 10);
403     else if (x == LEVWIDTH - 1)
404         tried &= ~(1 << 0);
405     else if (x == LEVWIDTH - 2)
406         tried &= ~(1 << 2 | 1 << 3 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 10);
407
408     if (y == 1)
409         tried &= ~(1 << 2 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 9 | 1 << 10);
410     else if (y == 0)
411         tried &= ~(1 << 1);
412     else if (y == LEVHEIGHT - 1)
413         tried &= ~(1 << 1);
414     else if (y == LEVHEIGHT - 2)
415         tried &= ~(1 << 3 | 1 << 4 | 1 << 7 | 1 << 8 | 1 << 9 | 1 << 10);
416
417     /* make a copy of the current level, so we can go back on the stack */
418     (void) memcpy (&savedlev, level, sizeof (lev_t));
419
420     /* while there are still some blocks left to try */
421     while (tried != 0x00) {
422         tilenr = tileprob[NRAND (MAXTILEPROB)];
423
424         if (!TESTNB (tried, tilenr))
425             continue;
426
427         if (tryset (level, x, y, pp->tiles[tilenr].block) != 0) {
428             if ((ret = nextstep (pp, level, x, y, pp->tiles[tilenr].dirvec,
429                                  pp->tiles[tilenr].ndirs)) != 0) {
430                 return ret + 1;
431             }
432             (void) memcpy (level, &savedlev, sizeof (lev_t));
433         }
434         tried &= ~(pp->tiles[tilenr].simular_to);
435     }
436     return 0;
437 }
438
439 /* Fills up all empty space so there is wall everywhere. */
440 static void
441 filllevel (lev_t * level)
442 {
443     unsigned x, y;
444
445     for (y = 0; y < LEVHEIGHT; y++)
446         for (x = 0; x < LEVWIDTH; x++)
447             if ((*level)[y][x] == BLOCK_EMPTY)
448                 (*level)[y][x] = BLOCK_WALL;
449 }
450 \f
451
452 /* Check to see if the x and y value are in the corners.
453  * we could probable compute these values once and avoid
454  * go through the loops every time.
455  */
456 static void
457 top_left (lev_t * level, unsigned int *passed_x, unsigned int *passed_y)
458 {
459     int x, y;
460     for (y = 0; y < LEVHEIGHT; y++)
461         for (x = 0; x < LEVWIDTH; x++) {
462             if (checkset (level, x, y) == 0) {
463                 *passed_x = x;
464                 *passed_y = y;
465                 return;
466             }
467         }
468 }
469
470
471 static void
472 bottom_left (lev_t * level, unsigned int *passed_x, unsigned int *passed_y)
473 {
474     int x, y;
475     for (y = LEVHEIGHT; y > -1; y--)
476         for (x = 0; x < LEVWIDTH; x++) {
477             if (checkset (level, x, y) == 0) {
478                 *passed_x = x;
479                 *passed_y = y;
480                 return;
481             }
482         }
483 }
484
485 static void
486 top_right (lev_t * level, unsigned int *passed_x, unsigned int *passed_y)
487 {
488     int x, y;
489
490     for (y = 0; y < LEVHEIGHT; y++)
491         for (x = LEVWIDTH; x >= 0; x--) {
492             if (checkset (level, x, y) == 0) {
493                 *passed_x = x;
494                 *passed_y = y;
495                 return;
496             }
497         }
498 }
499
500 static void
501 bottom_right (lev_t * level, unsigned int *passed_x, unsigned int *passed_y)
502 {
503     int x, y;
504
505     for (y = LEVHEIGHT; y >= 0; y--)
506         for (x = LEVWIDTH; x >= 0; x--) {
507             if (checkset (level, x, y) == 0) {
508                 *passed_x = x;
509                 *passed_y = y;
510                 return;
511             }
512         }
513 }
514
515 static void
516 init_bonus_dots (pacmangamestruct *pp, lev_t * level)
517 {
518     unsigned int x = 0, y = 0;
519     top_left (level, &x, &y);
520     pp->bonus_dots[TOP_LEFT].x = x;
521     pp->bonus_dots[TOP_LEFT].y = y;
522     pp->bonus_dots[TOP_LEFT].eaten = False;
523     top_right (level, &x, &y);
524     pp->bonus_dots[TOP_RIGHT].x = x;
525     pp->bonus_dots[TOP_RIGHT].y = y;
526     pp->bonus_dots[TOP_RIGHT].eaten = False;
527     bottom_left (level, &x, &y);
528     pp->bonus_dots[BOTTOM_LEFT].x = x;
529     pp->bonus_dots[BOTTOM_LEFT].y = y;
530     pp->bonus_dots[BOTTOM_LEFT].eaten = False;
531     bottom_right (level, &x, &y);
532     pp->bonus_dots[BOTTOM_RIGHT].x = x;
533     pp->bonus_dots[BOTTOM_RIGHT].y = y;
534     pp->bonus_dots[BOTTOM_RIGHT].eaten = False;
535 }
536
537 int
538 pacman_is_bonus_dot (pacmangamestruct *pp, int x, int y, int *idx)
539 {
540     int ret = False;
541     int i;
542     for (i = 0; i <= NUM_BONUS_DOTS; i++) {
543 /*     fprintf(stderr,"is bonus: passed x (%d, %d) bonus (%d, %d)\n",x,y,bonus_dots[i].x, bonus_dots[i].y); */
544         if (x == pp->bonus_dots[i].x && y == pp->bonus_dots[i].y) {
545             ret = True;
546             *idx = i;
547             break;
548         }
549     }
550     return ret;
551 }
552
553 static void
554 check_bonus_idx (int idx)
555 {
556     assert (0 <= idx && idx <= NUM_BONUS_DOTS);
557 }
558
559 int
560 pacman_bonus_dot_eaten (pacmangamestruct *pp, int idx)
561 {
562     check_bonus_idx (idx);
563     return pp->bonus_dots[idx].eaten;
564 }
565
566 void
567 pacman_eat_bonus_dot (pacmangamestruct *pp, int idx)
568 {
569     check_bonus_idx (idx);
570     pp->bonus_dots[idx].eaten = True;
571 }
572
573 void
574 pacman_bonus_dot_pos (pacmangamestruct *pp, int idx, int *x, int *y)
575 {
576     check_bonus_idx (idx);
577     *x = pp->bonus_dots[idx].x;
578     *y = pp->bonus_dots[idx].y;
579 }
580
581 /* Changes a level from a simple wall/nowall to a wall with rounded corners
582    and such.  Stupid algorithm, could be done better! */
583 static void
584 frmtlevel (pacmangamestruct *pp, lev_t * level)
585 {
586     lev_t frmtlev;
587     int x, y;
588     int idx;
589     register unsigned poscond;
590     register unsigned poscond2;
591
592     clearlevel (&frmtlev);
593     init_bonus_dots (pp, level);
594     for (y = 0; y < LEVHEIGHT; y++)
595         for (x = 0; x < LEVWIDTH; x++) {
596
597             if (checkset (level, x, y) == 0) {
598                 if (pacman_is_bonus_dot (pp, x, y, &idx)) {
599                     frmtlev[y][x] = BLOCK_DOT_BONUS;
600                 }
601                 else {
602                     frmtlev[y][x] = BLOCK_DOT_2;
603                 }
604                 continue;
605             }
606
607             if ((*level)[y][x] == BLOCK_GHOST_ONLY) {
608                 frmtlev[y][x] = BLOCK_GHOST_ONLY;
609                 continue;
610             }
611
612             poscond =
613                 (checksetout (level, x - 1, y - 1) != 0 ?
614                  0x01U : 0U) |
615                 (checksetout (level, x + 1, y - 1) != 0 ?
616                  0x02U : 0U) |
617                 (checksetout (level, x + 1, y + 1) != 0 ?
618                  0x04U : 0U) |
619                 (checksetout (level, x - 1, y + 1) != 0 ? 0x08U : 0U);
620
621             poscond2 =
622                 (checksetout (level, x - 1, y) != 0 ?
623                  0x01U : 0) |
624                 (checksetout (level, x, y - 1) != 0 ?
625                  0x02U : 0) |
626                 (checksetout (level, x + 1, y) != 0 ?
627                  0x04U : 0) |
628                 (checksetout (level, x, y + 1) != 0 ? 0x08U : 0);
629
630             switch (poscond) {
631                 /* completely filled */
632             case 0x01U | 0x02U | 0x04U | 0x08U:
633                 frmtlev[y][x] = BLOCK_EMPTY;
634                 continue;
635
636                 /* left to top corner */
637             case 0x01U:
638                 frmtlev[y][x] = BLOCK_WALL_TL;
639                 continue;
640                 /* top to right corner */
641             case 0x02U:
642                 frmtlev[y][x] = BLOCK_WALL_TR;
643                 continue;
644                 /* right to bottom corner */
645             case 0x04U:
646                 frmtlev[y][x] = BLOCK_WALL_BR;
647                 continue;
648                 /* bottom to left corner */
649             case 0x08U:
650                 frmtlev[y][x] = BLOCK_WALL_BL;
651                 continue;
652             }
653
654             switch (poscond2) {
655             case 0x01U | 0x04U:
656             case 0x01U | 0x04U | 0x08U:
657             case 0x01U | 0x04U | 0x02U:
658                 frmtlev[y][x] = BLOCK_WALL_HO;
659                 continue;
660             case 0x02U | 0x08U:
661             case 0x02U | 0x08U | 0x01U:
662             case 0x02U | 0x08U | 0x04U:
663                 frmtlev[y][x] = BLOCK_WALL_VE;
664                 continue;
665             case 0x01U | 0x02U:
666                 frmtlev[y][x] = BLOCK_WALL_TL;
667                 continue;
668             case 0x02U | 0x04U:
669                 frmtlev[y][x] = BLOCK_WALL_TR;
670                 continue;
671             case 0x04U | 0x08U:
672                 frmtlev[y][x] = BLOCK_WALL_BR;
673                 continue;
674             case 0x08U | 0x01U:
675                 frmtlev[y][x] = BLOCK_WALL_BL;
676                 continue;
677             }
678             switch (poscond) {
679             case 0x02U | 0x04U | 0x08U:
680                 frmtlev[y][x] = BLOCK_WALL_TL;
681                 continue;
682             case 0x01U | 0x04U | 0x08U:
683                 frmtlev[y][x] = BLOCK_WALL_TR;
684                 continue;
685             case 0x01U | 0x02U | 0x08U:
686                 frmtlev[y][x] = BLOCK_WALL_BR;
687                 continue;
688             case 0x01U | 0x02U | 0x04U:
689                 frmtlev[y][x] = BLOCK_WALL_BL;
690                 continue;
691             }
692             frmtlev[y][x] = BLOCK_EMPTY;
693         }
694     (void) memcpy ((lev_t *) level, (lev_t *) & frmtlev, sizeof (lev_t));
695 }
696
697 /* Counts the number of dots in the level, and returns that number. */
698 static unsigned
699 countdots (pacmangamestruct *pp)
700 {
701     unsigned i, count = 0;
702
703     for (i = 0; i < LEVWIDTH * LEVHEIGHT; i++)
704       if (pp->level[i] == BLOCK_DOT_2 || pp->level[i] == BLOCK_DOT_BONUS)
705             count++;
706
707     return count;
708 }
709
710 /* Creates a new level, and places that in the pacmangamestruct. */
711 int
712 pacman_createnewlevel (pacmangamestruct *pp)
713 {
714     lev_t *level;
715     unsigned dirvec[1] = { GO_UP };
716     unsigned ret = 0, i = 0;
717
718     if ((level = (lev_t *) calloc (1, sizeof (lev_t))) == NULL)
719         return i;
720
721     if (NRAND (2) == 0) {
722
723         do {
724             clearlevel (level);
725             createjail (level, JAILWIDTH, JAILHEIGHT);
726             if ((ret = nextstep (pp, level, LEVWIDTH / 2 - 1,
727                                  LEVHEIGHT / 2 - JAILHEIGHT / 2 - 3,
728                                  dirvec, 1)) == 0) {
729                 (void) free ((void *) level);
730                 return i;
731             }
732         } while (ret * 100 < (LEVWIDTH * LEVHEIGHT * MINDOTPERC));
733
734         filllevel (level);
735         frmtlevel (pp, level);
736         finishjail (level, JAILWIDTH, JAILHEIGHT);
737     }
738     else {
739         (void) memcpy (level, stdlevel, sizeof (lev_t));
740         frmtlevel (pp, level);
741         i = 1;
742     }
743     copylevel (pp->level, level);
744     pp->dotsleft = countdots (pp);
745
746     (void) free ((void *) level);
747     return i;
748 }
749
750 /* Checks if a position is allowable for ghosts/pacs to enter. */
751 int
752 pacman_check_pos (pacmangamestruct * pp, int y, int x, int ghostpass)
753 {
754     if ((pp->level[y * LEVWIDTH + x] == BLOCK_DOT_2) ||
755         (pp->level[y * LEVWIDTH + x] == BLOCK_EMPTY) ||
756         (pp->level[y * LEVWIDTH + x] == BLOCK_DOT_BONUS) ||
757         ((pp->level[y * LEVWIDTH + x] == BLOCK_GHOST_ONLY) && ghostpass)) {
758         return 1;
759     }
760     return 0;
761 }
762
763 /* Checks if there is a dot on the specified position in the level. */
764 int
765 pacman_check_dot (pacmangamestruct * pp, unsigned int x, unsigned int y)
766 {
767     if (x >= LEVWIDTH || y >= LEVHEIGHT)
768         return 0;
769     if (pp->level[y * LEVWIDTH + x] == BLOCK_DOT_2)
770         return 1;
771     return 0;
772 }