1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. 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 #if 0 39 static char sccsid[] = "@(#)room.c 8.1 (Berkeley) 5/31/93"; 40 #endif 41 static const char rcsid[] = 42 "$FreeBSD: src/games/rogue/room.c,v 1.7 1999/11/30 03:49:26 billf Exp $"; 43 #endif /* not lint */ 44 45 /* 46 * room.c 47 * 48 * This source herein may be modified and/or distributed by anybody who 49 * so desires, with the following restrictions: 50 * 1.) No portion of this notice shall be removed. 51 * 2.) Credit shall not be taken for the creation of this source. 52 * 3.) This code is not to be traded, sold, or used for personal 53 * gain or profit. 54 * 55 */ 56 57 #include "rogue.h" 58 59 room rooms[MAXROOMS]; 60 boolean rooms_visited[MAXROOMS]; 61 62 extern short blind; 63 extern boolean detect_monster, jump, passgo, no_skull, ask_quit, flush; 64 extern char *nick_name, *fruit, *save_file, *press_space; 65 66 #define NOPTS 8 67 68 struct option { 69 const char *prompt; 70 boolean is_bool; 71 char **strval; 72 boolean *bval; 73 } options[NOPTS] = { 74 { 75 "Flush typeahead during battle (\"flush\"): ", 76 1, (char **) 0, &flush 77 }, 78 { 79 "Show position only at end of run (\"jump\"): ", 80 1, (char **) 0, &jump 81 }, 82 { 83 "Follow turnings in passageways (\"passgo\"): ", 84 1, (char **) 0, &passgo 85 }, 86 { 87 "Don't print skull when killed (\"noskull\" or \"notombstone\"): ", 88 1, (char **) 0, &no_skull 89 }, 90 { 91 "Ask player before saying 'Okay, bye-bye!' (\"askquit\"): ", 92 1, (char **) 0, &ask_quit 93 }, 94 { 95 "Name (\"name\"): ", 96 0, &nick_name 97 }, 98 { 99 "Fruit (\"fruit\"): ", 100 0, &fruit 101 }, 102 { 103 "Save file (\"file\"): ", 104 0, &save_file 105 } 106 }; 107 108 light_up_room(rn) 109 int rn; 110 { 111 short i, j; 112 113 if (!blind) { 114 for (i = rooms[rn].top_row; 115 i <= rooms[rn].bottom_row; i++) { 116 for (j = rooms[rn].left_col; 117 j <= rooms[rn].right_col; j++) { 118 if (dungeon[i][j] & MONSTER) { 119 object *monster; 120 121 if (monster = object_at(&level_monsters, i, j)) { 122 dungeon[monster->row][monster->col] &= (~MONSTER); 123 monster->trail_char = 124 get_dungeon_char(monster->row, monster->col); 125 dungeon[monster->row][monster->col] |= MONSTER; 126 } 127 } 128 mvaddch(i, j, get_dungeon_char(i, j)); 129 } 130 } 131 mvaddch(rogue.row, rogue.col, rogue.fchar); 132 } 133 } 134 135 light_passage(row, col) 136 int row, col; 137 { 138 short i, j, i_end, j_end; 139 140 if (blind) { 141 return; 142 } 143 i_end = (row < (DROWS-2)) ? 1 : 0; 144 j_end = (col < (DCOLS-1)) ? 1 : 0; 145 146 for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) { 147 for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) { 148 if (can_move(row, col, row+i, col+j)) { 149 mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j)); 150 } 151 } 152 } 153 } 154 155 darken_room(rn) 156 short rn; 157 { 158 short i, j; 159 160 for (i = rooms[rn].top_row + 1; i < rooms[rn].bottom_row; i++) { 161 for (j = rooms[rn].left_col + 1; j < rooms[rn].right_col; j++) { 162 if (blind) { 163 mvaddch(i, j, ' '); 164 } else { 165 if (!(dungeon[i][j] & (OBJECT | STAIRS)) && 166 !(detect_monster && (dungeon[i][j] & MONSTER))) { 167 if (!imitating(i, j)) { 168 mvaddch(i, j, ' '); 169 } 170 if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) { 171 mvaddch(i, j, '^'); 172 } 173 } 174 } 175 } 176 } 177 } 178 179 get_dungeon_char(row, col) 180 int 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 get_mask_char(mask) 228 unsigned short mask; 229 { 230 switch(mask) { 231 case SCROL: 232 return('?'); 233 case POTION: 234 return('!'); 235 case GOLD: 236 return('*'); 237 case FOOD: 238 return(':'); 239 case WAND: 240 return('/'); 241 case ARMOR: 242 return(']'); 243 case WEAPON: 244 return(')'); 245 case RING: 246 return('='); 247 case AMULET: 248 return(','); 249 default: 250 return('~'); /* unknown, something is wrong */ 251 } 252 } 253 254 gr_row_col(row, col, mask) 255 short *row, *col; 256 unsigned short mask; 257 { 258 short rn; 259 short r, c; 260 261 do { 262 r = get_rand(MIN_ROW, DROWS-2); 263 c = get_rand(0, DCOLS-1); 264 rn = get_room_number(r, c); 265 } while ((rn == NO_ROOM) || 266 (!(dungeon[r][c] & mask)) || 267 (dungeon[r][c] & (~mask)) || 268 (!(rooms[rn].is_room & (R_ROOM | R_MAZE))) || 269 ((r == rogue.row) && (c == rogue.col))); 270 271 *row = r; 272 *col = c; 273 } 274 275 gr_room() 276 { 277 short i; 278 279 do { 280 i = get_rand(0, MAXROOMS-1); 281 } while (!(rooms[i].is_room & (R_ROOM | R_MAZE))); 282 283 return(i); 284 } 285 286 party_objects(rn) 287 { 288 short i, j, nf = 0; 289 object *obj; 290 short n, N, row, col; 291 boolean found; 292 293 N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) * 294 ((rooms[rn].right_col - rooms[rn].left_col) - 1); 295 n = get_rand(5, 10); 296 if (n > N) { 297 n = N - 2; 298 } 299 for (i = 0; i < n; i++) { 300 for (j = found = 0; ((!found) && (j < 250)); j++) { 301 row = get_rand(rooms[rn].top_row+1, 302 rooms[rn].bottom_row-1); 303 col = get_rand(rooms[rn].left_col+1, 304 rooms[rn].right_col-1); 305 if ((dungeon[row][col] == FLOOR) || (dungeon[row][col] == TUNNEL)) { 306 found = 1; 307 } 308 } 309 if (found) { 310 obj = gr_object(); 311 place_at(obj, row, col); 312 nf++; 313 } 314 } 315 return(nf); 316 } 317 318 get_room_number(row, col) 319 int row, col; 320 { 321 short i; 322 323 for (i = 0; i < MAXROOMS; i++) { 324 if ((row >= rooms[i].top_row) && (row <= rooms[i].bottom_row) && 325 (col >= rooms[i].left_col) && (col <= rooms[i].right_col)) { 326 return(i); 327 } 328 } 329 return(NO_ROOM); 330 } 331 332 is_all_connected() 333 { 334 short i, starting_room; 335 336 for (i = 0; i < MAXROOMS; i++) { 337 rooms_visited[i] = 0; 338 if (rooms[i].is_room & (R_ROOM | R_MAZE)) { 339 starting_room = i; 340 } 341 } 342 343 visit_rooms(starting_room); 344 345 for (i = 0; i < MAXROOMS; i++) { 346 if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) { 347 return(0); 348 } 349 } 350 return(1); 351 } 352 353 visit_rooms(rn) 354 int rn; 355 { 356 short i; 357 short oth_rn; 358 359 rooms_visited[rn] = 1; 360 361 for (i = 0; i < 4; i++) { 362 oth_rn = rooms[rn].doors[i].oth_room; 363 if ((oth_rn >= 0) && (!rooms_visited[oth_rn])) { 364 visit_rooms(oth_rn); 365 } 366 } 367 } 368 369 draw_magic_map() 370 { 371 short i, j, ch, och; 372 unsigned short mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS | 373 MONSTER); 374 unsigned short s; 375 376 for (i = 0; i < DROWS; i++) { 377 for (j = 0; j < DCOLS; j++) { 378 s = dungeon[i][j]; 379 if (s & mask) { 380 if (((ch = mvinch(i, j)) == ' ') || 381 ((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) { 382 och = ch; 383 dungeon[i][j] &= (~HIDDEN); 384 if (s & HORWALL) { 385 ch = '-'; 386 } else if (s & VERTWALL) { 387 ch = '|'; 388 } else if (s & DOOR) { 389 ch = '+'; 390 } else if (s & TRAP) { 391 ch = '^'; 392 } else if (s & STAIRS) { 393 ch = '%'; 394 } else if (s & TUNNEL) { 395 ch = '#'; 396 } else { 397 continue; 398 } 399 if ((!(s & MONSTER)) || (och == ' ')) { 400 addch(ch); 401 } 402 if (s & MONSTER) { 403 object *monster; 404 405 if (monster = object_at(&level_monsters, i, j)) { 406 monster->trail_char = ch; 407 } 408 } 409 } 410 } 411 } 412 } 413 } 414 415 dr_course(monster, entering, row, col) 416 object *monster; 417 boolean entering; 418 short row, col; 419 { 420 short i, j, k, rn; 421 short r, rr; 422 423 monster->row = row; 424 monster->col = col; 425 426 if (mon_sees(monster, rogue.row, rogue.col)) { 427 monster->trow = NO_ROOM; 428 return; 429 } 430 rn = get_room_number(row, col); 431 432 if (entering) { /* entering room */ 433 /* look for door to some other room */ 434 r = get_rand(0, MAXROOMS-1); 435 for (i = 0; i < MAXROOMS; i++) { 436 rr = (r + i) % MAXROOMS; 437 if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) { 438 continue; 439 } 440 for (k = 0; k < 4; k++) { 441 if (rooms[rr].doors[k].oth_room == rn) { 442 monster->trow = rooms[rr].doors[k].oth_row; 443 monster->tcol = rooms[rr].doors[k].oth_col; 444 if ((monster->trow == row) && 445 (monster->tcol == col)) { 446 continue; 447 } 448 return; 449 } 450 } 451 } 452 /* look for door to dead end */ 453 for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) { 454 for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) { 455 if ((i != monster->row) && (j != monster->col) && 456 (dungeon[i][j] & DOOR)) { 457 monster->trow = i; 458 monster->tcol = j; 459 return; 460 } 461 } 462 } 463 /* return monster to room that he came from */ 464 for (i = 0; i < MAXROOMS; i++) { 465 for (j = 0; j < 4; j++) { 466 if (rooms[i].doors[j].oth_room == rn) { 467 for (k = 0; k < 4; k++) { 468 if (rooms[rn].doors[k].oth_room == i) { 469 monster->trow = rooms[rn].doors[k].oth_row; 470 monster->tcol = rooms[rn].doors[k].oth_col; 471 return; 472 } 473 } 474 } 475 } 476 } 477 /* no place to send monster */ 478 monster->trow = NO_ROOM; 479 } else { /* exiting room */ 480 if (!get_oth_room(rn, &row, &col)) { 481 monster->trow = NO_ROOM; 482 } else { 483 monster->trow = row; 484 monster->tcol = col; 485 } 486 } 487 } 488 489 get_oth_room(rn, row, col) 490 short rn, *row, *col; 491 { 492 short d = -1; 493 494 if (*row == rooms[rn].top_row) { 495 d = UPWARD/2; 496 } else if (*row == rooms[rn].bottom_row) { 497 d = DOWN/2; 498 } else if (*col == rooms[rn].left_col) { 499 d = LEFT/2; 500 } else if (*col == rooms[rn].right_col) { 501 d = RIGHT/2; 502 } 503 if ((d != -1) && (rooms[rn].doors[d].oth_room >= 0)) { 504 *row = rooms[rn].doors[d].oth_row; 505 *col = rooms[rn].doors[d].oth_col; 506 return(1); 507 } 508 return(0); 509 } 510 511 edit_opts() 512 { 513 char save[NOPTS+1][DCOLS]; 514 short i, j; 515 short ch; 516 boolean done = 0; 517 char buf[MAX_OPT_LEN + 2]; 518 519 for (i = 0; i < NOPTS+1; i++) { 520 for (j = 0; j < DCOLS; j++) { 521 save[i][j] = mvinch(i, j); 522 } 523 if (i < NOPTS) { 524 opt_show(i); 525 } 526 } 527 opt_go(0); 528 i = 0; 529 530 while (!done) { 531 refresh(); 532 ch = rgetchar(); 533 CH: 534 switch(ch) { 535 case '\033': 536 done = 1; 537 break; 538 case '\012': 539 case '\015': 540 if (i == (NOPTS - 1)) { 541 mvaddstr(NOPTS, 0, press_space); 542 refresh(); 543 wait_for_ack(); 544 done = 1; 545 } else { 546 i++; 547 opt_go(i); 548 } 549 break; 550 case '-': 551 if (i > 0) { 552 opt_go(--i); 553 } else { 554 sound_bell(); 555 } 556 break; 557 case 't': 558 case 'T': 559 case 'f': 560 case 'F': 561 if (options[i].is_bool) { 562 *(options[i].bval) = (((ch == 't') || (ch == 'T')) ? 1 : 0); 563 opt_show(i); 564 opt_go(++i); 565 break; 566 } 567 default: 568 if (options[i].is_bool) { 569 sound_bell(); 570 break; 571 } 572 j = 0; 573 if ((ch == '\010') || ((ch >= ' ') && (ch <= '~'))) { 574 opt_erase(i); 575 do { 576 if ((ch >= ' ') && (ch <= '~') && (j < MAX_OPT_LEN)) { 577 buf[j++] = ch; 578 buf[j] = '\0'; 579 addch(ch); 580 } else if ((ch == '\010') && (j > 0)) { 581 buf[--j] = '\0'; 582 move(i, j + strlen(options[i].prompt)); 583 addch(' '); 584 move(i, j + strlen(options[i].prompt)); 585 } 586 refresh(); 587 ch = rgetchar(); 588 } while ((ch != '\012') && (ch != '\015') && (ch != '\033')); 589 if (j != 0) { 590 (void) strcpy(*(options[i].strval), buf); 591 } 592 opt_show(i); 593 goto CH; 594 } else { 595 sound_bell(); 596 } 597 break; 598 } 599 } 600 601 for (i = 0; i < NOPTS+1; i++) { 602 move(i, 0); 603 for (j = 0; j < DCOLS; j++) { 604 addch(save[i][j]); 605 } 606 } 607 } 608 609 opt_show(i) 610 int i; 611 { 612 const char *s; 613 struct option *opt = &options[i]; 614 615 opt_erase(i); 616 617 if (opt->is_bool) { 618 s = *(opt->bval) ? "True" : "False"; 619 } else { 620 s = *(opt->strval); 621 } 622 addstr(s); 623 } 624 625 opt_erase(i) 626 int i; 627 { 628 struct option *opt = &options[i]; 629 630 mvaddstr(i, 0, opt->prompt); 631 clrtoeol(); 632 } 633 634 opt_go(i) 635 int i; 636 { 637 move(i, strlen(options[i].prompt)); 638 } 639 640 do_shell() 641 { 642 #ifdef UNIX 643 const char *sh; 644 645 md_ignore_signals(); 646 if (!(sh = md_getenv("SHELL"))) { 647 sh = "/bin/sh"; 648 } 649 move(LINES-1, 0); 650 refresh(); 651 stop_window(); 652 printf("\nCreating new shell...\n"); 653 md_shell(sh); 654 start_window(); 655 wrefresh(curscr); 656 md_heed_signals(); 657 #endif 658 } 659