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