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