1 /* SCCS Id: @(#)lev_main.c 3.4 2002/03/27 */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /*
6 * This file contains the main function for the parser
7 * and some useful functions needed by yacc
8 */
9 #define SPEC_LEV /* for MPW */
10 /* although, why don't we move those special defines here.. and in dgn_main? */
11
12 #include <stdarg.h>
13
14 #include "hack.h"
15 #include "date.h"
16 #include "sp_lev.h"
17 #ifdef STRICT_REF_DEF
18 #include "tcap.h"
19 #endif
20
21 #ifdef MAC
22 # if defined(__SC__) || defined(__MRC__)
23 # define MPWTOOL
24 # define PREFIX ":dungeon:" /* place output files here */
25 # include <CursorCtl.h>
26 # else
27 # if !defined(__MACH__)
28 # define PREFIX ":lib:" /* place output files here */
29 # endif
30 # endif
31 #endif
32
33 #ifdef WIN_CE
34 #define PREFIX "\\nethack\\dat\\"
35 #endif
36
37 #ifndef MPWTOOL
38 # define SpinCursor(x)
39 #endif
40
41 #if defined(AMIGA) && defined(DLB)
42 # define PREFIX "NH:slib/"
43 #endif
44
45 #ifndef O_WRONLY
46 #include <fcntl.h>
47 #endif
48 #ifndef O_CREAT /* some older BSD systems do not define O_CREAT in <fcntl.h> */
49 #include <sys/file.h>
50 #endif
51 #ifndef O_BINARY /* used for micros, no-op for others */
52 # define O_BINARY 0
53 #endif
54
55 #if defined(MICRO) || defined(WIN32)
56 # define OMASK FCMASK
57 #else
58 # define OMASK 0644
59 #endif
60
61 #define ERR (-1)
62
63 #define NewTab(type, size) (type **) alloc(sizeof(type *) * size)
64 #define Free(ptr) if(ptr) free((genericptr_t) (ptr))
65 #define Write(fd, item, size) if (write(fd, (genericptr_t)(item), size) != size) return FALSE;
66
67 #if defined(__BORLANDC__) && !defined(_WIN32)
68 extern unsigned _stklen = STKSIZ;
69 #endif
70 #define MAX_ERRORS 25
71
72 extern int NDECL (yyparse);
73 extern void FDECL (init_yyin, (FILE *));
74 extern void FDECL (init_yyout, (FILE *));
75
76 int FDECL (main, (int, char **));
77 void FDECL (yyerror, (const char *));
78 void FDECL (yywarning, (const char *));
79 int NDECL (yywrap);
80 int FDECL(get_floor_type, (CHAR_P));
81 int FDECL(get_room_type, (char *));
82 int FDECL(get_trap_type, (char *));
83 int FDECL(get_monster_id, (char *,CHAR_P));
84 int FDECL(get_object_id, (char *,CHAR_P));
85 boolean FDECL(check_monster_char, (CHAR_P));
86 boolean FDECL(check_object_char, (CHAR_P));
87 char FDECL(what_map_char, (CHAR_P));
88 void FDECL(scan_map, (char *, sp_lev *));
89 boolean FDECL(check_subrooms, (sp_lev *));
90 boolean FDECL(write_level_file, (char *,sp_lev *));
91
92 struct lc_funcdefs *FDECL(funcdef_new,(long,char *));
93 void FDECL(funcdef_free_all,(struct lc_funcdefs *));
94 struct lc_funcdefs *FDECL(funcdef_defined,(struct lc_funcdefs *,char *, int));
95
96 struct lc_vardefs *FDECL(vardef_new,(long,char *));
97 void FDECL(vardef_free_all,(struct lc_vardefs *));
98 struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int));
99
100 void FDECL(splev_add_from, (sp_lev *, sp_lev *));
101
102 extern void NDECL(monst_init);
103 extern void NDECL(objects_init);
104 extern void NDECL(decl_init);
105
106 void FDECL(add_opcode, (sp_lev *, int, genericptr_t));
107
108 static boolean FDECL(write_common_data, (int,sp_lev *));
109 static boolean FDECL(write_maze, (int,sp_lev *));
110 static void NDECL(init_obj_classes);
111
112 static struct {
113 const char *name;
114 int type;
115 } trap_types[] = {
116 { "arrow", ARROW_TRAP },
117 { "dart", DART_TRAP },
118 { "falling rock", ROCKTRAP },
119 { "board", SQKY_BOARD },
120 { "bear", BEAR_TRAP },
121 { "land mine", LANDMINE },
122 { "rolling boulder", ROLLING_BOULDER_TRAP },
123 { "sleep gas", SLP_GAS_TRAP },
124 { "rust", RUST_TRAP },
125 { "fire", FIRE_TRAP },
126 { "pit", PIT },
127 { "spiked pit", SPIKED_PIT },
128 { "hole", HOLE },
129 { "trap door", TRAPDOOR },
130 { "teleport", TELEP_TRAP },
131 { "level teleport", LEVEL_TELEP },
132 { "magic portal", MAGIC_PORTAL },
133 { "web", WEB },
134 { "statue", STATUE_TRAP },
135 { "magic", MAGIC_TRAP },
136 { "anti magic", ANTI_MAGIC },
137 { "polymorph", POLY_TRAP },
138 { 0, 0 }
139 };
140
141 static struct {
142 const char *name;
143 int type;
144 } room_types[] = {
145 /* for historical reasons, room types are not contiguous numbers */
146 /* (type 1 is skipped) */
147 { "ordinary", OROOM },
148 { "throne", COURT },
149 { "swamp", SWAMP },
150 { "vault", VAULT },
151 { "beehive", BEEHIVE },
152 { "morgue", MORGUE },
153 { "barracks", BARRACKS },
154 { "zoo", ZOO },
155 { "delphi", DELPHI },
156 { "temple", TEMPLE },
157 { "lemurepit", LEMUREPIT },
158 { "anthole", ANTHOLE },
159 { "cocknest", COCKNEST },
160 { "garden", GARDEN },
161 { "leprehall", LEPREHALL },
162 { "shop", SHOPBASE },
163 { "armor shop", ARMORSHOP },
164 { "scroll shop", SCROLLSHOP },
165 { "potion shop", POTIONSHOP },
166 { "weapon shop", WEAPONSHOP },
167 { "food shop", FOODSHOP },
168 { "ring shop", RINGSHOP },
169 { "wand shop", WANDSHOP },
170 { "tool shop", TOOLSHOP },
171 { "book shop", BOOKSHOP },
172 { "tin shop", TINSHOP },
173 { "music shop", INSTRUMENTSHOP },
174 { "candle shop", CANDLESHOP },
175 { "pet shop", PETSHOP }, /* Stephen White */
176 #ifdef BLACKMARKET
177 { "black market", BLACKSHOP },
178 #endif /* BLACKMARKET */
179 { 0, 0 }
180 };
181
182 const char *fname = "(stdin)";
183 int fatal_error = 0;
184 int got_errors = 0;
185 int be_verbose = 0;
186 int decompile = 0;
187
188 #ifdef FLEX23_BUG
189 /* Flex 2.3 bug work around; not needed for 2.3.6 or later */
190 int yy_more_len = 0;
191 #endif
192
193 extern unsigned int max_x_map, max_y_map;
194
195 extern int line_number, colon_line_number;
196
197 struct lc_vardefs *variable_definitions = NULL;
198
199
200 int
main(argc,argv)201 main(argc, argv)
202 int argc;
203 char **argv;
204 {
205 FILE *fin;
206 int i;
207 boolean errors_encountered = FALSE;
208 #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
209 static char *mac_argv[] = { "lev_comp", /* dummy argv[0] */
210 ":dat:Arch.des",
211 ":dat:Barb.des",
212 ":dat:Caveman.des",
213 ":dat:Healer.des",
214 ":dat:Knight.des",
215 ":dat:Monk.des",
216 ":dat:Priest.des",
217 ":dat:Ranger.des",
218 ":dat:Rogue.des",
219 ":dat:Samurai.des",
220 ":dat:Tourist.des",
221 ":dat:Valkyrie.des",
222 ":dat:Wizard.des",
223 ":dat:bigroom.des",
224 ":dat:castle.des",
225 ":dat:endgame.des",
226 ":dat:gehennom.des",
227 ":dat:knox.des",
228 ":dat:medusa.des",
229 ":dat:mines.des",
230 ":dat:oracle.des",
231 ":dat:sokoban.des",
232 ":dat:tower.des",
233 ":dat:yendor.des"
234 };
235
236 argc = SIZE(mac_argv);
237 argv = mac_argv;
238 #endif
239 /* Note: these initializers don't do anything except guarantee that
240 we're linked properly.
241 */
242 monst_init();
243 objects_init();
244 decl_init();
245 /* this one does something... */
246 init_obj_classes();
247
248 init_yyout(stdout);
249 if (argc == 1) { /* Read standard input */
250 init_yyin(stdin);
251 (void) yyparse();
252 if (fatal_error > 0 || got_errors > 0) {
253 errors_encountered = TRUE;
254 }
255 } else { /* Otherwise every argument is a filename */
256 for(i=1; i<argc; i++) {
257 fname = argv[i];
258 if(!strcmp(fname, "-v")) {
259 be_verbose++;
260 continue;
261 }
262 if(!strcmp(fname, "-d")) {
263 decompile = 1;
264 continue;
265 }
266 fin = freopen(fname, "r", stdin);
267 if (!fin) {
268 (void) fprintf(stderr,"Can't open \"%s\" for input.\n",
269 fname);
270 perror(fname);
271 errors_encountered = TRUE;
272 } else {
273 init_yyin(fin);
274 (void) yyparse();
275 line_number = 1;
276 if (fatal_error > 0 || got_errors > 0) {
277 errors_encountered = TRUE;
278 fatal_error = 0;
279 }
280 }
281 (void) fclose(fin);
282 }
283 }
284 exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
285 /*NOTREACHED*/
286 return 0;
287 }
288
289 /*
290 * Each time the parser detects an error, it uses this function.
291 * Here we take count of the errors. To continue farther than
292 * MAX_ERRORS wouldn't be reasonable.
293 * Assume that explicit calls from lev_comp.y have the 1st letter
294 * capitalized, to allow printing of the line containing the start of
295 * the current declaration, instead of the beginning of the next declaration.
296 */
297 void
yyerror(s)298 yyerror(s)
299 const char *s;
300 {
301 (void) fprintf(stderr, "%s: line %d : %s\n", fname,
302 (*s >= 'A' && *s <= 'Z') ? colon_line_number : line_number, s);
303 if (++fatal_error > MAX_ERRORS) {
304 (void) fprintf(stderr,"Too many errors, good bye!\n");
305 exit(EXIT_FAILURE);
306 }
307 }
308
309
310 void
lc_error(const char * fmt,...)311 lc_error(const char *fmt, ...)
312 {
313 char buf[512];
314 va_list argp;
315
316 va_start(argp, fmt);
317 (void) vsnprintf(buf, 511, fmt, argp);
318 va_end(argp);
319
320 yyerror(buf);
321 }
322
323
324 /*
325 * Just display a warning (that is : a non fatal error)
326 */
327 void
yywarning(s)328 yywarning(s)
329 const char *s;
330 {
331 (void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
332 fname, colon_line_number, s);
333 }
334
335 void
lc_warning(const char * fmt,...)336 lc_warning(const char *fmt, ...)
337 {
338 char buf[512];
339 va_list argp;
340
341 va_start(argp, fmt);
342 (void) vsnprintf(buf, 511, fmt, argp);
343 va_end(argp);
344
345 yywarning(buf);
346 }
347
348
349 struct opvar *
set_opvar_int(ov,val)350 set_opvar_int(ov, val)
351 struct opvar *ov;
352 long val;
353 {
354 if (ov) {
355 ov->spovartyp = SPOVAR_INT;
356 ov->vardata.l = val;
357 }
358 return ov;
359 }
360
361 struct opvar *
set_opvar_coord(ov,val)362 set_opvar_coord(ov, val)
363 struct opvar *ov;
364 long val;
365 {
366 if (ov) {
367 ov->spovartyp = SPOVAR_COORD;
368 ov->vardata.l = val;
369 }
370 return ov;
371 }
372
373 struct opvar *
set_opvar_region(ov,val)374 set_opvar_region(ov, val)
375 struct opvar *ov;
376 long val;
377 {
378 if (ov) {
379 ov->spovartyp = SPOVAR_REGION;
380 ov->vardata.l = val;
381 }
382 return ov;
383 }
384
385 struct opvar *
set_opvar_mapchar(ov,val)386 set_opvar_mapchar(ov, val)
387 struct opvar *ov;
388 long val;
389 {
390 if (ov) {
391 ov->spovartyp = SPOVAR_MAPCHAR;
392 ov->vardata.l = val;
393 }
394 return ov;
395 }
396
397 struct opvar *
set_opvar_monst(ov,val)398 set_opvar_monst(ov, val)
399 struct opvar *ov;
400 long val;
401 {
402 if (ov) {
403 ov->spovartyp = SPOVAR_MONST;
404 ov->vardata.l = val;
405 }
406 return ov;
407 }
408
409 struct opvar *
set_opvar_obj(ov,val)410 set_opvar_obj(ov, val)
411 struct opvar *ov;
412 long val;
413 {
414 if (ov) {
415 ov->spovartyp = SPOVAR_OBJ;
416 ov->vardata.l = val;
417 }
418 return ov;
419 }
420
421 struct opvar *
set_opvar_str(ov,val)422 set_opvar_str(ov, val)
423 struct opvar *ov;
424 char *val;
425 {
426 if (ov) {
427 ov->spovartyp = SPOVAR_STRING;
428 ov->vardata.str = (val) ? strdup(val) : NULL;
429 }
430 return ov;
431 }
432
433 struct opvar *
set_opvar_var(ov,val)434 set_opvar_var(ov, val)
435 struct opvar *ov;
436 char *val;
437 {
438 if (ov) {
439 ov->spovartyp = SPOVAR_VARIABLE;
440 ov->vardata.str = (val) ? strdup(val) : NULL;
441 }
442 return ov;
443 }
444
445 #define New(type) \
446 (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type))
447
448 void
add_opvars(sp_lev * sp,const char * fmt,...)449 add_opvars(sp_lev *sp, const char *fmt, ...)
450 {
451 const char *p;
452 va_list argp;
453
454 va_start(argp, fmt);
455
456 for(p = fmt; *p != '\0'; p++) {
457 switch(*p) {
458 case ' ': break;
459 case 'i':
460 {
461 struct opvar *ov = New(struct opvar);
462 set_opvar_int(ov, va_arg(argp, long));
463 add_opcode(sp, SPO_PUSH, ov);
464 break;
465 }
466 case 'c':
467 {
468 struct opvar *ov = New(struct opvar);
469 set_opvar_coord(ov, va_arg(argp, long));
470 add_opcode(sp, SPO_PUSH, ov);
471 break;
472 }
473 case 'r':
474 {
475 struct opvar *ov = New(struct opvar);
476 set_opvar_region(ov, va_arg(argp, long));
477 add_opcode(sp, SPO_PUSH, ov);
478 break;
479 }
480 case 'm':
481 {
482 struct opvar *ov = New(struct opvar);
483 set_opvar_mapchar(ov, va_arg(argp, long));
484 add_opcode(sp, SPO_PUSH, ov);
485 break;
486 }
487 case 'M':
488 {
489 struct opvar *ov = New(struct opvar);
490 set_opvar_monst(ov, va_arg(argp, long));
491 add_opcode(sp, SPO_PUSH, ov);
492 break;
493 }
494 case 'O':
495 {
496 struct opvar *ov = New(struct opvar);
497 set_opvar_obj(ov, va_arg(argp, long));
498 add_opcode(sp, SPO_PUSH, ov);
499 break;
500 }
501 case 's':
502 {
503 struct opvar *ov = New(struct opvar);
504 set_opvar_str(ov, va_arg(argp, char *));
505 add_opcode(sp, SPO_PUSH, ov);
506 break;
507 }
508 case 'v':
509 {
510 struct opvar *ov = New(struct opvar);
511 set_opvar_var(ov, va_arg(argp, char *));
512 add_opcode(sp, SPO_PUSH, ov);
513 break;
514 }
515 case 'o':
516 {
517 long i = va_arg(argp, int);
518 if (i < 0 || i >= MAX_SP_OPCODES)
519 fprintf(stderr, "add_opvars: unknown opcode '%i'.\n", i);
520 add_opcode(sp, i, NULL);
521 break;
522 }
523 default:
524 fprintf(stderr, "add_opvars: illegal format character '%c'.\n", *p);
525 break;
526 }
527 }
528
529 va_end(argp);
530 }
531
532
533 struct lc_funcdefs *
funcdef_new(addr,name)534 funcdef_new(addr, name)
535 long addr;
536 char *name;
537 {
538 struct lc_funcdefs *f = New(struct lc_funcdefs);
539 if (!f) {
540 lc_error("Could not alloc function definition for '%s'.", name);
541 return NULL;
542 }
543 f->next = NULL;
544 f->addr = addr;
545 f->name = strdup(name);
546 f->n_called = 0;
547 f->code.opcodes = NULL;
548 f->code.n_opcodes = 0;
549 return f;
550 }
551
552 void
funcdef_free_all(fchain)553 funcdef_free_all(fchain)
554 struct lc_funcdefs *fchain;
555 {
556 struct lc_funcdefs *tmp = fchain;
557 struct lc_funcdefs *nxt;
558 while (tmp) {
559 nxt = tmp->next;
560 Free(tmp->name);
561 /* FIXME: free tmp->code */
562 Free(tmp);
563 tmp = nxt;
564 }
565 }
566
567 struct lc_funcdefs *
funcdef_defined(f,name,casesense)568 funcdef_defined(f, name, casesense)
569 struct lc_funcdefs *f;
570 char *name;
571 int casesense;
572 {
573 while (f) {
574 if (casesense) {
575 if (!strcmp(name, f->name)) return f;
576 } else {
577 if (!strcasecmp(name, f->name)) return f;
578 }
579 f = f->next;
580 }
581 return NULL;
582 }
583
584
585 struct lc_vardefs *
vardef_new(typ,name)586 vardef_new(typ, name)
587 long typ;
588 char *name;
589 {
590 struct lc_vardefs *f = New(struct lc_vardefs);
591 if (!f) {
592 lc_error("Could not alloc variable definition for '%s'.", name);
593 return NULL;
594 }
595 f->next = NULL;
596 f->var_type = typ;
597 f->name = strdup(name);
598 return f;
599 }
600
601 void
vardef_free_all(fchain)602 vardef_free_all(fchain)
603 struct lc_vardefs *fchain;
604 {
605 struct lc_vardefs *tmp = fchain;
606 struct lc_vardefs *nxt;
607 while (tmp) {
608 nxt = tmp->next;
609 Free(tmp->name);
610 Free(tmp);
611 tmp = nxt;
612 }
613 }
614
615 struct lc_vardefs *
vardef_defined(f,name,casesense)616 vardef_defined(f, name, casesense)
617 struct lc_vardefs *f;
618 char *name;
619 int casesense;
620 {
621 while (f) {
622 if (casesense) {
623 if (!strcmp(name, f->name)) return f;
624 } else {
625 if (!strcasecmp(name, f->name)) return f;
626 }
627 f = f->next;
628 }
629 return NULL;
630 }
631
632 const char *
spovar2str(spovar)633 spovar2str(spovar)
634 long spovar;
635 {
636 static togl = 0;
637 static char buf[2][128];
638 char *n;
639 int is_array = (spovar & SPOVAR_ARRAY);
640 spovar &= ~SPOVAR_ARRAY;
641
642 switch (spovar) {
643 default: lc_error("spovar2str(%li)", spovar); break;
644 case SPOVAR_INT: n = "integer"; break;
645 case SPOVAR_STRING: n = "string"; break;
646 case SPOVAR_VARIABLE: n = "variable"; break;
647 case SPOVAR_COORD: n = "coordinate"; break;
648 case SPOVAR_REGION: n = "region"; break;
649 case SPOVAR_MAPCHAR: n = "mapchar"; break;
650 case SPOVAR_MONST: n = "monster"; break;
651 case SPOVAR_OBJ: n = "object"; break;
652 }
653
654 togl = ((togl + 1) % 2);
655
656 snprintf(buf[togl], 127, "%s%s", n, (is_array ? " array" : ""));
657 return buf[togl];
658 }
659
660 void
check_vardef_type(vd,varname,vartype)661 check_vardef_type(vd, varname, vartype)
662 struct lc_vardefs *vd;
663 char *varname;
664 long vartype;
665 {
666 struct lc_vardefs *tmp;
667 if ((tmp = vardef_defined(vd, varname, 1))) {
668 if (tmp->var_type != vartype)
669 lc_error("Trying to use variable '%s' as %s, when it is %s.",
670 varname, spovar2str(vartype), spovar2str(tmp->var_type));
671 } else lc_error("Variable '%s' not defined.", varname);
672 }
673
674 struct lc_vardefs *
add_vardef_type(vd,varname,vartype)675 add_vardef_type(vd, varname, vartype)
676 struct lc_vardefs *vd;
677 char *varname;
678 long vartype;
679 {
680 struct lc_vardefs *tmp;
681 if ((tmp = vardef_defined(vd, varname, 1))) {
682 if (tmp->var_type != vartype)
683 lc_error("Trying to redefine variable '%s' as %s, when it is %s.",
684 varname, spovar2str(vartype), spovar2str(tmp->var_type));
685 } else {
686 tmp = vardef_new(vartype, varname);
687 tmp->next = vd;
688 return tmp;
689 }
690 return vd;
691 }
692
693 int
reverse_jmp_opcode(opcode)694 reverse_jmp_opcode(opcode)
695 int opcode;
696 {
697 switch (opcode) {
698 case SPO_JE: return SPO_JNE;
699 case SPO_JNE: return SPO_JE;
700 case SPO_JL: return SPO_JGE;
701 case SPO_JG: return SPO_JLE;
702 case SPO_JLE: return SPO_JG;
703 case SPO_JGE: return SPO_JL;
704 default: lc_error("Cannot reverse comparison jmp opcode %i.", opcode); return SPO_NULL;
705 }
706 }
707
708 /* basically copied from src/sp_lev.c */
709 struct opvar *
opvar_clone(ov)710 opvar_clone(ov)
711 struct opvar *ov;
712 {
713 if (ov) {
714 struct opvar *tmpov = (struct opvar *)alloc(sizeof(struct opvar));
715 if (!tmpov) panic("could not alloc opvar struct");
716 switch (ov->spovartyp) {
717 case SPOVAR_COORD:
718 case SPOVAR_REGION:
719 case SPOVAR_MAPCHAR:
720 case SPOVAR_MONST:
721 case SPOVAR_OBJ:
722 case SPOVAR_INT:
723 {
724 tmpov->spovartyp = ov->spovartyp;
725 tmpov->vardata.l = ov->vardata.l;
726 }
727 break;
728 case SPOVAR_VARIABLE:
729 case SPOVAR_STRING:
730 {
731 int len = strlen(ov->vardata.str);
732 tmpov->spovartyp = ov->spovartyp;
733 tmpov->vardata.str = (char *)alloc(len+1);
734 (void)memcpy((genericptr_t)tmpov->vardata.str,
735 (genericptr_t)ov->vardata.str, len);
736 tmpov->vardata.str[len] = '\0';
737 }
738 break;
739 default:
740 {
741 lc_error("Unknown opvar_clone value type (%i)!", ov->spovartyp);
742 }
743 }
744 return tmpov;
745 }
746 return NULL;
747 }
748
749
750 void
splev_add_from(splev,from_splev)751 splev_add_from(splev, from_splev)
752 sp_lev *splev;
753 sp_lev *from_splev;
754 {
755 int i;
756 if (splev && from_splev)
757 for (i = 0; i < from_splev->n_opcodes; i++)
758 add_opcode(splev, from_splev->opcodes[i].opcode, opvar_clone(from_splev->opcodes[i].opdat));
759 }
760
761
762 /*
763 * Find the type of floor, knowing its char representation.
764 */
765 int
get_floor_type(c)766 get_floor_type(c)
767 char c;
768 {
769 int val;
770
771 SpinCursor(3);
772 val = what_map_char(c);
773 if(val == INVALID_TYPE) {
774 val = ERR;
775 lc_warning("Invalid fill character '%c' in MAZE declaration", c);
776 }
777 return val;
778 }
779
780 /*
781 * Find the type of a room in the table, knowing its name.
782 */
783 int
get_room_type(s)784 get_room_type(s)
785 char *s;
786 {
787 register int i;
788
789 SpinCursor(3);
790 for(i=0; room_types[i].name; i++)
791 if (!strcmp(s, room_types[i].name))
792 return ((int) room_types[i].type);
793 return ERR;
794 }
795
796 /*
797 * Find the type of a trap in the table, knowing its name.
798 */
799 int
get_trap_type(s)800 get_trap_type(s)
801 char *s;
802 {
803 register int i;
804
805 SpinCursor(3);
806 for (i=0; trap_types[i].name; i++)
807 if(!strcmp(s,trap_types[i].name))
808 return trap_types[i].type;
809 return ERR;
810 }
811
812 /*
813 * Find the index of a monster in the table, knowing its name.
814 */
815 int
get_monster_id(s,c)816 get_monster_id(s, c)
817 char *s;
818 char c;
819 {
820 register int i, class;
821
822 SpinCursor(3);
823 class = c ? def_char_to_monclass(c) : 0;
824 if (class == MAXMCLASSES) return ERR;
825
826 for (i = LOW_PM; i < NUMMONS; i++)
827 if (!class || class == mons[i].mlet)
828 if (!strcmp(s, mons[i].mname)) return i;
829 /* didn't find it; lets try case insensitive search */
830 for (i = LOW_PM; i < NUMMONS; i++)
831 if (!class || class == mons[i].mlet)
832 if (!strcasecmp(s, mons[i].mname)) {
833 if (be_verbose)
834 lc_warning("Monster type \"%s\" matches \"%s\".", s, mons[i].mname);
835 return i;
836 }
837 return ERR;
838 }
839
840 /*
841 * Find the index of an object in the table, knowing its name.
842 */
843 int
get_object_id(s,c)844 get_object_id(s, c)
845 char *s;
846 char c; /* class */
847 {
848 int i, class;
849 const char *objname;
850
851 SpinCursor(3);
852 class = (c > 0) ? def_char_to_objclass(c) : 0;
853 if (class == MAXOCLASSES) return ERR;
854
855 for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
856 if (class && objects[i].oc_class != class) break;
857 objname = obj_descr[i].oc_name;
858 if (objname && !strcmp(s, objname))
859 return i;
860 }
861
862 for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
863 if (class && objects[i].oc_class != class) break;
864 objname = obj_descr[i].oc_name;
865 if (objname && !strcasecmp(s, objname)) {
866 if (be_verbose)
867 lc_warning("Object type \"%s\" matches \"%s\".", s, objname);
868 return i;
869 }
870 }
871
872 return ERR;
873 }
874
875 static void
init_obj_classes()876 init_obj_classes()
877 {
878 int i, class, prev_class;
879
880 prev_class = -1;
881 for (i = 0; i < NUM_OBJECTS; i++) {
882 class = objects[i].oc_class;
883 if (class != prev_class) {
884 bases[class] = i;
885 prev_class = class;
886 }
887 }
888 }
889
890 /*
891 * Is the character 'c' a valid monster class ?
892 */
893 boolean
check_monster_char(c)894 check_monster_char(c)
895 char c;
896 {
897 return (def_char_to_monclass(c) != MAXMCLASSES);
898 }
899
900 /*
901 * Is the character 'c' a valid object class ?
902 */
903 boolean
check_object_char(c)904 check_object_char(c)
905 char c;
906 {
907 return (def_char_to_objclass(c) != MAXOCLASSES);
908 }
909
910 /*
911 * Convert .des map letter into floor type.
912 */
913 char
what_map_char(c)914 what_map_char(c)
915 char c;
916 {
917 SpinCursor(3);
918 switch(c) {
919 case ' ' : return(STONE);
920 case '#' : return(CORR);
921 case '.' : return(ROOM);
922 case '-' : return(HWALL);
923 case '|' : return(VWALL);
924 case '+' : return(DOOR);
925 case 'A' : return(AIR);
926 case 'B' : return(CROSSWALL); /* hack: boundary location */
927 case 'C' : return(CLOUD);
928 case 'S' : return(SDOOR);
929 case 'H' : return(SCORR);
930 case '{' : return(FOUNTAIN);
931 case '\\' : return(THRONE);
932 case 'K' :
933 #ifdef SINKS
934 return(SINK);
935 #else
936 lc_warning("Sinks ('K') are not allowed in this version! Ignoring...");
937 return(ROOM);
938 #endif
939 case '}' : return(MOAT);
940 case 'P' : return(POOL);
941 case 'L' : return(LAVAPOOL);
942 case 'I' : return(ICE);
943 case 'W' : return(WATER);
944 case 'T' : return (TREE);
945 case 'F' : return (IRONBARS); /* Fe = iron */
946 case 'x' : return(MAX_TYPE); /* 'see-through' */
947 }
948 return(INVALID_TYPE);
949 }
950
951 void
add_opcode(sp,opc,dat)952 add_opcode(sp, opc, dat)
953 sp_lev *sp;
954 int opc;
955 genericptr_t dat;
956 {
957 long nop = sp->n_opcodes;
958 _opcode *tmp;
959
960 if ((opc < 0) || (opc >= MAX_SP_OPCODES))
961 lc_error("Unknown opcode '%i'", opc);
962
963 tmp = (_opcode *)alloc(sizeof(_opcode)*(nop+1));
964 if (sp->opcodes && nop) {
965 (void) memcpy(tmp, sp->opcodes, sizeof(_opcode)*nop);
966 free(sp->opcodes);
967 } else if (!tmp)
968 lc_error("Could not alloc opcode space");
969
970 sp->opcodes = tmp;
971
972 sp->opcodes[nop].opcode = opc;
973 sp->opcodes[nop].opdat = dat;
974
975 sp->n_opcodes++;
976 }
977
978 /*
979 * Yep! LEX gives us the map in a raw mode.
980 * Just analyze it here.
981 */
982 void
scan_map(map,sp)983 scan_map(map, sp)
984 char *map;
985 sp_lev *sp;
986 {
987 register int i, len;
988 register char *s1, *s2;
989 long max_len = 0;
990 long max_hig = 0;
991 char msg[256];
992 char *tmpmap[ROWNO];
993 int dx,dy;
994 char *mbuf;
995
996 /* First, strip out digits 0-9 (line numbering) */
997 for (s1 = s2 = map; *s1; s1++)
998 if (*s1 < '0' || *s1 > '9')
999 *s2++ = *s1;
1000 *s2 = '\0';
1001
1002 /* Second, find the max width of the map */
1003 s1 = map;
1004 while (s1 && *s1) {
1005 s2 = index(s1, '\n');
1006 if (s2) {
1007 len = (int) (s2 - s1);
1008 s1 = s2 + 1;
1009 } else {
1010 len = (int) strlen(s1);
1011 s1 = (char *) 0;
1012 }
1013 if (len > max_len) max_len = len;
1014 }
1015
1016 /* Then parse it now */
1017 while (map && *map) {
1018 tmpmap[max_hig] = (char *) alloc(max_len);
1019 s1 = index(map, '\n');
1020 if (s1) {
1021 len = (int) (s1 - map);
1022 s1++;
1023 } else {
1024 len = (int) strlen(map);
1025 s1 = map + len;
1026 }
1027 for(i=0; i<len; i++)
1028 if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
1029 lc_warning("Invalid character '%c' @ (%d, %d) - replacing with stone", map[i], max_hig, i);
1030 tmpmap[max_hig][i] = STONE;
1031 }
1032 while(i < max_len)
1033 tmpmap[max_hig][i++] = STONE;
1034 map = s1;
1035 max_hig++;
1036 }
1037
1038 /* Memorize boundaries */
1039
1040 max_x_map = max_len - 1;
1041 max_y_map = max_hig - 1;
1042
1043
1044 if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
1045 lc_error("Map too large at (%d x %d), max is (%d x %d)", max_len, max_hig, MAP_X_LIM, MAP_Y_LIM);
1046 }
1047
1048 mbuf = (char *) alloc(((max_hig-1) * max_len) + (max_len-1) + 2);
1049 for (dy = 0; dy < max_hig; dy++)
1050 for (dx = 0; dx < max_len; dx++)
1051 mbuf[(dy * max_len) + dx] = (tmpmap[dy][dx] + 1);
1052
1053 mbuf[((max_hig-1) * max_len) + (max_len-1) + 1] = '\0';
1054
1055 add_opvars(sp, "siio", mbuf, max_hig, max_len, SPO_MAP);
1056
1057 for (dy = 0; dy < max_hig; dy++)
1058 Free(tmpmap[dy]);
1059 Free(mbuf);
1060 }
1061
1062
1063 /*
1064 * Output some info common to all special levels.
1065 */
1066 static boolean
write_common_data(fd,lvl)1067 write_common_data(fd, lvl)
1068 int fd;
1069 sp_lev *lvl;
1070 {
1071 static struct version_info version_data = {
1072 VERSION_NUMBER, VERSION_FEATURES,
1073 VERSION_SANITY1, VERSION_SANITY2
1074 };
1075
1076 Write(fd, &version_data, sizeof version_data);
1077 /*Write(fd, &lvl->init_lev, sizeof(lev_init));*/
1078 return TRUE;
1079 }
1080
1081
1082 /*
1083 * Here we write the sp_lev structure in the specified file (fd).
1084 * Also, we have to free the memory allocated via alloc().
1085 */
1086 static boolean
write_maze(fd,maze)1087 write_maze(fd, maze)
1088 int fd;
1089 sp_lev *maze;
1090 {
1091 int i;
1092 uchar len;
1093
1094 if (!write_common_data(fd, maze))
1095 return FALSE;
1096
1097 Write(fd, &(maze->n_opcodes), sizeof(maze->n_opcodes));
1098
1099 for (i = 0; i < maze->n_opcodes; i++) {
1100 _opcode tmpo = maze->opcodes[i];
1101
1102 Write(fd, &(tmpo.opcode), sizeof(tmpo.opcode));
1103
1104 if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES)
1105 panic("write_maze: unknown opcode (%i).", tmpo.opcode);
1106
1107 if (tmpo.opcode == SPO_PUSH) {
1108 genericptr_t opdat = tmpo.opdat;
1109 if (opdat) {
1110 struct opvar *ov = (struct opvar *)opdat;
1111 int size;
1112 Write(fd, &(ov->spovartyp), sizeof(ov->spovartyp));
1113 switch (ov->spovartyp) {
1114 case SPOVAR_NULL: break;
1115 case SPOVAR_COORD:
1116 case SPOVAR_REGION:
1117 case SPOVAR_MAPCHAR:
1118 case SPOVAR_MONST:
1119 case SPOVAR_OBJ:
1120 case SPOVAR_INT:
1121 Write(fd, &(ov->vardata.l), sizeof(ov->vardata.l));
1122 break;
1123 case SPOVAR_VARIABLE:
1124 case SPOVAR_STRING:
1125 if (ov->vardata.str)
1126 size = strlen(ov->vardata.str);
1127 else size = 0;
1128 Write(fd, &size, sizeof(size));
1129 if (size) {
1130 Write(fd, ov->vardata.str, size);
1131 Free(ov->vardata.str);
1132 }
1133 break;
1134 default: panic("write_maze: unknown data type (%i).", ov->spovartyp);
1135 }
1136 } else panic("write_maze: PUSH with no data.");
1137 } else {
1138 /* sanity check */
1139 genericptr_t opdat = tmpo.opdat;
1140 if (opdat)
1141 panic("write_maze: opcode (%i) has data.", tmpo.opcode);
1142 }
1143
1144 Free(tmpo.opdat);
1145
1146 }
1147 /* clear the struct for next user */
1148 Free(maze->opcodes);
1149 maze->opcodes = NULL;
1150 /*(void) memset((genericptr_t) &maze->init_lev, 0, sizeof maze->init_lev);*/
1151
1152 return TRUE;
1153 }
1154
1155
1156 static boolean
decompile_maze(fd,maze)1157 decompile_maze(fd, maze)
1158 int fd;
1159 sp_lev *maze;
1160 {
1161 int i;
1162 uchar len;
1163 char debuf[128];
1164 const char *opcodestr[MAX_SP_OPCODES] = {
1165 "null",
1166 "message",
1167 "monster",
1168 "object",
1169 "engraving",
1170 "room",
1171 "subroom",
1172 "door",
1173 "stair",
1174 "ladder",
1175 "altar",
1176 "fountain",
1177 "sink",
1178 "pool",
1179 "trap",
1180 "gold",
1181 "corridor",
1182 "levregion",
1183 "drawbridge",
1184 "mazewalk",
1185 "non_diggable",
1186 "non_passwall",
1187 "wallify",
1188 "map",
1189 "room_door",
1190 "region",
1191 "cmp",
1192 "jmp",
1193 "jl",
1194 "jle",
1195 "jg",
1196 "jge",
1197 "je",
1198 "jne",
1199 "spill",
1200 "terrain",
1201 "replaceterrain",
1202 "exit",
1203 "endroom",
1204 "pop_container",
1205 "push",
1206 "pop",
1207 "rn2",
1208 "dec",
1209 "inc",
1210 "add",
1211 "sub",
1212 "mul",
1213 "div",
1214 "mod",
1215 "copy",
1216 "mon_generation",
1217 "end_moninvent",
1218 "grave",
1219 "frame_push",
1220 "frame_pop",
1221 "call",
1222 "return",
1223 "init_map",
1224 "flags",
1225 "sounds",
1226 "wallwalk",
1227 "var_init",
1228 "shuffle_array",
1229 "dice",
1230 "selection_add",
1231 "selection_point",
1232 "selection_rect",
1233 "selection_fillrect",
1234 "selection_line",
1235 "selection_rndline",
1236 "selection_grow",
1237 "selection_flood",
1238 "selection_rndcoord",
1239 "selection_ellipse",
1240 "selection_filter",
1241 };
1242
1243 /* don't bother with the header stuff */
1244
1245 for (i=0;i<maze->n_opcodes;i++) {
1246 _opcode tmpo = maze->opcodes[i];
1247
1248 if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES)
1249 panic("decompile_maze: unknown opcode (%i).", tmpo.opcode);
1250
1251 if (tmpo.opcode == SPO_PUSH) {
1252 genericptr_t opdat = tmpo.opdat;
1253 if (opdat) {
1254 struct opvar *ov = (struct opvar *)opdat;
1255 int size;
1256 switch (ov->spovartyp) {
1257 case SPOVAR_NULL: break;
1258 case SPOVAR_COORD:
1259 snprintf(debuf, 127, "%li:\t%s\tcoord:(%i,%i)\n", i, opcodestr[tmpo.opcode],
1260 (ov->vardata.l & 0xff), ((ov->vardata.l >> 16) & 0xff));
1261 Write(fd, debuf, strlen(debuf));
1262 break;
1263 case SPOVAR_REGION:
1264 snprintf(debuf, 127, "%li:\t%s\tregion:(%i,%i,%i,%i)\n", i, opcodestr[tmpo.opcode],
1265 (ov->vardata.l & 0xff), ((ov->vardata.l >> 8) & 0xff),
1266 ((ov->vardata.l >> 16) & 0xff), ((ov->vardata.l >> 24) & 0xff));
1267 Write(fd, debuf, strlen(debuf));
1268 break;
1269 case SPOVAR_OBJ:
1270 snprintf(debuf, 127, "%li:\t%s\tobj:(id=%i,class=\'%c\')\n",
1271 i, opcodestr[tmpo.opcode],
1272 SP_OBJ_TYP(ov->vardata.l), SP_OBJ_CLASS(ov->vardata.l));
1273 Write(fd, debuf, strlen(debuf));
1274 break;
1275 case SPOVAR_MONST:
1276 snprintf(debuf, 127, "%li:\t%s\tmonster:(pm=%i, class='%c')\n", i, opcodestr[tmpo.opcode],
1277 SP_MONST_PM(ov->vardata.l), SP_MONST_CLASS(ov->vardata.l));
1278 Write(fd, debuf, strlen(debuf));
1279 break;
1280 case SPOVAR_MAPCHAR:
1281 snprintf(debuf, 127, "%li:\t%s\tmapchar:(%li,%i)\n", i, opcodestr[tmpo.opcode],
1282 (int)SP_MAPCHAR_TYP(ov->vardata.l), (schar)SP_MAPCHAR_LIT(ov->vardata.l));
1283 Write(fd, debuf, strlen(debuf));
1284 break;
1285 case SPOVAR_INT:
1286 if (ov->vardata.l >= ' ' && ov->vardata.l <= '~')
1287 snprintf(debuf, 127, "%li:\t%s\tint:%li\t# '%c'\n", i, opcodestr[tmpo.opcode], ov->vardata.l, (char)ov->vardata.l);
1288 else
1289 snprintf(debuf, 127, "%li:\t%s\tint:%li\n", i, opcodestr[tmpo.opcode], ov->vardata.l);
1290 Write(fd, debuf, strlen(debuf));
1291 break;
1292 case SPOVAR_VARIABLE:
1293 case SPOVAR_STRING:
1294 if (ov->vardata.str)
1295 size = strlen(ov->vardata.str);
1296 else size = 0;
1297 if (size) {
1298 int x;
1299 int ok = (size > 127) ? 0 : 1;
1300 if (ok)
1301 for (x = 0; x < size; x++)
1302 if (ov->vardata.str[x] < ' ' || ov->vardata.str[x] > '~') {
1303 ok = 0;
1304 break;
1305 }
1306 if (ok) {
1307 if (ov->spovartyp == SPOVAR_VARIABLE)
1308 snprintf(debuf, 127, "%li:\t%s\tvar:$%s\n", i, opcodestr[tmpo.opcode], ov->vardata.str);
1309 else
1310 snprintf(debuf, 127, "%li:\t%s\tstr:\"%s\"\n", i, opcodestr[tmpo.opcode], ov->vardata.str);
1311 Write(fd, debuf, strlen(debuf));
1312 } else {
1313 snprintf(debuf, 127, "%li:\t%s\tstr:", i, opcodestr[tmpo.opcode]);
1314 Write(fd, debuf, strlen(debuf));
1315 for (x = 0; x < size; x++) {
1316 snprintf(debuf, 127, "%02x ", ov->vardata.str[x]);
1317 Write(fd, debuf, strlen(debuf));
1318 }
1319 snprintf(debuf, 127, "\n");
1320 Write(fd, debuf, strlen(debuf));
1321 }
1322 }
1323 break;
1324 default: panic("decompile_maze: unknown data type (%i).", ov->spovartyp);
1325 }
1326 } else panic("decompile_maze: PUSH with no data.");
1327 } else {
1328 /* sanity check */
1329 genericptr_t opdat = tmpo.opdat;
1330 if (opdat)
1331 panic("decompile_maze: opcode (%i) has data.", tmpo.opcode);
1332 snprintf(debuf, 127, "%li:\t%s\n", i, opcodestr[tmpo.opcode]);
1333 Write(fd, debuf, strlen(debuf));
1334 }
1335
1336 }
1337 return TRUE;
1338 }
1339
1340 /*
1341 * Open and write special level file.
1342 * Return TRUE on success, FALSE on failure.
1343 */
1344 boolean
write_level_file(filename,lvl)1345 write_level_file(filename, lvl)
1346 char *filename;
1347 sp_lev *lvl;
1348 {
1349 int fout;
1350 char lbuf[60];
1351
1352 if (decompile) {
1353 lbuf[0] = '\0';
1354 #ifdef PREFIX
1355 Strcat(lbuf, PREFIX);
1356 #endif
1357 Strcat(lbuf, filename);
1358 Strcat(lbuf, "_lev.txt");
1359 fout = open(lbuf, O_TRUNC|O_WRONLY|O_CREAT, OMASK);
1360 if (fout < 0) return FALSE;
1361 decompile_maze(fout, lvl);
1362 (void) close(fout);
1363 }
1364
1365 lbuf[0] = '\0';
1366 #ifdef PREFIX
1367 Strcat(lbuf, PREFIX);
1368 #endif
1369 Strcat(lbuf, filename);
1370 Strcat(lbuf, LEV_EXT);
1371
1372 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
1373 if (fout < 0) return FALSE;
1374
1375 if (!lvl) panic("write_level_file");
1376
1377 if (be_verbose)
1378 fprintf(stdout, "File: '%s', opcodes: %li\n", lbuf, lvl->n_opcodes);
1379
1380 if (!write_maze(fout, lvl))
1381 return FALSE;
1382
1383 (void) close(fout);
1384
1385 return TRUE;
1386 }
1387
1388 #ifdef STRICT_REF_DEF
1389 /*
1390 * Any globals declared in hack.h and descendents which aren't defined
1391 * in the modules linked into lev_comp should be defined here. These
1392 * definitions can be dummies: their sizes shouldn't matter as long as
1393 * as their types are correct; actual values are irrelevant.
1394 */
1395 #define ARBITRARY_SIZE 1
1396 /* attrib.c */
1397 struct attribs attrmax, attrmin;
1398 /* files.c */
1399 const char *configfile;
1400 char lock[ARBITRARY_SIZE];
1401 char SAVEF[ARBITRARY_SIZE];
1402 # ifdef MICRO
1403 char SAVEP[ARBITRARY_SIZE];
1404 # endif
1405 /* termcap.c */
1406 struct tc_lcl_data tc_lcl_data;
1407 # ifdef TEXTCOLOR
1408 # ifdef TOS
1409 const char *hilites[CLR_MAX];
1410 # else
1411 char NEARDATA *hilites[CLR_MAX];
1412 # endif
1413 # endif
1414 /* trap.c */
1415 const char *traps[TRAPNUM];
1416 /* window.c */
1417 struct window_procs windowprocs;
1418 /* xxxtty.c */
1419 # ifdef DEFINE_OSPEED
1420 short ospeed;
1421 # endif
1422 #endif /* STRICT_REF_DEF */
1423
1424 /*lev_main.c*/
1425