Mercurial > hg > early-roguelike
comparison rogue5/rooms.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Mon, 24 May 2010 20:10:59 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 32:2dcd75e6a736 | 33:f502bf60e6e4 |
|---|---|
| 1 /* | |
| 2 * Create the layout for the new level | |
| 3 * | |
| 4 * @(#)rooms.c 4.45 (Berkeley) 02/05/99 | |
| 5 * | |
| 6 * Rogue: Exploring the Dungeons of Doom | |
| 7 * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman | |
| 8 * All rights reserved. | |
| 9 * | |
| 10 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 11 */ | |
| 12 | |
| 13 #include <ctype.h> | |
| 14 #include <curses.h> | |
| 15 #include "rogue.h" | |
| 16 | |
| 17 typedef struct spot { /* position matrix for maze positions */ | |
| 18 int nexits; | |
| 19 coord exits[4]; | |
| 20 int used; | |
| 21 } SPOT; | |
| 22 | |
| 23 #define GOLDGRP 1 | |
| 24 | |
| 25 /* | |
| 26 * do_rooms: | |
| 27 * Create rooms and corridors with a connectivity graph | |
| 28 */ | |
| 29 | |
| 30 void | |
| 31 do_rooms(void) | |
| 32 { | |
| 33 int i; | |
| 34 struct room *rp; | |
| 35 THING *tp; | |
| 36 int left_out; | |
| 37 coord top; | |
| 38 coord bsze; /* maximum room size */ | |
| 39 coord mp; | |
| 40 | |
| 41 bsze.x = NUMCOLS / 3; | |
| 42 bsze.y = NUMLINES / 3; | |
| 43 /* | |
| 44 * Clear things for a new level | |
| 45 */ | |
| 46 for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) | |
| 47 { | |
| 48 rp->r_goldval = 0; | |
| 49 rp->r_nexits = 0; | |
| 50 rp->r_flags = 0; | |
| 51 } | |
| 52 /* | |
| 53 * Put the gone rooms, if any, on the level | |
| 54 */ | |
| 55 left_out = rnd(4); | |
| 56 for (i = 0; i < left_out; i++) | |
| 57 rooms[rnd_room()].r_flags |= ISGONE; | |
| 58 /* | |
| 59 * dig and populate all the rooms on the level | |
| 60 */ | |
| 61 for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++) | |
| 62 { | |
| 63 /* | |
| 64 * Find upper left corner of box that this room goes in | |
| 65 */ | |
| 66 top.x = (i % 3) * bsze.x + 1; | |
| 67 top.y = (i / 3) * bsze.y; | |
| 68 if (rp->r_flags & ISGONE) | |
| 69 { | |
| 70 /* | |
| 71 * Place a gone room. Make certain that there is a blank line | |
| 72 * for passage drawing. | |
| 73 */ | |
| 74 do | |
| 75 { | |
| 76 rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1; | |
| 77 rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1; | |
| 78 rp->r_max.x = -NUMCOLS; | |
| 79 rp->r_max.y = -NUMLINES; | |
| 80 } until (rp->r_pos.y > 0 && rp->r_pos.y < NUMLINES-1); | |
| 81 continue; | |
| 82 } | |
| 83 /* | |
| 84 * set room type | |
| 85 */ | |
| 86 if (rnd(10) < level - 1) | |
| 87 { | |
| 88 rp->r_flags |= ISDARK; /* dark room */ | |
| 89 if (rnd(15) == 0) | |
| 90 rp->r_flags = ISMAZE; /* maze room */ | |
| 91 } | |
| 92 /* | |
| 93 * Find a place and size for a random room | |
| 94 */ | |
| 95 if (rp->r_flags & ISMAZE) | |
| 96 { | |
| 97 rp->r_max.x = bsze.x - 1; | |
| 98 rp->r_max.y = bsze.y - 1; | |
| 99 if ((rp->r_pos.x = top.x) == 1) | |
| 100 rp->r_pos.x = 0; | |
| 101 if ((rp->r_pos.y = top.y) == 0) | |
| 102 { | |
| 103 rp->r_pos.y++; | |
| 104 rp->r_max.y--; | |
| 105 } | |
| 106 } | |
| 107 else | |
| 108 do | |
| 109 { | |
| 110 rp->r_max.x = rnd(bsze.x - 4) + 4; | |
| 111 rp->r_max.y = rnd(bsze.y - 4) + 4; | |
| 112 rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x); | |
| 113 rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y); | |
| 114 } until (rp->r_pos.y != 0); | |
| 115 draw_room(rp); | |
| 116 /* | |
| 117 * Put the gold in | |
| 118 */ | |
| 119 if (rnd(2) == 0 && (!amulet || level >= max_level)) | |
| 120 { | |
| 121 THING *gold; | |
| 122 | |
| 123 gold = new_item(); | |
| 124 gold->o_goldval = rp->r_goldval = GOLDCALC; | |
| 125 find_floor(rp, &rp->r_gold, FALSE, FALSE); | |
| 126 gold->o_pos = rp->r_gold; | |
| 127 chat(rp->r_gold.y, rp->r_gold.x) = GOLD; | |
| 128 gold->o_flags = ISMANY; | |
| 129 gold->o_group = GOLDGRP; | |
| 130 gold->o_type = GOLD; | |
| 131 attach(lvl_obj, gold); | |
| 132 } | |
| 133 /* | |
| 134 * Put the monster in | |
| 135 */ | |
| 136 if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25)) | |
| 137 { | |
| 138 tp = new_item(); | |
| 139 find_floor(rp, &mp, FALSE, TRUE); | |
| 140 new_monster(tp, randmonster(FALSE), &mp); | |
| 141 give_pack(tp); | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 /* | |
| 147 * draw_room: | |
| 148 * Draw a box around a room and lay down the floor for normal | |
| 149 * rooms; for maze rooms, draw maze. | |
| 150 */ | |
| 151 | |
| 152 void | |
| 153 draw_room(const struct room *rp) | |
| 154 { | |
| 155 int y, x; | |
| 156 | |
| 157 if (rp->r_flags & ISMAZE) | |
| 158 do_maze(rp); | |
| 159 else | |
| 160 { | |
| 161 vert(rp, rp->r_pos.x); /* Draw left side */ | |
| 162 vert(rp, rp->r_pos.x + rp->r_max.x - 1); /* Draw right side */ | |
| 163 horiz(rp, rp->r_pos.y); /* Draw top */ | |
| 164 horiz(rp, rp->r_pos.y + rp->r_max.y - 1); /* Draw bottom */ | |
| 165 | |
| 166 /* | |
| 167 * Put the floor down | |
| 168 */ | |
| 169 for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++) | |
| 170 for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++) | |
| 171 chat(y, x) = FLOOR; | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 /* | |
| 176 * vert: | |
| 177 * Draw a vertical line | |
| 178 */ | |
| 179 | |
| 180 void | |
| 181 vert(const struct room *rp, int startx) | |
| 182 { | |
| 183 int y; | |
| 184 | |
| 185 for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++) | |
| 186 chat(y, startx) = '|'; | |
| 187 } | |
| 188 | |
| 189 /* | |
| 190 * horiz: | |
| 191 * Draw a horizontal line | |
| 192 */ | |
| 193 | |
| 194 void | |
| 195 horiz(const struct room *rp, int starty) | |
| 196 { | |
| 197 int x; | |
| 198 | |
| 199 for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++) | |
| 200 chat(starty, x) = '-'; | |
| 201 } | |
| 202 | |
| 203 /* | |
| 204 * do_maze: | |
| 205 * Dig a maze | |
| 206 */ | |
| 207 | |
| 208 static int Maxy, Maxx, Starty, Startx; | |
| 209 | |
| 210 static SPOT maze[NUMLINES/3+1][NUMCOLS/3+1]; | |
| 211 | |
| 212 | |
| 213 void | |
| 214 do_maze(const struct room *rp) | |
| 215 { | |
| 216 SPOT *sp; | |
| 217 int starty, startx; | |
| 218 coord pos; | |
| 219 | |
| 220 for (sp = &maze[0][0]; sp <= &maze[NUMLINES / 3][NUMCOLS / 3]; sp++) | |
| 221 { | |
| 222 sp->used = FALSE; | |
| 223 sp->nexits = 0; | |
| 224 } | |
| 225 | |
| 226 Maxy = rp->r_max.y; | |
| 227 Maxx = rp->r_max.x; | |
| 228 Starty = rp->r_pos.y; | |
| 229 Startx = rp->r_pos.x; | |
| 230 starty = (rnd(rp->r_max.y) / 2) * 2; | |
| 231 startx = (rnd(rp->r_max.x) / 2) * 2; | |
| 232 pos.y = starty + Starty; | |
| 233 pos.x = startx + Startx; | |
| 234 putpass(&pos); | |
| 235 dig(starty, startx); | |
| 236 } | |
| 237 | |
| 238 /* | |
| 239 * dig: | |
| 240 * Dig out from around where we are now, if possible | |
| 241 */ | |
| 242 | |
| 243 void | |
| 244 dig(int y, int x) | |
| 245 { | |
| 246 coord *cp; | |
| 247 int cnt, newy, newx, nexty = 0, nextx = 0; | |
| 248 coord pos; | |
| 249 coord del[4] = { | |
| 250 {2, 0}, {-2, 0}, {0, 2}, {0, -2} | |
| 251 }; | |
| 252 | |
| 253 for (;;) | |
| 254 { | |
| 255 cnt = 0; | |
| 256 for (cp = del; cp <= &del[3]; cp++) | |
| 257 { | |
| 258 newy = y + cp->y; | |
| 259 newx = x + cp->x; | |
| 260 if (newy < 0 || newy > Maxy || newx < 0 || newx > Maxx) | |
| 261 continue; | |
| 262 if (flat(newy + Starty, newx + Startx) & F_PASS) | |
| 263 continue; | |
| 264 if (rnd(++cnt) == 0) | |
| 265 { | |
| 266 nexty = newy; | |
| 267 nextx = newx; | |
| 268 } | |
| 269 } | |
| 270 if (cnt == 0) | |
| 271 return; | |
| 272 accnt_maze(y, x, nexty, nextx); | |
| 273 accnt_maze(nexty, nextx, y, x); | |
| 274 if (nexty == y) | |
| 275 { | |
| 276 pos.y = y + Starty; | |
| 277 if (nextx - x < 0) | |
| 278 pos.x = nextx + Startx + 1; | |
| 279 else | |
| 280 pos.x = nextx + Startx - 1; | |
| 281 } | |
| 282 else | |
| 283 { | |
| 284 pos.x = x + Startx; | |
| 285 if (nexty - y < 0) | |
| 286 pos.y = nexty + Starty + 1; | |
| 287 else | |
| 288 pos.y = nexty + Starty - 1; | |
| 289 } | |
| 290 putpass(&pos); | |
| 291 pos.y = nexty + Starty; | |
| 292 pos.x = nextx + Startx; | |
| 293 putpass(&pos); | |
| 294 dig(nexty, nextx); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 /* | |
| 299 * accnt_maze: | |
| 300 * Account for maze exits | |
| 301 */ | |
| 302 | |
| 303 void | |
| 304 accnt_maze(int y, int x, int ny, int nx) | |
| 305 { | |
| 306 SPOT *sp; | |
| 307 coord *cp; | |
| 308 | |
| 309 sp = &maze[y][x]; | |
| 310 for (cp = sp->exits; cp < &sp->exits[sp->nexits]; cp++) | |
| 311 if (cp->y == ny && cp->x == nx) | |
| 312 return; | |
| 313 cp->y = ny; | |
| 314 cp->x = nx; | |
| 315 } | |
| 316 | |
| 317 /* | |
| 318 * rnd_pos: | |
| 319 * Pick a random spot in a room | |
| 320 */ | |
| 321 | |
| 322 void | |
| 323 rnd_pos(const struct room *rp, coord *cp) | |
| 324 { | |
| 325 cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1; | |
| 326 cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1; | |
| 327 } | |
| 328 | |
| 329 /* | |
| 330 * find_floor: | |
| 331 * Find a valid floor spot in this room. If rp is NULL, then | |
| 332 * pick a new room each time around the loop. | |
| 333 */ | |
| 334 int | |
| 335 find_floor(const struct room *rp, coord *cp, int limit, int monst) | |
| 336 { | |
| 337 PLACE *pp; | |
| 338 int cnt; | |
| 339 int compchar = 0; | |
| 340 int pickroom; | |
| 341 | |
| 342 pickroom = (rp == NULL); | |
| 343 | |
| 344 if (!pickroom) | |
| 345 compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR); | |
| 346 cnt = limit; | |
| 347 for (;;) | |
| 348 { | |
| 349 if (limit && cnt-- == 0) | |
| 350 return FALSE; | |
| 351 if (pickroom) | |
| 352 { | |
| 353 rp = &rooms[rnd_room()]; | |
| 354 compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR); | |
| 355 } | |
| 356 rnd_pos(rp, cp); | |
| 357 pp = INDEX(cp->y, cp->x); | |
| 358 if (monst) | |
| 359 { | |
| 360 if (pp->p_monst == NULL && step_ok(pp->p_ch)) | |
| 361 return TRUE; | |
| 362 } | |
| 363 else if (pp->p_ch == compchar) | |
| 364 return TRUE; | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 /* | |
| 369 * enter_room: | |
| 370 * Code that is executed whenver you appear in a room | |
| 371 */ | |
| 372 | |
| 373 void | |
| 374 enter_room(const coord *cp) | |
| 375 { | |
| 376 struct room *rp; | |
| 377 THING *tp; | |
| 378 int y, x; | |
| 379 chtype ch; | |
| 380 | |
| 381 rp = proom = roomin(cp); | |
| 382 door_open(rp); | |
| 383 if (!(rp->r_flags & ISDARK) && !on(player, ISBLIND)) | |
| 384 for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++) | |
| 385 { | |
| 386 move(y, rp->r_pos.x); | |
| 387 for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++) | |
| 388 { | |
| 389 tp = moat(y, x); |
