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