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 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)room.c 8.1 (Berkeley) 05/31/93";
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
light_up_room(rn)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
light_passage(row,col)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
darken_room(rn)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
get_dungeon_char(row,col)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
get_mask_char(mask)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
gr_row_col(row,col,mask)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
gr_room()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
party_objects(rn)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
get_room_number(row,col)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
is_all_connected()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
visit_rooms(rn)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
draw_magic_map()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
dr_course(monster,entering,row,col)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
get_oth_room(rn,row,col)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
edit_opts()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
opt_show(i)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
opt_erase(i)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
opt_go(i)599 opt_go(i)
600 int i;
601 {
602 move(i, strlen(options[i].prompt));
603 }
604
do_shell()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