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