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