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