Neale Pickett
·
2011-10-13
startup.c
1/*
2 * Create the layout for the new level
3 *
4 * @(#)startup.c 4.45 (Berkeley) 02/05/99
5 */
6
7#include <ctype.h>
8#include <curses.h>
9#include "netprot.h"
10
11typedef struct spot { /* position matrix for maze positions */
12 int nexits;
13 coord exits[4];
14 int used;
15} SPOT;
16
17#define GOLDGRP 1
18
19/*
20 * do_rooms:
21 * Create rooms and corridors with a connectivity graph
22 */
23void
24do_rooms(void)
25{
26 int i;
27 struct room *rp;
28 THING *tp;
29 int left_out;
30 static coord top;
31 coord bsze; /* maximum room size */
32 coord mp;
33
34 bsze.x = NUMCOLS / 3;
35 bsze.y = NUMLINES / 3;
36 /*
37 * Clear things for a new level
38 */
39 for (rp = Rooms; rp < &Rooms[MAXROOMS]; rp++)
40 {
41 rp->r_goldval = 0;
42 rp->r_nexits = 0;
43 rp->r_flags = 0;
44 }
45 /*
46 * Put the gone rooms, if any, on the level
47 */
48 left_out = rnd(4);
49 for (i = 0; i < left_out; i++)
50 Rooms[rnd_room()].r_flags |= ISGONE;
51 /*
52 * dig and populate all the rooms on the level
53 */
54 for (i = 0, rp = Rooms; i < MAXROOMS; rp++, i++)
55 {
56 /*
57 * Find upper left corner of box that this room goes in
58 */
59 top.x = (i % 3) * bsze.x + 1;
60 top.y = (i / 3) * bsze.y;
61 if (rp->r_flags & ISGONE)
62 {
63 /*
64 * Place a gone room. Make certain that there is a blank line
65 * for passage drawing.
66 */
67 do
68 {
69 rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1;
70 rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1;
71 rp->r_max.x = -NUMCOLS;
72 rp->r_max.y = -NUMLINES;
73 } until (rp->r_pos.y > 0 && rp->r_pos.y < NUMLINES-1);
74 continue;
75 }
76 /*
77 * set room type
78 */
79 if (rnd(10) < Level - 1)
80 {
81 rp->r_flags |= ISDARK; /* dark room */
82 if (rnd(15) == 0)
83 rp->r_flags = ISMAZE; /* maze room */
84 }
85 /*
86 * Find a place and size for a random room
87 */
88 if (rp->r_flags & ISMAZE)
89 {
90 rp->r_max.x = bsze.x - 1;
91 rp->r_max.y = bsze.y - 1;
92 if ((rp->r_pos.x = top.x) == 1)
93 rp->r_pos.x = 0;
94 if ((rp->r_pos.y = top.y) == 0)
95 {
96 rp->r_pos.y++;
97 rp->r_max.y--;
98 }
99 }
100 else
101 do
102 {
103 rp->r_max.x = rnd(bsze.x - 4) + 4;
104 rp->r_max.y = rnd(bsze.y - 4) + 4;
105 rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
106 rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
107 } until (rp->r_pos.y != 0);
108 draw_room(rp);
109 /*
110 * Put the gold in
111 */
112 if (rnd(2) == 0 && (!Amulet || Level >= Max_level))
113 {
114 THING *gold;
115
116 gold = new_item();
117 gold->o_goldval = rp->r_goldval = GOLDCALC;
118 find_floor(rp, &rp->r_gold, FALSE, FALSE);
119 gold->o_pos = rp->r_gold;
120 chat(rp->r_gold.y, rp->r_gold.x) = GOLD;
121 gold->o_flags = ISMANY;
122 gold->o_group = GOLDGRP;
123 gold->o_type = GOLD;
124 attach(Lvl_obj, gold);
125 }
126 /*
127 * Put the monster in
128 */
129 if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25))
130 {
131 tp = new_item();
132 find_floor(rp, &mp, FALSE, TRUE);
133 new_monster(tp, randmonster(FALSE), &mp);
134 give_pack(tp);
135 }
136 }
137}
138
139/*
140 * draw_room:
141 * Draw a box around a room and lay down the floor for normal
142 * rooms; for maze rooms, draw maze.
143 */
144void
145draw_room(struct room *rp)
146{
147 int y, x;
148
149 if (rp->r_flags & ISMAZE)
150 do_maze(rp);
151 else
152 {
153 vert(rp, rp->r_pos.x); /* Draw left side */
154 vert(rp, rp->r_pos.x + rp->r_max.x - 1); /* Draw right side */
155 horiz(rp, rp->r_pos.y); /* Draw top */
156 horiz(rp, rp->r_pos.y + rp->r_max.y - 1); /* Draw bottom */
157
158 /*
159 * Put the floor down
160 */
161 for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++)
162 for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++)
163 chat(y, x) = FLOOR;
164 }
165}
166
167/*
168 * vert:
169 * Draw a vertical line
170 */
171void
172vert(struct room *rp, int startx)
173{
174 int y;
175
176 for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++)
177 chat(y, startx) = '|';
178}
179
180/*
181 * horiz:
182 * Draw a horizontal line
183 */
184void
185horiz(struct room *rp, int starty)
186{
187 int x;
188
189 for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++)
190 chat(starty, x) = '-';
191}
192
193/*
194 * do_maze:
195 * Dig a maze
196 */
197
198static int Maxy, Maxx, Starty, Startx;
199
200static SPOT Maze[NUMLINES/3+1][NUMCOLS/3+1];
201
202void
203do_maze(struct room *rp)
204{
205 SPOT *sp;
206 int starty, startx;
207 static coord pos;
208
209 for (sp = &Maze[0][0]; sp < &Maze[NUMLINES / 3][NUMCOLS / 3 + 1]; sp++)
210 {
211 sp->used = FALSE;
212 sp->nexits = 0;
213 }
214
215 Maxy = rp->r_max.y;
216 Maxx = rp->r_max.x;
217 Starty = rp->r_pos.y;
218 Startx = rp->r_pos.x;
219 starty = (rnd(rp->r_max.y) / 2) * 2;
220 startx = (rnd(rp->r_max.x) / 2) * 2;
221 pos.y = starty + Starty;
222 pos.x = startx + Startx;
223 putpass(&pos);
224 dig(starty, startx);
225}
226
227/*
228 * dig:
229 * Dig out from around where we are now, if possible
230 */
231void
232dig(int y, int x)
233{
234 coord *cp;
235 int cnt, newy, newx, nexty, nextx;
236 static coord pos;
237 static coord del[4] = {
238 {2, 0}, {-2, 0}, {0, 2}, {0, -2}
239 };
240
241 for (;;)
242 {
243 cnt = 0;
244 for (cp = del; cp < &del[4]; cp++)
245 {
246 newy = y + cp->y;
247 newx = x + cp->x;
248 if (newy < 0 || newy > Maxy || newx < 0 || newx > Maxx)
249 continue;
250 if (flat(newy + Starty, newx + Startx) & F_PASS)
251 continue;
252 if (rnd(++cnt) == 0)
253 {
254 nexty = newy;
255 nextx = newx;
256 }
257 }
258 if (cnt == 0)
259 return;
260 accnt_maze(y, x, nexty, nextx);
261 accnt_maze(nexty, nextx, y, x);
262 if (nexty == y)
263 {
264 pos.y = y + Starty;
265 if (nextx - x < 0)
266 pos.x = nextx + Startx + 1;
267 else
268 pos.x = nextx + Startx - 1;
269 }
270 else
271 {
272 pos.x = x + Startx;
273 if (nexty - y < 0)
274 pos.y = nexty + Starty + 1;
275 else
276 pos.y = nexty + Starty - 1;
277 }
278 putpass(&pos);
279 pos.y = nexty + Starty;
280 pos.x = nextx + Startx;
281 putpass(&pos);
282 dig(nexty, nextx);
283 }
284}
285
286/*
287 * accnt_maze:
288 * Account for maze exits
289 */
290void
291accnt_maze(int y, int x, int ny, int nx)
292{
293 SPOT *sp;
294 coord *cp;
295
296 sp = &Maze[y][x];
297 for (cp = sp->exits; cp < &sp->exits[sp->nexits]; cp++)
298 if (cp->y == ny && cp->x == nx)
299 return;
300 cp->y = ny;
301 cp->x = nx;
302}
303
304/*
305 * rnd_pos:
306 * Pick a random spot in a room
307 */
308void
309rnd_pos(struct room *rp, coord *cp)
310{
311 cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
312 cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
313}
314
315/*
316 * find_floor:
317 * Find a valid floor spot in this room. If rp is NULL, then
318 * pick a new room each time around the loop.
319 */
320bool
321find_floor(struct room *rp, coord *cp, int limit, bool monst)
322{
323 PLACE *pp;
324 int cnt;
325 char compchar;
326 bool pickroom;
327
328 if (!(pickroom = (rp == NULL)))
329 compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
330 cnt = limit;
331 for (;;)
332 {
333 if (limit && cnt-- == 0)
334 return FALSE;
335 if (pickroom)
336 {
337 rp = &Rooms[rnd_room()];
338 compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
339 }
340 rnd_pos(rp, cp);
341 pp = INDEX(cp->y, cp->x);
342 if (monst)
343 {
344 if (pp->p_monst == NULL && step_ok(pp->p_ch))
345 return TRUE;
346 }
347 else if (pp->p_ch == compchar)
348 return TRUE;
349 }
350}
351
352/*
353 * enter_room:
354 * Code that is executed whenver you appear in a room
355 */
356void
357enter_room(coord *cp)
358{
359 struct room *rp;
360 THING *tp;
361 int y, x;
362 char ch;
363
364 rp = Proom = roomin(cp);
365 door_open(rp);
366 if (!(rp->r_flags & ISDARK) && !on(Player, ISBLIND))
367 for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
368 {
369 move(y, rp->r_pos.x);
370 for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
371 {
372 tp = moat(y, x);
373 ch = chat(y, x);
374 if (tp == NULL)
375 if (inch() != ch)
376 addch(ch);
377 else
378 move(y, x + 1);
379 else
380 {
381 tp->t_oldch = ch;
382 if (!see_monst(tp))
383 if (on(Player, SEEMONST))
384 {
385 standout();
386 addch(tp->t_disguise);
387 standend();
388 }
389 else
390 addch(ch);
391 else
392 addch(tp->t_disguise);
393 }
394 }
395 }
396}
397
398/*
399 * leave_room:
400 * Code for when we exit a room
401 */
402void
403leave_room(coord *cp)
404{
405 PLACE *pp;
406 struct room *rp;
407 int y, x;
408 char floor;
409 char ch;
410
411 rp = Proom;
412
413 if (rp->r_flags & ISMAZE)
414 return;
415
416 if (rp->r_flags & ISGONE)
417 floor = PASSAGE;
418 else if (!(rp->r_flags & ISDARK) || on(Player, ISBLIND))
419 floor = FLOOR;
420 else
421 floor = ' ';
422
423 Proom = &Passages[flat(cp->y, cp->x) & F_PNUM];
424 for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
425 for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
426 {
427 move(y, x);
428 switch (ch = inch())
429 {
430 case FLOOR:
431 if (floor == ' ' && ch != ' ')
432 addch(' ');
433 break;
434 default:
435 /*
436 * to check for monster, we have to strip out
437 * standout bit
438 */
439 if (isupper(toascii(ch)))
440 {
441 if (on(Player, SEEMONST))
442 {
443 standout();
444 addch(ch);
445 standend();
446 break;
447 }
448 pp = INDEX(cp->y, cp->x);
449 addch(pp->p_ch == DOOR ? DOOR : floor);
450 }
451 }
452 }
453 door_open(rp);
454}