1 | /* SCCS Id: @(#)extralev.c 3.3 1999/11/26 */
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);
306 | ghostobj->quan = (long) rnd(7);
307 | ghostobj->owt = weight(ghostobj);
308 | }
309 | if (rn2(2)) {
310 | ghostobj = mksobj_at(MACE,x,y,FALSE);
311 | ghostobj->spe = rnd(3);
312 | if (rn2(4)) curse(ghostobj);
313 | } else {
314 | ghostobj = mksobj_at(TWO_HANDED_SWORD,x,y,FALSE);
315 | ghostobj->spe = rnd(5) - 2;
316 | if (rn2(4)) curse(ghostobj);
317 | }
318 | ghostobj = mksobj_at(BOW,x,y,FALSE);
319 | ghostobj->spe = 1;
320 | if (rn2(4)) curse(ghostobj);
321 |
322 | ghostobj = mksobj_at(ARROW,x,y,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);
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);
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);
341 | ghostobj->known = TRUE;
342 | }
343 | }
344 | #endif /* REINCARNATION */
345 |
346 | /*extralev.c*/