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 /*-Copyright (c) Robert Patrick Rankin, 2011. */
4 /* NetHack may be freely redistributed. See license for details. */
8 * mkroom() -- make and stock a room of a given type
9 * nexttodoor() -- return TRUE if adjacent to a door
10 * has_dnstairs() -- return TRUE if given room has a down staircase
11 * has_upstairs() -- return TRUE if given room has an up staircase
12 * courtmon() -- generate a court monster
13 * save_rooms() -- save rooms into file fd
14 * rest_rooms() -- restore rooms from file fd
15 * cmap_to_type() -- convert S_xxx symbol to XXX topology code
20 STATIC_DCL boolean FDECL(isbig, (struct mkroom *));
21 STATIC_DCL struct mkroom *FDECL(pick_room, (BOOLEAN_P));
22 STATIC_DCL void NDECL(mkshop), FDECL(mkzoo, (int)), NDECL(mkswamp);
23 STATIC_DCL void NDECL(mktemple);
24 STATIC_DCL coord *FDECL(shrine_pos, (int));
25 STATIC_DCL struct permonst *NDECL(morguemon);
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 *));
30 #define sq(x) ((x) * (x))
32 extern const struct shclass shtypes[]; /* defined in shknam.c */
36 register struct mkroom *sroom;
38 register int area = (sroom->hx - sroom->lx + 1)
39 * (sroom->hy - sroom->ly + 1);
41 return (boolean) (area > 20);
44 /* make and stock a room of a given type */
49 if (roomtype >= SHOPBASE)
50 mkshop(); /* someday, we should be able to specify shop type */
84 impossible("Tried to make a room of type %d.", roomtype);
91 register struct mkroom *sroom;
93 char *ep = (char *) 0; /* (init == lint suppression) */
95 /* first determine shoptype */
98 ep = nh_getenv("SHOPTYPE");
100 if (*ep == 'z' || *ep == 'Z') {
104 if (*ep == 'm' || *ep == 'M') {
108 if (*ep == 'b' || *ep == 'B') {
112 if (*ep == 't' || *ep == 'T' || *ep == '\\') {
116 if (*ep == 's' || *ep == 'S') {
120 if (*ep == 'a' || *ep == 'A') {
124 if (*ep == 'c' || *ep == 'C') {
128 if (*ep == 'l' || *ep == 'L') {
140 for (i = 0; shtypes[i].name; i++)
141 if (*ep == def_oc_syms[(int) shtypes[i].symb].sym)
143 if (*ep == 'g' || *ep == 'G')
145 else if (*ep == 'v' || *ep == 'V')
146 i = FODDERSHOP - SHOPBASE; /* veggy food */
155 for (sroom = &rooms[0];; sroom++) {
158 if (sroom - rooms >= nroom) {
159 pline("rooms not closed by -1?");
162 if (sroom->rtype != OROOM)
164 if (has_dnstairs(sroom) || has_upstairs(sroom))
166 if ((wizard && ep && sroom->doorct != 0) || sroom->doorct == 1)
172 for (x = sroom->lx - 1; x <= sroom->hx + 1; x++)
173 for (y = sroom->ly - 1; y <= sroom->hy + 1; y++)
178 if (i < 0) { /* shoptype not yet determined */
181 /* pick a shop type at random */
182 for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
185 /* big rooms cannot be wand or book shops,
186 * - so make them general stores
188 if (isbig(sroom) && (shtypes[i].symb == WAND_CLASS
189 || shtypes[i].symb == SPBOOK_CLASS))
192 sroom->rtype = SHOPBASE + i;
194 /* set room bits before stocking the shop */
195 #ifdef SPECIALIZATION
196 topologize(sroom, FALSE); /* doesn't matter - this is a special room */
201 /* stock the room with a shopkeeper and artifacts */
202 stock_room(i, sroom);
205 /* pick an unused room, preferably with only one door */
206 STATIC_OVL struct mkroom *
208 register boolean strict;
210 register struct mkroom *sroom;
211 register int i = nroom;
213 for (sroom = &rooms[rn2(nroom)]; i--; sroom++) {
214 if (sroom == &rooms[nroom])
217 return (struct mkroom *) 0;
218 if (sroom->rtype != OROOM)
221 if (has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
223 } else if (has_upstairs(sroom) || has_dnstairs(sroom))
225 if (sroom->doorct == 1 || !rn2(5) || wizard)
228 return (struct mkroom *) 0;
235 register struct mkroom *sroom;
237 if ((sroom = pick_room(FALSE)) != 0) {
244 mk_zoo_thronemon(x,y)
247 int i = rnd(level_difficulty());
248 int pm = (i > 9) ? PM_OGRE_KING
249 : (i > 5) ? PM_ELVENKING
250 : (i > 2) ? PM_DWARF_KING
252 struct monst *mon = makemon(&mons[pm], x, y, NO_MM_FLAGS);
258 /* Give him a sceptre to pound in judgment */
259 (void) mongets(mon, MACE);
265 struct mkroom *sroom;
268 register int sx, sy, i;
269 int sh, tx = 0, ty = 0, goldlim = 0, type = sroom->rtype;
270 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
276 if (level.flags.is_maze_lev) {
277 for (tx = sroom->lx; tx <= sroom->hx; tx++)
278 for (ty = sroom->ly; ty <= sroom->hy; ty++)
279 if (IS_THRONE(levl[tx][ty].typ))
283 do { /* don't place throne on top of stairs */
284 (void) somexy(sroom, &mm);
287 } while (occupied((xchar) tx, (xchar) ty) && --i > 0);
289 mk_zoo_thronemon(tx, ty);
292 tx = sroom->lx + (sroom->hx - sroom->lx + 1) / 2;
293 ty = sroom->ly + (sroom->hy - sroom->ly + 1) / 2;
294 if (sroom->irregular) {
295 /* center might not be valid, so put queen elsewhere */
296 if ((int) levl[tx][ty].roomno != rmno || levl[tx][ty].edge) {
297 (void) somexy(sroom, &mm);
305 goldlim = 500 * level_difficulty();
309 for (sx = sroom->lx; sx <= sroom->hx; sx++)
310 for (sy = sroom->ly; sy <= sroom->hy; sy++) {
311 if (sroom->irregular) {
312 if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge
314 && distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1))
316 } else if (!SPACE_POS(levl[sx][sy].typ)
318 && ((sx == sroom->lx && doors[sh].x == sx - 1)
319 || (sx == sroom->hx && doors[sh].x == sx + 1)
320 || (sy == sroom->ly && doors[sh].y == sy - 1)
322 && doors[sh].y == sy + 1))))
324 /* don't place monster on explicitly placed throne */
325 if (type == COURT && IS_THRONE(levl[sx][sy].typ))
327 mon = makemon((type == COURT)
334 ? (sx == tx && sy == ty
335 ? &mons[PM_QUEEN_BEE]
336 : &mons[PM_KILLER_BEE])
337 : (type == LEPREHALL)
338 ? &mons[PM_LEPRECHAUN]
340 ? &mons[PM_COCKATRICE]
343 : (struct permonst *) 0,
347 if (type == COURT && mon->mpeaceful) {
356 int distval = dist2(sx, sy, doors[sh].x, doors[sh].y);
361 i = 5 * level_difficulty();
363 (void) mkgold((long) rn1(i, 10), sx, sy);
367 (void) mk_tt_object(CORPSE, sx, sy);
368 if (!rn2(10)) /* lots of treasure buried with dead */
369 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
372 make_grave(sx, sy, (char *) 0);
376 (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE,
380 if (!rn2(20)) /* the payroll and some loot */
381 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
386 struct obj *sobj = mk_tt_object(STATUE, sx, sy);
389 for (i = rn2(5); i; i--)
390 (void) add_to_container(
391 sobj, mkobj(RANDOM_CLASS, FALSE));
392 sobj->owt = weight(sobj);
398 (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
404 struct obj *chest, *gold;
405 levl[tx][ty].typ = THRONE;
406 (void) somexy(sroom, &mm);
407 gold = mksobj(GOLD_PIECE, TRUE, FALSE);
408 gold->quan = (long) rn1(50 * level_difficulty(), 10);
409 gold->owt = weight(gold);
410 /* the royal coffers */
411 chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE);
412 add_to_container(chest, gold);
413 chest->owt = weight(chest);
414 chest->spe = 2; /* so it can be found later */
415 level.flags.has_court = 1;
419 level.flags.has_barracks = 1;
422 level.flags.has_zoo = 1;
425 level.flags.has_morgue = 1;
428 level.flags.has_swamp = 1;
431 level.flags.has_beehive = 1;
436 /* make a swarm of undead around mm */
438 mkundead(mm, revive_corpses, mm_flags)
440 boolean revive_corpses;
443 int cnt = (level_difficulty() + 1) / 10 + rnd(5);
444 struct permonst *mdat;
450 if (mdat && enexto(&cc, mm->x, mm->y, mdat)
452 || !(otmp = sobj_at(CORPSE, cc.x, cc.y))
453 || !revive(otmp, FALSE)))
454 (void) makemon(mdat, cc.x, cc.y, mm_flags);
456 level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
459 STATIC_OVL struct permonst *
462 register int i = rn2(100), hd = rn2(level_difficulty());
464 if (hd > 10 && i < 10) {
465 if (Inhell || In_endgame(&u.uz)) {
466 return mkclass(S_DEMON, 0);
468 int ndemon_res = ndemon(A_NONE);
469 if (ndemon_res != NON_PM)
470 return &mons[ndemon_res];
471 /* else do what? As is, it will drop to ghost/wraith/zombie */
475 if (hd > 8 && i > 85)
476 return mkclass(S_VAMPIRE, 0);
478 return ((i < 20) ? &mons[PM_GHOST]
479 : (i < 40) ? &mons[PM_WRAITH]
480 : mkclass(S_ZOMBIE, 0));
486 int mtyp, indx, trycnt = 0;
488 /* casts are for dealing with time_t */
489 indx = (int) ((long) ubirthday % 3L);
490 indx += level_difficulty();
491 /* Same monsters within a level, different ones between levels */
493 switch ((indx + trycnt) % 3) {
495 mtyp = PM_SOLDIER_ANT;
504 /* try again if chosen type has been genocided or used up */
505 } while (++trycnt < 3 && (mvitals[mtyp].mvflags & G_GONE));
507 return ((mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0
512 mkswamp() /* Michiel Huisjes & Fred de Wilde */
514 register struct mkroom *sroom;
515 register int sx, sy, i, eelct = 0;
517 for (i = 0; i < 5; i++) { /* turn up to 5 rooms swampy */
518 sroom = &rooms[rn2(nroom)];
519 if (sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom)
520 || has_dnstairs(sroom))
523 /* satisfied; make a swamp */
524 sroom->rtype = SWAMP;
525 for (sx = sroom->lx; sx <= sroom->hx; sx++)
526 for (sy = sroom->ly; sy <= sroom->hy; sy++)
527 if (!OBJ_AT(sx, sy) && !MON_AT(sx, sy) && !t_at(sx, sy)
528 && !nexttodoor(sx, sy)) {
530 levl[sx][sy].typ = POOL;
531 if (!eelct || !rn2(4)) {
532 /* mkclass() won't do, as we might get kraken */
533 (void) makemon(rn2(5)
534 ? &mons[PM_GIANT_EEL]
537 : &mons[PM_ELECTRIC_EEL],
538 sx, sy, NO_MM_FLAGS);
541 } else if (!rn2(4)) /* swamps tend to be moldy */
542 (void) makemon(mkclass(S_FUNGUS, 0), sx, sy,
545 level.flags.has_swamp = 1;
555 struct mkroom *troom = &rooms[roomno - ROOMOFFSET];
557 /* if width and height are odd, placement will be the exact center;
558 if either or both are even, center point is a hypothetical spot
559 between map locations and placement will be adjacent to that */
560 delta = troom->hx - troom->lx;
561 buf.x = troom->lx + delta / 2;
562 if ((delta % 2) && rn2(2))
564 delta = troom->hy - troom->ly;
565 buf.y = troom->ly + delta / 2;
566 if ((delta % 2) && rn2(2))
574 register struct mkroom *sroom;
576 register struct rm *lev;
578 if (!(sroom = pick_room(TRUE)))
581 /* set up Priest and shrine */
582 sroom->rtype = TEMPLE;
584 * In temples, shrines are blessed altars
585 * located in the center of the room
587 shrine_spot = shrine_pos((int) ((sroom - rooms) + ROOMOFFSET));
588 lev = &levl[shrine_spot->x][shrine_spot->y];
590 lev->altarmask = induced_align(80);
591 priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
592 lev->altarmask |= AM_SHRINE;
593 level.flags.has_temple = 1;
601 register struct rm *lev;
603 for (dx = -1; dx <= 1; dx++)
604 for (dy = -1; dy <= 1; dy++) {
605 if (!isok(sx + dx, sy + dy))
607 lev = &levl[sx + dx][sy + dy];
608 if (IS_DOOR(lev->typ) || lev->typ == SDOOR)
616 register struct mkroom *sroom;
618 if (sroom == dnstairs_room)
620 if (sstairs.sx && !sstairs.up)
621 return (boolean) (sroom == sstairs_room);
627 register struct mkroom *sroom;
629 if (sroom == upstairs_room)
631 if (sstairs.sx && sstairs.up)
632 return (boolean) (sroom == sstairs_room);
638 register struct mkroom *croom;
640 return rn1(croom->hx - croom->lx + 1, croom->lx);
645 register struct mkroom *croom;
647 return rn1(croom->hy - croom->ly + 1, croom->ly);
651 inside_room(croom, x, y)
652 struct mkroom *croom;
655 return (boolean) (x >= croom->lx - 1 && x <= croom->hx + 1
656 && y >= croom->ly - 1 && y <= croom->hy + 1);
661 struct mkroom *croom;
667 if (croom->irregular) {
668 i = (int) ((croom - rooms) + ROOMOFFSET);
670 while (try_cnt++ < 100) {
673 if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i)
676 /* try harder; exhaustively search until one is found */
677 for (c->x = croom->lx; c->x <= croom->hx; c->x++)
678 for (c->y = croom->ly; c->y <= croom->hy; c->y++)
679 if (!levl[c->x][c->y].edge
680 && (int) levl[c->x][c->y].roomno == i)
685 if (!croom->nsubrooms) {
691 /* Check that coords doesn't fall into a subroom or into a wall */
693 while (try_cnt++ < 100) {
696 if (IS_WALL(levl[c->x][c->y].typ))
698 for (i = 0; i < croom->nsubrooms; i++)
699 if (inside_room(croom->sbrooms[i], c->x, c->y))
711 * Search for a special room given its type (zoo, court, etc...)
720 register struct mkroom *croom;
722 for (croom = &rooms[0]; croom->hx >= 0; croom++)
723 if ((type == ANY_TYPE && croom->rtype != OROOM)
724 || (type == ANY_SHOP && croom->rtype >= SHOPBASE)
725 || croom->rtype == type)
727 for (croom = &subrooms[0]; croom->hx >= 0; croom++)
728 if ((type == ANY_TYPE && croom->rtype != OROOM)
729 || (type == ANY_SHOP && croom->rtype >= SHOPBASE)
730 || croom->rtype == type)
732 return (struct mkroom *) 0;
738 int i = rn2(60) + rn2(3 * level_difficulty());
741 return mkclass(S_DRAGON, 0);
743 return mkclass(S_GIANT, 0);
745 return mkclass(S_TROLL, 0);
747 return mkclass(S_CENTAUR, 0);
749 return mkclass(S_ORC, 0);
751 return &mons[PM_BUGBEAR];
753 return &mons[PM_HOBGOBLIN];
755 return mkclass(S_GNOME, 0);
757 return mkclass(S_KOBOLD, 0);
760 #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
765 } squadprob[NSTYPES] = { { PM_SOLDIER, 80 },
767 { PM_LIEUTENANT, 4 },
770 /* return soldier types. */
771 STATIC_OVL struct permonst *
774 int sel_prob, i, cpro, mndx;
776 sel_prob = rnd(80 + level_difficulty());
779 for (i = 0; i < NSTYPES; i++) {
780 cpro += squadprob[i].prob;
781 if (cpro > sel_prob) {
782 mndx = squadprob[i].pm;
786 mndx = squadprob[rn2(NSTYPES)].pm;
788 if (!(mvitals[mndx].mvflags & G_GONE))
791 return (struct permonst *) 0;
795 * save_room : A recursive function that saves a room and its subrooms
806 * Well, I really should write only useful information instead
807 * of writing the whole structure. That is I should not write
808 * the subrooms pointers, but who cares ?
810 bwrite(fd, (genericptr_t) r, sizeof (struct mkroom));
811 for (i = 0; i < r->nsubrooms; i++)
812 save_room(fd, r->sbrooms[i]);
816 * save_rooms : Save all the rooms on disk!
824 /* First, write the number of rooms */
825 bwrite(fd, (genericptr_t) &nroom, sizeof(nroom));
826 for (i = 0; i < nroom; i++)
827 save_room(fd, &rooms[i]);
837 mread(fd, (genericptr_t) r, sizeof(struct mkroom));
838 for (i = 0; i < r->nsubrooms; i++) {
839 r->sbrooms[i] = &subrooms[nsubroom];
840 rest_room(fd, &subrooms[nsubroom]);
841 subrooms[nsubroom++].resident = (struct monst *) 0;
846 * rest_rooms : That's for restoring rooms. Read the rooms structure from
855 mread(fd, (genericptr_t) &nroom, sizeof(nroom));
857 for (i = 0; i < nroom; i++) {
858 rest_room(fd, &rooms[i]);
859 rooms[i].resident = (struct monst *) 0;
861 rooms[nroom].hx = -1; /* restore ending flags */
862 subrooms[nsubroom].hx = -1;
865 /* convert a display symbol for terrain into topology type;
866 used for remembered terrain when mimics pose as furniture */
871 int typ = STONE; /* catchall */
910 case S_ndoor: /* no door (empty doorway) */
911 case S_vodoor: /* open door in vertical wall */
912 case S_hodoor: /* open door in horizontal wall */
913 case S_vcdoor: /* closed door in vertical wall */
962 case S_vodbridge: /* open drawbridge spanning north/south */
964 typ = DRAWBRIDGE_DOWN;
965 break; /* east/west */
966 case S_vcdbridge: /* closed drawbridge in vertical wall */
980 break; /* not a cmap symbol? */