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