room.c revision 1.2
1/* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Timothy C. Stoehr. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38/*static char sccsid[] = "from: @(#)room.c 5.3 (Berkeley) 6/1/90";*/ 39static char rcsid[] = "$Id: room.c,v 1.2 1993/08/01 18:52:16 mycroft Exp $"; 40#endif /* not lint */ 41 42/* 43 * room.c 44 * 45 * This source herein may be modified and/or distributed by anybody who 46 * so desires, with the following restrictions: 47 * 1.) No portion of this notice shall be removed. 48 * 2.) Credit shall not be taken for the creation of this source. 49 * 3.) This code is not to be traded, sold, or used for personal 50 * gain or profit. 51 * 52 */ 53 54#include "rogue.h" 55 56room rooms[MAXROOMS]; 57boolean rooms_visited[MAXROOMS]; 58 59extern short blind; 60extern boolean detect_monster, jump, passgo, no_skull, ask_quit; 61extern char *nick_name, *fruit, *save_file, *press_space; 62 63#define NOPTS 7 64 65struct option { 66 char *prompt; 67 boolean is_bool; 68 char **strval; 69 boolean *bval; 70} options[NOPTS] = { 71 { 72 "Show position only at end of run (\"jump\"): ", 73 1, (char **) 0, &jump 74 }, 75 { 76 "Follow turnings in passageways (\"passgo\"): ", 77 1, (char **) 0, &passgo 78 }, 79 { 80 "Don't print skull when killed (\"noskull\" or \"notombstone\"): ", 81 1, (char **) 0, &no_skull 82 }, 83 { 84 "Ask player before saying 'Okay, bye-bye!' (\"askquit\"): ", 85 1, (char **) 0, &ask_quit 86 }, 87 { 88 "Name (\"name\"): ", 89 0, &nick_name 90 }, 91 { 92 "Fruit (\"fruit\"): ", 93 0, &fruit 94 }, 95 { 96 "Save file (\"file\"): ", 97 0, &save_file 98 } 99}; 100 101light_up_room(rn) 102int rn; 103{ 104 short i, j; 105 106 if (!blind) { 107 for (i = rooms[rn].top_row; 108 i <= rooms[rn].bottom_row; i++) { 109 for (j = rooms[rn].left_col; 110 j <= rooms[rn].right_col; j++) { 111 if (dungeon[i][j] & MONSTER) { 112 object *monster; 113 114 if (monster = object_at(&level_monsters, i, j)) { 115 dungeon[monster->row][monster->col] &= (~MONSTER); 116 monster->trail_char = 117 get_dungeon_char(monster->row, monster->col); 118 dungeon[monster->row][monster->col] |= MONSTER; 119 } 120 } 121 mvaddch(i, j, get_dungeon_char(i, j)); 122 } 123 } 124 mvaddch(rogue.row, rogue.col, rogue.fchar); 125 } 126} 127 128light_passage(row, col) 129{ 130 short i, j, i_end, j_end; 131 132 if (blind) { 133 return; 134 } 135 i_end = (row < (DROWS-2)) ? 1 : 0; 136 j_end = (col < (DCOLS-1)) ? 1 : 0; 137 138 for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) { 139 for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) { 140 if (can_move(row, col, row+i, col+j)) { 141 mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j)); 142 } 143 } 144 } 145} 146 147darken_room(rn) 148short rn; 149{ 150 short i, j; 151 152 for (i = rooms[rn].top_row + 1; i < rooms[rn].bottom_row; i++) { 153 for (j = rooms[rn].left_col + 1; j < rooms[rn].right_col; j++) { 154 if (blind) { 155 mvaddch(i, j, ' '); 156 } else { 157 if (!(dungeon[i][j] & (OBJECT | STAIRS)) && 158 !(detect_monster && (dungeon[i][j] & MONSTER))) { 159 if (!imitating(i, j)) { 160 mvaddch(i, j, ' '); 161 } 162 if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) { 163 mvaddch(i, j, '^'); 164 } 165 } 166 } 167 } 168 } 169} 170 171get_dungeon_char(row, col) 172register row, col; 173{ 174 register unsigned short mask = dungeon[row][col]; 175 176 if (mask & MONSTER) { 177 return(gmc_row_col(row, col)); 178 } 179 if (mask & OBJECT) { 180 object *obj; 181 182 obj = object_at(&level_objects, row, col); 183 return(get_mask_char(obj->what_is)); 184 } 185 if (mask & (TUNNEL | STAIRS | HORWALL | VERTWALL | FLOOR | DOOR)) { 186 if ((mask & (TUNNEL| STAIRS)) && (!(mask & HIDDEN))) { 187 return(((mask & STAIRS) ? '%' : '#')); 188 } 189 if (mask & HORWALL) { 190 return('-'); 191 } 192 if (mask & VERTWALL) { 193 return('|'); 194 } 195 if (mask & FLOOR) { 196 if (mask & TRAP) { 197 if (!(dungeon[row][col] & HIDDEN)) { 198 return('^'); 199 } 200 } 201 return('.'); 202 } 203 if (mask & DOOR) { 204 if (mask & HIDDEN) { 205 if (((col > 0) && (dungeon[row][col-1] & HORWALL)) || 206 ((col < (DCOLS-1)) && (dungeon[row][col+1] & HORWALL))) { 207 return('-'); 208 } else { 209 return('|'); 210 } 211 } else { 212 return('+'); 213 } 214 } 215 } 216 return(' '); 217} 218 219get_mask_char(mask) 220register unsigned short mask; 221{ 222 switch(mask) { 223 case SCROL: 224 return('?'); 225 case POTION: 226 return('!'); 227 case GOLD: 228 return('*'); 229 case FOOD: 230 return(':'); 231 case WAND: 232 return('/'); 233 case ARMOR: 234 return(']'); 235 case WEAPON: 236 return(')'); 237 case RING: 238 return('='); 239 case AMULET: 240 return(','); 241 default: 242 return('~'); /* unknown, something is wrong */ 243 } 244} 245 246gr_row_col(row, col, mask) 247short *row, *col; 248unsigned short mask; 249{ 250 short rn; 251 short r, c; 252 253 do { 254 r = get_rand(MIN_ROW, DROWS-2); 255 c = get_rand(0, DCOLS-1); 256 rn = get_room_number(r, c); 257 } while ((rn == NO_ROOM) || 258 (!(dungeon[r][c] & mask)) || 259 (dungeon[r][c] & (~mask)) || 260 (!(rooms[rn].is_room & (R_ROOM | R_MAZE))) || 261 ((r == rogue.row) && (c == rogue.col))); 262 263 *row = r; 264 *col = c; 265} 266 267gr_room() 268{ 269 short i; 270 271 do { 272 i = get_rand(0, MAXROOMS-1); 273 } while (!(rooms[i].is_room & (R_ROOM | R_MAZE))); 274 275 return(i); 276} 277 278party_objects(rn) 279{ 280 short i, j, nf = 0; 281 object *obj; 282 short n, N, row, col; 283 boolean found; 284 285 N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) * 286 ((rooms[rn].right_col - rooms[rn].left_col) - 1); 287 n = get_rand(5, 10); 288 if (n > N) { 289 n = N - 2; 290 } 291 for (i = 0; i < n; i++) { 292 for (j = found = 0; ((!found) && (j < 250)); j++) { 293 row = get_rand(rooms[rn].top_row+1, 294 rooms[rn].bottom_row-1); 295 col = get_rand(rooms[rn].left_col+1, 296 rooms[rn].right_col-1); 297 if ((dungeon[row][col] == FLOOR) || (dungeon[row][col] == TUNNEL)) { 298 found = 1; 299 } 300 } 301 if (found) { 302 obj = gr_object(); 303 place_at(obj, row, col); 304 nf++; 305 } 306 } 307 return(nf); 308} 309 310get_room_number(row, col) 311register row, col; 312{ 313 short i; 314 315 for (i = 0; i < MAXROOMS; i++) { 316 if ((row >= rooms[i].top_row) && (row <= rooms[i].bottom_row) && 317 (col >= rooms[i].left_col) && (col <= rooms[i].right_col)) { 318 return(i); 319 } 320 } 321 return(NO_ROOM); 322} 323 324is_all_connected() 325{ 326 short i, starting_room; 327 328 for (i = 0; i < MAXROOMS; i++) { 329 rooms_visited[i] = 0; 330 if (rooms[i].is_room & (R_ROOM | R_MAZE)) { 331 starting_room = i; 332 } 333 } 334 335 visit_rooms(starting_room); 336 337 for (i = 0; i < MAXROOMS; i++) { 338 if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) { 339 return(0); 340 } 341 } 342 return(1); 343} 344 345visit_rooms(rn) 346int rn; 347{ 348 short i; 349 short oth_rn; 350 351 rooms_visited[rn] = 1; 352 353 for (i = 0; i < 4; i++) { 354 oth_rn = rooms[rn].doors[i].oth_room; 355 if ((oth_rn >= 0) && (!rooms_visited[oth_rn])) { 356 visit_rooms(oth_rn); 357 } 358 } 359} 360 361draw_magic_map() 362{ 363 short i, j, ch, och; 364 unsigned short mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS | 365 MONSTER); 366 unsigned short s; 367 368 for (i = 0; i < DROWS; i++) { 369 for (j = 0; j < DCOLS; j++) { 370 s = dungeon[i][j]; 371 if (s & mask) { 372 if (((ch = mvinch(i, j)) == ' ') || 373 ((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) { 374 och = ch; 375 dungeon[i][j] &= (~HIDDEN); 376 if (s & HORWALL) { 377 ch = '-'; 378 } else if (s & VERTWALL) { 379 ch = '|'; 380 } else if (s & DOOR) { 381 ch = '+'; 382 } else if (s & TRAP) { 383 ch = '^'; 384 } else if (s & STAIRS) { 385 ch = '%'; 386 } else if (s & TUNNEL) { 387 ch = '#'; 388 } else { 389 continue; 390 } 391 if ((!(s & MONSTER)) || (och == ' ')) { 392 addch(ch); 393 } 394 if (s & MONSTER) { 395 object *monster; 396 397 if (monster = object_at(&level_monsters, i, j)) { 398 monster->trail_char = ch; 399 } 400 } 401 } 402 } 403 } 404 } 405} 406 407dr_course(monster, entering, row, col) 408object *monster; 409boolean entering; 410short row, col; 411{ 412 short i, j, k, rn; 413 short r, rr; 414 415 monster->row = row; 416 monster->col = col; 417 418 if (mon_sees(monster, rogue.row, rogue.col)) { 419 monster->trow = NO_ROOM; 420 return; 421 } 422 rn = get_room_number(row, col); 423 424 if (entering) { /* entering room */ 425 /* look for door to some other room */ 426 r = get_rand(0, MAXROOMS-1); 427 for (i = 0; i < MAXROOMS; i++) { 428 rr = (r + i) % MAXROOMS; 429 if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) { 430 continue; 431 } 432 for (k = 0; k < 4; k++) { 433 if (rooms[rr].doors[k].oth_room == rn) { 434 monster->trow = rooms[rr].doors[k].oth_row; 435 monster->tcol = rooms[rr].doors[k].oth_col; 436 if ((monster->trow == row) && 437 (monster->tcol == col)) { 438 continue; 439 } 440 return; 441 } 442 } 443 } 444 /* look for door to dead end */ 445 for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) { 446 for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) { 447 if ((i != monster->row) && (j != monster->col) && 448 (dungeon[i][j] & DOOR)) { 449 monster->trow = i; 450 monster->tcol = j; 451 return; 452 } 453 } 454 } 455 /* return monster to room that he came from */ 456 for (i = 0; i < MAXROOMS; i++) { 457 for (j = 0; j < 4; j++) { 458 if (rooms[i].doors[j].oth_room == rn) { 459 for (k = 0; k < 4; k++) { 460 if (rooms[rn].doors[k].oth_room == i) { 461 monster->trow = rooms[rn].doors[k].oth_row; 462 monster->tcol = rooms[rn].doors[k].oth_col; 463 return; 464 } 465 } 466 } 467 } 468 } 469 /* no place to send monster */ 470 monster->trow = NO_ROOM; 471 } else { /* exiting room */ 472 if (!get_oth_room(rn, &row, &col)) { 473 monster->trow = NO_ROOM; 474 } else { 475 monster->trow = row; 476 monster->tcol = col; 477 } 478 } 479} 480 481get_oth_room(rn, row, col) 482short rn, *row, *col; 483{ 484 short d = -1; 485 486 if (*row == rooms[rn].top_row) { 487 d = UPWARD/2; 488 } else if (*row == rooms[rn].bottom_row) { 489 d = DOWN/2; 490 } else if (*col == rooms[rn].left_col) { 491 d = LEFT/2; 492 } else if (*col == rooms[rn].right_col) { 493 d = RIGHT/2; 494 } 495 if ((d != -1) && (rooms[rn].doors[d].oth_room >= 0)) { 496 *row = rooms[rn].doors[d].oth_row; 497 *col = rooms[rn].doors[d].oth_col; 498 return(1); 499 } 500 return(0); 501} 502 503edit_opts() 504{ 505 char save[NOPTS+1][DCOLS]; 506 short i, j; 507 short ch; 508 boolean done = 0; 509 char buf[MAX_OPT_LEN + 2]; 510 511 for (i = 0; i < NOPTS+1; i++) { 512 for (j = 0; j < DCOLS; j++) { 513 save[i][j] = mvinch(i, j); 514 } 515 if (i < NOPTS) { 516 opt_show(i); 517 } 518 } 519 opt_go(0); 520 i = 0; 521 522 while (!done) { 523 refresh(); 524 ch = rgetchar(); 525CH: 526 switch(ch) { 527 case '\033': 528 done = 1; 529 break; 530 case '\012': 531 case '\015': 532 if (i == (NOPTS - 1)) { 533 mvaddstr(NOPTS, 0, press_space); 534 refresh(); 535 wait_for_ack(); 536 done = 1; 537 } else { 538 i++; 539 opt_go(i); 540 } 541 break; 542 case '-': 543 if (i > 0) { 544 opt_go(--i); 545 } else { 546 sound_bell(); 547 } 548 break; 549 case 't': 550 case 'T': 551 case 'f': 552 case 'F': 553 if (options[i].is_bool) { 554 *(options[i].bval) = (((ch == 't') || (ch == 'T')) ? 1 : 0); 555 opt_show(i); 556 opt_go(++i); 557 break; 558 } 559 default: 560 if (options[i].is_bool) { 561 sound_bell(); 562 break; 563 } 564 j = 0; 565 if ((ch == '\010') || ((ch >= ' ') && (ch <= '~'))) { 566 opt_erase(i); 567 do { 568 if ((ch >= ' ') && (ch <= '~') && (j < MAX_OPT_LEN)) { 569 buf[j++] = ch; 570 buf[j] = '\0'; 571 addch(ch); 572 } else if ((ch == '\010') && (j > 0)) { 573 buf[--j] = '\0'; 574 move(i, j + strlen(options[i].prompt)); 575 addch(' '); 576 move(i, j + strlen(options[i].prompt)); 577 } 578 refresh(); 579 ch = rgetchar(); 580 } while ((ch != '\012') && (ch != '\015') && (ch != '\033')); 581 if (j != 0) { 582 (void) strcpy(*(options[i].strval), buf); 583 } 584 opt_show(i); 585 goto CH; 586 } else { 587 sound_bell(); 588 } 589 break; 590 } 591 } 592 593 for (i = 0; i < NOPTS+1; i++) { 594 move(i, 0); 595 for (j = 0; j < DCOLS; j++) { 596 addch(save[i][j]); 597 } 598 } 599} 600 601opt_show(i) 602int i; 603{ 604 char *s; 605 struct option *opt = &options[i]; 606 607 opt_erase(i); 608 609 if (opt->is_bool) { 610 s = *(opt->bval) ? "True" : "False"; 611 } else { 612 s = *(opt->strval); 613 } 614 addstr(s); 615} 616 617opt_erase(i) 618int i; 619{ 620 struct option *opt = &options[i]; 621 622 mvaddstr(i, 0, opt->prompt); 623 clrtoeol(); 624} 625 626opt_go(i) 627int i; 628{ 629 move(i, strlen(options[i].prompt)); 630} 631 632do_shell() 633{ 634#ifdef UNIX 635 char *sh; 636 637 md_ignore_signals(); 638 if (!(sh = md_getenv("SHELL"))) { 639 sh = "/bin/sh"; 640 } 641 move(LINES-1, 0); 642 refresh(); 643 stop_window(); 644 printf("\nCreating new shell...\n"); 645 md_shell(sh); 646 start_window(); 647 wrefresh(curscr); 648 md_heed_signals(); 649#endif 650} 651