Commit | Line | Data |
---|---|---|
8bb0f55f WJ |
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[] = "@(#)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 | ||
55 | room rooms[MAXROOMS]; | |
56 | boolean rooms_visited[MAXROOMS]; | |
57 | ||
58 | extern short blind; | |
59 | extern boolean detect_monster, jump, passgo, no_skull, ask_quit; | |
60 | extern char *nick_name, *fruit, *save_file, *press_space; | |
61 | ||
62 | #define NOPTS 7 | |
63 | ||
64 | struct 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 | ||
100 | light_up_room(rn) | |
101 | int 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 | ||
127 | light_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 | ||
146 | darken_room(rn) | |
147 | short 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 | ||
170 | get_dungeon_char(row, col) | |
171 | register 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 | ||
218 | get_mask_char(mask) | |
219 | register 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 | ||
245 | gr_row_col(row, col, mask) | |
246 | short *row, *col; | |
247 | unsigned 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 | ||
266 | gr_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 | ||
277 | party_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 | ||
309 | get_room_number(row, col) | |
310 | register 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 | ||
323 | is_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 | ||
344 | visit_rooms(rn) | |
345 | int 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 | ||
360 | draw_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 | ||
406 | dr_course(monster, entering, row, col) | |
407 | object *monster; | |
408 | boolean entering; | |
409 | short 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 | ||
480 | get_oth_room(rn, row, col) | |
481 | short 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 | ||
502 | edit_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(); | |
524 | CH: | |
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 | ||
600 | opt_show(i) | |
601 | int 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 | ||
616 | opt_erase(i) | |
617 | int i; | |
618 | { | |
619 | struct option *opt = &options[i]; | |
620 | ||
621 | mvaddstr(i, 0, opt->prompt); | |
622 | clrtoeol(); | |
623 | } | |
624 | ||
625 | opt_go(i) | |
626 | int i; | |
627 | { | |
628 | move(i, strlen(options[i].prompt)); | |
629 | } | |
630 | ||
631 | do_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 | } |