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? */