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