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
);
383 struct obj
*chest
, *gold
;
384 levl
[tx
][ty
].typ
= THRONE
;
385 (void) somexy(sroom
, &mm
);
386 gold
= mksobj(GOLD_PIECE
, TRUE
, FALSE
);
387 gold
->quan
= (long) rn1(50 * level_difficulty(), 10);
388 gold
->owt
= weight(gold
);
389 /* the royal coffers */
390 chest
= mksobj_at(CHEST
, mm
.x
, mm
.y
, TRUE
, FALSE
);
391 add_to_container(chest
, gold
);
392 chest
->owt
= weight(chest
);
393 chest
->spe
= 2; /* so it can be found later */
394 level
.flags
.has_court
= 1;
398 level
.flags
.has_barracks
= 1;
401 level
.flags
.has_zoo
= 1;
404 level
.flags
.has_morgue
= 1;
407 level
.flags
.has_swamp
= 1;
410 level
.flags
.has_beehive
= 1;
415 /* make a swarm of undead around mm */
417 mkundead(mm
, revive_corpses
, mm_flags
)
419 boolean revive_corpses
;
422 int cnt
= (level_difficulty() + 1) / 10 + rnd(5);
423 struct permonst
*mdat
;
429 if (mdat
&& enexto(&cc
, mm
->x
, mm
->y
, mdat
)
431 || !(otmp
= sobj_at(CORPSE
, cc
.x
, cc
.y
))
432 || !revive(otmp
, FALSE
)))
433 (void) makemon(mdat
, cc
.x
, cc
.y
, mm_flags
);
435 level
.flags
.graveyard
= TRUE
; /* reduced chance for undead corpse */
438 STATIC_OVL
struct permonst
*
441 register int i
= rn2(100), hd
= rn2(level_difficulty());
443 if (hd
> 10 && i
< 10) {
444 if (Inhell
|| In_endgame(&u
.uz
)) {
445 return mkclass(S_DEMON
, 0);
447 int ndemon_res
= ndemon(A_NONE
);
448 if (ndemon_res
!= NON_PM
)
449 return &mons
[ndemon_res
];
450 /* else do what? As is, it will drop to ghost/wraith/zombie */
454 if (hd
> 8 && i
> 85)
455 return mkclass(S_VAMPIRE
, 0);
457 return ((i
< 20) ? &mons
[PM_GHOST
]
458 : (i
< 40) ? &mons
[PM_WRAITH
]
459 : mkclass(S_ZOMBIE
, 0));
465 int mtyp
, indx
, trycnt
= 0;
467 /* casts are for dealing with time_t */
468 indx
= (int) ((long) ubirthday
% 3L);
469 indx
+= level_difficulty();
470 /* Same monsters within a level, different ones between levels */
472 switch ((indx
+ trycnt
) % 3) {
474 mtyp
= PM_SOLDIER_ANT
;
483 /* try again if chosen type has been genocided or used up */
484 } while (++trycnt
< 3 && (mvitals
[mtyp
].mvflags
& G_GONE
));
486 return ((mvitals
[mtyp
].mvflags
& G_GONE
) ? (struct permonst
*) 0
491 mkswamp() /* Michiel Huisjes & Fred de Wilde */
493 register struct mkroom
*sroom
;
494 register int sx
, sy
, i
, eelct
= 0;
496 for (i
= 0; i
< 5; i
++) { /* turn up to 5 rooms swampy */
497 sroom
= &rooms
[rn2(nroom
)];
498 if (sroom
->hx
< 0 || sroom
->rtype
!= OROOM
|| has_upstairs(sroom
)
499 || has_dnstairs(sroom
))
502 /* satisfied; make a swamp */
503 sroom
->rtype
= SWAMP
;
504 for (sx
= sroom
->lx
; sx
<= sroom
->hx
; sx
++)
505 for (sy
= sroom
->ly
; sy
<= sroom
->hy
; sy
++)
506 if (!OBJ_AT(sx
, sy
) && !MON_AT(sx
, sy
) && !t_at(sx
, sy
)
507 && !nexttodoor(sx
, sy
)) {
509 levl
[sx
][sy
].typ
= POOL
;
510 if (!eelct
|| !rn2(4)) {
511 /* mkclass() won't do, as we might get kraken */
512 (void) makemon(rn2(5)
513 ? &mons
[PM_GIANT_EEL
]
516 : &mons
[PM_ELECTRIC_EEL
],
517 sx
, sy
, NO_MM_FLAGS
);
520 } else if (!rn2(4)) /* swamps tend to be moldy */
521 (void) makemon(mkclass(S_FUNGUS
, 0), sx
, sy
,
524 level
.flags
.has_swamp
= 1;
534 struct mkroom
*troom
= &rooms
[roomno
- ROOMOFFSET
];
536 /* if width and height are odd, placement will be the exact center;
537 if either or both are even, center point is a hypothetical spot
538 between map locations and placement will be adjacent to that */
539 delta
= troom
->hx
- troom
->lx
;
540 buf
.x
= troom
->lx
+ delta
/ 2;
541 if ((delta
% 2) && rn2(2))
543 delta
= troom
->hy
- troom
->ly
;
544 buf
.y
= troom
->ly
+ delta
/ 2;
545 if ((delta
% 2) && rn2(2))
553 register struct mkroom
*sroom
;
555 register struct rm
*lev
;
557 if (!(sroom
= pick_room(TRUE
)))
560 /* set up Priest and shrine */
561 sroom
->rtype
= TEMPLE
;
563 * In temples, shrines are blessed altars
564 * located in the center of the room
566 shrine_spot
= shrine_pos((int) ((sroom
- rooms
) + ROOMOFFSET
));
567 lev
= &levl
[shrine_spot
->x
][shrine_spot
->y
];
569 lev
->altarmask
= induced_align(80);
570 priestini(&u
.uz
, sroom
, shrine_spot
->x
, shrine_spot
->y
, FALSE
);
571 lev
->altarmask
|= AM_SHRINE
;
572 level
.flags
.has_temple
= 1;
580 register struct rm
*lev
;
582 for (dx
= -1; dx
<= 1; dx
++)
583 for (dy
= -1; dy
<= 1; dy
++) {
584 if (!isok(sx
+ dx
, sy
+ dy
))
586 lev
= &levl
[sx
+ dx
][sy
+ dy
];
587 if (IS_DOOR(lev
->typ
) || lev
->typ
== SDOOR
)
595 register struct mkroom
*sroom
;
597 if (sroom
== dnstairs_room
)
599 if (sstairs
.sx
&& !sstairs
.up
)
600 return (boolean
) (sroom
== sstairs_room
);
606 register struct mkroom
*sroom
;
608 if (sroom
== upstairs_room
)
610 if (sstairs
.sx
&& sstairs
.up
)
611 return (boolean
) (sroom
== sstairs_room
);
617 register struct mkroom
*croom
;
619 return rn1(croom
->hx
- croom
->lx
+ 1, croom
->lx
);
624 register struct mkroom
*croom
;
626 return rn1(croom
->hy
- croom
->ly
+ 1, croom
->ly
);
630 inside_room(croom
, x
, y
)
631 struct mkroom
*croom
;
634 return (boolean
) (x
>= croom
->lx
- 1 && x
<= croom
->hx
+ 1
635 && y
>= croom
->ly
- 1 && y
<= croom
->hy
+ 1);
640 struct mkroom
*croom
;
646 if (croom
->irregular
) {
647 i
= (int) ((croom
- rooms
) + ROOMOFFSET
);
649 while (try_cnt
++ < 100) {
652 if (!levl
[c
->x
][c
->y
].edge
&& (int) levl
[c
->x
][c
->y
].roomno
== i
)
655 /* try harder; exhaustively search until one is found */
656 for (c
->x
= croom
->lx
; c
->x
<= croom
->hx
; c
->x
++)
657 for (c
->y
= croom
->ly
; c
->y
<= croom
->hy
; c
->y
++)
658 if (!levl
[c
->x
][c
->y
].edge
659 && (int) levl
[c
->x
][c
->y
].roomno
== i
)
664 if (!croom
->nsubrooms
) {
670 /* Check that coords doesn't fall into a subroom or into a wall */
672 while (try_cnt
++ < 100) {
675 if (IS_WALL(levl
[c
->x
][c
->y
].typ
))
677 for (i
= 0; i
< croom
->nsubrooms
; i
++)
678 if (inside_room(croom
->sbrooms
[i
], c
->x
, c
->y
))
690 * Search for a special room given its type (zoo, court, etc...)
699 register struct mkroom
*croom
;
701 for (croom
= &rooms
[0]; croom
->hx
>= 0; croom
++)
702 if ((type
== ANY_TYPE
&& croom
->rtype
!= OROOM
)
703 || (type
== ANY_SHOP
&& croom
->rtype
>= SHOPBASE
)
704 || croom
->rtype
== type
)
706 for (croom
= &subrooms
[0]; croom
->hx
>= 0; croom
++)
707 if ((type
== ANY_TYPE
&& croom
->rtype
!= OROOM
)
708 || (type
== ANY_SHOP
&& croom
->rtype
>= SHOPBASE
)
709 || croom
->rtype
== type
)
711 return (struct mkroom
*) 0;
717 int i
= rn2(60) + rn2(3 * level_difficulty());
720 return mkclass(S_DRAGON
, 0);
722 return mkclass(S_GIANT
, 0);
724 return mkclass(S_TROLL
, 0);
726 return mkclass(S_CENTAUR
, 0);
728 return mkclass(S_ORC
, 0);
730 return &mons
[PM_BUGBEAR
];
732 return &mons
[PM_HOBGOBLIN
];
734 return mkclass(S_GNOME
, 0);
736 return mkclass(S_KOBOLD
, 0);
739 #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1)
744 } squadprob
[NSTYPES
] = { { PM_SOLDIER
, 80 },
746 { PM_LIEUTENANT
, 4 },
749 /* return soldier types. */
750 STATIC_OVL
struct permonst
*
753 int sel_prob
, i
, cpro
, mndx
;
755 sel_prob
= rnd(80 + level_difficulty());
758 for (i
= 0; i
< NSTYPES
; i
++) {
759 cpro
+= squadprob
[i
].prob
;
760 if (cpro
> sel_prob
) {
761 mndx
= squadprob
[i
].pm
;
765 mndx
= squadprob
[rn2(NSTYPES
)].pm
;
767 if (!(mvitals
[mndx
].mvflags
& G_GONE
))
770 return (struct permonst
*) 0;
774 * save_room : A recursive function that saves a room and its subrooms
785 * Well, I really should write only useful information instead
786 * of writing the whole structure. That is I should not write
787 * the subrooms pointers, but who cares ?
789 bwrite(fd
, (genericptr_t
) r
, sizeof (struct mkroom
));
790 for (i
= 0; i
< r
->nsubrooms
; i
++)
791 save_room(fd
, r
->sbrooms
[i
]);
795 * save_rooms : Save all the rooms on disk!
803 /* First, write the number of rooms */
804 bwrite(fd
, (genericptr_t
) &nroom
, sizeof(nroom
));
805 for (i
= 0; i
< nroom
; i
++)
806 save_room(fd
, &rooms
[i
]);
816 mread(fd
, (genericptr_t
) r
, sizeof(struct mkroom
));
817 for (i
= 0; i
< r
->nsubrooms
; i
++) {
818 r
->sbrooms
[i
] = &subrooms
[nsubroom
];
819 rest_room(fd
, &subrooms
[nsubroom
]);
820 subrooms
[nsubroom
++].resident
= (struct monst
*) 0;
825 * rest_rooms : That's for restoring rooms. Read the rooms structure from
834 mread(fd
, (genericptr_t
) &nroom
, sizeof(nroom
));
836 for (i
= 0; i
< nroom
; i
++) {
837 rest_room(fd
, &rooms
[i
]);
838 rooms
[i
].resident
= (struct monst
*) 0;
840 rooms
[nroom
].hx
= -1; /* restore ending flags */
841 subrooms
[nsubroom
].hx
= -1;
844 /* convert a display symbol for terrain into topology type;
845 used for remembered terrain when mimics pose as furniture */
850 int typ
= STONE
; /* catchall */
889 case S_ndoor
: /* no door (empty doorway) */
890 case S_vodoor
: /* open door in vertical wall */
891 case S_hodoor
: /* open door in horizontal wall */
892 case S_vcdoor
: /* closed door in vertical wall */
941 case S_vodbridge
: /* open drawbridge spanning north/south */
943 typ
= DRAWBRIDGE_DOWN
;
944 break; /* east/west */
945 case S_vcdbridge
: /* closed drawbridge in vertical wall */
959 break; /* not a cmap symbol? */