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