1 | /* SCCS Id: @(#)mkroom.c 3.3 97/05/25 */
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 | */
15 |
16 | #include "hack.h"
17 |
18 | #ifdef OVLB
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(antholemon);
26 | STATIC_DCL struct permonst * NDECL(squadmon);
27 | STATIC_DCL void FDECL(save_room, (int,struct mkroom *));
28 | STATIC_DCL void FDECL(rest_room, (int,struct mkroom *));
29 | #endif /* OVLB */
30 |
31 | #define sq(x) ((x)*(x))
32 |
33 | extern const struct shclass shtypes[]; /* defined in shknam.c */
34 |
35 | #ifdef OVLB
36 |
37 | STATIC_OVL boolean
38 | isbig(sroom)
39 | register struct mkroom *sroom;
40 | {
41 | register int area = (sroom->hx - sroom->lx + 1)
42 | * (sroom->hy - sroom->ly + 1);
43 | return((boolean)( area > 20 ));
44 | }
45 |
46 | void
47 | mkroom(roomtype)
48 | /* make and stock a room of a given type */
49 | int roomtype;
50 | {
51 | if (roomtype >= SHOPBASE)
52 | mkshop(); /* someday, we should be able to specify shop type */
53 | else switch(roomtype) {
54 | case COURT: mkzoo(COURT); break;
55 | case ZOO: mkzoo(ZOO); break;
56 | case BEEHIVE: mkzoo(BEEHIVE); break;
57 | case MORGUE: mkzoo(MORGUE); break;
58 | case BARRACKS: mkzoo(BARRACKS); break;
59 | case SWAMP: mkswamp(); break;
60 | case TEMPLE: mktemple(); break;
61 | case LEPREHALL: mkzoo(LEPREHALL); break;
62 | case COCKNEST: mkzoo(COCKNEST); break;
63 | case ANTHOLE: mkzoo(ANTHOLE); break;
64 | default: impossible("Tried to make a room of type %d.", roomtype);
65 | }
66 | }
67 |
68 | STATIC_OVL void
69 | mkshop()
70 | {
71 | register struct mkroom *sroom;
72 | int i = -1;
73 | #ifdef WIZARD
74 | char *ep = (char *)0; /* (init == lint suppression) */
75 |
76 | /* first determine shoptype */
77 | if(wizard){
78 | #ifndef MAC
79 | ep = nh_getenv("SHOPTYPE");
80 | if(ep){
81 | if(*ep == 'z' || *ep == 'Z'){
82 | mkzoo(ZOO);
83 | return;
84 | }
85 | if(*ep == 'm' || *ep == 'M'){
86 | mkzoo(MORGUE);
87 | return;
88 | }
89 | if(*ep == 'b' || *ep == 'B'){
90 | mkzoo(BEEHIVE);
91 | return;
92 | }
93 | if(*ep == 't' || *ep == 'T' || *ep == '\\'){
94 | mkzoo(COURT);
95 | return;
96 | }
97 | if(*ep == 's' || *ep == 'S'){
98 | mkzoo(BARRACKS);
99 | return;
100 | }
101 | if(*ep == 'a' || *ep == 'A'){
102 | mkzoo(ANTHOLE);
103 | return;
104 | }
105 | if(*ep == 'c' || *ep == 'C'){
106 | mkzoo(COCKNEST);
107 | return;
108 | }
109 | if(*ep == 'l' || *ep == 'L'){
110 | mkzoo(LEPREHALL);
111 | return;
112 | }
113 | if(*ep == '_'){
114 | mktemple();
115 | return;
116 | }
117 | if(*ep == '}'){
118 | mkswamp();
119 | return;
120 | }
121 | for(i=0; shtypes[i].name; i++)
122 | if(*ep == def_oc_syms[(int)shtypes[i].symb])
123 | goto gottype;
124 | if(*ep == 'g' || *ep == 'G')
125 | i = 0;
126 | else
127 | i = -1;
128 | }
129 | #endif
130 | }
131 | gottype:
132 | #endif
133 | for(sroom = &rooms[0]; ; sroom++){
134 | if(sroom->hx < 0) return;
135 | if(sroom - rooms >= nroom) {
136 | pline("rooms not closed by -1?");
137 | return;
138 | }
139 | if(sroom->rtype != OROOM) continue;
140 | if(has_dnstairs(sroom) || has_upstairs(sroom))
141 | continue;
142 | if(
143 | #ifdef WIZARD
144 | (wizard && ep && sroom->doorct != 0) ||
145 | #endif
146 | sroom->doorct == 1) break;
147 | }
148 | if (!sroom->rlit) {
149 | int x, y;
150 |
151 | for(x = sroom->lx - 1; x <= sroom->hx + 1; x++)
152 | for(y = sroom->ly - 1; y <= sroom->hy + 1; y++)
153 | levl[x][y].lit = 1;
154 | sroom->rlit = 1;
155 | }
156 |
157 | if(i < 0) { /* shoptype not yet determined */
158 | register int j;
159 |
160 | /* pick a shop type at random */
161 | for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
162 | continue;
163 |
164 | /* big rooms cannot be wand or book shops,
165 | * - so make them general stores
166 | */
167 | if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS
168 | || shtypes[i].symb == SPBOOK_CLASS)) i = 0;
169 | }
170 | sroom->rtype = SHOPBASE + i;
171 |
172 | /* set room bits before stocking the shop */
173 | #ifdef SPECIALIZATION
174 | topologize(sroom, FALSE); /* doesn't matter - this is a special room */
175 | #else
176 | topologize(sroom);
177 | #endif
178 |
179 | /* stock the room with a shopkeeper and artifacts */
180 | stock_room(i, sroom);
181 | }
182 |
183 | STATIC_OVL struct mkroom *
184 | pick_room(strict)
185 | register boolean strict;
186 | /* pick an unused room, preferably with only one door */
187 | {
188 | register struct mkroom *sroom;
189 | register int i = nroom;
190 |
191 | for(sroom = &rooms[rn2(nroom)]; i--; sroom++) {
192 | if(sroom == &rooms[nroom])
193 | sroom = &rooms[0];
194 | if(sroom->hx < 0)
195 | return (struct mkroom *)0;
196 | if(sroom->rtype != OROOM) continue;
197 | if(!strict) {
198 | if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
199 | continue;
200 | } else if(has_upstairs(sroom) || has_dnstairs(sroom))
201 | continue;
202 | if(sroom->doorct == 1 || !rn2(5)
203 | #ifdef WIZARD
204 | || wizard
205 | #endif
206 | )
207 | return sroom;
208 | }
209 | return (struct mkroom *)0;
210 | }
211 |
212 | STATIC_OVL void
213 | mkzoo(type)
214 | int type;
215 | {
216 | register struct mkroom *sroom;
217 |
218 | if ((sroom = pick_room(FALSE)) != 0) {
219 | sroom->rtype = type;
220 | fill_zoo(sroom);
221 | }
222 | }
223 |
224 | void
225 | fill_zoo(sroom)
226 | struct mkroom *sroom;
227 | {
228 | struct monst *mon;
229 | register int sx,sy,i;
230 | int sh, tx, ty, goldlim, type = sroom->rtype;
231 | int rmno = (sroom - rooms) + ROOMOFFSET;
232 | coord mm;
233 |
234 | #ifdef GCC_WARN
235 | tx = ty = goldlim = 0;
236 | #endif
237 |
238 | sh = sroom->fdoor;
239 | switch(type) {
240 | case COURT:
241 | if(level.flags.is_maze_lev) {
242 | for(tx = sroom->lx; tx <= sroom->hx; tx++)
243 | for(ty = sroom->ly; ty <= sroom->hy; ty++)
244 | if(IS_THRONE(levl[tx][ty].typ))
245 | goto throne_placed;
246 | }
247 | i = 100;
248 | do { /* don't place throne on top of stairs */
249 | (void) somexy(sroom, &mm);
250 | tx = mm.x; ty = mm.y;
251 | } while (occupied((xchar)tx, (xchar)ty) && --i > 0);
252 | throne_placed:
253 | /* TODO: try to ensure the enthroned monster is an M2_PRINCE */
254 | break;
255 | case BEEHIVE:
256 | tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2;
257 | ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2;
258 | if(sroom->irregular) {
259 | /* center might not be valid, so put queen elsewhere */
260 | if ((int) levl[tx][ty].roomno != rmno ||
261 | levl[tx][ty].edge) {
262 | (void) somexy(sroom, &mm);
263 | tx = mm.x; ty = mm.y;
264 | }
265 | }
266 | break;
267 | case ZOO:
268 | case LEPREHALL:
269 | goldlim = 500 * level_difficulty();
270 | break;
271 | }
272 | for(sx = sroom->lx; sx <= sroom->hx; sx++)
273 | for(sy = sroom->ly; sy <= sroom->hy; sy++) {
274 | if(sroom->irregular) {
275 | if ((int) levl[sx][sy].roomno != rmno ||
276 | levl[sx][sy].edge ||
277 | (sroom->doorct &&
278 | distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
279 | continue;
280 | } else if(!SPACE_POS(levl[sx][sy].typ) ||
281 | (sroom->doorct &&
282 | ((sx == sroom->lx && doors[sh].x == sx-1) ||
283 | (sx == sroom->hx && doors[sh].x == sx+1) ||
284 | (sy == sroom->ly && doors[sh].y == sy-1) ||
285 | (sy == sroom->hy && doors[sh].y == sy+1))))
286 | continue;
287 | /* don't place monster on explicitly placed throne */
288 | if(type == COURT && IS_THRONE(levl[sx][sy].typ))
289 | continue;
290 | mon = makemon(
291 | (type == COURT) ? courtmon() :
292 | (type == BARRACKS) ? squadmon() :
293 | (type == MORGUE) ? morguemon() :
294 | (type == BEEHIVE) ?
295 | (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] :
296 | &mons[PM_KILLER_BEE]) :
297 | (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] :
298 | (type == COCKNEST) ? &mons[PM_COCKATRICE] :
299 | (type == ANTHOLE) ? antholemon() :
300 | (struct permonst *) 0,
301 | sx, sy, NO_MM_FLAGS);
302 | if(mon) {
303 | mon->msleeping = 1;
304 | if (type==COURT && mon->mpeaceful) {
305 | mon->mpeaceful = 0;
306 | set_malign(mon);
307 | }
308 | }
309 | switch(type) {
310 | case ZOO:
311 | case LEPREHALL:
312 | if(sroom->doorct)
313 | {
314 | int distval = dist2(sx,sy,doors[sh].x,doors[sh].y);
315 | i = sq(distval);
316 | }
317 | else
318 | i = goldlim;
319 | if(i >= goldlim) i = 5*level_difficulty();
320 | goldlim -= i;
321 | (void) mkgold((long) rn1(i, 10), sx, sy);
322 | break;
323 | case MORGUE:
324 | if(!rn2(5))
325 | (void) mk_tt_object(CORPSE, sx, sy);
326 | if(!rn2(10)) /* lots of treasure buried with dead */
327 | (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
328 | sx, sy, TRUE);
329 | if (!rn2(5))
330 | make_grave(sx, sy, (char *)0);
331 | break;
332 | case BEEHIVE:
333 | if(!rn2(3))
334 | (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE);
335 | break;
336 | case BARRACKS:
337 | if(!rn2(20)) /* the payroll and some loot */
338 | (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
339 | sx, sy, TRUE);
340 | break;
341 | case COCKNEST:
342 | if(!rn2(3)) {
343 | struct obj *sobj = mk_tt_object(STATUE, sx, sy);
344 |
345 | if (sobj)
346 | for (i = rn2(5); i; i--)
347 | add_to_container(sobj, mkobj(RANDOM_CLASS, FALSE));
348 | }
349 | break;
350 | case ANTHOLE:
351 | if(!rn2(3))
352 | (void) mkobj_at(FOOD_CLASS, sx, sy, TRUE);
353 | break;
354 | }
355 | }
356 | switch (type) {
357 | case COURT:
358 | {
359 | struct obj *chest;
360 | levl[tx][ty].typ = THRONE;
361 | (void) somexy(sroom, &mm);
362 | (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y);
363 | chest = mksobj_at(CHEST, mm.x, mm.y, TRUE); /* the royal coffers */
364 | chest->spe = 2; /* so it can be found later */
365 | level.flags.has_court = 1;
366 | break;
367 | }
368 | case BARRACKS:
369 | level.flags.has_barracks = 1;
370 | break;
371 | case ZOO:
372 | level.flags.has_zoo = 1;
373 | break;
374 | case MORGUE:
375 | level.flags.has_morgue = 1;
376 | break;
377 | case SWAMP:
378 | level.flags.has_swamp = 1;
379 | break;
380 | case BEEHIVE:
381 | level.flags.has_beehive = 1;
382 | break;
383 | }
384 | }
385 |
386 | /* make a swarm of undead around mm */
387 | void
388 | mkundead(mm, revive_corpses, mm_flags)
389 | coord *mm;
390 | boolean revive_corpses;
391 | int mm_flags;
392 | {
393 | int cnt = (level_difficulty() + 1)/10 + rnd(5);
394 | struct permonst *mdat;
395 | struct obj *otmp;
396 | coord cc;
397 |
398 | while (cnt--) {
399 | mdat = morguemon();
400 | if (enexto(&cc, mm->x, mm->y, mdat) &&
401 | (!revive_corpses ||
402 | !(otmp = sobj_at(CORPSE, cc.x, cc.y)) ||
403 | !revive(otmp)))
404 | (void) makemon(mdat, cc.x, cc.y, mm_flags);
405 | }
406 | level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
407 | }
408 |
409 | STATIC_OVL struct permonst *
410 | morguemon()
411 | {
412 | register int i = rn2(100), hd = rn2(level_difficulty());
413 |
414 | if(hd > 10 && i < 10)
415 | return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) :
416 | &mons[ndemon(A_NONE)]);
417 | if(hd > 8 && i > 85)
418 | return(mkclass(S_VAMPIRE,0));
419 |
420 | return((i < 20) ? &mons[PM_GHOST]
421 | : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0));
422 | }
423 |
424 | STATIC_OVL struct permonst *
425 | antholemon()
426 | {
427 | int mtyp;
428 |
429 | /* Same monsters within a level, different ones between levels */
430 | switch ((level_difficulty() + ((long)u.ubirthday)) % 3) {
431 | default: mtyp = PM_GIANT_ANT; break;
432 | case 0: mtyp = PM_SOLDIER_ANT; break;
433 | case 1: mtyp = PM_FIRE_ANT; break;
434 | }
435 | return ((mvitals[mtyp].mvflags & G_GONE) ?
436 | (struct permonst *)0 : &mons[mtyp]);
437 | }
438 |
439 | STATIC_OVL void
440 | mkswamp() /* Michiel Huisjes & Fred de Wilde */
441 | {
442 | register struct mkroom *sroom;
443 | register int sx,sy,i,eelct = 0;
444 |
445 | for(i=0; i<5; i++) { /* turn up to 5 rooms swampy */
446 | sroom = &rooms[rn2(nroom)];
447 | if(sroom->hx < 0 || sroom->rtype != OROOM ||
448 | has_upstairs(sroom) || has_dnstairs(sroom))
449 | continue;
450 |
451 | /* satisfied; make a swamp */
452 | sroom->rtype = SWAMP;
453 | for(sx = sroom->lx; sx <= sroom->hx; sx++)
454 | for(sy = sroom->ly; sy <= sroom->hy; sy++)
455 | if(!OBJ_AT(sx, sy) &&
456 | !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) {
457 | if((sx+sy)%2) {
458 | levl[sx][sy].typ = POOL;
459 | if(!eelct || !rn2(4)) {
460 | /* mkclass() won't do, as we might get kraken */
461 | (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL]
462 | : rn2(2) ? &mons[PM_PIRANHA]
463 | : &mons[PM_ELECTRIC_EEL],
464 | sx, sy, NO_MM_FLAGS);
465 | eelct++;
466 | }
467 | } else
468 | if(!rn2(4)) /* swamps tend to be moldy */
469 | (void) makemon(mkclass(S_FUNGUS,0),
470 | sx, sy, NO_MM_FLAGS);
471 | }
472 | level.flags.has_swamp = 1;
473 | }
474 | }
475 |
476 | STATIC_OVL coord *
477 | shrine_pos(roomno)
478 | int roomno;
479 | {
480 | static coord buf;
481 | struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
482 |
483 | buf.x = troom->lx + ((troom->hx - troom->lx) / 2);
484 | buf.y = troom->ly + ((troom->hy - troom->ly) / 2);
485 | return(&buf);
486 | }
487 |
488 | STATIC_OVL void
489 | mktemple()
490 | {
491 | register struct mkroom *sroom;
492 | coord *shrine_spot;
493 | register struct rm *lev;
494 |
495 | if(!(sroom = pick_room(TRUE))) return;
496 |
497 | /* set up Priest and shrine */
498 | sroom->rtype = TEMPLE;
499 | /*
500 | * In temples, shrines are blessed altars
501 | * located in the center of the room
502 | */
503 | shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET);
504 | lev = &levl[shrine_spot->x][shrine_spot->y];
505 | lev->typ = ALTAR;
506 | lev->altarmask = induced_align(80);
507 | priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
508 | lev->altarmask |= AM_SHRINE;
509 | level.flags.has_temple = 1;
510 | }
511 |
512 | boolean
513 | nexttodoor(sx,sy)
514 | register int sx, sy;
515 | {
516 | register int dx, dy;
517 | register struct rm *lev;
518 | for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) {
519 | if(!isok(sx+dx, sy+dy)) continue;
520 | if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) ||
521 | lev->typ == SDOOR)
522 | return(TRUE);
523 | }
524 | return(FALSE);
525 | }
526 |
527 | boolean
528 | has_dnstairs(sroom)
529 | register struct mkroom *sroom;
530 | {
531 | if (sroom == dnstairs_room)
532 | return TRUE;
533 | if (sstairs.sx && !sstairs.up)
534 | return((boolean)(sroom == sstairs_room));
535 | return FALSE;
536 | }
537 |
538 | boolean
539 | has_upstairs(sroom)
540 | register struct mkroom *sroom;
541 | {
542 | if (sroom == upstairs_room)
543 | return TRUE;
544 | if (sstairs.sx && sstairs.up)
545 | return((boolean)(sroom == sstairs_room));
546 | return FALSE;
547 | }
548 |
549 | #endif /* OVLB */
550 | #ifdef OVL0
551 |
552 | int
553 | somex(croom)
554 | register struct mkroom *croom;
555 | {
556 | return rn2(croom->hx-croom->lx+1) + croom->lx;
557 | }
558 |
559 | int
560 | somey(croom)
561 | register struct mkroom *croom;
562 | {
563 | return rn2(croom->hy-croom->ly+1) + croom->ly;
564 | }
565 |
566 | boolean
567 | inside_room(croom, x, y)
568 | struct mkroom *croom;
569 | xchar x, y;
570 | {
571 | return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 &&
572 | y >= croom->ly-1 && y <= croom->hy+1));
573 | }
574 |
575 | boolean
576 | somexy(croom, c)
577 | struct mkroom *croom;
578 | coord *c;
579 | {
580 | int try_cnt = 0;
581 | int i;
582 |
583 | if (croom->irregular) {
584 | i = (croom - rooms) + ROOMOFFSET;
585 |
586 | while(try_cnt++ < 100) {
587 | c->x = somex(croom);
588 | c->y = somey(croom);
589 | if (!levl[c->x][c->y].edge &&
590 | (int) levl[c->x][c->y].roomno == i)
591 | return TRUE;
592 | }
593 | /* try harder; exhaustively search until one is found */
594 | for(c->x = croom->lx; c->x <= croom->hx; c->x++)
595 | for(c->y = croom->ly; c->y <= croom->hy; c->y++)
596 | if (!levl[c->x][c->y].edge &&
597 | (int) levl[c->x][c->y].roomno == i)
598 | return TRUE;
599 | return FALSE;
600 | }
601 |
602 | if (!croom->nsubrooms) {
603 | c->x = somex(croom);
604 | c->y = somey(croom);
605 | return TRUE;
606 | }
607 |
608 | /* Check that coords doesn't fall into a subroom or into a wall */
609 |
610 | while(try_cnt++ < 100) {
611 | c->x = somex(croom);
612 | c->y = somey(croom);
613 | if (IS_WALL(levl[c->x][c->y].typ))
614 | continue;
615 | for(i=0 ; i<croom->nsubrooms;i++)
616 | if(inside_room(croom->sbrooms[i], c->x, c->y))
617 | goto you_lose;
618 | break;
619 | you_lose: ;
620 | }
621 | if (try_cnt >= 100)
622 | return FALSE;
623 | return TRUE;
624 | }
625 |
626 | /*
627 | * Search for a special room given its type (zoo, court, etc...)
628 | * Special values :
629 | * - ANY_SHOP
630 | * - ANY_TYPE
631 | */
632 |
633 | struct mkroom *
634 | search_special(type)
635 | schar type;
636 | {
637 | register struct mkroom *croom;
638 |
639 | for(croom = &rooms[0]; croom->hx >= 0; croom++)
640 | if((type == ANY_TYPE && croom->rtype != OROOM) ||
641 | (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
642 | croom->rtype == type)
643 | return croom;
644 | for(croom = &subrooms[0]; croom->hx >= 0; croom++)
645 | if((type == ANY_TYPE && croom->rtype != OROOM) ||
646 | (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
647 | croom->rtype == type)
648 | return croom;
649 | return (struct mkroom *) 0;
650 | }
651 |
652 | #endif /* OVL0 */
653 | #ifdef OVLB
654 |
655 | struct permonst *
656 | courtmon()
657 | {
658 | int i = rn2(60) + rn2(3*level_difficulty());
659 | if (i > 100) return(mkclass(S_DRAGON,0));
660 | else if (i > 95) return(mkclass(S_GIANT,0));
661 | else if (i > 85) return(mkclass(S_TROLL,0));
662 | else if (i > 75) return(mkclass(S_CENTAUR,0));
663 | else if (i > 60) return(mkclass(S_ORC,0));
664 | else if (i > 45) return(&mons[PM_BUGBEAR]);
665 | else if (i > 30) return(&mons[PM_HOBGOBLIN]);
666 | else if (i > 15) return(mkclass(S_GNOME,0));
667 | else return(mkclass(S_KOBOLD,0));
668 | }
669 |
670 | #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
671 |
672 | static struct {
673 | unsigned pm;
674 | unsigned prob;
675 | } squadprob[NSTYPES] = {
676 | {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1}
677 | };
678 |
679 | STATIC_OVL struct permonst *
680 | squadmon() /* return soldier types. */
681 | {
682 | int sel_prob, i, cpro, mndx;
683 |
684 | sel_prob = rnd(80+level_difficulty());
685 |
686 | cpro = 0;
687 | for (i = 0; i < NSTYPES; i++) {
688 | cpro += squadprob[i].prob;
689 | if (cpro > sel_prob) {
690 | mndx = squadprob[i].pm;
691 | goto gotone;
692 | }
693 | }
694 | mndx = squadprob[rn2(NSTYPES)].pm;
695 | gotone:
696 | if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]);
697 | else return((struct permonst *) 0);
698 | }
699 |
700 | /*
701 | * save_room : A recursive function that saves a room and its subrooms
702 | * (if any).
703 | */
704 |
705 | STATIC_OVL void
706 | save_room(fd, r)
707 | int fd;
708 | struct mkroom *r;
709 | {
710 | short i;
711 | /*
712 | * Well, I really should write only useful information instead
713 | * of writing the whole structure. That is I should not write
714 | * the subrooms pointers, but who cares ?
715 | */
716 | bwrite(fd, (genericptr_t) r, sizeof(struct mkroom));
717 | for(i=0; i<r->nsubrooms; i++)
718 | save_room(fd, r->sbrooms[i]);
719 | }
720 |
721 | /*
722 | * save_rooms : Save all the rooms on disk!
723 | */
724 |
725 | void
726 | save_rooms(fd)
727 | int fd;
728 | {
729 | short i;
730 |
731 | /* First, write the number of rooms */
732 | bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
733 | for(i=0; i<nroom; i++)
734 | save_room(fd, &rooms[i]);
735 | }
736 |
737 | STATIC_OVL void
738 | rest_room(fd, r)
739 | int fd;
740 | struct mkroom *r;
741 | {
742 | short i;
743 |
744 | mread(fd, (genericptr_t) r, sizeof(struct mkroom));
745 | for(i=0; i<r->nsubrooms; i++) {
746 | r->sbrooms[i] = &subrooms[nsubroom];
747 | rest_room(fd, &subrooms[nsubroom]);
748 | subrooms[nsubroom++].resident = (struct monst *)0;
749 | }
750 | }
751 |
752 | /*
753 | * rest_rooms : That's for restoring rooms. Read the rooms structure from
754 | * the disk.
755 | */
756 |
757 | void
758 | rest_rooms(fd)
759 | int fd;
760 | {
761 | short i;
762 |
763 | mread(fd, (genericptr_t) &nroom, sizeof(nroom));
764 | nsubroom = 0;
765 | for(i = 0; i<nroom; i++) {
766 | rest_room(fd, &rooms[i]);
767 | rooms[i].resident = (struct monst *)0;
768 | }
769 | rooms[nroom].hx = -1; /* restore ending flags */
770 | subrooms[nsubroom].hx = -1;
771 | }
772 | #endif /* OVLB */
773 |
774 | /*mkroom.c*/