OSDN Git Service

fix #36659
[jnethack/source.git] / src / extralev.c
1 /* NetHack 3.6  extralev.c      $NHDT-Date: 1446975468 2015/11/08 09:37:48 $  $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */
2 /*      Copyright 1988, 1989 by Ken Arromdee                      */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  * Support code for "rogue"-style level.
7  */
8
9 #include "hack.h"
10
11 struct rogueroom {
12     xchar rlx, rly;
13     xchar dx, dy;
14     boolean real;
15     uchar doortable;
16     int nroom; /* Only meaningful for "real" rooms */
17 };
18 #define UP 1
19 #define DOWN 2
20 #define LEFT 4
21 #define RIGHT 8
22
23 static NEARDATA struct rogueroom r[3][3];
24 STATIC_DCL void FDECL(roguejoin, (int, int, int, int, int));
25 STATIC_DCL void FDECL(roguecorr, (int, int, int));
26 STATIC_DCL void FDECL(miniwalk, (int, int));
27
28 STATIC_OVL
29 void
30 roguejoin(x1, y1, x2, y2, horiz)
31 int x1, y1, x2, y2;
32 int horiz;
33 {
34     register int x, y, middle;
35     if (horiz) {
36         middle = x1 + rn2(x2 - x1 + 1);
37         for (x = min(x1, middle); x <= max(x1, middle); x++)
38             corr(x, y1);
39         for (y = min(y1, y2); y <= max(y1, y2); y++)
40             corr(middle, y);
41         for (x = min(middle, x2); x <= max(middle, x2); x++)
42             corr(x, y2);
43     } else {
44         middle = y1 + rn2(y2 - y1 + 1);
45         for (y = min(y1, middle); y <= max(y1, middle); y++)
46             corr(x1, y);
47         for (x = min(x1, x2); x <= max(x1, x2); x++)
48             corr(x, middle);
49         for (y = min(middle, y2); y <= max(middle, y2); y++)
50             corr(x2, y);
51     }
52 }
53
54 STATIC_OVL
55 void
56 roguecorr(x, y, dir)
57 int x, y, dir;
58 {
59     register int fromx, fromy, tox, toy;
60
61     if (dir == DOWN) {
62         r[x][y].doortable &= ~DOWN;
63         if (!r[x][y].real) {
64             fromx = r[x][y].rlx;
65             fromy = r[x][y].rly;
66             fromx += 1 + 26 * x;
67             fromy += 7 * y;
68         } else {
69             fromx = r[x][y].rlx + rn2(r[x][y].dx);
70             fromy = r[x][y].rly + r[x][y].dy;
71             fromx += 1 + 26 * x;
72             fromy += 7 * y;
73             if (!IS_WALL(levl[fromx][fromy].typ))
74                 impossible("down: no wall at %d,%d?", fromx, fromy);
75             dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
76             levl[fromx][fromy].doormask = D_NODOOR;
77             fromy++;
78         }
79         if (y >= 2) {
80             impossible("down door from %d,%d going nowhere?", x, y);
81             return;
82         }
83         y++;
84         r[x][y].doortable &= ~UP;
85         if (!r[x][y].real) {
86             tox = r[x][y].rlx;
87             toy = r[x][y].rly;
88             tox += 1 + 26 * x;
89             toy += 7 * y;
90         } else {
91             tox = r[x][y].rlx + rn2(r[x][y].dx);
92             toy = r[x][y].rly - 1;
93             tox += 1 + 26 * x;
94             toy += 7 * y;
95             if (!IS_WALL(levl[tox][toy].typ))
96                 impossible("up: no wall at %d,%d?", tox, toy);
97             dodoor(tox, toy, &rooms[r[x][y].nroom]);
98             levl[tox][toy].doormask = D_NODOOR;
99             toy--;
100         }
101         roguejoin(fromx, fromy, tox, toy, FALSE);
102         return;
103     } else if (dir == RIGHT) {
104         r[x][y].doortable &= ~RIGHT;
105         if (!r[x][y].real) {
106             fromx = r[x][y].rlx;
107             fromy = r[x][y].rly;
108             fromx += 1 + 26 * x;
109             fromy += 7 * y;
110         } else {
111             fromx = r[x][y].rlx + r[x][y].dx;
112             fromy = r[x][y].rly + rn2(r[x][y].dy);
113             fromx += 1 + 26 * x;
114             fromy += 7 * y;
115             if (!IS_WALL(levl[fromx][fromy].typ))
116                 impossible("down: no wall at %d,%d?", fromx, fromy);
117             dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
118             levl[fromx][fromy].doormask = D_NODOOR;
119             fromx++;
120         }
121         if (x >= 2) {
122             impossible("right door from %d,%d going nowhere?", x, y);
123             return;
124         }
125         x++;
126         r[x][y].doortable &= ~LEFT;
127         if (!r[x][y].real) {
128             tox = r[x][y].rlx;
129             toy = r[x][y].rly;
130             tox += 1 + 26 * x;
131             toy += 7 * y;
132         } else {
133             tox = r[x][y].rlx - 1;
134             toy = r[x][y].rly + rn2(r[x][y].dy);
135             tox += 1 + 26 * x;
136             toy += 7 * y;
137             if (!IS_WALL(levl[tox][toy].typ))
138                 impossible("left: no wall at %d,%d?", tox, toy);
139             dodoor(tox, toy, &rooms[r[x][y].nroom]);
140             levl[tox][toy].doormask = D_NODOOR;
141             tox--;
142         }
143         roguejoin(fromx, fromy, tox, toy, TRUE);
144         return;
145     } else
146         impossible("corridor in direction %d?", dir);
147 }
148
149 /* Modified walkfrom() from mkmaze.c */
150 STATIC_OVL
151 void
152 miniwalk(x, y)
153 int x, y;
154 {
155     register int q, dir;
156     int dirs[4];
157
158     while (1) {
159         q = 0;
160 #define doorhere (r[x][y].doortable)
161         if (x > 0 && (!(doorhere & LEFT))
162             && (!r[x - 1][y].doortable || !rn2(10)))
163             dirs[q++] = 0;
164         if (x < 2 && (!(doorhere & RIGHT))
165             && (!r[x + 1][y].doortable || !rn2(10)))
166             dirs[q++] = 1;
167         if (y > 0 && (!(doorhere & UP))
168             && (!r[x][y - 1].doortable || !rn2(10)))
169             dirs[q++] = 2;
170         if (y < 2 && (!(doorhere & DOWN))
171             && (!r[x][y + 1].doortable || !rn2(10)))
172             dirs[q++] = 3;
173         /* Rogue levels aren't just 3 by 3 mazes; they have some extra
174          * connections, thus that 1/10 chance
175          */
176         if (!q)
177             return;
178         dir = dirs[rn2(q)];
179         switch (dir) { /* Move in direction */
180         case 0:
181             doorhere |= LEFT;
182             x--;
183             doorhere |= RIGHT;
184             break;
185         case 1:
186             doorhere |= RIGHT;
187             x++;
188             doorhere |= LEFT;
189             break;
190         case 2:
191             doorhere |= UP;
192             y--;
193             doorhere |= DOWN;
194             break;
195         case 3:
196             doorhere |= DOWN;
197             y++;
198             doorhere |= UP;
199             break;
200         }
201         miniwalk(x, y);
202     }
203 }
204
205 void
206 makeroguerooms()
207 {
208     register int x, y;
209     /* Rogue levels are structured 3 by 3, with each section containing
210      * a room or an intersection.  The minimum width is 2 each way.
211      * One difference between these and "real" Rogue levels: real Rogue
212      * uses 24 rows and NetHack only 23.  So we cheat a bit by making the
213      * second row of rooms not as deep.
214      *
215      * Each normal space has 6/7 rows and 25 columns in which a room may
216      * actually be placed.  Walls go from rows 0-5/6 and columns 0-24.
217      * Not counting walls, the room may go in
218      * rows 1-5 and columns 1-23 (numbering starting at 0).  A room
219      * coordinate of this type may be converted to a level coordinate
220      * by adding 1+28*x to the column, and 7*y to the row.  (The 1
221      * is because column 0 isn't used [we only use 1-78]).
222      * Room height may be 2-4 (2-5 on last row), length 2-23 (not
223      * counting walls).
224      */
225 #define here r[x][y]
226
227     nroom = 0;
228     for (y = 0; y < 3; y++)
229         for (x = 0; x < 3; x++) {
230             /* Note: we want to insure at least 1 room.  So, if the
231              * first 8 are all dummies, force the last to be a room.
232              */
233             if (!rn2(5) && (nroom || (x < 2 && y < 2))) {
234                 /* Arbitrary: dummy rooms may only go where real
235                  * ones do.
236                  */
237                 here.real = FALSE;
238                 here.rlx = rn1(22, 2);
239                 here.rly = rn1((y == 2) ? 4 : 3, 2);
240             } else {
241                 here.real = TRUE;
242                 here.dx = rn1(22, 2); /* 2-23 long, plus walls */
243                 here.dy = rn1((y == 2) ? 4 : 3, 2); /* 2-5 high, plus walls */
244
245                 /* boundaries of room floor */
246                 here.rlx = rnd(23 - here.dx + 1);
247                 here.rly = rnd(((y == 2) ? 5 : 4) - here.dy + 1);
248                 nroom++;
249             }
250             here.doortable = 0;
251         }
252     miniwalk(rn2(3), rn2(3));
253     nroom = 0;
254     for (y = 0; y < 3; y++)
255         for (x = 0; x < 3; x++) {
256             if (here.real) { /* Make a room */
257                 int lowx, lowy, hix, hiy;
258
259                 r[x][y].nroom = nroom;
260                 smeq[nroom] = nroom;
261
262                 lowx = 1 + 26 * x + here.rlx;
263                 lowy = 7 * y + here.rly;
264                 hix = 1 + 26 * x + here.rlx + here.dx - 1;
265                 hiy = 7 * y + here.rly + here.dy - 1;
266                 /* Strictly speaking, it should be lit only if above
267                  * level 10, but since Rogue rooms are only
268                  * encountered below level 10, use !rn2(7).
269                  */
270                 add_room(lowx, lowy, hix, hiy, (boolean) !rn2(7), OROOM,
271                          FALSE);
272             }
273         }
274
275     /* Now, add connecting corridors. */
276     for (y = 0; y < 3; y++)
277         for (x = 0; x < 3; x++) {
278             if (here.doortable & DOWN)
279                 roguecorr(x, y, DOWN);
280             if (here.doortable & RIGHT)
281                 roguecorr(x, y, RIGHT);
282             if (here.doortable & LEFT)
283                 impossible("left end of %d, %d never connected?", x, y);
284             if (here.doortable & UP)
285                 impossible("up end of %d, %d never connected?", x, y);
286         }
287 }
288
289 void
290 corr(x, y)
291 int x, y;
292 {
293     if (rn2(50)) {
294         levl[x][y].typ = CORR;
295     } else {
296         levl[x][y].typ = SCORR;
297     }
298 }
299
300 void
301 makerogueghost()
302 {
303     register struct monst *ghost;
304     struct obj *ghostobj;
305     struct mkroom *croom;
306     int x, y;
307
308     if (!nroom)
309         return; /* Should never happen */
310     croom = &rooms[rn2(nroom)];
311     x = somex(croom);
312     y = somey(croom);
313     if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS)))
314         return;
315     ghost->msleeping = 1;
316     ghost = christen_monst(ghost, roguename());
317
318     if (rn2(4)) {
319         ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE);
320         ghostobj->quan = (long) rnd(7);
321         ghostobj->owt = weight(ghostobj);
322     }
323     if (rn2(2)) {
324         ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE);
325         ghostobj->spe = rnd(3);
326         if (rn2(4))
327             curse(ghostobj);
328     } else {
329         ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE);
330         ghostobj->spe = rnd(5) - 2;
331         if (rn2(4))
332             curse(ghostobj);
333     }
334     ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE);
335     ghostobj->spe = 1;
336     if (rn2(4))
337         curse(ghostobj);
338
339     ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE);
340     ghostobj->spe = 0;
341     ghostobj->quan = (long) rn1(10, 25);
342     ghostobj->owt = weight(ghostobj);
343     if (rn2(4))
344         curse(ghostobj);
345
346     if (rn2(2)) {
347         ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE);
348         ghostobj->spe = rn2(3);
349         if (!rn2(3))
350             ghostobj->oerodeproof = TRUE;
351         if (rn2(4))
352             curse(ghostobj);
353     } else {
354         ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE);
355         ghostobj->spe = rnd(5) - 2;
356         if (!rn2(3))
357             ghostobj->oerodeproof = TRUE;
358         if (rn2(4))
359             curse(ghostobj);
360     }
361     if (rn2(2)) {
362         ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE);
363         ghostobj->known = TRUE;
364     }
365 }
366
367 /*extralev.c*/