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