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