OSDN Git Service

version++
[jnethack/source.git] / src / mkroom.c
1 /* NetHack 3.6  mkroom.c        $NHDT-Date: 1446887530 2015/11/07 09:12:10 $  $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  * Entry points:
7  *      mkroom() -- make and stock a room of a given type
8  *      nexttodoor() -- return TRUE if adjacent to a door
9  *      has_dnstairs() -- return TRUE if given room has a down staircase
10  *      has_upstairs() -- return TRUE if given room has an up staircase
11  *      courtmon() -- generate a court monster
12  *      save_rooms() -- save rooms into file fd
13  *      rest_rooms() -- restore rooms from file fd
14  *      cmap_to_type() -- convert S_xxx symbol to XXX topology code
15  */
16
17 #include "hack.h"
18
19 STATIC_DCL boolean FDECL(isbig, (struct mkroom *));
20 STATIC_DCL struct mkroom *FDECL(pick_room, (BOOLEAN_P));
21 STATIC_DCL void NDECL(mkshop), FDECL(mkzoo, (int)), NDECL(mkswamp);
22 STATIC_DCL void NDECL(mktemple);
23 STATIC_DCL coord *FDECL(shrine_pos, (int));
24 STATIC_DCL struct permonst *NDECL(morguemon);
25 STATIC_DCL struct permonst *NDECL(squadmon);
26 STATIC_DCL void FDECL(save_room, (int, struct mkroom *));
27 STATIC_DCL void FDECL(rest_room, (int, struct mkroom *));
28
29 #define sq(x) ((x) * (x))
30
31 extern const struct shclass shtypes[]; /* defined in shknam.c */
32
33 STATIC_OVL boolean
34 isbig(sroom)
35 register struct mkroom *sroom;
36 {
37     register int area = (sroom->hx - sroom->lx + 1)
38                         * (sroom->hy - sroom->ly + 1);
39
40     return (boolean) (area > 20);
41 }
42
43 /* make and stock a room of a given type */
44 void
45 mkroom(roomtype)
46 int roomtype;
47 {
48     if (roomtype >= SHOPBASE)
49         mkshop(); /* someday, we should be able to specify shop type */
50     else
51         switch (roomtype) {
52         case COURT:
53             mkzoo(COURT);
54             break;
55         case ZOO:
56             mkzoo(ZOO);
57             break;
58         case BEEHIVE:
59             mkzoo(BEEHIVE);
60             break;
61         case MORGUE:
62             mkzoo(MORGUE);
63             break;
64         case BARRACKS:
65             mkzoo(BARRACKS);
66             break;
67         case SWAMP:
68             mkswamp();
69             break;
70         case TEMPLE:
71             mktemple();
72             break;
73         case LEPREHALL:
74             mkzoo(LEPREHALL);
75             break;
76         case COCKNEST:
77             mkzoo(COCKNEST);
78             break;
79         case ANTHOLE:
80             mkzoo(ANTHOLE);
81             break;
82         default:
83             impossible("Tried to make a room of type %d.", roomtype);
84         }
85 }
86
87 STATIC_OVL void
88 mkshop()
89 {
90     register struct mkroom *sroom;
91     int i = -1;
92     char *ep = (char *) 0; /* (init == lint suppression) */
93
94     /* first determine shoptype */
95     if (wizard) {
96 #ifndef MAC
97         ep = nh_getenv("SHOPTYPE");
98         if (ep) {
99             if (*ep == 'z' || *ep == 'Z') {
100                 mkzoo(ZOO);
101                 return;
102             }
103             if (*ep == 'm' || *ep == 'M') {
104                 mkzoo(MORGUE);
105                 return;
106             }
107             if (*ep == 'b' || *ep == 'B') {
108                 mkzoo(BEEHIVE);
109                 return;
110             }
111             if (*ep == 't' || *ep == 'T' || *ep == '\\') {
112                 mkzoo(COURT);
113                 return;
114             }
115             if (*ep == 's' || *ep == 'S') {
116                 mkzoo(BARRACKS);
117                 return;
118             }
119             if (*ep == 'a' || *ep == 'A') {
120                 mkzoo(ANTHOLE);
121                 return;
122             }
123             if (*ep == 'c' || *ep == 'C') {
124                 mkzoo(COCKNEST);
125                 return;
126             }
127             if (*ep == 'l' || *ep == 'L') {
128                 mkzoo(LEPREHALL);
129                 return;
130             }
131             if (*ep == '_') {
132                 mktemple();
133                 return;
134             }
135             if (*ep == '}') {
136                 mkswamp();
137                 return;
138             }
139             for (i = 0; shtypes[i].name; i++)
140                 if (*ep == def_oc_syms[(int) shtypes[i].symb].sym)
141                     goto gottype;
142             if (*ep == 'g' || *ep == 'G')
143                 i = 0;
144             else if (*ep == 'v' || *ep == 'V')
145                 i = FODDERSHOP - SHOPBASE; /* veggy food */
146             else
147                 i = -1;
148         }
149 #endif
150     }
151 #ifndef MAC
152 gottype:
153 #endif
154     for (sroom = &rooms[0];; sroom++) {
155         if (sroom->hx < 0)
156             return;
157         if (sroom - rooms >= nroom) {
158             pline("rooms not closed by -1?");
159             return;
160         }
161         if (sroom->rtype != OROOM)
162             continue;
163         if (has_dnstairs(sroom) || has_upstairs(sroom))
164             continue;
165         if ((wizard && ep && sroom->doorct != 0) || sroom->doorct == 1)
166             break;
167     }
168     if (!sroom->rlit) {
169         int x, y;
170
171         for (x = sroom->lx - 1; x <= sroom->hx + 1; x++)
172             for (y = sroom->ly - 1; y <= sroom->hy + 1; y++)
173                 levl[x][y].lit = 1;
174         sroom->rlit = 1;
175     }
176
177     if (i < 0) { /* shoptype not yet determined */
178         register int j;
179
180         /* pick a shop type at random */
181         for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
182             continue;
183
184         /* big rooms cannot be wand or book shops,
185          * - so make them general stores
186          */
187         if (isbig(sroom) && (shtypes[i].symb == WAND_CLASS
188                              || shtypes[i].symb == SPBOOK_CLASS))
189             i = 0;
190     }
191     sroom->rtype = SHOPBASE + i;
192
193     /* set room bits before stocking the shop */
194 #ifdef SPECIALIZATION
195     topologize(sroom, FALSE); /* doesn't matter - this is a special room */
196 #else
197     topologize(sroom);
198 #endif
199
200     /* stock the room with a shopkeeper and artifacts */
201     stock_room(i, sroom);
202 }
203
204 /* pick an unused room, preferably with only one door */
205 STATIC_OVL struct mkroom *
206 pick_room(strict)
207 register boolean strict;
208 {
209     register struct mkroom *sroom;
210     register int i = nroom;
211
212     for (sroom = &rooms[rn2(nroom)]; i--; sroom++) {
213         if (sroom == &rooms[nroom])
214             sroom = &rooms[0];
215         if (sroom->hx < 0)
216             return (struct mkroom *) 0;
217         if (sroom->rtype != OROOM)
218             continue;
219         if (!strict) {
220             if (has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
221                 continue;
222         } else if (has_upstairs(sroom) || has_dnstairs(sroom))
223             continue;
224         if (sroom->doorct == 1 || !rn2(5) || wizard)
225             return sroom;
226     }
227     return (struct mkroom *) 0;
228 }
229
230 STATIC_OVL void
231 mkzoo(type)
232 int type;
233 {
234     register struct mkroom *sroom;
235
236     if ((sroom = pick_room(FALSE)) != 0) {
237         sroom->rtype = type;
238         fill_zoo(sroom);
239     }
240 }
241
242 void
243 fill_zoo(sroom)
244 struct mkroom *sroom;
245 {
246     struct monst *mon;
247     register int sx, sy, i;
248     int sh, tx = 0, ty = 0, goldlim = 0, type = sroom->rtype;
249     int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
250     coord mm;
251
252     sh = sroom->fdoor;
253     switch (type) {
254     case COURT:
255         if (level.flags.is_maze_lev) {
256             for (tx = sroom->lx; tx <= sroom->hx; tx++)
257                 for (ty = sroom->ly; ty <= sroom->hy; ty++)
258                     if (IS_THRONE(levl[tx][ty].typ))
259                         goto throne_placed;
260         }
261         i = 100;
262         do { /* don't place throne on top of stairs */
263             (void) somexy(sroom, &mm);
264             tx = mm.x;
265             ty = mm.y;
266         } while (occupied((xchar) tx, (xchar) ty) && --i > 0);
267     throne_placed:
268         /* TODO: try to ensure the enthroned monster is an M2_PRINCE */
269         break;
270     case BEEHIVE:
271         tx = sroom->lx + (sroom->hx - sroom->lx + 1) / 2;
272         ty = sroom->ly + (sroom->hy - sroom->ly + 1) / 2;
273         if (sroom->irregular) {
274             /* center might not be valid, so put queen elsewhere */
275             if ((int) levl[tx][ty].roomno != rmno || levl[tx][ty].edge) {
276                 (void) somexy(sroom, &mm);
277                 tx = mm.x;
278                 ty = mm.y;
279             }
280         }
281         break;
282     case ZOO:
283     case LEPREHALL:
284         goldlim = 500 * level_difficulty();
285         break;
286     }
287
288     for (sx = sroom->lx; sx <= sroom->hx; sx++)
289         for (sy = sroom->ly; sy <= sroom->hy; sy++) {
290             if (sroom->irregular) {
291                 if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge
292                     || (sroom->doorct
293                         && distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
294                     continue;
295             } else if (!SPACE_POS(levl[sx][sy].typ)
296                        || (sroom->doorct
297                            && ((sx == sroom->lx && doors[sh].x == sx - 1)
298                                || (sx == sroom->hx && doors[sh].x == sx + 1)
299                                || (sy == sroom->ly && doors[sh].y == sy - 1)
300                                || (sy == sroom->hy
301                                    && doors[sh].y == sy + 1))))
302                 continue;
303             /* don't place monster on explicitly placed throne */
304             if (type == COURT && IS_THRONE(levl[sx][sy].typ))
305                 continue;
306             mon = makemon((type == COURT)
307                            ? courtmon()
308                            : (type == BARRACKS)
309                               ? squadmon()
310                               : (type == MORGUE)
311                                  ? morguemon()
312                                  : (type == BEEHIVE)
313                                      ? (sx == tx && sy == ty
314                                          ? &mons[PM_QUEEN_BEE]
315                                          : &mons[PM_KILLER_BEE])
316                                      : (type == LEPREHALL)
317                                          ? &mons[PM_LEPRECHAUN]
318                                          : (type == COCKNEST)
319                                              ? &mons[PM_COCKATRICE]
320                                              : (type == ANTHOLE)
321                                                  ? antholemon()
322                                                  : (struct permonst *) 0,
323                           sx, sy, NO_MM_FLAGS);
324             if (mon) {
325                 mon->msleeping = 1;
326                 if (type == COURT && mon->mpeaceful) {
327                     mon->mpeaceful = 0;
328                     set_malign(mon);
329                 }
330             }
331             switch (type) {
332             case ZOO:
333             case LEPREHALL:
334                 if (sroom->doorct) {
335                     int distval = dist2(sx, sy, doors[sh].x, doors[sh].y);
336                     i = sq(distval);
337                 } else
338                     i = goldlim;
339                 if (i >= goldlim)
340                     i = 5 * level_difficulty();
341                 goldlim -= i;
342                 (void) mkgold((long) rn1(i, 10), sx, sy);
343                 break;
344             case MORGUE:
345                 if (!rn2(5))
346                     (void) mk_tt_object(CORPSE, sx, sy);
347                 if (!rn2(10)) /* lots of treasure buried with dead */
348                     (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
349                                      TRUE, FALSE);
350                 if (!rn2(5))
351                     make_grave(sx, sy, (char *) 0);
352                 break;
353             case BEEHIVE:
354                 if (!rn2(3))
355                     (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE,
356                                      FALSE);
357                 break;
358             case BARRACKS:
359                 if (!rn2(20)) /* the payroll and some loot */
360                     (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
361                                      TRUE, FALSE);
362                 break;
363             case COCKNEST:
364                 if (!rn2(3)) {
365                     struct obj *sobj = mk_tt_object(STATUE, sx, sy);
366
367                     if (sobj) {
368                         for (i = rn2(5); i; i--)
369                             (void) add_to_container(
370                                 sobj, mkobj(RANDOM_CLASS, FALSE));
371                         sobj->owt = weight(sobj);
372                     }
373                 }
374                 break;
375             case ANTHOLE:
376                 if (!rn2(3))
377                     (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
378                 break;
379             }
380         }
381     switch (type) {
382     case COURT: {
383         struct obj *chest;
384         levl[tx][ty].typ = THRONE;
385         (void) somexy(sroom, &mm);
386         (void) mkgold((long) rn1(50 * level_difficulty(), 10), mm.x, mm.y);
387         /* the royal coffers */
388         chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE);
389         chest->spe = 2; /* so it can be found later */
390         level.flags.has_court = 1;
391         break;
392     }
393     case BARRACKS:
394         level.flags.has_barracks = 1;
395         break;
396     case ZOO:
397         level.flags.has_zoo = 1;
398         break;
399     case MORGUE:
400         level.flags.has_morgue = 1;
401         break;
402     case SWAMP:
403         level.flags.has_swamp = 1;
404         break;
405     case BEEHIVE:
406         level.flags.has_beehive = 1;
407         break;
408     }
409 }
410
411 /* make a swarm of undead around mm */
412 void
413 mkundead(mm, revive_corpses, mm_flags)
414 coord *mm;
415 boolean revive_corpses;
416 int mm_flags;
417 {
418     int cnt = (level_difficulty() + 1) / 10 + rnd(5);
419     struct permonst *mdat;
420     struct obj *otmp;
421     coord cc;
422
423     while (cnt--) {
424         mdat = morguemon();
425         if (mdat && enexto(&cc, mm->x, mm->y, mdat)
426             && (!revive_corpses
427                 || !(otmp = sobj_at(CORPSE, cc.x, cc.y))
428                 || !revive(otmp, FALSE)))
429             (void) makemon(mdat, cc.x, cc.y, mm_flags);
430     }
431     level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
432 }
433
434 STATIC_OVL struct permonst *
435 morguemon()
436 {
437     register int i = rn2(100), hd = rn2(level_difficulty());
438
439     if (hd > 10 && i < 10) {
440         if (Inhell || In_endgame(&u.uz)) {
441             return mkclass(S_DEMON, 0);
442         } else {
443             int ndemon_res = ndemon(A_NONE);
444             if (ndemon_res != NON_PM)
445                 return &mons[ndemon_res];
446             /* else do what? As is, it will drop to ghost/wraith/zombie */
447         }
448     }
449
450     if (hd > 8 && i > 85)
451         return mkclass(S_VAMPIRE, 0);
452
453     return ((i < 20) ? &mons[PM_GHOST]
454                      : (i < 40) ? &mons[PM_WRAITH]
455                                 : mkclass(S_ZOMBIE, 0));
456 }
457
458 struct permonst *
459 antholemon()
460 {
461     int mtyp, indx, trycnt = 0;
462
463     /* casts are for dealing with time_t */
464     indx = (int) ((long) ubirthday % 3L);
465     indx += level_difficulty();
466     /* Same monsters within a level, different ones between levels */
467     do {
468         switch ((indx + trycnt) % 3) {
469         case 0:
470             mtyp = PM_SOLDIER_ANT;
471             break;
472         case 1:
473             mtyp = PM_FIRE_ANT;
474             break;
475         default:
476             mtyp = PM_GIANT_ANT;
477             break;
478         }
479         /* try again if chosen type has been genocided or used up */
480     } while (++trycnt < 3 && (mvitals[mtyp].mvflags & G_GONE));
481
482     return ((mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0
483                                              : &mons[mtyp]);
484 }
485
486 STATIC_OVL void
487 mkswamp() /* Michiel Huisjes & Fred de Wilde */
488 {
489     register struct mkroom *sroom;
490     register int sx, sy, i, eelct = 0;
491
492     for (i = 0; i < 5; i++) { /* turn up to 5 rooms swampy */
493         sroom = &rooms[rn2(nroom)];
494         if (sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom)
495             || has_dnstairs(sroom))
496             continue;
497
498         /* satisfied; make a swamp */
499         sroom->rtype = SWAMP;
500         for (sx = sroom->lx; sx <= sroom->hx; sx++)
501             for (sy = sroom->ly; sy <= sroom->hy; sy++)
502                 if (!OBJ_AT(sx, sy) && !MON_AT(sx, sy) && !t_at(sx, sy)
503                     && !nexttodoor(sx, sy)) {
504                     if ((sx + sy) % 2) {
505                         levl[sx][sy].typ = POOL;
506                         if (!eelct || !rn2(4)) {
507                             /* mkclass() won't do, as we might get kraken */
508                             (void) makemon(rn2(5)
509                                               ? &mons[PM_GIANT_EEL]
510                                               : rn2(2)
511                                                  ? &mons[PM_PIRANHA]
512                                                  : &mons[PM_ELECTRIC_EEL],
513                                            sx, sy, NO_MM_FLAGS);
514                             eelct++;
515                         }
516                     } else if (!rn2(4)) /* swamps tend to be moldy */
517                         (void) makemon(mkclass(S_FUNGUS, 0), sx, sy,
518                                        NO_MM_FLAGS);
519                 }
520         level.flags.has_swamp = 1;
521     }
522 }
523
524 STATIC_OVL coord *
525 shrine_pos(roomno)
526 int roomno;
527 {
528     static coord buf;
529     int delta;
530     struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
531
532     /* if width and height are odd, placement will be the exact center;
533        if either or both are even, center point is a hypothetical spot
534        between map locations and placement will be adjacent to that */
535     delta = troom->hx - troom->lx;
536     buf.x = troom->lx + delta / 2;
537     if ((delta % 2) && rn2(2))
538         buf.x++;
539     delta = troom->hy - troom->ly;
540     buf.y = troom->ly + delta / 2;
541     if ((delta % 2) && rn2(2))
542         buf.y++;
543     return &buf;
544 }
545
546 STATIC_OVL void
547 mktemple()
548 {
549     register struct mkroom *sroom;
550     coord *shrine_spot;
551     register struct rm *lev;
552
553     if (!(sroom = pick_room(TRUE)))
554         return;
555
556     /* set up Priest and shrine */
557     sroom->rtype = TEMPLE;
558     /*
559      * In temples, shrines are blessed altars
560      * located in the center of the room
561      */
562     shrine_spot = shrine_pos((int) ((sroom - rooms) + ROOMOFFSET));
563     lev = &levl[shrine_spot->x][shrine_spot->y];
564     lev->typ = ALTAR;
565     lev->altarmask = induced_align(80);
566     priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
567     lev->altarmask |= AM_SHRINE;
568     level.flags.has_temple = 1;
569 }
570
571 boolean
572 nexttodoor(sx, sy)
573 register int sx, sy;
574 {
575     register int dx, dy;
576     register struct rm *lev;
577
578     for (dx = -1; dx <= 1; dx++)
579         for (dy = -1; dy <= 1; dy++) {
580             if (!isok(sx + dx, sy + dy))
581                 continue;
582             lev = &levl[sx + dx][sy + dy];
583             if (IS_DOOR(lev->typ) || lev->typ == SDOOR)
584                 return TRUE;
585         }
586     return FALSE;
587 }
588
589 boolean
590 has_dnstairs(sroom)
591 register struct mkroom *sroom;
592 {
593     if (sroom == dnstairs_room)
594         return TRUE;
595     if (sstairs.sx && !sstairs.up)
596         return (boolean) (sroom == sstairs_room);
597     return FALSE;
598 }
599
600 boolean
601 has_upstairs(sroom)
602 register struct mkroom *sroom;
603 {
604     if (sroom == upstairs_room)
605         return TRUE;
606     if (sstairs.sx && sstairs.up)
607         return (boolean) (sroom == sstairs_room);
608     return FALSE;
609 }
610
611 int
612 somex(croom)
613 register struct mkroom *croom;
614 {
615     return rn1(croom->hx - croom->lx + 1, croom->lx);
616 }
617
618 int
619 somey(croom)
620 register struct mkroom *croom;
621 {
622     return rn1(croom->hy - croom->ly + 1, croom->ly);
623 }
624
625 boolean
626 inside_room(croom, x, y)
627 struct mkroom *croom;
628 xchar x, y;
629 {
630     return (boolean) (x >= croom->lx - 1 && x <= croom->hx + 1
631                       && y >= croom->ly - 1 && y <= croom->hy + 1);
632 }
633
634 boolean
635 somexy(croom, c)
636 struct mkroom *croom;
637 coord *c;
638 {
639     int try_cnt = 0;
640     int i;
641
642     if (croom->irregular) {
643         i = (int) ((croom - rooms) + ROOMOFFSET);
644
645         while (try_cnt++ < 100) {
646             c->x = somex(croom);
647             c->y = somey(croom);
648             if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i)
649                 return TRUE;
650         }
651         /* try harder; exhaustively search until one is found */
652         for (c->x = croom->lx; c->x <= croom->hx; c->x++)
653             for (c->y = croom->ly; c->y <= croom->hy; c->y++)
654                 if (!levl[c->x][c->y].edge
655                     && (int) levl[c->x][c->y].roomno == i)
656                     return TRUE;
657         return FALSE;
658     }
659
660     if (!croom->nsubrooms) {
661         c->x = somex(croom);
662         c->y = somey(croom);
663         return TRUE;
664     }
665
666     /* Check that coords doesn't fall into a subroom or into a wall */
667
668     while (try_cnt++ < 100) {
669         c->x = somex(croom);
670         c->y = somey(croom);
671         if (IS_WALL(levl[c->x][c->y].typ))
672             continue;
673         for (i = 0; i < croom->nsubrooms; i++)
674             if (inside_room(croom->sbrooms[i], c->x, c->y))
675                 goto you_lose;
676         break;
677     you_lose:
678         ;
679     }
680     if (try_cnt >= 100)
681         return FALSE;
682     return TRUE;
683 }
684
685 /*
686  * Search for a special room given its type (zoo, court, etc...)
687  *      Special values :
688  *              - ANY_SHOP
689  *              - ANY_TYPE
690  */
691 struct mkroom *
692 search_special(type)
693 schar type;
694 {
695     register struct mkroom *croom;
696
697     for (croom = &rooms[0]; croom->hx >= 0; croom++)
698         if ((type == ANY_TYPE && croom->rtype != OROOM)
699             || (type == ANY_SHOP && croom->rtype >= SHOPBASE)
700             || croom->rtype == type)
701             return croom;
702     for (croom = &subrooms[0]; croom->hx >= 0; croom++)
703         if ((type == ANY_TYPE && croom->rtype != OROOM)
704             || (type == ANY_SHOP && croom->rtype >= SHOPBASE)
705             || croom->rtype == type)
706             return croom;
707     return (struct mkroom *) 0;
708 }
709
710 struct permonst *
711 courtmon()
712 {
713     int i = rn2(60) + rn2(3 * level_difficulty());
714
715     if (i > 100)
716         return mkclass(S_DRAGON, 0);
717     else if (i > 95)
718         return mkclass(S_GIANT, 0);
719     else if (i > 85)
720         return mkclass(S_TROLL, 0);
721     else if (i > 75)
722         return mkclass(S_CENTAUR, 0);
723     else if (i > 60)
724         return mkclass(S_ORC, 0);
725     else if (i > 45)
726         return &mons[PM_BUGBEAR];
727     else if (i > 30)
728         return &mons[PM_HOBGOBLIN];
729     else if (i > 15)
730         return mkclass(S_GNOME, 0);
731     else
732         return mkclass(S_KOBOLD, 0);
733 }
734
735 #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
736
737 static struct {
738     unsigned pm;
739     unsigned prob;
740 } squadprob[NSTYPES] = { { PM_SOLDIER, 80 },
741                          { PM_SERGEANT, 15 },
742                          { PM_LIEUTENANT, 4 },
743                          { PM_CAPTAIN, 1 } };
744
745 /* return soldier types. */
746 STATIC_OVL struct permonst *
747 squadmon()
748 {
749     int sel_prob, i, cpro, mndx;
750
751     sel_prob = rnd(80 + level_difficulty());
752
753     cpro = 0;
754     for (i = 0; i < NSTYPES; i++) {
755         cpro += squadprob[i].prob;
756         if (cpro > sel_prob) {
757             mndx = squadprob[i].pm;
758             goto gotone;
759         }
760     }
761     mndx = squadprob[rn2(NSTYPES)].pm;
762 gotone:
763     if (!(mvitals[mndx].mvflags & G_GONE))
764         return &mons[mndx];
765     else
766         return (struct permonst *) 0;
767 }
768
769 /*
770  * save_room : A recursive function that saves a room and its subrooms
771  * (if any).
772  */
773 STATIC_OVL void
774 save_room(fd, r)
775 int fd;
776 struct mkroom *r;
777 {
778     short i;
779
780     /*
781      * Well, I really should write only useful information instead
782      * of writing the whole structure. That is I should not write
783      * the subrooms pointers, but who cares ?
784      */
785     bwrite(fd, (genericptr_t) r, sizeof (struct mkroom));
786     for (i = 0; i < r->nsubrooms; i++)
787         save_room(fd, r->sbrooms[i]);
788 }
789
790 /*
791  * save_rooms : Save all the rooms on disk!
792  */
793 void
794 save_rooms(fd)
795 int fd;
796 {
797     short i;
798
799     /* First, write the number of rooms */
800     bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
801     for (i = 0; i < nroom; i++)
802         save_room(fd, &rooms[i]);
803 }
804
805 STATIC_OVL void
806 rest_room(fd, r)
807 int fd;
808 struct mkroom *r;
809 {
810     short i;
811
812     mread(fd, (genericptr_t) r, sizeof(struct mkroom));
813     for (i = 0; i < r->nsubrooms; i++) {
814         r->sbrooms[i] = &subrooms[nsubroom];
815         rest_room(fd, &subrooms[nsubroom]);
816         subrooms[nsubroom++].resident = (struct monst *) 0;
817     }
818 }
819
820 /*
821  * rest_rooms : That's for restoring rooms. Read the rooms structure from
822  * the disk.
823  */
824 void
825 rest_rooms(fd)
826 int fd;
827 {
828     short i;
829
830     mread(fd, (genericptr_t) &nroom, sizeof(nroom));
831     nsubroom = 0;
832     for (i = 0; i < nroom; i++) {
833         rest_room(fd, &rooms[i]);
834         rooms[i].resident = (struct monst *) 0;
835     }
836     rooms[nroom].hx = -1; /* restore ending flags */
837     subrooms[nsubroom].hx = -1;
838 }
839
840 /* convert a display symbol for terrain into topology type;
841    used for remembered terrain when mimics pose as furniture */
842 int
843 cmap_to_type(sym)
844 int sym;
845 {
846     int typ = STONE; /* catchall */
847
848     switch (sym) {
849     case S_stone:
850         typ = STONE;
851         break;
852     case S_vwall:
853         typ = VWALL;
854         break;
855     case S_hwall:
856         typ = HWALL;
857         break;
858     case S_tlcorn:
859         typ = TLCORNER;
860         break;
861     case S_trcorn:
862         typ = TRCORNER;
863         break;
864     case S_blcorn:
865         typ = BLCORNER;
866         break;
867     case S_brcorn:
868         typ = BRCORNER;
869         break;
870     case S_crwall:
871         typ = CROSSWALL;
872         break;
873     case S_tuwall:
874         typ = TUWALL;
875         break;
876     case S_tdwall:
877         typ = TDWALL;
878         break;
879     case S_tlwall:
880         typ = TLWALL;
881         break;
882     case S_trwall:
883         typ = TRWALL;
884         break;
885     case S_ndoor:  /* no door (empty doorway) */
886     case S_vodoor: /* open door in vertical wall */
887     case S_hodoor: /* open door in horizontal wall */
888     case S_vcdoor: /* closed door in vertical wall */
889     case S_hcdoor:
890         typ = DOOR;
891         break;
892     case S_bars:
893         typ = IRONBARS;
894         break;
895     case S_tree:
896         typ = TREE;
897         break;
898     case S_room:
899         typ = ROOM;
900         break;
901     case S_corr:
902     case S_litcorr:
903         typ = CORR;
904         break;
905     case S_upstair:
906     case S_dnstair:
907         typ = STAIRS;
908         break;
909     case S_upladder:
910     case S_dnladder:
911         typ = LADDER;
912         break;
913     case S_altar:
914         typ = ALTAR;
915         break;
916     case S_grave:
917         typ = GRAVE;
918         break;
919     case S_throne:
920         typ = THRONE;
921         break;
922     case S_sink:
923         typ = SINK;
924         break;
925     case S_fountain:
926         typ = FOUNTAIN;
927         break;
928     case S_pool:
929         typ = POOL;
930         break;
931     case S_ice:
932         typ = ICE;
933         break;
934     case S_lava:
935         typ = LAVAPOOL;
936         break;
937     case S_vodbridge: /* open drawbridge spanning north/south */
938     case S_hodbridge:
939         typ = DRAWBRIDGE_DOWN;
940         break;        /* east/west */
941     case S_vcdbridge: /* closed drawbridge in vertical wall */
942     case S_hcdbridge:
943         typ = DBWALL;
944         break;
945     case S_air:
946         typ = AIR;
947         break;
948     case S_cloud:
949         typ = CLOUD;
950         break;
951     case S_water:
952         typ = WATER;
953         break;
954     default:
955         break; /* not a cmap symbol? */
956     }
957     return typ;
958 }
959
960 /*mkroom.c*/