OSDN Git Service

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