1 /* File: init2.c */
2
3
4 /*
5 * Copyright (c) 1997 Ben Harrison
6 *
7 * This software may be copied and distributed for educational, research,
8 * and not for profit purposes provided that this copyright and statement
9 * are included in all such copies. Other copyrights may also apply.
10 */
11
12 #include "angband.h"
13
14 #include "script.h"
15
16 #include "init.h"
17
18 #ifdef CHECK_MODIFICATION_TIME
19 #ifndef RISCOS
20 #ifdef MACINTOSH
21 #include <stat.h>
22 #else
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #endif /* MACINTOSH */
26 #endif /* !RISCOS */
27 #endif /* CHECK_MODIFICATION_TIME */
28
29 #ifdef HAVE_MMAP
30 #include <sys/mman.h>
31 #endif
32
33
34 /*
35 * This file is used to initialize various variables and arrays for the
36 * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass
37 * the common limitation of "read()" and "write()" to only 32767 bytes
38 * at a time.
39 *
40 * Several of the arrays for Angband are built from "template" files in
41 * the "lib/file" directory, from which quick-load binary "image" files
42 * are constructed whenever they are not present in the "lib/data"
43 * directory, or if those files become obsolete, if we are allowed.
44 *
45 * Warning -- the "ascii" file parsers use a minor hack to collect the
46 * name and text information in a single pass. Thus, the game will not
47 * be able to load any template file with more than 20K of names or 60K
48 * of text, even though technically, up to 64K should be legal.
49 *
50 * The "init1.c" file is used only to parse the ascii template files,
51 * to create the binary image files. If you include the binary image
52 * files instead of the ascii template files, then you can undefine
53 * "ALLOW_TEMPLATES", saving about 20K by removing "init1.c". Note
54 * that the binary image files are extremely system dependant.
55 */
56
57
58
59 /*
60 * Find the default paths to all of our important sub-directories.
61 *
62 * The purpose of each sub-directory is described in "variable.c".
63 *
64 * All of the sub-directories should, by default, be located inside
65 * the main "lib" directory, whose location is very system dependant.
66 *
67 * This function takes a writable buffer, initially containing the
68 * "path" to the "lib" directory, for example, "/pkg/lib/angband/",
69 * or a system dependant string, for example, ":lib:". The buffer
70 * must be large enough to contain at least 32 more characters.
71 *
72 * Various command line options may allow some of the important
73 * directories to be changed to user-specified directories, most
74 * importantly, the "info" and "user" and "save" directories,
75 * but this is done after this function, see "main.c".
76 *
77 * In general, the initial path should end in the appropriate "PATH_SEP"
78 * string. All of the "sub-directory" paths (created below or supplied
79 * by the user) will NOT end in the "PATH_SEP" string, see the special
80 * "path_build()" function in "util.c" for more information. (Note that
81 * we call this via the path_make() macro in defines.h)
82 *
83 * Mega-Hack -- support fat raw files under NEXTSTEP, using special
84 * "suffixed" directories for the "ANGBAND_DIR_DATA" directory, but
85 * requiring the directories to be created by hand by the user.
86 *
87 * Hack -- first we free all the strings, since this is known
88 * to succeed even if the strings have not been allocated yet,
89 * as long as the variables start out as "NULL". This allows
90 * this function to be called multiple times, for example, to
91 * try several base "path" values until a good one is found.
92 */
init_file_paths(char * path)93 void init_file_paths(char *path)
94 {
95 char *tail;
96
97 #ifdef PRIVATE_USER_PATH
98 char buf[1024];
99 #endif /* PRIVATE_USER_PATH */
100
101 /*** Free everything ***/
102
103 /* Free the main path */
104 string_free(ANGBAND_DIR);
105
106 /* Free the sub-paths */
107 string_free(ANGBAND_DIR_APEX);
108 string_free(ANGBAND_DIR_BONE);
109 string_free(ANGBAND_DIR_DATA);
110 string_free(ANGBAND_DIR_EDIT);
111 string_free(ANGBAND_DIR_SCRIPT);
112 string_free(ANGBAND_DIR_FILE);
113 string_free(ANGBAND_DIR_HELP);
114 string_free(ANGBAND_DIR_INFO);
115 string_free(ANGBAND_DIR_SAVE);
116 string_free(ANGBAND_DIR_PREF);
117 string_free(ANGBAND_DIR_USER);
118 string_free(ANGBAND_DIR_XTRA);
119
120
121 /*** Prepare the "path" ***/
122
123 /* Hack -- save the main directory */
124 ANGBAND_DIR = string_make(path);
125
126 /* Prepare to append to the Base Path */
127 tail = path + strlen(path);
128
129
130 #ifdef VM
131
132
133 /*** Use "flat" paths with VM/ESA ***/
134
135 /* Use "blank" path names */
136 ANGBAND_DIR_APEX = string_make("");
137 ANGBAND_DIR_BONE = string_make("");
138 ANGBAND_DIR_DATA = string_make("");
139 ANGBAND_DIR_EDIT = string_make("");
140 ANGBAND_DIR_SCRIPT = string_make("");
141 ANGBAND_DIR_FILE = string_make("");
142 ANGBAND_DIR_HELP = string_make("");
143 ANGBAND_DIR_INFO = string_make("");
144 ANGBAND_DIR_SAVE = string_make("");
145 ANGBAND_DIR_PREF = string_make("");
146 ANGBAND_DIR_USER = string_make("");
147 ANGBAND_DIR_XTRA = string_make("");
148
149
150 #else /* VM */
151
152
153 /*** Build the sub-directory names ***/
154
155 /* Build a path name */
156 strcpy(tail, "edit");
157 ANGBAND_DIR_EDIT = string_make(path);
158
159 /* Build a path name */
160 strcpy(tail, "script");
161 ANGBAND_DIR_SCRIPT = string_make(path);
162
163 /* Build a path name */
164 strcpy(tail, "file");
165 ANGBAND_DIR_FILE = string_make(path);
166
167 /* Build a path name */
168 strcpy(tail, "help");
169 ANGBAND_DIR_HELP = string_make(path);
170
171 /* Build a path name */
172 strcpy(tail, "info");
173 ANGBAND_DIR_INFO = string_make(path);
174
175 /* Build a path name */
176 strcpy(tail, "pref");
177 ANGBAND_DIR_PREF = string_make(path);
178
179 #ifdef PRIVATE_USER_PATH
180
181 /* Build the path to the user specific directory */
182 path_make(buf, PRIVATE_USER_PATH, VERSION_NAME);
183
184 /* Build a relative path name */
185 ANGBAND_DIR_USER = string_make(buf);
186
187 #else /* PRIVATE_USER_PATH */
188
189 /* Build a path name */
190 strcpy(tail, "user");
191 ANGBAND_DIR_USER = string_make(path);
192
193 #endif /* PRIVATE_USER_PATH */
194
195 #ifdef USE_PRIVATE_PATHS
196
197 /* Build a path name */
198 path_make(buf, ANGBAND_DIR_USER, "scores");
199 ANGBAND_DIR_APEX = string_make(buf);
200
201 /* Build a path name */
202 path_make(buf, ANGBAND_DIR_USER, "bone");
203 ANGBAND_DIR_BONE = string_make(buf);
204
205 /* Build a path name */
206 path_make(buf, ANGBAND_DIR_USER, "data");
207 ANGBAND_DIR_DATA = string_make(buf);
208
209 /* Build a path name */
210 path_make(buf, ANGBAND_DIR_USER, "save");
211 ANGBAND_DIR_SAVE = string_make(buf);
212
213 #else /* USE_PRIVATE_PATHS */
214
215 /* Build a path name */
216 strcpy(tail, "apex");
217 ANGBAND_DIR_APEX = string_make(path);
218
219 /* Build a path name */
220 strcpy(tail, "bone");
221 ANGBAND_DIR_BONE = string_make(path);
222
223 /* Build a path name */
224 strcpy(tail, "data");
225 ANGBAND_DIR_DATA = string_make(path);
226
227 /* Build a path name */
228 strcpy(tail, "save");
229 ANGBAND_DIR_SAVE = string_make(path);
230
231 #endif /* USE_PRIVATE_PATHS */
232
233 /* Build a path name */
234 strcpy(tail, "xtra");
235 ANGBAND_DIR_XTRA = string_make(path);
236
237 #endif /* VM */
238 }
239
240
241
242 #ifdef ALLOW_TEMPLATES
243
244
245 /*
246 * Hack -- help give useful error messages
247 */
248 int error_idx;
249 int error_line;
250
251
252 /*
253 * Standard error message text
254 */
255 cptr err_str[PARSE_ERROR_MAX] =
256 {
257 NULL,
258 "parse error",
259 "obsolete file",
260 "missing record header",
261 "non-sequential records",
262 "invalid flag specification",
263 "undefined directive",
264 "out of memory",
265 "value out of bounds",
266 "too few arguments",
267 "too many arguments",
268 "too many allocation entries",
269 "invalid spell frequency",
270 "invalid number of items (0-99)",
271 "too many entries",
272 };
273
274
275 #endif /* ALLOW_TEMPLATES */
276
277
278 #ifndef RISCOS
279 #ifdef CHECK_MODIFICATION_TIME
280
check_modification_date(int fd,cptr template_file)281 extern errr check_modification_date(int fd, cptr template_file)
282 {
283 char buf[1024];
284
285 struct stat txt_stat, raw_stat;
286
287 /* Build the filename */
288 path_make(buf, ANGBAND_DIR_EDIT, template_file);
289
290 /* Access stats on text file */
291 if (stat(buf, &txt_stat))
292 {
293 /* No text file - continue */
294 }
295
296 /* Access stats on raw file */
297 else if (fstat(fd, &raw_stat))
298 {
299 /* Error */
300 return (-1);
301 }
302
303 /* Ensure text file is not newer than raw file */
304 else if (txt_stat.st_mtime > raw_stat.st_mtime)
305 {
306 /* Reprocess text file */
307 return (-1);
308 }
309
310 return (0);
311 }
312
313 #endif /* CHECK_MODIFICATION_TIME */
314 #endif /* !RISCOS */
315
316 /*
317 * File headers
318 */
319 header z_head;
320 header v_head;
321 header f_head;
322 header k_head;
323 header a_head;
324 header e_head;
325 header r_head;
326
327
328
329 /*** Initialize from binary image files ***/
330
331
332 /*
333 * Initialize a "*_info" array, by parsing a binary "image" file
334 *
335 * If possible, just mmap() the image file directory into memory.
336 * This is faster than reading it from disk, because it delays
337 * the loading until it's actually accessed. It may also save memory.
338 */
init_info_raw(int fd,header * head)339 static errr init_info_raw(int fd, header *head)
340 {
341 header test;
342 #ifdef HAVE_MMAP
343 char *data;
344 #endif /* HAVE_MMAP */
345
346 /* Read and verify the header */
347 if (fd_read(fd, (char *)(&test), sizeof(header)) ||
348 (test.v_major != head->v_major) ||
349 (test.v_minor != head->v_minor) ||
350 (test.v_patch != head->v_patch) ||
351 (test.v_extra != head->v_extra) ||
352 (test.info_num != head->info_num) ||
353 (test.info_len != head->info_len) ||
354 (test.head_size != head->head_size) ||
355 (test.info_size != head->info_size))
356 {
357 /* Error */
358 return (-1);
359 }
360
361
362 /* Accept the header */
363 COPY(head, &test, header);
364
365 #ifdef HAVE_MMAP
366 data = mmap(NULL, sizeof(header) + head->info_size +
367 head->name_size + head->text_size,
368 PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
369
370 if (data != MAP_FAILED)
371 {
372 head->mmap_base = data;
373
374 /* Skip the header */
375 data += sizeof(header);
376
377 /* Save a pointer to the info */
378 head->info_ptr = data;
379 data += head->info_size;
380
381 /* Save a pointer to the names */
382 head->name_ptr = data;
383 data += head->name_size;
384
385 /* Save a pointer to the text */
386 head->text_ptr = data;
387 }
388 else
389 {
390 #endif /* HAVE_MMAP */
391
392 head->mmap_base = NULL;
393
394 /* Allocate the "*_info" array */
395 C_MAKE(head->info_ptr, head->info_size, char);
396
397 /* Read the "*_info" array */
398 fd_read(fd, head->info_ptr, head->info_size);
399
400 if (head->name_size)
401 {
402 /* Allocate the "*_name" array */
403 C_MAKE(head->name_ptr, head->name_size, char);
404
405 /* Read the "*_name" array */
406 fd_read(fd, head->name_ptr, head->name_size);
407 }
408
409 if (head->text_size)
410 {
411 /* Allocate the "*_text" array */
412 C_MAKE(head->text_ptr, head->text_size, char);
413
414 /* Read the "*_text" array */
415 fd_read(fd, head->text_ptr, head->text_size);
416 }
417
418 #ifdef HAVE_MMAP
419 }
420 #endif /* HAVE_MMAP */
421
422 /* Success */
423 return (0);
424 }
425
426
427 /*
428 * Initialize the header of an *_info.raw file.
429 */
init_header(header * head,int num,int len)430 static void init_header(header *head, int num, int len)
431 {
432 /* Save the "version" */
433 head->v_major = VER_MAJOR;
434 head->v_minor = VER_MINOR;
435 head->v_patch = VER_PATCH;
436 head->v_extra = VER_EXTRA;
437
438 /* Save the "record" information */
439 head->info_num = num;
440 head->info_len = len;
441
442 /* Save the size of "*_head" and "*_info" */
443 head->head_size = sizeof(header);
444 head->info_size = head->info_num * head->info_len;
445 }
446
447
448 #ifdef ALLOW_TEMPLATES
449
450 /*
451 * Display a parser error message.
452 */
display_parse_error(cptr filename,errr err,cptr buf)453 static void display_parse_error(cptr filename, errr err, cptr buf)
454 {
455 cptr oops;
456
457 /* Error string */
458 oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
459
460 /* Oops */
461 msgf("Error at line %d of '%s'.", error_line, filename);
462 msgf("Record %d contains a '%s' error.", error_idx, oops);
463 msgf("Parsing '%s'.", buf);
464 message_flush();
465
466 /* Quit */
467 quit_fmt("Error in '%s.txt' file.", filename);
468 }
469
470 #endif /* ALLOW_TEMPLATES */
471
472
473 /*
474 * Initialize a "*_info" array
475 *
476 * Note that we let each entry have a unique "name" and "text" string,
477 * even if the string happens to be empty (everyone has a unique '\0').
478 */
init_info(cptr filename,header * head,void ** info,char ** name,char ** text)479 static errr init_info(cptr filename, header *head,
480 void **info, char **name, char **text)
481 {
482 int fd;
483
484 errr err = 1;
485
486 FILE *fp;
487
488 /* General buffer */
489 char buf[1024];
490
491
492 #ifdef ALLOW_TEMPLATES
493
494 /*** Load the binary image file ***/
495
496 /* Build the filename */
497 path_make(buf, ANGBAND_DIR_DATA, format("%s.raw", filename));
498
499 /* Attempt to open the "raw" file */
500 fd = fd_open(buf, O_RDONLY);
501
502 /* Process existing "raw" file */
503 if (fd >= 0)
504 {
505 #ifdef CHECK_MODIFICATION_TIME
506
507 err = check_modification_date(fd, format("%s.txt", filename));
508
509 #endif /* CHECK_MODIFICATION_TIME */
510
511 /* Attempt to parse the "raw" file */
512 if (!err)
513 err = init_info_raw(fd, head);
514
515 /* Close it */
516 fd_close(fd);
517 }
518
519 /* Do we have to parse the *.txt file? */
520 if (err)
521 {
522 /*** Make the fake arrays ***/
523
524 /* Allocate the "*_info" array */
525 C_MAKE(head->info_ptr, head->info_size, char);
526
527 /* Hack -- make "fake" arrays */
528 if (name)
529 C_MAKE(head->name_ptr, z_info->fake_name_size, char);
530
531 if (text)
532 C_MAKE(head->text_ptr, z_info->fake_text_size, char);
533
534 if (info) (*info) = head->info_ptr;
535 if (name) (*name) = head->name_ptr;
536 if (text) (*text) = head->text_ptr;
537
538 /*** Load the ascii template file ***/
539
540 /* Build the filename */
541 path_make(buf, ANGBAND_DIR_EDIT, format("%s.txt", filename));
542
543 /* Open the file */
544 fp = my_fopen(buf, "r");
545
546 /* Parse it */
547 if (!fp) quit_fmt("Cannot open '%s.txt' file.", filename);
548
549 /* Parse the file */
550 err = init_info_txt(fp, buf, head, head->parse_info_txt);
551
552 /* Close it */
553 my_fclose(fp);
554
555 /* Errors */
556 if (err) display_parse_error(filename, err, buf);
557
558
559 /*** Dump the binary image file ***/
560
561 /* File type is "DATA" */
562 FILE_TYPE(FILE_TYPE_DATA);
563
564 /* Build the filename */
565 path_make(buf, ANGBAND_DIR_DATA, format("%s.raw", filename));
566
567
568 /* Attempt to open the file */
569 fd = fd_open(buf, O_RDONLY);
570
571 /* Failure */
572 if (fd < 0)
573 {
574 int mode = 0644;
575
576 /* Grab permissions */
577 safe_setuid_grab();
578
579 /* Create a new file */
580 fd = fd_make(buf, mode);
581
582 /* Drop permissions */
583 safe_setuid_drop();
584
585 /* Failure */
586 if (fd < 0)
587 {
588 /* Crash and burn */
589 quit_fmt("Cannot create the '%s' file!", buf);
590 }
591 }
592
593 /* Close it */
594 fd_close(fd);
595
596 /* Grab permissions */
597 safe_setuid_grab();
598
599 /* Attempt to create the raw file */
600 fd = fd_open(buf, O_WRONLY);
601
602 /* Drop permissions */
603 safe_setuid_drop();
604
605 /* Dump to the file */
606 if (fd >= 0)
607 {
608 /* Dump it */
609 fd_write(fd, (cptr)head, head->head_size);
610
611 /* Dump the "*_info" array */
612 fd_write(fd, head->info_ptr, head->info_size);
613
614 /* Dump the "*_name" array */
615 fd_write(fd, head->name_ptr, head->name_size);
616
617 /* Dump the "*_text" array */
618 fd_write(fd, head->text_ptr, head->text_size);
619
620 /* Close */
621 fd_close(fd);
622 }
623
624
625 /*** Kill the fake arrays ***/
626
627 /* Free the "*_info" array */
628 KILL(head->info_ptr);
629
630 /* Hack -- Free the "fake" arrays */
631 if (name)
632 KILL(head->name_ptr);
633
634 if (text)
635 KILL(head->text_ptr);
636
637 #endif /* ALLOW_TEMPLATES */
638
639
640 /*** Load the binary image file ***/
641
642 /* Build the filename */
643 path_make(buf, ANGBAND_DIR_DATA, format("%s.raw", filename));
644
645 /* Attempt to open the "raw" file */
646 fd = fd_open(buf, O_RDONLY);
647
648 /* Process existing "raw" file */
649 if (fd < 0) quit_fmt("Cannot load '%s.raw' file.", filename);
650
651 /* Attempt to parse the "raw" file */
652 err = init_info_raw(fd, head);
653
654 /* Close it */
655 fd_close(fd);
656
657 /* Error */
658 if (err) quit_fmt("Cannot parse '%s.raw' file.", filename);
659
660 #ifdef ALLOW_TEMPLATES
661 }
662 #endif /* ALLOW_TEMPLATES */
663
664 if (info) (*info) = head->info_ptr;
665 if (name) (*name) = head->name_ptr;
666 if (text) (*text) = head->text_ptr;
667
668 /* Success */
669 return (0);
670 }
671
672
673 /*
674 * Free the allocated memory for the info-, name-, and text- arrays.
675 */
free_info(header * head)676 static errr free_info(header *head)
677 {
678 #ifdef HAVE_MMAP
679 if (head->mmap_base)
680 {
681 munmap(head->mmap_base, sizeof(header) + head->info_size +
682 head->name_size + head->text_size);
683
684 /* Success */
685 return (0);
686 }
687 #endif /* HAVE_MMAP */
688
689 if (head->info_size)
690 FREE(head->info_ptr);
691
692 if (head->name_size)
693 FREE(head->name_ptr);
694
695 if (head->text_size)
696 FREE(head->text_ptr);
697
698 /* Success */
699 return (0);
700 }
701
702
703 /*
704 * Initialize the "z_info" array
705 */
init_z_info(void)706 static errr init_z_info(void)
707 {
708 /* Init the header */
709 init_header(&z_head, 1, sizeof(maxima));
710
711 #ifdef ALLOW_TEMPLATES
712
713 /* Save a pointer to the parsing function */
714 z_head.parse_info_txt = parse_z_info;
715
716 #endif /* ALLOW_TEMPLATES */
717
718 return init_info("misc", &z_head, (void *)&z_info, NULL, NULL);
719 }
720
721
722 /*
723 * Initialize the "f_info" array
724 */
init_f_info(void)725 static errr init_f_info(void)
726 {
727 /* Init the header */
728 init_header(&f_head, z_info->f_max, sizeof(feature_type));
729
730 #ifdef ALLOW_TEMPLATES
731
732 /* Save a pointer to the parsing function */
733 f_head.parse_info_txt = parse_f_info;
734
735 #endif /* ALLOW_TEMPLATES */
736
737 return init_info("f_info", &f_head,
738 (void *)&f_info, (void *)&f_name, (void *)&f_text);
739 }
740
741
742
743 /*
744 * Initialize the "k_info" array
745 */
init_k_info(void)746 static errr init_k_info(void)
747 {
748 /* Init the header */
749 init_header(&k_head, z_info->k_max, sizeof(object_kind));
750
751 #ifdef ALLOW_TEMPLATES
752
753 /* Save a pointer to the parsing function */
754 k_head.parse_info_txt = parse_k_info;
755
756 #endif /* ALLOW_TEMPLATES */
757
758 return init_info("k_info", &k_head,
759 (void *)&k_info, (void *)&k_name, (void *)&k_text);
760 }
761
762
763
764 /*
765 * Initialize the "a_info" array
766 */
init_a_info(void)767 static errr init_a_info(void)
768 {
769 /* Init the header */
770 init_header(&a_head, z_info->a_max, sizeof(artifact_type));
771
772 #ifdef ALLOW_TEMPLATES
773
774 /* Save a pointer to the parsing function */
775 a_head.parse_info_txt = parse_a_info;
776
777 #endif /* ALLOW_TEMPLATES */
778
779 return init_info("a_info", &a_head,
780 (void *)&a_info, (void *)&a_name, (void *)&a_text);
781 }
782
783
784
785 /*
786 * Initialize the "e_info" array
787 */
init_e_info(void)788 static errr init_e_info(void)
789 {
790 /* Init the header */
791 init_header(&e_head, z_info->e_max, sizeof(ego_item_type));
792
793 #ifdef ALLOW_TEMPLATES
794
795 /* Save a pointer to the parsing function */
796 e_head.parse_info_txt = parse_e_info;
797
798 #endif /* ALLOW_TEMPLATES */
799
800 return init_info("e_info", &e_head,
801 (void *)&e_info, (void *)&e_name, (void *)&e_text);
802 }
803
804
805
806 /*
807 * Initialize the "r_info" array
808 */
init_r_info(void)809 static errr init_r_info(void)
810 {
811 /* Init the header */
812 init_header(&r_head, z_info->r_max, sizeof(monster_race));
813
814 #ifdef ALLOW_TEMPLATES
815
816 /* Save a pointer to the parsing function */
817 r_head.parse_info_txt = parse_r_info;
818
819 #endif /* ALLOW_TEMPLATES */
820
821 return init_info("r_info", &r_head,
822 (void *)&r_info, (void *)&r_name, (void *)&r_text);
823 }
824
825
826
827 /*
828 * Initialize the "v_info" array
829 */
init_v_info(void)830 static errr init_v_info(void)
831 {
832 /* Init the header */
833 init_header(&v_head, z_info->v_max, sizeof(vault_type));
834
835 #ifdef ALLOW_TEMPLATES
836
837 /* Save a pointer to the parsing function */
838 v_head.parse_info_txt = parse_v_info;
839
840 #endif /* ALLOW_TEMPLATES */
841
842 return init_info("v_info", &v_head,
843 (void *)&v_info, (void *)&v_name, (void *)&v_text);
844 }
845
846
847
848
849 /*** Initialize others ***/
850
851
852
853
854 /*
855 * Initialize the "wild_choice_tree" array and the
856 * "wild_gen_data" array.
857 *
858 */
init_w_info(void)859 errr init_w_info(void)
860 {
861 errr err;
862
863 FILE *fp;
864
865 /* General buffer */
866 char buf[1024];
867
868
869 /* Later must add in raw file support later. */
870 C_MAKE(wild_choice_tree, z_info->wn_max, wild_choice_tree_type);
871 C_MAKE(wild_gen_data, z_info->wt_max, wild_gen_data_type);
872
873 /*** Load the ascii template file ***/
874
875 /* Build the filename */
876 path_make(buf, ANGBAND_DIR_EDIT, "w_info.txt");
877
878 /* Open the file */
879 fp = my_fopen(buf, "r");
880
881 /* Parse it */
882 if (!fp) quit("Cannot open 'w_info.txt' file.");
883
884 /* Parse the file */
885 err = init_w_info_txt(fp, buf);
886
887 /* Close it */
888 my_fclose(fp);
889
890 /* Errors */
891 if (err)
892 {
893 cptr oops;
894
895 /* Error string */
896 oops =
897 (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
898
899 /* Oops */
900 msgf("Error %d at line %d of 'w_info.txt'.", err, error_line);
901 msgf("Record %d contains a '%s' error.", error_idx, oops);
902 msgf("Parsing '%s'.", buf);
903 message_flush();
904
905 /* Quit */
906 quit("Error in 'w_info.txt' file.");
907 }
908
909 /* Success */
910 return (0);
911 }
912
913 /*
914 * Initialize the field data structures
915 */
init_t_info(void)916 errr init_t_info(void)
917 {
918 errr err;
919
920 FILE *fp;
921
922 /* General buffer */
923 char buf[1024];
924
925 /* Later must add in python support. */
926 C_MAKE(t_info, z_info->t_max, field_thaum);
927 C_MAKE(fld_list, z_info->fld_max, field_type);
928
929
930 /*** Load the ascii template file ***/
931
932 /* Build the filename */
933 path_make(buf, ANGBAND_DIR_EDIT, "t_info.txt");
934
935 /* Open the file */
936 fp = my_fopen(buf, "r");
937
938 /* Parse it */
939 if (!fp) quit("Cannot open 't_info.txt' file.");
940
941 /* Parse the file */
942 err = init_t_info_txt(fp, buf);
943
944 /* Close it */
945 my_fclose(fp);
946
947 /* Errors */
948 if (err)
949 {
950 cptr oops;
951
952 /* Error string */
953 oops =
954 (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
955
956 /* Oops */
957 msgf("Error %d at line %d of 't_info.txt'.", err, error_line);
958 msgf("Record %d contains a '%s' error.", error_idx, oops);
959 msgf("Parsing '%s'.", buf);
960 message_flush();
961
962 /* Quit */
963 quit("Error in 't_info.txt' file.");
964 }
965
966 /* Success */
967 return (0);
968 }
969
970 /*
971 * The list of available format functions
972 *
973 * (They should be in order of most-called
974 * through to least-called.)
975 */
976 static vstrnfmt_aux_func my_format_functions[9] =
977 {
978 set_message_type,
979 object_fmt,
980 object_store_fmt,
981 monster_fmt,
982 stat_format,
983 center_string,
984 likert,
985 binary_fmt,
986 NULL
987 };
988
989
990 /*
991 * Initialize some other arrays
992 */
init_other(void)993 static errr init_other(void)
994 {
995 int i, j, k, n;
996
997 /*** Pre-allocate space for the "format()" buffer ***/
998
999 /* Hack -- Just call the "format()" function */
1000 (void)format("%s (%s).", "Steven Fuerst", MAINTAINER);
1001
1002 /* Initialise the "%v" user-defined format function list */
1003 register_format_funcs(my_format_functions);
1004
1005
1006 /*** Prepare the various "bizarre" arrays ***/
1007
1008 /* Macro variables */
1009 C_MAKE(macro__pat, MACRO_MAX, cptr);
1010 C_MAKE(macro__act, MACRO_MAX, cptr);
1011 C_MAKE(macro__cmd, MACRO_MAX, bool);
1012
1013 /* Macro action buffer */
1014 C_MAKE(macro__buf, 1024, char);
1015
1016
1017 /* Clear the spell colour strings */
1018 (void)C_WIPE(gf_color, MAX_GF, cptr);
1019
1020
1021 /* Initialize the "quark" package */
1022 (void)quarks_init();
1023
1024 /* Initialize the "message" package */
1025 (void)messages_init();
1026
1027
1028 /*** Prepare region list ***/
1029 C_MAKE(rg_list, z_info->rg_max, region_type);
1030 C_MAKE(ri_list, z_info->rg_max, region_info);
1031
1032
1033 /*** Hack - Allocate the player information for each grid ***/
1034 for (i = 0; i < MAX_HGT; i++)
1035 {
1036 /* Allocate one row of the cave */
1037 C_MAKE(p_ptr->pcave[i], MAX_WID, pcave_type);
1038 }
1039
1040 /*** Prepare wilderness stuff ***/
1041
1042 /* Allocate temporary wilderness block */
1043 for (i = 0; i < WILD_BLOCK_SIZE + 1; i++)
1044 {
1045 /* Allocate one row of the temp_block */
1046 C_MAKE(temp_block[i], WILD_BLOCK_SIZE + 1, u16b);
1047 }
1048
1049 /* Make the list of pointers to blocks */
1050 C_MAKE(wild_cache, WILD_CACHE, blk_ptr);
1051
1052 /* Allocate each block */
1053 for (i = 0; i < WILD_CACHE; i++)
1054 {
1055 /* Allocate block */
1056 C_MAKE(wild_cache[i], WILD_BLOCK_SIZE, cave_type *);
1057
1058 /* Allocate rows of a block */
1059 for (j = 0; j < WILD_BLOCK_SIZE; j++)
1060 {
1061 C_MAKE(wild_cache[i][j], WILD_BLOCK_SIZE, cave_type);
1062 }
1063 }
1064
1065 /* Allocate the player information for each grid (wilderness) */
1066
1067 /* Allocate WILD_VIEW by WILD_VIEW blocks */
1068 C_MAKE(p_ptr->pwild, WILD_VIEW, pblk_ptr *);
1069
1070 for (i = 0; i < WILD_VIEW; i++)
1071 {
1072 C_MAKE(p_ptr->pwild[i], WILD_VIEW, pblk_ptr);
1073
1074 /* Allocate each block */
1075 for (j = 0; j < WILD_VIEW; j++)
1076 {
1077 C_MAKE(p_ptr->pwild[i][j], WILD_BLOCK_SIZE, pcave_type *);
1078
1079 for (k = 0; k < WILD_BLOCK_SIZE; k++)
1080 {
1081 C_MAKE(p_ptr->pwild[i][j][k], WILD_BLOCK_SIZE, pcave_type);
1082 }
1083 }
1084 }
1085
1086 /* Allocate the wilderness itself */
1087 C_MAKE(wild, WILD_SIZE, wild_type *);
1088 C_MAKE(wild_grid, WILD_SIZE, blk_ptr *);
1089 C_MAKE(wild_refcount, WILD_SIZE, int *);
1090
1091 for (i = 0; i < WILD_SIZE; i++)
1092 {
1093 /* Allocate one row of the wilderness */
1094 C_MAKE(wild[i], WILD_SIZE, wild_type);
1095 C_MAKE(wild_grid[i], WILD_SIZE, blk_ptr);
1096 C_MAKE(wild_refcount[i], WILD_SIZE, int);
1097 }
1098
1099 /*** Prepare "vinfo" array ***/
1100
1101 /* Used by "update_view()" */
1102 (void)vinfo_init();
1103
1104
1105 /*** Prepare entity arrays ***/
1106
1107 /* Objects */
1108 C_MAKE(o_list, z_info->o_max, object_type);
1109
1110 /* Monsters */
1111 C_MAKE(m_list, z_info->m_max, monster_type);
1112
1113 /*** Prepare the options ***/
1114
1115
1116 init_options(OPT_FLAG_BIRTH | OPT_FLAG_SERVER | OPT_FLAG_PLAYER);
1117
1118 /* Initialize the options */
1119 for (i = 0; i < OPT_MAX; i++)
1120 {
1121 if (option_info[i].o_text)
1122 {
1123 /* Accept */
1124 option_mask[i / 32] |= (1L << (i % 32));
1125 }
1126 }
1127
1128
1129 /* Initialize the window flags */
1130 for (n = 0; n < ANGBAND_TERM_MAX; n++)
1131 {
1132 /* Analyze the options */
1133 for (i = 0; i < 32; i++)
1134 {
1135 /* Accept */
1136 if (window_flag_desc[i])
1137 {
1138 /* Accept */
1139 window_mask[n] |= (1L << i);
1140 }
1141 }
1142 }
1143
1144
1145 /*** Make store stock cache ***/
1146
1147 C_MAKE(store_cache, STORE_CACHE_AMNT, store_type *);
1148
1149 /* Allocate the towns */
1150 C_MAKE(place, z_info->wp_max, place_type);
1151
1152 /* Get size of shop owner name arrays */
1153 for (i = 0; owner_names[i]; i++)
1154 {
1155 /* Do nothing */
1156 }
1157 owner_names_max = i;
1158
1159 for (i = 0; owner_suffix[i]; i++)
1160 {
1161 /* Do nothing */
1162 }
1163 owner_suffix_max = i;
1164
1165
1166 /* Success */
1167 return (0);
1168 }
1169
1170
1171
1172 /*
1173 * Initialize some other arrays
1174 */
init_alloc(void)1175 static errr init_alloc(void)
1176 {
1177 int i;
1178 monster_race *r_ptr;
1179
1180 alloc_entry *table;
1181 s16b num[MAX_DEPTH];
1182 s16b aux[MAX_DEPTH];
1183
1184 /*** Analyze monster allocation info ***/
1185
1186 /* Clear the "aux" array */
1187 (void)C_WIPE(&aux, MAX_DEPTH, s16b);
1188
1189 /* Clear the "num" array */
1190 (void)C_WIPE(&num, MAX_DEPTH, s16b);
1191
1192 /* Size of "alloc_race_table" */
1193 alloc_race_size = 0;
1194
1195 /* Scan the monsters (not the ghost) */
1196 for (i = 1; i < z_info->r_max - 1; i++)
1197 {
1198 /* Get the i'th race */
1199 r_ptr = &r_info[i];
1200
1201 /* Legal monsters */
1202 if (r_ptr->rarity)
1203 {
1204 /* Count the entries */
1205 alloc_race_size++;
1206
1207 /* Group by level */
1208 num[r_ptr->level]++;
1209 }
1210 }
1211
1212 /* Collect the level indexes */
1213 for (i = 1; i < MAX_DEPTH; i++)
1214 {
1215 /* Group by level */
1216 num[i] += num[i - 1];
1217 }
1218
1219 /* Paranoia */
1220 if (!num[0]) quit("No town monsters!");
1221
1222
1223 /*** Initialize monster allocation info ***/
1224
1225 /* Allocate the alloc_race_table */
1226 C_MAKE(alloc_race_table, alloc_race_size, alloc_entry);
1227
1228 /* Get the table entry */
1229 table = alloc_race_table;
1230
1231 /* Scan the monsters */
1232 for (i = 1; i < z_info->r_max; i++)
1233 {
1234 /* Get the i'th race */
1235 r_ptr = &r_info[i];
1236
1237 /* Count valid pairs */
1238 if (r_ptr->rarity)
1239 {
1240 int p, x, y, z;
1241
1242 /* Extract the base level */
1243 x = r_ptr->level;
1244
1245 /* Extract the base probability */
1246 p = (100 / r_ptr->rarity);
1247
1248 /* Skip entries preceding our locale */
1249 y = (x > 0) ? num[x - 1] : 0;
1250
1251 /* Skip previous entries at this locale */
1252 z = y + aux[x];
1253
1254 /* Load the entry */
1255 table[z].index = i;
1256 table[z].level = x;
1257 table[z].prob1 = p;
1258 table[z].prob2 = p;
1259 table[z].prob3 = p;
1260
1261 /* Another entry complete for this locale */
1262 aux[x]++;
1263 }
1264 }
1265
1266 /* Init "alloc_kind_table" and "alloc_ego_table" */
1267 (void)init_object_alloc();
1268
1269 /* Success */
1270 return (0);
1271 }
1272
1273
1274 /*
1275 * Hack -- take notes on line 23
1276 */
note(cptr str)1277 static void note(cptr str)
1278 {
1279 clear_row(23);
1280 put_fstr(20, 23, str);
1281 Term_fresh();
1282 }
1283
1284
1285
1286 /*
1287 * Hack -- Explain a broken "lib" folder and quit (see below).
1288 *
1289 * XXX XXX XXX This function is "messy" because various things
1290 * may or may not be initialized, but the "plog()" and "quit()"
1291 * functions are "supposed" to work under any conditions.
1292 */
init_angband_fail(void)1293 static void init_angband_fail(void)
1294 {
1295 /* Explain */
1296 plog("The 'lib' directory is probably missing or broken.");
1297
1298 /* More details */
1299 plog("Perhaps the archive was not extracted correctly.");
1300
1301 /* Explain */
1302 plog("See the 'README' file for more information.");
1303
1304 /* Quit with error */
1305 quit("Fatal Error.");
1306 }
1307
1308
1309 /*
1310 * Hack -- main Angband initialization entry point
1311 *
1312 * Verify some files, display the "news.txt" file, create
1313 * the high score file, initialize all internal arrays, and
1314 * load the basic "user pref files".
1315 *
1316 * Be very careful to keep track of the order in which things
1317 * are initialized, in particular, the only thing *known* to
1318 * be available when this function is called is the "z-term.c"
1319 * package, and that may not be fully initialized until the
1320 * end of this function, when the default "user pref files"
1321 * are loaded and "Term_xtra(TERM_XTRA_REACT,0)" is called.
1322 *
1323 * Note that this function attempts to verify the "news" file,
1324 * and the game aborts (cleanly) on failure, since without the
1325 * "news" file, it is likely that the "lib" folder has not been
1326 * correctly located. Otherwise, the news file is displayed for
1327 * the user.
1328 *
1329 * Note that this function attempts to verify (or create) the
1330 * "high score" file, and the game aborts (cleanly) on failure,
1331 * since one of the most common "extraction" failures involves
1332 * failing to extract all sub-directories (even empty ones), such
1333 * as by failing to use the "-d" option of "pkunzip", or failing
1334 * to use the "save empty directories" option with "Compact Pro".
1335 * This error will often be caught by the "high score" creation
1336 * code below, since the "lib/apex" directory, being empty in the
1337 * standard distributions, is most likely to be "lost", making it
1338 * impossible to create the high score file.
1339 *
1340 * Note that various things are initialized by this function,
1341 * including everything that was once done by "init_some_arrays".
1342 *
1343 * This initialization involves the parsing of special files
1344 * in the "lib/data" and sometimes the "lib/edit" directories.
1345 *
1346 * Note that the "template" files are initialized first, since they
1347 * often contain errors. This means that macros and message recall
1348 * and things like that are not available until after they are done.
1349 *
1350 * We load the default "user pref files" here in case any "color"
1351 * changes are needed before character creation.
1352 *
1353 * Note that the "graf-xxx.prf" file must be loaded separately,
1354 * if needed, in the first (?) pass through "TERM_XTRA_REACT".
1355 */
init_angband(void)1356 void init_angband(void)
1357 {
1358 int fd = -1;
1359
1360 int mode = 0644;
1361
1362 FILE *fp;
1363
1364 char buf[1024];
1365
1366
1367 /*** Verify the "news" file ***/
1368
1369 /* Build the filename */
1370 path_make(buf, ANGBAND_DIR_FILE, "news.txt");
1371
1372 /* Attempt to open the file */
1373 fd = fd_open(buf, O_RDONLY);
1374
1375 /* Failure */
1376 if (fd < 0)
1377 {
1378 /* Message */
1379 plog_fmt("Cannot access the '%s' file!", buf);
1380
1381 /* Crash and burn */
1382 init_angband_fail();
1383 }
1384
1385 /* Close it */
1386 (void)fd_close(fd);
1387
1388
1389 /*** Display the "news" file ***/
1390
1391 /* Clear screen */
1392 Term_clear();
1393
1394 /* Build the filename */
1395 path_make(buf, ANGBAND_DIR_FILE, "news.txt");
1396
1397 /* Open the News file */
1398 fp = my_fopen(buf, "r");
1399
1400 /* Dump */
1401 if (fp)
1402 {
1403 int i = 0;
1404
1405 /* Dump the file to the screen */
1406 while (0 == my_fgets(fp, buf, 1024))
1407 {
1408 /* Display and advance */
1409 put_fstr(0, i++, buf);
1410 }
1411
1412 /* Close */
1413 my_fclose(fp);
1414 }
1415
1416 /* Display version number */
1417 put_fstr(42, 3, "%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH);
1418
1419 /* Flush it */
1420 Term_fresh();
1421
1422
1423 /*** Verify (or create) the "high score" file ***/
1424
1425 /* Build the filename */
1426 path_make(buf, ANGBAND_DIR_APEX, "scores.raw");
1427
1428 /* Attempt to open the high score file */
1429 fd = fd_open(buf, O_RDONLY);
1430
1431 /* Failure */
1432 if (fd < 0)
1433 {
1434 /* File type is "DATA" */
1435 FILE_TYPE(FILE_TYPE_DATA);
1436
1437 /* Grab permissions */
1438 safe_setuid_grab();
1439
1440 /* Create a new high score file */
1441 fd = fd_make(buf, mode);
1442
1443 /* Drop permissions */
1444 safe_setuid_drop();
1445
1446 /* Failure */
1447 if (fd < 0)
1448 {
1449 /* Message */
1450 plog_fmt("Cannot create the '%s' file!", buf);
1451
1452 /* Crash and burn */
1453 init_angband_fail();
1454 }
1455 }
1456
1457 /* Close it */
1458 (void)fd_close(fd);
1459
1460
1461 /*** Initialize some arrays ***/
1462
1463 /* Init the interface callbacks */
1464 init_term_callbacks();
1465
1466 /* Initialize size info */
1467 note("[Initializing array sizes...]");
1468 if (init_z_info()) quit("Cannot initialize sizes");
1469
1470 /* Initialize scripting */
1471 note("[Initializing scripts... (scripts)]");
1472 if (script_init()) quit("Cannot initialize scripts");
1473
1474 /* Initialize feature info */
1475 note("[Initializing arrays... (features)]");
1476 if (init_f_info()) quit("Cannot initialize features");
1477
1478 /* Initialize object info */
1479 note("[Initializing arrays... (objects)]");
1480 if (init_k_info()) quit("Cannot initialize objects");
1481
1482 /* Initialize artifact info */
1483 note("[Initializing arrays... (artifacts)]");
1484 if (init_a_info()) quit("Cannot initialize artifacts");
1485
1486 /* Initialize ego-item info */
1487 note("[Initializing arrays... (ego-items)]");
1488 if (init_e_info()) quit("Cannot initialize ego-items");
1489
1490 /* Initialize monster info */
1491 note("[Initializing arrays... (monsters)]");
1492 if (init_r_info()) quit("Cannot initialize monsters");
1493
1494 /* Initialize feature info */
1495 note("[Initializing arrays... (vaults)]");
1496 if (init_v_info()) quit("Cannot initialize vaults");
1497
1498 /* Initialize quest array */
1499 note("[Initializing arrays... (quests)]");
1500 if (init_quests()) quit("Cannot initialize quests");
1501
1502 /* Initialize some other arrays */
1503 note("[Initializing arrays... (other)]");
1504 if (init_other()) quit("Cannot initialize other stuff");
1505
1506 /* Initialize some other arrays */
1507 note("[Initializing arrays... (alloc)]");
1508 if (init_alloc()) quit("Cannot initialize alloc stuff");
1509
1510
1511 /*** Load default user pref files ***/
1512
1513 /* Initialize feature info */
1514 note("[Initializing user pref files...]");
1515
1516 /* Access the "basic" pref file */
1517 (void)process_pref_file("pref.prf");
1518
1519 /* Access the "user" pref file */
1520 (void)process_pref_file("user.prf");
1521
1522 /* Initialise the fake monochrome flag */
1523 fake_monochrome = (!use_graphics
1524 || streq(ANGBAND_SYS, "ibm")) ? TRUE : FALSE;
1525
1526 /* Initialise the overhead map */
1527 init_overhead_map();
1528
1529 /* Done */
1530 note("[Initialization complete]");
1531 }
1532
1533
1534
1535
cleanup_angband(void)1536 void cleanup_angband(void)
1537 {
1538 int i, j;
1539
1540 /* Free the macros */
1541 for (i = 0; i < macro__num; ++i)
1542 {
1543 string_free(macro__pat[i]);
1544 string_free(macro__act[i]);
1545 }
1546
1547 FREE((void *)macro__pat);
1548 FREE((void *)macro__act);
1549
1550 /* Free the keymaps */
1551 for (i = 0; i < KEYMAP_MODES; ++i)
1552 {
1553 for (j = 0; j < 256; ++j)
1554 {
1555 string_free(keymap_act[i][j]);
1556 }
1557 }
1558
1559 /* Free the allocation tables */
1560 FREE(alloc_ego_table);
1561 FREE(alloc_race_table);
1562 FREE(alloc_kind_table);
1563
1564 /* Free the towns */
1565 FREE(place);
1566
1567 /* Free the stores */
1568 FREE(store_cache);
1569
1570 /* Free the quest list */
1571 FREE(quest);
1572
1573 /* Free the lore, monster, and object lists */
1574 FREE(m_list);
1575 FREE(o_list);
1576
1577 #ifdef MONSTER_FLOW
1578
1579 /* Flow arrays */
1580 FREE(cave_when);
1581 FREE(cave_cost);
1582
1583 #endif /* MONSTER_FLOW */
1584
1585 /* Delete the overhead map */
1586 del_overhead_map();
1587
1588 /*
1589 * Note that this causes problems if Zangband exits due to an error
1590 * parsing the info files since at that point the wilderness is not
1591 * initiated. It works fine thereafter.
1592 */
1593 #if 0
1594
1595 This code is wrong - the wilderness works differently now. - SF -
1596 /* Free the wilderness */
1597 for (i = 0; i < WILD_SIZE; i++)
1598 {
1599 /* Free one row of the wilderness */
1600 FREE(wild[i]);
1601 }
1602
1603 /* Free the wilderness itself */
1604 FREE(wild);
1605
1606
1607 /* Free cache of wilderness blocks */
1608 for (i = 0; i < WILD_BLOCKS; i++)
1609 {
1610 /* Free rows of a block */
1611 for (j = 0; j < WILD_BLOCK_SIZE; j++)
1612 {
1613 FREE(wild_cache[i][j]);
1614 }
1615
1616 /* Free block */
1617 FREE(wild_cache[i]);
1618 }
1619
1620 /* Free temporary wilderness block */
1621 for (i = 0; i < WILD_BLOCK_SIZE + 1; i++)
1622 {
1623 /* Allocate one row of the temp_block */
1624 FREE(temp_block[i]);
1625 }
1626
1627 /* Free the cave */
1628 for (i = 0; i < MAX_HGT; i++)
1629 {
1630 /* Allocate one row of the cave */
1631 FREE(cave[i]);
1632 }
1633 #endif /* 0 */
1634
1635 /* Free the messages */
1636 messages_free();
1637
1638 /* Free the "quarks" */
1639 quarks_free();
1640
1641 /* Free the info, name, and text arrays */
1642 free_info(&v_head);
1643 free_info(&r_head);
1644 free_info(&e_head);
1645 free_info(&a_head);
1646 free_info(&k_head);
1647 free_info(&f_head);
1648 free_info(&z_head);
1649
1650 /* Free the interface callbacks */
1651 free_term_callbacks();
1652
1653 /* Free the directories */
1654 string_free(ANGBAND_DIR);
1655 string_free(ANGBAND_DIR_APEX);
1656 string_free(ANGBAND_DIR_BONE);
1657 string_free(ANGBAND_DIR_DATA);
1658 string_free(ANGBAND_DIR_EDIT);
1659 string_free(ANGBAND_DIR_SCRIPT);
1660 string_free(ANGBAND_DIR_FILE);
1661 string_free(ANGBAND_DIR_HELP);
1662 string_free(ANGBAND_DIR_INFO);
1663 string_free(ANGBAND_DIR_SAVE);
1664 string_free(ANGBAND_DIR_PREF);
1665 string_free(ANGBAND_DIR_USER);
1666 string_free(ANGBAND_DIR_XTRA);
1667 }
1668