1 /* SCCS Id: @(#)mkroom.c 3.4 2001/09/06 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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
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 *));
31 #define sq(x) ((x)*(x))
33 extern const struct shclass shtypes[]; /* defined in shknam.c */
39 register struct mkroom *sroom;
41 register int area = (sroom->hx - sroom->lx + 1)
42 * (sroom->hy - sroom->ly + 1);
43 return((boolean)( area > 20 ));
48 /* make and stock a room of a given type */
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);
71 register struct mkroom *sroom;
74 char *ep = (char *)0; /* (init == lint suppression) */
76 /* first determine shoptype */
79 ep = nh_getenv("SHOPTYPE");
81 if(*ep == 'z' || *ep == 'Z'){
85 if(*ep == 'm' || *ep == 'M'){
89 if(*ep == 'b' || *ep == 'B'){
93 if(*ep == 't' || *ep == 'T' || *ep == '\\'){
97 if(*ep == 's' || *ep == 'S'){
101 if(*ep == 'a' || *ep == 'A'){
105 if(*ep == 'c' || *ep == 'C'){
109 if(*ep == 'l' || *ep == 'L'){
121 for(i=0; shtypes[i].name; i++)
122 if(*ep == def_oc_syms[(int)shtypes[i].symb])
124 if(*ep == 'g' || *ep == 'G')
135 for(sroom = &rooms[0]; ; sroom++){
136 if(sroom->hx < 0) return;
137 if(sroom - rooms >= nroom) {
138 pline("rooms not closed by -1?");
141 if(sroom->rtype != OROOM) continue;
142 if(has_dnstairs(sroom) || has_upstairs(sroom))
146 (wizard && ep && sroom->doorct != 0) ||
148 sroom->doorct == 1) break;
153 for(x = sroom->lx - 1; x <= sroom->hx + 1; x++)
154 for(y = sroom->ly - 1; y <= sroom->hy + 1; y++)
159 if(i < 0) { /* shoptype not yet determined */
162 /* pick a shop type at random */
163 for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
166 /* big rooms cannot be wand or book shops,
167 * - so make them general stores
169 if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS
170 || shtypes[i].symb == SPBOOK_CLASS)) i = 0;
172 sroom->rtype = SHOPBASE + i;
174 /* set room bits before stocking the shop */
175 #ifdef SPECIALIZATION
176 topologize(sroom, FALSE); /* doesn't matter - this is a special room */
181 /* stock the room with a shopkeeper and artifacts */
182 stock_room(i, sroom);
185 STATIC_OVL struct mkroom *
187 register boolean strict;
188 /* pick an unused room, preferably with only one door */
190 register struct mkroom *sroom;
191 register int i = nroom;
193 for(sroom = &rooms[rn2(nroom)]; i--; sroom++) {
194 if(sroom == &rooms[nroom])
197 return (struct mkroom *)0;
198 if(sroom->rtype != OROOM) continue;
200 if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
202 } else if(has_upstairs(sroom) || has_dnstairs(sroom))
204 if(sroom->doorct == 1 || !rn2(5)
211 return (struct mkroom *)0;
218 register struct mkroom *sroom;
220 if ((sroom = pick_room(FALSE)) != 0) {
228 struct mkroom *sroom;
231 register int sx,sy,i;
232 int sh, tx, ty, goldlim, type = sroom->rtype;
233 int rmno = (sroom - rooms) + ROOMOFFSET;
237 tx = ty = goldlim = 0;
243 if(level.flags.is_maze_lev) {
244 for(tx = sroom->lx; tx <= sroom->hx; tx++)
245 for(ty = sroom->ly; ty <= sroom->hy; ty++)
246 if(IS_THRONE(levl[tx][ty].typ))
250 do { /* don't place throne on top of stairs */
251 (void) somexy(sroom, &mm);
252 tx = mm.x; ty = mm.y;
253 } while (occupied((xchar)tx, (xchar)ty) && --i > 0);
255 /* TODO: try to ensure the enthroned monster is an M2_PRINCE */
258 tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2;
259 ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2;
260 if(sroom->irregular) {
261 /* center might not be valid, so put queen elsewhere */
262 if ((int) levl[tx][ty].roomno != rmno ||
264 (void) somexy(sroom, &mm);
265 tx = mm.x; ty = mm.y;
271 goldlim = 500 * level_difficulty();
274 for(sx = sroom->lx; sx <= sroom->hx; sx++)
275 for(sy = sroom->ly; sy <= sroom->hy; sy++) {
276 if(sroom->irregular) {
277 if ((int) levl[sx][sy].roomno != rmno ||
280 distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
282 } else if(!SPACE_POS(levl[sx][sy].typ) ||
284 ((sx == sroom->lx && doors[sh].x == sx-1) ||
285 (sx == sroom->hx && doors[sh].x == sx+1) ||
286 (sy == sroom->ly && doors[sh].y == sy-1) ||
287 (sy == sroom->hy && doors[sh].y == sy+1))))
289 /* don't place monster on explicitly placed throne */
290 if(type == COURT && IS_THRONE(levl[sx][sy].typ))
293 (type == COURT) ? courtmon() :
294 (type == BARRACKS) ? squadmon() :
295 (type == MORGUE) ? morguemon() :
297 (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] :
298 &mons[PM_KILLER_BEE]) :
299 (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] :
300 (type == COCKNEST) ? &mons[PM_COCKATRICE] :
301 (type == ANTHOLE) ? antholemon() :
302 (struct permonst *) 0,
303 sx, sy, NO_MM_FLAGS);
306 if (type==COURT && mon->mpeaceful) {
316 int distval = dist2(sx,sy,doors[sh].x,doors[sh].y);
321 if(i >= goldlim) i = 5*level_difficulty();
323 (void) mkgold((long) rn1(i, 10), sx, sy);
327 (void) mk_tt_object(CORPSE, sx, sy);
328 if(!rn2(10)) /* lots of treasure buried with dead */
329 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
330 sx, sy, TRUE, FALSE);
332 make_grave(sx, sy, (char *)0);
336 (void) mksobj_at(LUMP_OF_ROYAL_JELLY,
337 sx, sy, TRUE, FALSE);
340 if(!rn2(20)) /* the payroll and some loot */
341 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
342 sx, sy, TRUE, FALSE);
346 struct obj *sobj = mk_tt_object(STATUE, sx, sy);
349 for (i = rn2(5); i; i--)
350 (void) add_to_container(sobj,
351 mkobj(RANDOM_CLASS, FALSE));
352 sobj->owt = weight(sobj);
358 (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
366 levl[tx][ty].typ = THRONE;
367 (void) somexy(sroom, &mm);
368 (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y);
369 /* the royal coffers */
370 chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE);
371 chest->spe = 2; /* so it can be found later */
372 level.flags.has_court = 1;
376 level.flags.has_barracks = 1;
379 level.flags.has_zoo = 1;
382 level.flags.has_morgue = 1;
385 level.flags.has_swamp = 1;
388 level.flags.has_beehive = 1;
393 /* make a swarm of undead around mm */
395 mkundead(mm, revive_corpses, mm_flags)
397 boolean revive_corpses;
400 int cnt = (level_difficulty() + 1)/10 + rnd(5);
401 struct permonst *mdat;
407 if (enexto(&cc, mm->x, mm->y, mdat) &&
409 !(otmp = sobj_at(CORPSE, cc.x, cc.y)) ||
411 (void) makemon(mdat, cc.x, cc.y, mm_flags);
413 level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
416 STATIC_OVL struct permonst *
419 register int i = rn2(100), hd = rn2(level_difficulty());
421 if(hd > 10 && i < 10)
422 return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) :
423 &mons[ndemon(A_NONE)]);
425 return(mkclass(S_VAMPIRE,0));
427 return((i < 20) ? &mons[PM_GHOST]
428 : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0));
431 STATIC_OVL struct permonst *
436 /* Same monsters within a level, different ones between levels */
437 switch ((level_difficulty() + ((long)u.ubirthday)) % 3) {
438 default: mtyp = PM_GIANT_ANT; break;
439 case 0: mtyp = PM_SOLDIER_ANT; break;
440 case 1: mtyp = PM_FIRE_ANT; break;
442 return ((mvitals[mtyp].mvflags & G_GONE) ?
443 (struct permonst *)0 : &mons[mtyp]);
447 mkswamp() /* Michiel Huisjes & Fred de Wilde */
449 register struct mkroom *sroom;
450 register int sx,sy,i,eelct = 0;
452 for(i=0; i<5; i++) { /* turn up to 5 rooms swampy */
453 sroom = &rooms[rn2(nroom)];
454 if(sroom->hx < 0 || sroom->rtype != OROOM ||
455 has_upstairs(sroom) || has_dnstairs(sroom))
458 /* satisfied; make a swamp */
459 sroom->rtype = SWAMP;
460 for(sx = sroom->lx; sx <= sroom->hx; sx++)
461 for(sy = sroom->ly; sy <= sroom->hy; sy++)
462 if(!OBJ_AT(sx, sy) &&
463 !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) {
465 levl[sx][sy].typ = POOL;
466 if(!eelct || !rn2(4)) {
467 /* mkclass() won't do, as we might get kraken */
468 (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL]
469 : rn2(2) ? &mons[PM_PIRANHA]
470 : &mons[PM_ELECTRIC_EEL],
471 sx, sy, NO_MM_FLAGS);
475 if(!rn2(4)) /* swamps tend to be moldy */
476 (void) makemon(mkclass(S_FUNGUS,0),
477 sx, sy, NO_MM_FLAGS);
479 level.flags.has_swamp = 1;
488 struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
490 buf.x = troom->lx + ((troom->hx - troom->lx) / 2);
491 buf.y = troom->ly + ((troom->hy - troom->ly) / 2);
498 register struct mkroom *sroom;
500 register struct rm *lev;
502 if(!(sroom = pick_room(TRUE))) return;
504 /* set up Priest and shrine */
505 sroom->rtype = TEMPLE;
507 * In temples, shrines are blessed altars
508 * located in the center of the room
510 shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET);
511 lev = &levl[shrine_spot->x][shrine_spot->y];
513 lev->altarmask = induced_align(80);
514 priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
515 lev->altarmask |= AM_SHRINE;
516 level.flags.has_temple = 1;
524 register struct rm *lev;
525 for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) {
526 if(!isok(sx+dx, sy+dy)) continue;
527 if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) ||
536 register struct mkroom *sroom;
538 if (sroom == dnstairs_room)
540 if (sstairs.sx && !sstairs.up)
541 return((boolean)(sroom == sstairs_room));
547 register struct mkroom *sroom;
549 if (sroom == upstairs_room)
551 if (sstairs.sx && sstairs.up)
552 return((boolean)(sroom == sstairs_room));
561 register struct mkroom *croom;
563 return rn2(croom->hx-croom->lx+1) + croom->lx;
568 register struct mkroom *croom;
570 return rn2(croom->hy-croom->ly+1) + croom->ly;
574 inside_room(croom, x, y)
575 struct mkroom *croom;
578 return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 &&
579 y >= croom->ly-1 && y <= croom->hy+1));
584 struct mkroom *croom;
590 if (croom->irregular) {
591 i = (croom - rooms) + ROOMOFFSET;
593 while(try_cnt++ < 100) {
596 if (!levl[c->x][c->y].edge &&
597 (int) levl[c->x][c->y].roomno == i)
600 /* try harder; exhaustively search until one is found */
601 for(c->x = croom->lx; c->x <= croom->hx; c->x++)
602 for(c->y = croom->ly; c->y <= croom->hy; c->y++)
603 if (!levl[c->x][c->y].edge &&
604 (int) levl[c->x][c->y].roomno == i)
609 if (!croom->nsubrooms) {
615 /* Check that coords doesn't fall into a subroom or into a wall */
617 while(try_cnt++ < 100) {
620 if (IS_WALL(levl[c->x][c->y].typ))
622 for(i=0 ; i<croom->nsubrooms;i++)
623 if(inside_room(croom->sbrooms[i], c->x, c->y))
634 * Search for a special room given its type (zoo, court, etc...)
644 register struct mkroom *croom;
646 for(croom = &rooms[0]; croom->hx >= 0; croom++)
647 if((type == ANY_TYPE && croom->rtype != OROOM) ||
648 (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
649 croom->rtype == type)
651 for(croom = &subrooms[0]; croom->hx >= 0; croom++)
652 if((type == ANY_TYPE && croom->rtype != OROOM) ||
653 (type == ANY_SHOP && croom->rtype >= SHOPBASE) ||
654 croom->rtype == type)
656 return (struct mkroom *) 0;
665 int i = rn2(60) + rn2(3*level_difficulty());
666 if (i > 100) return(mkclass(S_DRAGON,0));
667 else if (i > 95) return(mkclass(S_GIANT,0));
668 else if (i > 85) return(mkclass(S_TROLL,0));
669 else if (i > 75) return(mkclass(S_CENTAUR,0));
670 else if (i > 60) return(mkclass(S_ORC,0));
671 else if (i > 45) return(&mons[PM_BUGBEAR]);
672 else if (i > 30) return(&mons[PM_HOBGOBLIN]);
673 else if (i > 15) return(mkclass(S_GNOME,0));
674 else return(mkclass(S_KOBOLD,0));
677 #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
682 } squadprob[NSTYPES] = {
683 {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1}
686 STATIC_OVL struct permonst *
687 squadmon() /* return soldier types. */
689 int sel_prob, i, cpro, mndx;
691 sel_prob = rnd(80+level_difficulty());
694 for (i = 0; i < NSTYPES; i++) {
695 cpro += squadprob[i].prob;
696 if (cpro > sel_prob) {
697 mndx = squadprob[i].pm;
701 mndx = squadprob[rn2(NSTYPES)].pm;
703 if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]);
704 else return((struct permonst *) 0);
708 * save_room : A recursive function that saves a room and its subrooms
719 * Well, I really should write only useful information instead
720 * of writing the whole structure. That is I should not write
721 * the subrooms pointers, but who cares ?
723 bwrite(fd, (genericptr_t) r, sizeof(struct mkroom));
724 for(i=0; i<r->nsubrooms; i++)
725 save_room(fd, r->sbrooms[i]);
729 * save_rooms : Save all the rooms on disk!
738 /* First, write the number of rooms */
739 bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
740 for(i=0; i<nroom; i++)
741 save_room(fd, &rooms[i]);
751 mread(fd, (genericptr_t) r, sizeof(struct mkroom));
752 for(i=0; i<r->nsubrooms; i++) {
753 r->sbrooms[i] = &subrooms[nsubroom];
754 rest_room(fd, &subrooms[nsubroom]);
755 subrooms[nsubroom++].resident = (struct monst *)0;
760 * rest_rooms : That's for restoring rooms. Read the rooms structure from
770 mread(fd, (genericptr_t) &nroom, sizeof(nroom));
772 for(i = 0; i<nroom; i++) {
773 rest_room(fd, &rooms[i]);
774 rooms[i].resident = (struct monst *)0;
776 rooms[nroom].hx = -1; /* restore ending flags */
777 subrooms[nsubroom].hx = -1;