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