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. */
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
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 *));
29 #define sq(x) ((x) * (x))
31 extern const struct shclass shtypes[]; /* defined in shknam.c */
35 register struct mkroom *sroom;
37 register int area = (sroom->hx - sroom->lx + 1)
38 * (sroom->hy - sroom->ly + 1);
40 return (boolean) (area > 20);
43 /* make and stock a room of a given type */
48 if (roomtype >= SHOPBASE)
49 mkshop(); /* someday, we should be able to specify shop type */
83 impossible("Tried to make a room of type %d.", roomtype);
90 register struct mkroom *sroom;
92 char *ep = (char *) 0; /* (init == lint suppression) */
94 /* first determine shoptype */
97 ep = nh_getenv("SHOPTYPE");
99 if (*ep == 'z' || *ep == 'Z') {
103 if (*ep == 'm' || *ep == 'M') {
107 if (*ep == 'b' || *ep == 'B') {
111 if (*ep == 't' || *ep == 'T' || *ep == '\\') {
115 if (*ep == 's' || *ep == 'S') {
119 if (*ep == 'a' || *ep == 'A') {
123 if (*ep == 'c' || *ep == 'C') {
127 if (*ep == 'l' || *ep == 'L') {
139 for (i = 0; shtypes[i].name; i++)
140 if (*ep == def_oc_syms[(int) shtypes[i].symb].sym)
142 if (*ep == 'g' || *ep == 'G')
144 else if (*ep == 'v' || *ep == 'V')
145 i = FODDERSHOP - SHOPBASE; /* veggy food */
154 for (sroom = &rooms[0];; sroom++) {
157 if (sroom - rooms >= nroom) {
158 pline("rooms not closed by -1?");
161 if (sroom->rtype != OROOM)
163 if (has_dnstairs(sroom) || has_upstairs(sroom))
165 if ((wizard && ep && sroom->doorct != 0) || sroom->doorct == 1)
171 for (x = sroom->lx - 1; x <= sroom->hx + 1; x++)
172 for (y = sroom->ly - 1; y <= sroom->hy + 1; y++)
177 if (i < 0) { /* shoptype not yet determined */
180 /* pick a shop type at random */
181 for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
184 /* big rooms cannot be wand or book shops,
185 * - so make them general stores
187 if (isbig(sroom) && (shtypes[i].symb == WAND_CLASS
188 || shtypes[i].symb == SPBOOK_CLASS))
191 sroom->rtype = SHOPBASE + i;
193 /* set room bits before stocking the shop */
194 #ifdef SPECIALIZATION
195 topologize(sroom, FALSE); /* doesn't matter - this is a special room */
200 /* stock the room with a shopkeeper and artifacts */
201 stock_room(i, sroom);
204 /* pick an unused room, preferably with only one door */
205 STATIC_OVL struct mkroom *
207 register boolean strict;
209 register struct mkroom *sroom;
210 register int i = nroom;
212 for (sroom = &rooms[rn2(nroom)]; i--; sroom++) {
213 if (sroom == &rooms[nroom])
216 return (struct mkroom *) 0;
217 if (sroom->rtype != OROOM)
220 if (has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
222 } else if (has_upstairs(sroom) || has_dnstairs(sroom))
224 if (sroom->doorct == 1 || !rn2(5) || wizard)
227 return (struct mkroom *) 0;
234 register struct mkroom *sroom;
236 if ((sroom = pick_room(FALSE)) != 0) {
244 struct mkroom *sroom;
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);
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))
262 do { /* don't place throne on top of stairs */
263 (void) somexy(sroom, &mm);
266 } while (occupied((xchar) tx, (xchar) ty) && --i > 0);
268 /* TODO: try to ensure the enthroned monster is an M2_PRINCE */
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);
284 goldlim = 500 * level_difficulty();
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
293 && distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
295 } else if (!SPACE_POS(levl[sx][sy].typ)
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)
301 && doors[sh].y == sy + 1))))
303 /* don't place monster on explicitly placed throne */
304 if (type == COURT && IS_THRONE(levl[sx][sy].typ))
306 mon = makemon((type == COURT)
313 ? (sx == tx && sy == ty
314 ? &mons[PM_QUEEN_BEE]
315 : &mons[PM_KILLER_BEE])
316 : (type == LEPREHALL)
317 ? &mons[PM_LEPRECHAUN]
319 ? &mons[PM_COCKATRICE]
322 : (struct permonst *) 0,
323 sx, sy, NO_MM_FLAGS);
326 if (type == COURT && mon->mpeaceful) {
335 int distval = dist2(sx, sy, doors[sh].x, doors[sh].y);
340 i = 5 * level_difficulty();
342 (void) mkgold((long) rn1(i, 10), sx, sy);
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,
351 make_grave(sx, sy, (char *) 0);
355 (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE,
359 if (!rn2(20)) /* the payroll and some loot */
360 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
365 struct obj *sobj = mk_tt_object(STATUE, sx, sy);
368 for (i = rn2(5); i; i--)
369 (void) add_to_container(
370 sobj, mkobj(RANDOM_CLASS, FALSE));
371 sobj->owt = weight(sobj);
377 (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
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;
394 level.flags.has_barracks = 1;
397 level.flags.has_zoo = 1;
400 level.flags.has_morgue = 1;
403 level.flags.has_swamp = 1;
406 level.flags.has_beehive = 1;
411 /* make a swarm of undead around mm */
413 mkundead(mm, revive_corpses, mm_flags)
415 boolean revive_corpses;
418 int cnt = (level_difficulty() + 1) / 10 + rnd(5);
419 struct permonst *mdat;
425 if (mdat && enexto(&cc, mm->x, mm->y, mdat)
427 || !(otmp = sobj_at(CORPSE, cc.x, cc.y))
428 || !revive(otmp, FALSE)))
429 (void) makemon(mdat, cc.x, cc.y, mm_flags);
431 level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
434 STATIC_OVL struct permonst *
437 register int i = rn2(100), hd = rn2(level_difficulty());
439 if (hd > 10 && i < 10) {
440 if (Inhell || In_endgame(&u.uz)) {
441 return mkclass(S_DEMON, 0);
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 */
450 if (hd > 8 && i > 85)
451 return mkclass(S_VAMPIRE, 0);
453 return ((i < 20) ? &mons[PM_GHOST]
454 : (i < 40) ? &mons[PM_WRAITH]
455 : mkclass(S_ZOMBIE, 0));
461 int mtyp, indx, trycnt = 0;
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 */
468 switch ((indx + trycnt) % 3) {
470 mtyp = PM_SOLDIER_ANT;
479 /* try again if chosen type has been genocided or used up */
480 } while (++trycnt < 3 && (mvitals[mtyp].mvflags & G_GONE));
482 return ((mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0
487 mkswamp() /* Michiel Huisjes & Fred de Wilde */
489 register struct mkroom *sroom;
490 register int sx, sy, i, eelct = 0;
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))
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)) {
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]
512 : &mons[PM_ELECTRIC_EEL],
513 sx, sy, NO_MM_FLAGS);
516 } else if (!rn2(4)) /* swamps tend to be moldy */
517 (void) makemon(mkclass(S_FUNGUS, 0), sx, sy,
520 level.flags.has_swamp = 1;
530 struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
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))
539 delta = troom->hy - troom->ly;
540 buf.y = troom->ly + delta / 2;
541 if ((delta % 2) && rn2(2))
549 register struct mkroom *sroom;
551 register struct rm *lev;
553 if (!(sroom = pick_room(TRUE)))
556 /* set up Priest and shrine */
557 sroom->rtype = TEMPLE;
559 * In temples, shrines are blessed altars
560 * located in the center of the room
562 shrine_spot = shrine_pos((int) ((sroom - rooms) + ROOMOFFSET));
563 lev = &levl[shrine_spot->x][shrine_spot->y];
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;
576 register struct rm *lev;
578 for (dx = -1; dx <= 1; dx++)
579 for (dy = -1; dy <= 1; dy++) {
580 if (!isok(sx + dx, sy + dy))
582 lev = &levl[sx + dx][sy + dy];
583 if (IS_DOOR(lev->typ) || lev->typ == SDOOR)
591 register struct mkroom *sroom;
593 if (sroom == dnstairs_room)
595 if (sstairs.sx && !sstairs.up)
596 return (boolean) (sroom == sstairs_room);
602 register struct mkroom *sroom;
604 if (sroom == upstairs_room)
606 if (sstairs.sx && sstairs.up)
607 return (boolean) (sroom == sstairs_room);
613 register struct mkroom *croom;
615 return rn1(croom->hx - croom->lx + 1, croom->lx);
620 register struct mkroom *croom;
622 return rn1(croom->hy - croom->ly + 1, croom->ly);
626 inside_room(croom, x, y)
627 struct mkroom *croom;
630 return (boolean) (x >= croom->lx - 1 && x <= croom->hx + 1
631 && y >= croom->ly - 1 && y <= croom->hy + 1);
636 struct mkroom *croom;
642 if (croom->irregular) {
643 i = (int) ((croom - rooms) + ROOMOFFSET);
645 while (try_cnt++ < 100) {
648 if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i)
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)
660 if (!croom->nsubrooms) {
666 /* Check that coords doesn't fall into a subroom or into a wall */
668 while (try_cnt++ < 100) {
671 if (IS_WALL(levl[c->x][c->y].typ))
673 for (i = 0; i < croom->nsubrooms; i++)
674 if (inside_room(croom->sbrooms[i], c->x, c->y))
686 * Search for a special room given its type (zoo, court, etc...)
695 register struct mkroom *croom;
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)
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)
707 return (struct mkroom *) 0;
713 int i = rn2(60) + rn2(3 * level_difficulty());
716 return mkclass(S_DRAGON, 0);
718 return mkclass(S_GIANT, 0);
720 return mkclass(S_TROLL, 0);
722 return mkclass(S_CENTAUR, 0);
724 return mkclass(S_ORC, 0);
726 return &mons[PM_BUGBEAR];
728 return &mons[PM_HOBGOBLIN];
730 return mkclass(S_GNOME, 0);
732 return mkclass(S_KOBOLD, 0);
735 #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
740 } squadprob[NSTYPES] = { { PM_SOLDIER, 80 },
742 { PM_LIEUTENANT, 4 },
745 /* return soldier types. */
746 STATIC_OVL struct permonst *
749 int sel_prob, i, cpro, mndx;
751 sel_prob = rnd(80 + level_difficulty());
754 for (i = 0; i < NSTYPES; i++) {
755 cpro += squadprob[i].prob;
756 if (cpro > sel_prob) {
757 mndx = squadprob[i].pm;
761 mndx = squadprob[rn2(NSTYPES)].pm;
763 if (!(mvitals[mndx].mvflags & G_GONE))
766 return (struct permonst *) 0;
770 * save_room : A recursive function that saves a room and its subrooms
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 ?
785 bwrite(fd, (genericptr_t) r, sizeof (struct mkroom));
786 for (i = 0; i < r->nsubrooms; i++)
787 save_room(fd, r->sbrooms[i]);
791 * save_rooms : Save all the rooms on disk!
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]);
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;
821 * rest_rooms : That's for restoring rooms. Read the rooms structure from
830 mread(fd, (genericptr_t) &nroom, sizeof(nroom));
832 for (i = 0; i < nroom; i++) {
833 rest_room(fd, &rooms[i]);
834 rooms[i].resident = (struct monst *) 0;
836 rooms[nroom].hx = -1; /* restore ending flags */
837 subrooms[nsubroom].hx = -1;
840 /* convert a display symbol for terrain into topology type;
841 used for remembered terrain when mimics pose as furniture */
846 int typ = STONE; /* catchall */
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 */
937 case S_vodbridge: /* open drawbridge spanning north/south */
939 typ = DRAWBRIDGE_DOWN;
940 break; /* east/west */
941 case S_vcdbridge: /* closed drawbridge in vertical wall */
955 break; /* not a cmap symbol? */