1 /* File: init1.c */
2 
3 /* Purpose: Initialization (part 1) -BEN- */
4 
5 #include "mangband.h"
6 
7 /*
8  * This file is used to initialize various variables and arrays for the
9  * Angband game.  Note the use of "fd_read()" and "fd_write()" to bypass
10  * the common limitation of "read()" and "write()" to only 32767 bytes
11  * at a time.
12  *
13  * Several of the arrays for Angband are built from "template" files in
14  * the "lib/file" directory, from which quick-load binary "image" files
15  * are constructed whenever they are not present in the "lib/data"
16  * directory, or if those files become obsolete, if we are allowed.
17  *
18  * Warning -- the "ascii" file parsers use a minor hack to collect the
19  * name and text information in a single pass.  Thus, the game will not
20  * be able to load any template file with more than 20K of names or 60K
21  * of text, even though technically, up to 64K should be legal.
22  *
23  * Note that if "ALLOW_TEMPLATES" is not defined, then a lot of the code
24  * in this file is compiled out, and the game will not run unless valid
25  * "binary template files" already exist in "lib/data".  Thus, one can
26  * compile Angband with ALLOW_TEMPLATES defined, run once to create the
27  * "*.raw" files in "lib/data", and then quit, and recompile without
28  * defining ALLOW_TEMPLATES, which will both save 20K and prevent people
29  * from changing the ascii template files in potentially dangerous ways.
30  *
31  * The code could actually be removed and placed into a "stand-alone"
32  * program, but that feels a little silly, especially considering some
33  * of the platforms that we currently support.
34  */
35 
36 
37 #ifdef ALLOW_TEMPLATES
38 
39 #include "init.h"
40 
41 /*
42  * Hack -- error tracking
43  */
44 extern s16b error_idx;
45 extern s16b error_line;
46 
47 
48 /*
49  * Hack -- size of the "fake" arrays
50  */
51 extern u32b fake_name_size;
52 extern u32b fake_text_size;
53 
54 
55 
56 /*** Helper arrays for parsing ascii template files ***/
57 
58 /*
59  * Monster Blow Methods
60  */
61 static cptr r_info_blow_method[] =
62 {
63 	"",
64 	"HIT",
65 	"TOUCH",
66 	"PUNCH",
67 	"KICK",
68 	"CLAW",
69 	"BITE",
70 	"STING",
71 	"XXX1",
72 	"BUTT",
73 	"CRUSH",
74 	"ENGULF",
75 	"XXX2",
76 	"CRAWL",
77 	"DROOL",
78 	"SPIT",
79 	"XXX3",
80 	"GAZE",
81 	"WAIL",
82 	"SPORE",
83 	"XXX4",
84 	"BEG",
85 	"INSULT",
86 	"MOAN",
87 	"XXX5",
88 	NULL
89 };
90 
91 
92 /*
93  * Monster Blow Effects
94  */
95 static cptr r_info_blow_effect[] =
96 {
97 	"",
98 	"HURT",
99 	"POISON",
100 	"UN_BONUS",
101 	"UN_POWER",
102 	"EAT_GOLD",
103 	"EAT_ITEM",
104 	"EAT_FOOD",
105 	"EAT_LITE",
106 	"ACID",
107 	"ELEC",
108 	"FIRE",
109 	"COLD",
110 	"BLIND",
111 	"CONFUSE",
112 	"TERRIFY",
113 	"PARALYZE",
114 	"LOSE_STR",
115 	"LOSE_INT",
116 	"LOSE_WIS",
117 	"LOSE_DEX",
118 	"LOSE_CON",
119 	"LOSE_CHR",
120 	"LOSE_ALL",
121 	"SHATTER",
122 	"EXP_10",
123 	"EXP_20",
124 	"EXP_40",
125 	"EXP_80",
126 	"HALLU",
127 	NULL
128 };
129 
130 
131 /*
132  * Monster race flags
133  */
134 static cptr r_info_flags1[] =
135 {
136 	"UNIQUE",
137 	"QUESTOR",
138 	"MALE",
139 	"FEMALE",
140 	"CHAR_CLEAR",
141 	"CHAR_MULTI",
142 	"ATTR_CLEAR",
143 	"ATTR_MULTI",
144 	"FORCE_DEPTH",
145 	"FORCE_MAXHP",
146 	"FORCE_SLEEP",
147 	"FORCE_EXTRA",
148 	"FRIEND",
149 	"FRIENDS",
150 	"ESCORT",
151 	"ESCORTS",
152 	"NEVER_BLOW",
153 	"NEVER_MOVE",
154 	"RAND_25",
155 	"RAND_50",
156 	"ONLY_GOLD",
157 	"ONLY_ITEM",
158 	"DROP_60",
159 	"DROP_90",
160 	"DROP_1D2",
161 	"DROP_2D2",
162 	"DROP_3D2",
163 	"DROP_4D2",
164 	"DROP_GOOD",
165 	"DROP_GREAT",
166 	"DROP_USEFUL",
167 	"DROP_CHOSEN"
168 };
169 
170 /*
171  * Monster race flags
172  */
173 static cptr r_info_flags2[] =
174 {
175 	"STUPID",
176 	"SMART",
177 	"XXX1X2",
178 	"XXX2X2",
179 	"INVISIBLE",
180 	"COLD_BLOOD",
181 	"EMPTY_MIND",
182 	"WEIRD_MIND",
183 	"MULTIPLY",
184 	"REGENERATE",
185 	"XXX3X2",
186 	"XXX4X2",
187 	"POWERFUL",
188 	"XXX5X2",
189 	"XXX7X2",
190 	"XXX6X2",
191 	"OPEN_DOOR",
192 	"BASH_DOOR",
193 	"PASS_WALL",
194 	"KILL_WALL",
195 	"MOVE_BODY",
196 	"KILL_BODY",
197 	"TAKE_ITEM",
198 	"KILL_ITEM",
199 	"WANDERER",
200 	"BRAIN_2",
201 	"BRAIN_3",
202 	"BRAIN_4",
203 	"BRAIN_5",
204 	"BRAIN_6",
205 	"BRAIN_7",
206 	"BRAIN_8"
207 };
208 
209 /*
210  * Monster race flags
211  */
212 static cptr r_info_flags3[] =
213 {
214 	"ORC",
215 	"TROLL",
216 	"GIANT",
217 	"DRAGON",
218 	"DEMON",
219 	"UNDEAD",
220 	"EVIL",
221 	"ANIMAL",
222 	"XXX1X3",
223 	"XXX2X3",
224 	"XXX3X3",
225 	"XXX4X3",
226 	"HURT_LITE",
227 	"HURT_ROCK",
228 	"HURT_FIRE",
229 	"HURT_COLD",
230 	"IM_ACID",
231 	"IM_ELEC",
232 	"IM_FIRE",
233 	"IM_COLD",
234 	"IM_POIS",
235 	"XXX5X3",
236 	"RES_NETH",
237 	"IM_WATER",
238 	"RES_PLAS",
239 	"RES_NEXUS",
240 	"RES_DISE",
241 	"XXX6X3",
242 	"NO_FEAR",
243 	"NO_STUN",
244 	"NO_CONF",
245 	"NO_SLEEP"
246 };
247 
248 /*
249  * Monster race flags
250  */
251 static cptr r_info_flags4[] =
252 {
253 	"SHRIEK",
254 	"XXX2X4",
255 	"XXX3X4",
256 	"XXX4X4",
257 	"ARROW_1",
258 	"ARROW_2",
259 	"ARROW_3",
260 	"ARROW_4",
261 	"BR_ACID",
262 	"BR_ELEC",
263 	"BR_FIRE",
264 	"BR_COLD",
265 	"BR_POIS",
266 	"BR_NETH",
267 	"BR_LITE",
268 	"BR_DARK",
269 	"BR_CONF",
270 	"BR_SOUN",
271 	"BR_CHAO",
272 	"BR_DISE",
273 	"BR_NEXU",
274 	"BR_TIME",
275 	"BR_INER",
276 	"BR_GRAV",
277 	"BR_SHAR",
278 	"BR_PLAS",
279 	"BR_WALL",
280 	"BR_MANA",
281 	"XXX5X4",
282 	"XXX6X4",
283 	"XXX7X4",
284 	"BOULDER"
285 };
286 
287 /*
288  * Monster race flags
289  */
290 static cptr r_info_flags5[] =
291 {
292 	"BA_ACID",
293 	"BA_ELEC",
294 	"BA_FIRE",
295 	"BA_COLD",
296 	"BA_POIS",
297 	"BA_NETH",
298 	"BA_WATE",
299 	"BA_MANA",
300 	"BA_DARK",
301 	"DRAIN_MANA",
302 	"MIND_BLAST",
303 	"BRAIN_SMASH",
304 	"CAUSE_1",
305 	"CAUSE_2",
306 	"CAUSE_3",
307 	"CAUSE_4",
308 	"BO_ACID",
309 	"BO_ELEC",
310 	"BO_FIRE",
311 	"BO_COLD",
312 	"BO_POIS",
313 	"BO_NETH",
314 	"BO_WATE",
315 	"BO_MANA",
316 	"BO_PLAS",
317 	"BO_ICEE",
318 	"MISSILE",
319 	"SCARE",
320 	"BLIND",
321 	"CONF",
322 	"SLOW",
323 	"HOLD"
324 };
325 
326 /*
327  * Monster race flags
328  */
329 static cptr r_info_flags6[] =
330 {
331 	"HASTE",
332 	"XXX1X6",
333 	"HEAL",
334 	"XXX2X6",
335 	"BLINK",
336 	"TPORT",
337 	"XXX3X6",
338 	"XXX4X6",
339 	"TELE_TO",
340 	"TELE_AWAY",
341 	"TELE_LEVEL",
342 	"XXX5",
343 	"DARKNESS",
344 	"TRAPS",
345 	"FORGET",
346 	"XXX6X6",
347 	"S_KIN",
348 	"S_HI_DEMON",
349 	"S_MONSTER",
350 	"S_MONSTERS",
351 	"S_ANIMAL",
352 	"S_SPIDER",
353 	"S_HOUND",
354 	"S_HYDRA",
355 	"S_ANGEL",
356 	"S_DEMON",
357 	"S_UNDEAD",
358 	"S_DRAGON",
359 	"S_HI_UNDEAD",
360 	"S_HI_DRAGON",
361 	"S_WRAITH",
362 	"S_UNIQUE"
363 };
364 
365 /*
366  * Object flags
367  */
368 static cptr k_info_flags1[] =
369 {
370 	"STR",
371 	"INT",
372 	"WIS",
373 	"DEX",
374 	"CON",
375 	"CHR",
376 	"XXX1",
377 	"XXX2",
378 	"STEALTH",
379 	"SEARCH",
380 	"INFRA",
381 	"TUNNEL",
382 	"SPEED",
383 	"BLOWS",
384 	"SHOTS",
385 	"MIGHT",
386 	"SLAY_ANIMAL",
387 	"SLAY_EVIL",
388 	"SLAY_UNDEAD",
389 	"SLAY_DEMON",
390 	"SLAY_ORC",
391 	"SLAY_TROLL",
392 	"SLAY_GIANT",
393 	"SLAY_DRAGON",
394 	"KILL_DRAGON",
395 	"KILL_DEMON",
396 	"KILL_UNDEAD",
397 	"BRAND_POIS",
398 	"BRAND_ACID",
399 	"BRAND_ELEC",
400 	"BRAND_FIRE",
401 	"BRAND_COLD"
402 };
403 
404 /*
405  * Object flags
406  */
407 static cptr k_info_flags2[] =
408 {
409 	"SUST_STR",
410 	"SUST_INT",
411 	"SUST_WIS",
412 	"SUST_DEX",
413 	"SUST_CON",
414 	"SUST_CHR",
415 	"XXX1",
416 	"XXX2",
417 	"XXX3",
418 	"XXX4",
419 	"XXX5",
420 	"XXX6",
421 	"IM_ACID",
422 	"IM_ELEC",
423 	"IM_FIRE",
424 	"IM_COLD",
425 	"RES_ACID",
426 	"RES_ELEC",
427 	"RES_FIRE",
428 	"RES_COLD",
429 	"RES_POIS",
430 	"RES_FEAR",
431 	"RES_LITE",
432 	"RES_DARK",
433 	"RES_BLIND",
434 	"RES_CONFU",
435 	"RES_SOUND",
436 	"RES_SHARD",
437 	"RES_NEXUS",
438 	"RES_NETHR",
439 	"RES_CHAOS",
440 	"RES_DISEN"
441 };
442 
443 /*
444  * Object flags
445  */
446 static cptr k_info_flags3[] =
447 {
448 	"SLOW_DIGEST",
449 	"FEATHER",
450 	"LITE",
451 	"REGEN",
452 	"TELEPATHY",
453 	"SEE_INVIS",
454 	"FREE_ACT",
455 	"HOLD_LIFE",
456 	"XXX1",
457 	"XXX2",
458 	"XXX3",
459 	"XXX4",
460 	"IMPACT",
461 	"TELEPORT",
462 	"AGGRAVATE",
463 	"DRAIN_EXP",
464 	"IGNORE_ACID",
465 	"IGNORE_ELEC",
466 	"IGNORE_FIRE",
467 	"IGNORE_COLD",
468 	"XXX5",
469 	"XXX6",
470 	"BLESSED",
471 	"ACTIVATE",
472 	"INSTA_ART",
473 	"EASY_KNOW",
474 	"HIDE_TYPE",
475 	"SHOW_MODS",
476 	"XXX7",
477 	"LIGHT_CURSE",
478 	"HEAVY_CURSE",
479 	"PERMA_CURSE"
480 };
481 
482 /*
483  * Activation type flags
484  */
485 static cptr a_info_act[ACT_MAX] =
486 {
487 	"ILLUMINATION",
488 	"MAGIC_MAP",
489 	"CLAIRVOYANCE",
490 	"PROT_EVIL",
491 	"DISP_EVIL",
492 	"HEAL1",
493 	"HEAL2",
494 	"CURE_WOUNDS",
495 	"HASTE1",
496 	"HASTE2",
497 	"FIRE1",
498 	"FIRE2",
499 	"FIRE3",
500 	"FROST1",
501 	"FROST2",
502 	"FROST3",
503 	"FROST4",
504 	"FROST5",
505 	"ACID1",
506 	"RECHARGE1",
507 	"SLEEP",
508 	"LIGHTNING_BOLT",
509 	"ELEC2",
510 	"BANISHMENT",
511 	"MASS_BANISHMENT",
512 	"IDENTIFY",
513 	"DRAIN_LIFE1",
514 	"DRAIN_LIFE2",
515 	"BIZZARE",
516 	"STAR_BALL",
517 	"RAGE_BLESS_RESIST",
518 	"PHASE",
519 	"TRAP_DOOR_DEST",
520 	"DETECT",
521 	"RESIST",
522 	"TELEPORT",
523 	"RESTORE_LIFE",
524 	"MISSILE",
525 	"ARROW",
526 	"REM_FEAR_POIS",
527 	"STINKING_CLOUD",
528 	"STONE_TO_MUD",
529 	"TELE_AWAY",
530 	"WOR",
531 	"CONFUSE",
532 	"PROBE",
533 	"FIREBRAND",
534 	"STARLIGHT",
535 	"MANA_BOLT",
536 	"BERSERKER"
537 };
538 
539 
540 /*
541  * Class flags
542  */
543 static cptr c_info_flags[] =
544 {
545 	"EXTRA_SHOT",
546 	"BRAVERY_30",
547 	"BLESS_WEAPON",
548 	"CUMBER_GLOVE",
549 	"ZERO_FAIL",
550 	"BEAM",
551 	"CHOOSE_SPELLS",
552 	"PSEUDO_ID_HEAVY",
553 	"PSEUDO_ID_IMPROV",
554 	"XXX10",
555 	"XXX11",
556 	"XXX12",
557 	"XXX13",
558 	"XXX14",
559 	"XXX15",
560 	"XXX16",
561 	"BACK_STAB",
562 	"STEALTH_MODE",
563 	"STEALING_IMPROV",
564 	"SPEED_BONUS",
565 	"HP_BONUS",
566 	"XXX22",
567 	"XXX23",
568 	"XXX24",
569 	"XXX25",
570 	"XXX26",
571 	"XXX27",
572 	"XXX28",
573 	"XXX29",
574 	"XXX30",
575 	"XXX31",
576 	"XXX32"
577 };
578 
579 
580 /*** Initialize from ascii template files ***/
581 
582 
583 /*
584  * Initialize an "*_info" array, by parsing an ascii "template" file
585  */
init_info_txt(ang_file * fp,char * buf,header * head,parse_info_txt_func parse_info_txt_line)586 errr init_info_txt(ang_file* fp, char *buf, header *head,
587                    parse_info_txt_func parse_info_txt_line)
588 {
589 	errr err;
590 
591 	/* Not ready yet */
592 	bool okay = FALSE;
593 
594 	/* Just before the first record */
595 	error_idx = -1;
596 
597 	/* Just before the first line */
598 	error_line = 0;
599 
600 
601 	/* Prepare the "fake" stuff */
602 	head->name_size = 0;
603 	head->text_size = 0;
604 
605 	/* Parse */
606 	while (file_getl(fp, buf, 1024))
607 	{
608 		/* Advance the line number */
609 		error_line++;
610 
611 		/* Skip comments and blank lines */
612 		if (!buf[0] || (buf[0] == '#')) continue;
613 
614 		/* Verify correct "colon" format */
615 		if (buf[1] != ':') return (PARSE_ERROR_GENERIC);
616 
617 
618 		/* Hack -- Process 'V' for "Version" */
619 		if (buf[0] == 'V')
620 		{
621 			int v1, v2, v3;
622 
623 			/* Scan for the values */
624 			if ((3 != sscanf(buf+2, "%d.%d.%d", &v1, &v2, &v3)) ||
625 				(v1 != head->v_major) ||
626 				(v2 != head->v_minor) ||
627 				(v3 != head->v_patch))
628 			{
629 				return (PARSE_ERROR_OBSOLETE_FILE);
630 			}
631 
632 			/* Okay to proceed */
633 			okay = TRUE;
634 
635 			/* Continue */
636 			continue;
637 		}
638 
639 		/* No version yet */
640 		if (!okay) return (PARSE_ERROR_OBSOLETE_FILE);
641 
642 		/* Parse the line */
643 		if ((err = (*parse_info_txt_line)(buf, head)) != 0)
644 			return (err);
645 	}
646 
647 
648 	/* Complete the "name" and "text" sizes */
649 	if (head->name_size) head->name_size++;
650 	if (head->text_size) head->text_size++;
651 
652 
653 	/* No version yet */
654 	if (!okay) return (PARSE_ERROR_OBSOLETE_FILE);
655 
656 
657 	/* Success */
658 	return (0);
659 }
660 
661 
662 /*
663  * Add a text to the text-storage and store offset to it.
664  *
665  * Returns FALSE when there isn't enough space available to store
666  * the text.
667  */
add_text(u32b * offset,header * head,cptr buf)668 static bool add_text(u32b *offset, header *head, cptr buf)
669 {
670 	/* Hack -- Verify space */
671 	if (head->text_size + strlen(buf) + 8 > z_info->fake_text_size)
672 		return (FALSE);
673 
674 	/* New text? */
675 	if (*offset == 0)
676 	{
677 		/* Advance and save the text index */
678 		*offset = ++head->text_size;
679 	}
680 
681 	/* Append chars to the text */
682 	strcpy(head->text_ptr + head->text_size, buf);
683 
684 	/* Advance the index */
685 	head->text_size += strlen(buf);
686 
687 	/* Success */
688 	return (TRUE);
689 }
690 
691 
692 /*
693  * Add a name to the name-storage and return an offset to it.
694  *
695  * Returns 0 when there isn't enough space available to store
696  * the name.
697  */
add_name(header * head,cptr buf)698 static u32b add_name(header *head, cptr buf)
699 {
700 	u32b index;
701 
702 	/* Hack -- Verify space */
703 	if (head->name_size + strlen(buf) + 8 > z_info->fake_name_size)
704 		return (0);
705 
706 	/* Advance and save the name index */
707 	index = ++head->name_size;
708 
709 	/* Append chars to the names */
710 	strcpy(head->name_ptr + head->name_size, buf);
711 
712 	/* Advance the index */
713 	head->name_size += strlen(buf);
714 
715 	/* Return the name index */
716 	return (index);
717 }
718 
719 
720 /*
721  * Initialize the "z_info" structure, by parsing an ascii "template" file
722  */
parse_z_info(char * buf,header * head)723 errr parse_z_info(char *buf, header *head)
724 {
725 	maxima *z_info = head->info_ptr;
726 
727 	/* Hack - Verify 'M:x:' format */
728 	if (buf[0] != 'M') return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
729 	if (!buf[2]) return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
730 	if (buf[3] != ':') return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
731 
732 
733 	/* Process 'F' for "Maximum f_info[] index" */
734 	if (buf[2] == 'F')
735 	{
736 		int max;
737 
738 		/* Scan for the value */
739 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
740 
741 		/* Save the value */
742 		z_info->f_max = max;
743 	}
744 
745 	/* Process 'K' for "Maximum k_info[] index" */
746 	else if (buf[2] == 'K')
747 	{
748 		int max;
749 
750 		/* Scan for the value */
751 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
752 
753 		/* Save the value */
754 		z_info->k_max = max;
755 	}
756 
757 	/* Process 'A' for "Maximum a_info[] index" */
758 	else if (buf[2] == 'A')
759 	{
760 		int max;
761 
762 		/* Scan for the value */
763 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
764 
765 		/* Save the value */
766 		z_info->a_max = max;
767 	}
768 
769 	/* Process 'E' for "Maximum e_info[] index" */
770 	else if (buf[2] == 'E')
771 	{
772 		int max;
773 
774 		/* Scan for the value */
775 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
776 
777 		/* Save the value */
778 		z_info->e_max = max;
779 	}
780 
781 	/* Process 'R' for "Maximum r_info[] index" */
782 	else if (buf[2] == 'R')
783 	{
784 		int max;
785 
786 		/* Scan for the value */
787 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
788 
789 		/* Save the value */
790 		z_info->r_max = max;
791 	}
792 
793 
794 	/* Process 'V' for "Maximum v_info[] index" */
795 	else if (buf[2] == 'V')
796 	{
797 		int max;
798 
799 		/* Scan for the value */
800 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
801 
802 		/* Save the value */
803 		z_info->v_max = max;
804 	}
805 
806 
807 	/* Process 'P' for "Maximum p_info[] index" */
808 	else if (buf[2] == 'P')
809 	{
810 		int max;
811 
812 		/* Scan for the value */
813 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
814 
815 		/* Save the value */
816 		z_info->p_max = max;
817 	}
818 
819 	/* Process 'C' for "Maximum c_info[] index" */
820 	else if (buf[2] == 'C')
821 	{
822 		int max;
823 
824 		/* Scan for the value */
825 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
826 
827 		/* Save the value */
828 		z_info->c_max = max;
829 	}
830 
831 	/* Process 'H' for "Maximum h_info[] index" */
832 	else if (buf[2] == 'H')
833 	{
834 		int max;
835 
836 		/* Scan for the value */
837 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
838 
839 		/* Save the value */
840 		z_info->h_max = max;
841 	}
842 
843 	/* Process 'B' for "Maximum b_info[] subindex" */
844 	else if (buf[2] == 'B')
845 	{
846 		int max;
847 
848 		/* Scan for the value */
849 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
850 
851 		/* Save the value */
852 		z_info->b_max = max;
853 	}
854 
855 	/* Process 'L' for "Maximum flavor_info[] subindex" */
856 	else if (buf[2] == 'L')
857 	{
858 		int max;
859 
860 		/* Scan for the value */
861 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
862 
863 		/* Save the value */
864 		z_info->flavor_max = max;
865 	}
866 
867 	/* Process 'O' for "Maximum o_list[] index" */
868 	else if (buf[2] == 'O')
869 	{
870 		int max;
871 
872 		/* Scan for the value */
873 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
874 
875 		/* Save the value */
876 		z_info->o_max = max;
877 	}
878 
879 	/* Process 'M' for "Maximum mon_list[] index" */
880 	else if (buf[2] == 'M')
881 	{
882 		int max;
883 
884 		/* Scan for the value */
885 		if (1 != sscanf(buf+4, "%d", &max)) return (PARSE_ERROR_GENERIC);
886 
887 		/* Save the value */
888 		z_info->m_max = max;
889 	}
890 
891 	/* Process 'N' for "Fake name size" */
892 	else if (buf[2] == 'N')
893 	{
894 		long max;
895 
896 		/* Scan for the value */
897 		if (1 != sscanf(buf+4, "%ld", &max)) return (PARSE_ERROR_GENERIC);
898 
899 		/* Save the value */
900 		z_info->fake_name_size = max;
901 	}
902 
903 	/* Process 'T' for "Fake text size" */
904 	else if (buf[2] == 'T')
905 	{
906 		long max;
907 
908 		/* Scan for the value */
909 		if (1 != sscanf(buf+4, "%ld", &max)) return (PARSE_ERROR_GENERIC);
910 
911 		/* Save the value */
912 		z_info->fake_text_size = max;
913 	}
914 	else
915 	{
916 		/* Oops */
917 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
918 	}
919 
920 	/* Success */
921 	return (0);
922 }
923 
924 
925 /*
926  * Initialize the "v_info" array, by parsing an ascii "template" file
927  */
parse_v_info(char * buf,header * head)928 errr parse_v_info(char *buf, header *head)
929 {
930 	int i;
931 
932 	char *s;
933 
934 	/* Current entry */
935 	static vault_type *v_ptr = NULL;
936 
937 
938 	/* Process 'N' for "New/Number/Name" */
939 	if (buf[0] == 'N')
940 	{
941 		/* Find the colon before the name */
942 		s = strchr(buf+2, ':');
943 
944 		/* Verify that colon */
945 		if (!s) return (PARSE_ERROR_GENERIC);
946 
947 		/* Nuke the colon, advance to the name */
948 		*s++ = '\0';
949 
950 		/* Paranoia -- require a name */
951 		if (!*s) return (PARSE_ERROR_GENERIC);
952 
953 		/* Get the index */
954 		i = atoi(buf+2);
955 
956 		/* Verify information */
957 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
958 
959 		/* Verify information */
960 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
961 
962 		/* Save the index */
963 		error_idx = i;
964 
965 		/* Point at the "info" */
966 		v_ptr = (vault_type*)head->info_ptr + i;
967 
968 		/* Store the name */
969 		if (!(v_ptr->name = add_name(head, s)))
970 			return (PARSE_ERROR_OUT_OF_MEMORY);
971 	}
972 
973 	/* Process 'D' for "Description" */
974 	else if (buf[0] == 'D')
975 	{
976 		/* There better be a current v_ptr */
977 		if (!v_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
978 
979 		/* Get the text */
980 		s = buf+2;
981 
982 		/* Store the text */
983 		if (!add_text(&v_ptr->text, head, s))
984 			return (PARSE_ERROR_OUT_OF_MEMORY);
985 	}
986 
987 	/* Process 'X' for "Extra info" (one line only) */
988 	else if (buf[0] == 'X')
989 	{
990 		int typ, rat, hgt, wid;
991 
992 		/* There better be a current v_ptr */
993 		if (!v_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
994 
995 		/* Scan for the values */
996 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
997 			            &typ, &rat, &hgt, &wid)) return (PARSE_ERROR_GENERIC);
998 
999 		/* Save the values */
1000 		v_ptr->typ = typ;
1001 		v_ptr->rat = rat;
1002 		v_ptr->hgt = hgt;
1003 		v_ptr->wid = wid;
1004 
1005 		/* Check for maximum vault sizes */
1006 		if ((v_ptr->typ == 7) && ((v_ptr->wid > 33) || (v_ptr->hgt > 22)))
1007 			return (PARSE_ERROR_VAULT_TOO_BIG);
1008 
1009 		if ((v_ptr->typ == 8) && ((v_ptr->wid > 66) || (v_ptr->hgt > 44)))
1010 			return (PARSE_ERROR_VAULT_TOO_BIG);
1011 
1012 		/* HACK -- Allow Gigantic vaults */
1013 		if ((v_ptr->typ == 9) && ((v_ptr->wid > 99) || (v_ptr->hgt > 66)))
1014 			return (PARSE_ERROR_VAULT_TOO_BIG);
1015 		if (v_ptr->typ == 9) v_ptr->typ = 8;
1016 	}
1017 	else
1018 	{
1019 		/* Oops */
1020 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1021 	}
1022 
1023 	/* Success */
1024 	return (0);
1025 }
1026 
1027 
1028 /*
1029  * Grab one flag from a textual string
1030  */
grab_one_flag(u32b * flags,cptr names[],cptr what)1031 static errr grab_one_flag(u32b *flags, cptr names[], cptr what)
1032 {
1033 	int i;
1034 
1035 	/* Check flags */
1036 	for (i = 0; i < 32; i++)
1037 	{
1038 		if (streq(what, names[i]))
1039 		{
1040 			*flags |= (1L << i);
1041 			return (0);
1042 		}
1043 	}
1044 
1045 	return (-1);
1046 }
1047 
1048 /*
1049  * Grab one flag in a player class from a textual string
1050  */
grab_one_class_flag(player_class * pc_ptr,cptr what)1051 static errr grab_one_class_flag(player_class *pc_ptr, cptr what)
1052 {
1053 	if (grab_one_flag(&pc_ptr->flags, c_info_flags, what) == 0)
1054 		return (0);
1055 
1056 	/* Oops */
1057 	//msg_format("Unknown player class flag '%s'.", what);
1058 
1059 	/* Error */
1060 	return (PARSE_ERROR_GENERIC);
1061 }
1062 
1063 /*
1064  * Initialize the "c_info" array, by parsing an ascii "template" file
1065  */
parse_c_info(char * buf,header * head)1066 errr parse_c_info(char *buf, header *head)
1067 {
1068 	int i, j;
1069 
1070 	char *s, *t;
1071 
1072 	/* Current entry */
1073 	static player_class *pc_ptr = NULL;
1074 
1075 	static int cur_title = 0;
1076 	static int cur_equip = 0;
1077 
1078 	/* Process 'N' for "New/Number/Name" */
1079 	if (buf[0] == 'N')
1080 	{
1081 		/* Find the colon before the name */
1082 		s = strchr(buf+2, ':');
1083 
1084 		/* Verify that colon */
1085 		if (!s) return (PARSE_ERROR_GENERIC);
1086 
1087 		/* Nuke the colon, advance to the name */
1088 		*s++ = '\0';
1089 
1090 		/* Paranoia -- require a name */
1091 		if (!*s) return (PARSE_ERROR_GENERIC);
1092 
1093 		/* Get the index */
1094 		i = atoi(buf+2);
1095 
1096 		/* Verify information */
1097 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1098 
1099 		/* Verify information */
1100 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1101 
1102 		/* Save the index */
1103 		error_idx = i;
1104 
1105 		/* Point at the "info" */
1106 		pc_ptr = (player_class*)head->info_ptr + i;
1107 
1108 		/* Store the name */
1109 		if (!(pc_ptr->name = add_name(head, s)))
1110 			return (PARSE_ERROR_OUT_OF_MEMORY);
1111 
1112 		/* No titles and equipment yet */
1113 		cur_title = 0;
1114 		cur_equip = 0;
1115 
1116 		/* MAngband-specific hack: default color! */
1117 		pc_ptr->attr = TERM_WHITE;
1118 	}
1119 
1120 	/* Process 'S' for "Stats" (one line only) */
1121 	else if (buf[0] == 'S')
1122 	{
1123 		int adj;
1124 
1125 		/* There better be a current pc_ptr */
1126 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1127 
1128 		/* Start the string */
1129 		s = buf+1;
1130 
1131 		/* For each stat */
1132 		for (j = 0; j < A_MAX; j++)
1133 		{
1134 			/* Find the colon before the subindex */
1135 			s = strchr(s, ':');
1136 
1137 			/* Verify that colon */
1138 			if (!s) return (PARSE_ERROR_GENERIC);
1139 
1140 			/* Nuke the colon, advance to the subindex */
1141 			*s++ = '\0';
1142 
1143 			/* Get the value */
1144 			adj = atoi(s);
1145 
1146 			/* Save the value */
1147 			pc_ptr->c_adj[j] = adj;
1148 
1149 			/* Next... */
1150 			continue;
1151 		}
1152 	}
1153 
1154 	/* Process 'C' for "Class Skills" (one line only) */
1155 	else if (buf[0] == 'C')
1156 	{
1157 		int dis, dev, sav, stl, srh, fos, thn, thb;
1158 
1159 		/* There better be a current pc_ptr */
1160 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1161 
1162 		/* Scan for the values */
1163 		if (8 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d",
1164 			            &dis, &dev, &sav, &stl,
1165 			            &srh, &fos, &thn, &thb)) return (PARSE_ERROR_GENERIC);
1166 
1167 		/* Save the values */
1168 		pc_ptr->c_dis = dis;
1169 		pc_ptr->c_dev = dev;
1170 		pc_ptr->c_sav = sav;
1171 		pc_ptr->c_stl = stl;
1172 		pc_ptr->c_srh = srh;
1173 		pc_ptr->c_fos = fos;
1174 		pc_ptr->c_thn = thn;
1175 		pc_ptr->c_thb = thb;
1176 	}
1177 
1178 	/* Process 'X' for "Extra Skills" (one line only) */
1179 	else if (buf[0] == 'X')
1180 	{
1181 		int dis, dev, sav, stl, srh, fos, thn, thb;
1182 
1183 		/* There better be a current pc_ptr */
1184 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1185 
1186 		/* Scan for the values */
1187 		if (8 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d",
1188 			            &dis, &dev, &sav, &stl,
1189 			            &srh, &fos, &thn, &thb)) return (PARSE_ERROR_GENERIC);
1190 
1191 		/* Save the values */
1192 		pc_ptr->x_dis = dis;
1193 		pc_ptr->x_dev = dev;
1194 		pc_ptr->x_sav = sav;
1195 		pc_ptr->x_stl = stl;
1196 		pc_ptr->x_srh = srh;
1197 		pc_ptr->x_fos = fos;
1198 		pc_ptr->x_thn = thn;
1199 		pc_ptr->x_thb = thb;
1200 	}
1201 
1202 	/* Process 'I' for "Info" (one line only) */
1203 	else if (buf[0] == 'I')
1204 	{
1205 		int mhp, exp, sense_div;
1206 		long sense_base;
1207 
1208 		/* There better be a current pc_ptr */
1209 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1210 
1211 		/* Scan for the values */
1212 		if (4 != sscanf(buf+2, "%d:%d:%ld:%d",
1213 			            &mhp, &exp, &sense_base, &sense_div))
1214 			return (PARSE_ERROR_GENERIC);
1215 
1216 		/* Save the values */
1217 		pc_ptr->c_mhp = mhp;
1218 		pc_ptr->c_exp = exp;
1219 		pc_ptr->sense_base = sense_base;
1220 		pc_ptr->sense_div = sense_div;
1221 	}
1222 
1223 	/* Process 'A' for "Attack Info" (one line only) */
1224 	else if (buf[0] == 'A')
1225 	{
1226 		int max_attacks, min_weight, att_multiply;
1227 
1228 		/* There better be a current pc_ptr */
1229 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1230 
1231 		/* Scan for the values */
1232 		if (3 != sscanf(buf+2, "%d:%d:%d",
1233 			            &max_attacks, &min_weight, &att_multiply))
1234 			return (PARSE_ERROR_GENERIC);
1235 
1236 		/* Save the values */
1237 		pc_ptr->max_attacks = max_attacks;
1238 		pc_ptr->min_weight = min_weight;
1239 		pc_ptr->att_multiply = att_multiply;
1240 	}
1241 
1242 	/* Process 'M' for "Magic Info" (one line only) */
1243 	else if (buf[0] == 'M')
1244 	{
1245 		int spell_book, spell_stat, spell_first, spell_weight;
1246 
1247 		/* There better be a current pc_ptr */
1248 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1249 
1250 		/* Scan for the values */
1251 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1252 		                &spell_book, &spell_stat,
1253 		                &spell_first, &spell_weight))
1254 			return (PARSE_ERROR_GENERIC);
1255 
1256 		/* Save the values */
1257 		pc_ptr->spell_book = spell_book;
1258 		pc_ptr->spell_stat = spell_stat;
1259 		pc_ptr->spell_first = spell_first;
1260 		pc_ptr->spell_weight = spell_weight;
1261 	}
1262 
1263 	/* Process 'B' for "Spell/Prayer book info" */
1264 	else if (buf[0] == 'B')
1265 	{
1266 		int spell, level, mana, fail, exp;
1267 		player_magic *mp_ptr;
1268 		magic_type *spell_ptr;
1269 
1270 		/* There better be a current pc_ptr */
1271 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1272 
1273 		/* Scan for the values */
1274 		if (5 != sscanf(buf+2, "%d:%d:%d:%d:%d",
1275 		                &spell, &level, &mana, &fail, &exp))
1276 			return (PARSE_ERROR_GENERIC);
1277 
1278 		/* Validate the spell index */
1279 		if ((spell >= PY_MAX_SPELLS) || (spell < 0))
1280 			return (PARSE_ERROR_OUT_OF_BOUNDS);
1281 
1282 		mp_ptr = &pc_ptr->spells;
1283 		spell_ptr = &mp_ptr->info[spell];
1284 
1285 		/* Save the values */
1286 		spell_ptr->slevel = level;
1287 		spell_ptr->smana = mana;
1288 		spell_ptr->sfail = fail;
1289 		spell_ptr->sexp = exp;
1290 	}
1291 
1292 	/* Process 'T' for "Titles" */
1293 	else if (buf[0] == 'T')
1294 	{
1295 		/* There better be a current pc_ptr */
1296 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1297 
1298 		/* Get the text */
1299 		s = buf+2;
1300 
1301 		/* Store the text */
1302 		if (!add_text(&pc_ptr->title[cur_title], head, s))
1303 			return (PARSE_ERROR_OUT_OF_MEMORY);
1304 
1305 		/* Next title */
1306 		cur_title++;
1307 
1308 		/* Limit number of titles */
1309 		if (cur_title > PY_MAX_LEVEL / 5)
1310 			return (PARSE_ERROR_TOO_MANY_ARGUMENTS);
1311 	}
1312 
1313 	/* Process 'E' for "Starting Equipment" */
1314 	else if (buf[0] == 'E' || buf[0] == 'Y')
1315 	{
1316 		int tval, sval, min, max;
1317 
1318 		start_item *e_ptr;
1319 
1320 		/* Skip (non)Ironman items */
1321 		if ((buf[0] == 'E' && cfg_ironman) || (buf[0] == 'Y' && !cfg_ironman)) return (0);
1322 
1323 		/* There better be a current pc_ptr */
1324 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1325 
1326 		/* Access the item */
1327 		e_ptr = &pc_ptr->start_items[cur_equip];
1328 
1329 		/* Scan for the values */
1330 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1331 			            &tval, &sval, &min, &max)) return (PARSE_ERROR_GENERIC);
1332 
1333 		if ((min < 0) || (max < 0) || (min > 99) || (max > 99))
1334 			return (PARSE_ERROR_INVALID_ITEM_NUMBER);
1335 
1336 		/* Save the values */
1337 		e_ptr->tval = tval;
1338 		e_ptr->sval = sval;
1339 		e_ptr->min = min;
1340 		e_ptr->max = max;
1341 
1342 		/* Next item */
1343 		cur_equip++;
1344 
1345 		/* Limit number of starting items */
1346 		if (cur_equip > MAX_START_ITEMS)
1347 			return (PARSE_ERROR_GENERIC);
1348 	}
1349 
1350 	/* Process 'F' for flags */
1351 	else if (buf[0] == 'F')
1352 	{
1353 		/* There better be a current pc_ptr */
1354 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1355 
1356 		/* Parse every entry textually */
1357 		for (s = buf + 2; *s; )
1358 		{
1359 			/* Find the end of this entry */
1360 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1361 
1362 			/* Nuke and skip any dividers */
1363 			if (*t)
1364 			{
1365 				*t++ = '\0';
1366 				while ((*t == ' ') || (*t == '|')) t++;
1367 			}
1368 
1369 			/* Parse this entry */
1370 			if (0 != grab_one_class_flag(pc_ptr, s))
1371 				return (PARSE_ERROR_INVALID_FLAG);
1372 
1373 			/* Start the next entry */
1374 			s = t;
1375 		}
1376 	}
1377 
1378 	/* MAngband-specific HACK -- Process 'G' for class color */
1379 	else if (buf[0] == 'G')
1380 	{
1381 		/* There better be a current pr_ptr */
1382 		if (!pc_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1383 
1384 		/* Find the colon before the color */
1385 		s = strchr(buf+1, ':');
1386 
1387 		/* Verify that colon */
1388 		if (!s) return (PARSE_ERROR_GENERIC);
1389 
1390 		/* Nuke the colon, advance to the color */
1391 		*s++ = '\0';
1392 
1393 		/* Paranoia -- require a color */
1394 		if (!*s) return (PARSE_ERROR_GENERIC);
1395 
1396 		/* Get the color */
1397 		pc_ptr->attr = color_char_to_attr(s[0]);
1398 	}
1399 	else
1400 	{
1401 		/* Oops */
1402 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1403 	}
1404 
1405 	/* Success */
1406 	return (0);
1407 }
1408 
1409 
1410 
1411 /*
1412  * Initialize the "h_info" array, by parsing an ascii "template" file
1413  */
parse_h_info(char * buf,header * head)1414 errr parse_h_info(char *buf, header *head)
1415 {
1416 	int i;
1417 
1418 	char *s;
1419 
1420 	/* Current entry */
1421 	static hist_type *h_ptr = NULL;
1422 
1423 
1424 	/* Process 'N' for "New/Number" */
1425 	if (buf[0] == 'N')
1426 	{
1427 		int prv, nxt, prc, soc;
1428 
1429 		/* Hack - get the index */
1430 		i = error_idx + 1;
1431 
1432 		/* Verify information */
1433 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1434 
1435 		/* Verify information */
1436 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1437 
1438 		/* Save the index */
1439 		error_idx = i;
1440 
1441 		/* Point at the "info" */
1442 		h_ptr = (hist_type*)head->info_ptr + i;
1443 
1444 		/* Scan for the values */
1445 		if (4 != sscanf(buf, "N:%d:%d:%d:%d",
1446 			            &prv, &nxt, &prc, &soc)) return (PARSE_ERROR_GENERIC);
1447 
1448 		/* Save the values */
1449 		h_ptr->chart = prv;
1450 		h_ptr->next = nxt;
1451 		h_ptr->roll = prc;
1452 		h_ptr->bonus = soc;
1453 	}
1454 
1455 	/* Process 'D' for "Description" */
1456 	else if (buf[0] == 'D')
1457 	{
1458 		/* There better be a current h_ptr */
1459 		if (!h_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1460 
1461 		/* Get the text */
1462 		s = buf+2;
1463 
1464 		/* Store the text */
1465 		if (!add_text(&h_ptr->text, head, s))
1466 			return (PARSE_ERROR_OUT_OF_MEMORY);
1467 	}
1468 	else
1469 	{
1470 		/* Oops */
1471 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1472 	}
1473 
1474 	/* Success */
1475 	return (0);
1476 }
1477 
1478 
1479 
1480 /*
1481  * Initialize the "b_info" array, by parsing an ascii "template" file
1482  */
parse_b_info(char * buf,header * head)1483 errr parse_b_info(char *buf, header *head)
1484 {
1485 	int i, j;
1486 
1487 	char *s, *t;
1488 
1489 	/* Current entry */
1490 	static owner_type *ot_ptr = NULL;
1491 
1492 
1493 	/* Process 'N' for "New/Number/Name" */
1494 	if (buf[0] == 'N')
1495 	{
1496 		/* Find the colon before the subindex */
1497 		s = strchr(buf+2, ':');
1498 
1499 		/* Verify that colon */
1500 		if (!s) return (PARSE_ERROR_GENERIC);
1501 
1502 		/* Nuke the colon, advance to the subindex */
1503 		*s++ = '\0';
1504 
1505 		/* Get the index */
1506 		i = atoi(buf+2);
1507 
1508 		/* Find the colon before the name */
1509 		t = strchr(s, ':');
1510 
1511 		/* Verify that colon */
1512 		if (!t) return (PARSE_ERROR_GENERIC);
1513 
1514 		/* Nuke the colon, advance to the name */
1515 		*t++ = '\0';
1516 
1517 		/* Paranoia -- require a name */
1518 		if (!*t) return (PARSE_ERROR_GENERIC);
1519 
1520 		/* Get the subindex */
1521 		j = atoi(s);
1522 
1523 		/* Verify information */
1524 		if (j >= z_info->b_max) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1525 
1526 		/* Get the *real* index */
1527 		i = (i * z_info->b_max) + j;
1528 
1529 		/* Verify information */
1530 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1531 
1532 		/* Verify information */
1533 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1534 
1535 		/* Save the index */
1536 		error_idx = i;
1537 
1538 		/* Point at the "info" */
1539 		ot_ptr = (owner_type*)head->info_ptr + i;
1540 
1541 		/* Store the name */
1542 		if (!(ot_ptr->owner_name = add_name(head, t)))
1543 			return (PARSE_ERROR_OUT_OF_MEMORY);
1544 	}
1545 
1546 	/* Process 'I' for "Info" (one line only) */
1547 	else if (buf[0] == 'I')
1548 	{
1549 		int idx, gld, inflate, max_inflate  = 0;
1550 
1551 		/* There better be a current ot_ptr */
1552 		if (!ot_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1553 
1554 		/* Scan for the values */
1555 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1556 			            &idx, &gld, &inflate, &max_inflate))
1557 		if (3 != sscanf(buf+2, "%d:%d:%d",
1558 			            &idx, &gld, &inflate)) return (PARSE_ERROR_GENERIC);
1559 
1560 		/* Hack */
1561 		if (!max_inflate) max_inflate = inflate;
1562 
1563 		/* Save the values */
1564 		ot_ptr->owner_race = idx;
1565 		ot_ptr->max_cost = gld * PURSE_MULTIPLIER;
1566 		/*ot_ptr->inflate = inflate;*/
1567 		ot_ptr->max_inflate = max_inflate;
1568 		ot_ptr->min_inflate = inflate;
1569 	}
1570 	else
1571 	{
1572 		/* Oops */
1573 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1574 	}
1575 
1576 	/* Success */
1577 	return (0);
1578 }
1579 
1580 
1581 
1582 /*
1583  * Initialize the "g_info" array, by parsing an ascii "template" file
1584  */
parse_g_info(char * buf,header * head)1585 errr parse_g_info(char *buf, header *head)
1586 {
1587 	int i, j;
1588 
1589 	char *s;
1590 
1591 	/* Current entry */
1592 	static byte *g_ptr;
1593 
1594 
1595 	/* Process 'A' for "Adjustments" */
1596 	if (buf[0] == 'A')
1597 	{
1598 		int adj;
1599 
1600 		/* Start the string */
1601 		s = buf+1;
1602 
1603 		/* Initialize the counter to max races */
1604 		j = z_info->p_max;
1605 
1606 		/* Repeat */
1607 		while (j-- > 0)
1608 		{
1609 			/* Hack - get the index */
1610 			i = error_idx + 1;
1611 
1612 			/* Verify information */
1613 			if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1614 
1615 			/* Verify information */
1616 			if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1617 
1618 			/* Save the index */
1619 			error_idx = i;
1620 
1621 			/* Point at the "info" */
1622 			g_ptr = (byte*)head->info_ptr + i;
1623 
1624 			/* Find the colon before the subindex */
1625 			s = strchr(s, ':');
1626 
1627 			/* Verify that colon */
1628 			if (!s) return (PARSE_ERROR_GENERIC);
1629 
1630 			/* Nuke the colon, advance to the subindex */
1631 			*s++ = '\0';
1632 
1633 			/* Get the value */
1634 			adj = atoi(s);
1635 
1636 			/* Save the value */
1637 			*g_ptr = adj;
1638 		}
1639 	}
1640 	else
1641 	{
1642 		/* Oops */
1643 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1644 	}
1645 
1646 	/* Success */
1647 	return (0);
1648 }
1649 
1650 
1651 
1652 /*
1653  * Initialize the "f_info" array, by parsing an ascii "template" file
1654  */
parse_f_info(char * buf,header * head)1655 errr parse_f_info(char *buf, header *head)
1656 {
1657 	int i;
1658 
1659 	char *s;
1660 
1661 	/* Current entry */
1662 	static feature_type *f_ptr = NULL;
1663 
1664 
1665 	/* Process 'N' for "New/Number/Name" */
1666 	if (buf[0] == 'N')
1667 	{
1668 		/* Find the colon before the name */
1669 		s = strchr(buf+2, ':');
1670 
1671 		/* Verify that colon */
1672 		if (!s) return (PARSE_ERROR_GENERIC);
1673 
1674 		/* Nuke the colon, advance to the name */
1675 		*s++ = '\0';
1676 
1677 		/* Paranoia -- require a name */
1678 		if (!*s) return (PARSE_ERROR_GENERIC);
1679 
1680 		/* Get the index */
1681 		i = atoi(buf+2);
1682 
1683 		/* Verify information */
1684 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1685 
1686 		/* Verify information */
1687 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1688 
1689 		/* Save the index */
1690 		error_idx = i;
1691 
1692 		/* Point at the "info" */
1693 		f_ptr = (feature_type*)head->info_ptr + i;
1694 
1695 		/* Store the name */
1696 		if (!(f_ptr->name = add_name(head, s)))
1697 			return (PARSE_ERROR_OUT_OF_MEMORY);
1698 
1699 		/* Default "mimic" */
1700 		f_ptr->mimic = i;
1701 	}
1702 
1703 	/* Process 'M' for "Mimic" (one line only) */
1704 	else if (buf[0] == 'M')
1705 	{
1706 		int mimic;
1707 
1708 		/* There better be a current f_ptr */
1709 		if (!f_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1710 
1711 		/* Scan for the values */
1712 		if (1 != sscanf(buf+2, "%d",
1713 			            &mimic)) return (PARSE_ERROR_GENERIC);
1714 
1715 		/* Save the values */
1716 		f_ptr->mimic = mimic;
1717 	}
1718 
1719 	/* Process 'G' for "Graphics" (one line only) */
1720 	else if (buf[0] == 'G')
1721 	{
1722 		char d_char;
1723 		int d_attr;
1724 
1725 		/* There better be a current f_ptr */
1726 		if (!f_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1727 
1728 		/* Paranoia */
1729 		if (!buf[2]) return (PARSE_ERROR_GENERIC);
1730 		if (!buf[3]) return (PARSE_ERROR_GENERIC);
1731 		if (!buf[4]) return (PARSE_ERROR_GENERIC);
1732 
1733 		/* Extract d_char */
1734 		d_char = buf[2];
1735 
1736 		/* If we have a longer string than expected ... */
1737 		if (buf[5])
1738 		{
1739 			/* Advance "buf" on by 4 */
1740 			buf += 4;
1741 
1742 			/* Extract the colour */
1743 			d_attr = color_text_to_attr(buf);
1744 		}
1745 		else
1746 		{
1747 			/* Extract the attr */
1748 			d_attr = color_char_to_attr(buf[4]);
1749 		}
1750 
1751 		/* Paranoia */
1752 		if (d_attr < 0) return (PARSE_ERROR_GENERIC);
1753 
1754 		/* Save the values */
1755 		f_ptr->d_attr = d_attr;
1756 		f_ptr->d_char = d_char;
1757 	}
1758 	else
1759 	{
1760 		/* Oops */
1761 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
1762 	}
1763 
1764 	/* Success */
1765 	return (0);
1766 }
1767 
1768 
1769 
1770 /*
1771  * Grab one flag in a player_race from a textual string
1772  */
grab_one_racial_flag(player_race * pr_ptr,cptr what)1773 static errr grab_one_racial_flag(player_race *pr_ptr, cptr what)
1774 {
1775 	if (grab_one_flag(&pr_ptr->flags1, k_info_flags1, what) == 0)
1776 		return (0);
1777 
1778 	if (grab_one_flag(&pr_ptr->flags2, k_info_flags2, what) == 0)
1779 		return (0);
1780 
1781 	if (grab_one_flag(&pr_ptr->flags3, k_info_flags3, what) == 0)
1782 		return (0);
1783 
1784 	/* Oops */
1785 	//msg_format("Unknown player flag '%s'.", what);
1786 
1787 	/* Error */
1788 	return (PARSE_ERROR_GENERIC);
1789 }
1790 
1791 /*
1792  * Initialize the "p_info" array, by parsing an ascii "template" file
1793  */
parse_p_info(char * buf,header * head)1794 errr parse_p_info(char *buf, header *head)
1795 {
1796 	int i, j;
1797 
1798 	char *s, *t;
1799 
1800 	/* Current entry */
1801 	static player_race *pr_ptr = NULL;
1802 
1803 
1804 	/* Process 'N' for "New/Number/Name" */
1805 	if (buf[0] == 'N')
1806 	{
1807 		/* Find the colon before the name */
1808 		s = strchr(buf+2, ':');
1809 
1810 		/* Verify that colon */
1811 		if (!s) return (PARSE_ERROR_GENERIC);
1812 
1813 		/* Nuke the colon, advance to the name */
1814 		*s++ = '\0';
1815 
1816 		/* Paranoia -- require a name */
1817 		if (!*s) return (PARSE_ERROR_GENERIC);
1818 
1819 		/* Get the index */
1820 		i = atoi(buf+2);
1821 
1822 		/* Verify information */
1823 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
1824 
1825 		/* Verify information */
1826 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
1827 
1828 		/* Save the index */
1829 		error_idx = i;
1830 
1831 		/* Point at the "info" */
1832 		pr_ptr = (player_race*)head->info_ptr + i;
1833 
1834 		/* Store the name */
1835 		if (!(pr_ptr->name = add_name(head, s)))
1836 			return (PARSE_ERROR_OUT_OF_MEMORY);
1837 	}
1838 
1839 	/* Process 'S' for "Stats" (one line only) */
1840 	else if (buf[0] == 'S')
1841 	{
1842 		int adj;
1843 
1844 		/* There better be a current pr_ptr */
1845 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1846 
1847 		/* Start the string */
1848 		s = buf+1;
1849 
1850 		/* For each stat */
1851 		for (j = 0; j < A_MAX; j++)
1852 		{
1853 			/* Find the colon before the subindex */
1854 			s = strchr(s, ':');
1855 
1856 			/* Verify that colon */
1857 			if (!s) return (PARSE_ERROR_GENERIC);
1858 
1859 			/* Nuke the colon, advance to the subindex */
1860 			*s++ = '\0';
1861 
1862 			/* Get the value */
1863 			adj = atoi(s);
1864 
1865 			/* Save the value */
1866 			pr_ptr->r_adj[j] = adj;
1867 
1868 			/* Next... */
1869 			continue;
1870 		}
1871 	}
1872 
1873 	/* Process 'R' for "Racial Skills" (one line only) */
1874 	else if (buf[0] == 'R')
1875 	{
1876 		int dis, dev, sav, stl, srh, fos, thn, thb;
1877 
1878 		/* There better be a current pr_ptr */
1879 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1880 
1881 		/* Scan for the values */
1882 		if (8 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d",
1883 			            &dis, &dev, &sav, &stl,
1884 			            &srh, &fos, &thn, &thb)) return (PARSE_ERROR_GENERIC);
1885 
1886 		/* Save the values */
1887 		pr_ptr->r_dis = dis;
1888 		pr_ptr->r_dev = dev;
1889 		pr_ptr->r_sav = sav;
1890 		pr_ptr->r_stl = stl;
1891 		pr_ptr->r_srh = srh;
1892 		pr_ptr->r_fos = fos;
1893 		pr_ptr->r_thn = thn;
1894 		pr_ptr->r_thb = thb;
1895 	}
1896 
1897 	/* Process 'X' for "Extra Info" (one line only) */
1898 	else if (buf[0] == 'X')
1899 	{
1900 		int mhp, exp, infra;
1901 
1902 		/* There better be a current pr_ptr */
1903 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1904 
1905 		/* Scan for the values */
1906 		if (3 != sscanf(buf+2, "%d:%d:%d",
1907 			            &mhp, &exp, &infra)) return (PARSE_ERROR_GENERIC);
1908 
1909 		/* Save the values */
1910 		pr_ptr->r_mhp = mhp;
1911 		pr_ptr->r_exp = exp;
1912 		pr_ptr->infra = infra;
1913 	}
1914 
1915 	/* Hack -- Process 'I' for "info" and such */
1916 	else if (buf[0] == 'I')
1917 	{
1918 		int hist, b_age, m_age;
1919 
1920 		/* There better be a current pr_ptr */
1921 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1922 
1923 		/* Scan for the values */
1924 		if (3 != sscanf(buf+2, "%d:%d:%d",
1925 			            &hist, &b_age, &m_age)) return (PARSE_ERROR_GENERIC);
1926 
1927 		pr_ptr->hist = hist;
1928 		pr_ptr->b_age = b_age;
1929 		pr_ptr->m_age = m_age;
1930 	}
1931 
1932 	/* Hack -- Process 'H' for "Height" */
1933 	else if (buf[0] == 'H')
1934 	{
1935 		int m_b_ht, m_m_ht, f_b_ht, f_m_ht;
1936 
1937 		/* There better be a current pr_ptr */
1938 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1939 
1940 		/* Scan for the values */
1941 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1942 			            &m_b_ht, &m_m_ht, &f_b_ht, &f_m_ht)) return (PARSE_ERROR_GENERIC);
1943 
1944 		pr_ptr->m_b_ht = m_b_ht;
1945 		pr_ptr->m_m_ht = m_m_ht;
1946 		pr_ptr->f_b_ht = f_b_ht;
1947 		pr_ptr->f_m_ht = f_m_ht;
1948 	}
1949 
1950 	/* Hack -- Process 'W' for "Weight" */
1951 	else if (buf[0] == 'W')
1952 	{
1953 		int m_b_wt, m_m_wt, f_b_wt, f_m_wt;
1954 
1955 		/* There better be a current pr_ptr */
1956 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1957 
1958 		/* Scan for the values */
1959 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1960 			            &m_b_wt, &m_m_wt, &f_b_wt, &f_m_wt)) return (PARSE_ERROR_GENERIC);
1961 
1962 		pr_ptr->m_b_wt = m_b_wt;
1963 		pr_ptr->m_m_wt = m_m_wt;
1964 		pr_ptr->f_b_wt = f_b_wt;
1965 		pr_ptr->f_m_wt = f_m_wt;
1966 	}
1967 
1968 	/* Hack -- Process 'F' for flags */
1969 	else if (buf[0] == 'F')
1970 	{
1971 		/* There better be a current pr_ptr */
1972 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
1973 
1974 		/* Parse every entry textually */
1975 		for (s = buf + 2; *s; )
1976 		{
1977 			/* Find the end of this entry */
1978 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1979 
1980 			/* Nuke and skip any dividers */
1981 			if (*t)
1982 			{
1983 				*t++ = '\0';
1984 				while ((*t == ' ') || (*t == '|')) t++;
1985 			}
1986 
1987 			/* Parse this entry */
1988 			if (0 != grab_one_racial_flag(pr_ptr, s)) return (PARSE_ERROR_INVALID_FLAG);
1989 
1990 			/* Start the next entry */
1991 			s = t;
1992 		}
1993 	}
1994 
1995 	/* Hack -- Process 'C' for class choices */
1996 	else if (buf[0] == 'C')
1997 	{
1998 		/* There better be a current pr_ptr */
1999 		if (!pr_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2000 
2001 		/* Parse every entry textually */
2002 		for (s = buf + 2; *s; )
2003 		{
2004 			/* Find the end of this entry */
2005 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2006 
2007 			/* Nuke and skip any dividers */
2008 			if (*t)
2009 			{
2010 				*t++ = '\0';
2011 				while ((*t == ' ') || (*t == '|')) t++;
2012 			}
2013 
2014 			/* Hack - Parse this entry */
2015 			pr_ptr->choice |= (1 << atoi(s));
2016 
2017 			/* Start the next entry */
2018 			s = t;
2019 		}
2020 	}
2021 	else
2022 	{
2023 		/* Oops */
2024 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
2025 	}
2026 
2027 	/* Success */
2028 	return (0);
2029 }
2030 
2031 
2032 
2033 /*
2034  * Grab one flag in an object_kind from a textual string
2035  */
grab_one_kind_flag(object_kind * k_ptr,cptr what)2036 static errr grab_one_kind_flag(object_kind *k_ptr, cptr what)
2037 {
2038 	int i;
2039 
2040 	/* Check flags1 */
2041 	for (i = 0; i < 32; i++)
2042 	{
2043 		if (streq(what, k_info_flags1[i]))
2044 		{
2045 			k_ptr->flags1 |= (1L << i);
2046 			return (0);
2047 		}
2048 	}
2049 
2050 	/* Check flags2 */
2051 	for (i = 0; i < 32; i++)
2052 	{
2053 		if (streq(what, k_info_flags2[i]))
2054 		{
2055 			k_ptr->flags2 |= (1L << i);
2056 			return (0);
2057 		}
2058 	}
2059 
2060 	/* Check flags3 */
2061 	for (i = 0; i < 32; i++)
2062 	{
2063 		if (streq(what, k_info_flags3[i]))
2064 		{
2065 			k_ptr->flags3 |= (1L << i);
2066 			return (0);
2067 		}
2068 	}
2069 
2070     /* Check flags4 */
2071     /*
2072     for (i = 0; i < 32; i++)
2073     {
2074         if (streq(what, k_info_flags4[i]))
2075         {
2076             k_ptr->flags4 |= (1L << i);
2077             return (0);
2078         }
2079     }
2080     */
2081 
2082 	/* Oops */
2083 	plog(format("Unknown object flag '%s'.", what));
2084 
2085 	/* Error */
2086 	return (1);
2087 }
2088 
2089 /*
2090  * Initialize the "k_info" array, by parsing an ascii "template" file
2091  */
parse_k_info(char * buf,header * head)2092 errr parse_k_info(char *buf, header *head)
2093 {
2094 	int i;
2095 
2096 	char *s, *t;
2097 
2098 	/* Current entry */
2099 	static object_kind *k_ptr = NULL;
2100 
2101 
2102 	/* Process 'N' for "New/Number/Name" */
2103 	if (buf[0] == 'N')
2104 	{
2105 		/* Find the colon before the name */
2106 		s = strchr(buf+2, ':');
2107 
2108 		/* Verify that colon */
2109 		if (!s) return (PARSE_ERROR_GENERIC);
2110 
2111 		/* Nuke the colon, advance to the name */
2112 		*s++ = '\0';
2113 
2114 		/* Paranoia -- require a name */
2115 		if (!*s) return (PARSE_ERROR_GENERIC);
2116 
2117 		/* Get the index */
2118 		i = atoi(buf+2);
2119 
2120 		/* Verify information */
2121 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
2122 
2123 		/* Verify information */
2124 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
2125 
2126 		/* Save the index */
2127 		error_idx = i;
2128 
2129 		/* Point at the "info" */
2130 		k_ptr = (object_kind*)head->info_ptr + i;
2131 
2132 		/* Store the name */
2133 		if (!(k_ptr->name = add_name(head, s)))
2134 			return (PARSE_ERROR_OUT_OF_MEMORY);
2135 	}
2136 
2137 	/* Process 'G' for "Graphics" (one line only) */
2138 	else if (buf[0] == 'G')
2139 	{
2140 		char d_char;
2141 		int d_attr;
2142 
2143 		/* There better be a current k_ptr */
2144 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2145 
2146 		/* Paranoia */
2147 		if (!buf[2]) return (PARSE_ERROR_GENERIC);
2148 		if (!buf[3]) return (PARSE_ERROR_GENERIC);
2149 		if (!buf[4]) return (PARSE_ERROR_GENERIC);
2150 
2151 		/* Extract d_char */
2152 		d_char = buf[2];
2153 
2154 		/* If we have a longer string than expected ... */
2155 		if (buf[5])
2156 		{
2157 			/* Advance "buf" on by 4 */
2158 			buf += 4;
2159 
2160 			/* Extract the colour */
2161 			d_attr = color_text_to_attr(buf);
2162 		}
2163 		else
2164 		{
2165 			/* Extract the attr */
2166 			d_attr = color_char_to_attr(buf[4]);
2167 		}
2168 
2169 		/* Paranoia */
2170 		if (d_attr < 0) return (PARSE_ERROR_GENERIC);
2171 
2172 		/* Save the values */
2173 		k_ptr->d_attr = d_attr;
2174 		k_ptr->d_char = d_char;
2175 	}
2176 
2177 	/* Process 'I' for "Info" (one line only) */
2178 	else if (buf[0] == 'I')
2179 	{
2180 		int tval, sval, pval;
2181 
2182 		/* There better be a current k_ptr */
2183 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2184 
2185 		/* Scan for the values */
2186 		if (3 != sscanf(buf+2, "%d:%d:%d",
2187 			            &tval, &sval, &pval)) return (PARSE_ERROR_GENERIC);
2188 
2189 		/* Save the values */
2190 		k_ptr->tval = tval;
2191 		k_ptr->sval = sval;
2192 		k_ptr->pval = pval;
2193 	}
2194 
2195 	/* Process 'W' for "More Info" (one line only) */
2196 	else if (buf[0] == 'W')
2197 	{
2198 		int level, extra, wgt;
2199 		long cost;
2200 
2201 		/* There better be a current k_ptr */
2202 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2203 
2204 		/* Scan for the values */
2205 		if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
2206 			            &level, &extra, &wgt, &cost)) return (PARSE_ERROR_GENERIC);
2207 
2208 		/* Save the values */
2209 		k_ptr->level = level;
2210 		k_ptr->extra = extra;
2211 		k_ptr->weight = wgt;
2212 		k_ptr->cost = cost;
2213 	}
2214 
2215 	/* Process 'A' for "Allocation" (one line only) */
2216 	else if (buf[0] == 'A')
2217 	{
2218 		int i;
2219 
2220 		/* There better be a current k_ptr */
2221 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2222 
2223 		/* XXX Simply read each number following a colon */
2224 		for (i = 0, s = buf+1; s && (s[0] == ':') && s[1]; ++i)
2225 		{
2226 			/* Sanity check */
2227 			if (i > 3) return (PARSE_ERROR_TOO_MANY_ALLOCATIONS);
2228 
2229 			/* Default chance */
2230 			k_ptr->chance[i] = 1;
2231 
2232 			/* Store the attack damage index */
2233 			k_ptr->locale[i] = atoi(s+1);
2234 
2235 			/* Find the slash */
2236 			t = strchr(s+1, '/');
2237 
2238 			/* Find the next colon */
2239 			s = strchr(s+1, ':');
2240 
2241 			/* If the slash is "nearby", use it */
2242 			if (t && (!s || t < s))
2243 			{
2244 				int chance = atoi(t+1);
2245 				if (chance > 0) k_ptr->chance[i] = chance;
2246 			}
2247 		}
2248 	}
2249 
2250 	/* Hack -- Process 'P' for "power" and such */
2251 	else if (buf[0] == 'P')
2252 	{
2253 		int ac, hd1, hd2, th, td, ta;
2254 
2255 		/* There better be a current k_ptr */
2256 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2257 
2258 		/* Scan for the values */
2259 		if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
2260 			            &ac, &hd1, &hd2, &th, &td, &ta)) return (PARSE_ERROR_GENERIC);
2261 
2262 		k_ptr->ac = ac;
2263 		k_ptr->dd = hd1;
2264 		k_ptr->ds = hd2;
2265 		k_ptr->to_h = th;
2266 		k_ptr->to_d = td;
2267 		k_ptr->to_a =  ta;
2268 	}
2269 
2270 	/* Hack -- Process 'F' for flags */
2271 	else if (buf[0] == 'F')
2272 	{
2273 		/* There better be a current k_ptr */
2274 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2275 
2276 		/* Parse every entry textually */
2277 		for (s = buf + 2; *s; )
2278 		{
2279 			/* Find the end of this entry */
2280 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2281 
2282 			/* Nuke and skip any dividers */
2283 			if (*t)
2284 			{
2285 				*t++ = '\0';
2286 				while (*t == ' ' || *t == '|') t++;
2287 			}
2288 
2289 			/* Parse this entry */
2290 			if (0 != grab_one_kind_flag(k_ptr, s)) return (PARSE_ERROR_INVALID_FLAG);
2291 
2292 			/* Start the next entry */
2293 			s = t;
2294 		}
2295 	}
2296 
2297 	/* Process 'D' for "Description" */
2298 	else if (buf[0] == 'D')
2299 	{
2300 		/* There better be a current k_ptr */
2301 		if (!k_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2302 
2303 		/* Get the text */
2304 		s = buf+2;
2305 
2306 		/* Store the text */
2307 		if (!add_text(&(k_ptr->text), head, s))
2308 			return (PARSE_ERROR_OUT_OF_MEMORY);
2309 	}
2310 
2311 	else
2312 	{
2313 		/* Oops */
2314 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
2315 	}
2316 
2317 	/* Success */
2318 	return (0);
2319 }
2320 
2321 
2322 
2323 /*
2324  * Grab one flag in an artifact_type from a textual string
2325  */
grab_one_artifact_flag(artifact_type * a_ptr,cptr what)2326 static errr grab_one_artifact_flag(artifact_type *a_ptr, cptr what)
2327 {
2328 	int i;
2329 
2330 	/* Check flags1 */
2331 	for (i = 0; i < 32; i++)
2332 	{
2333 		if (streq(what, k_info_flags1[i]))
2334 		{
2335 			a_ptr->flags1 |= (1L << i);
2336 			return (0);
2337 		}
2338 	}
2339 
2340 	/* Check flags2 */
2341 	for (i = 0; i < 32; i++)
2342 	{
2343 		if (streq(what, k_info_flags2[i]))
2344 		{
2345 			a_ptr->flags2 |= (1L << i);
2346 			return (0);
2347 		}
2348 	}
2349 
2350 	/* Check flags3 */
2351 	for (i = 0; i < 32; i++)
2352 	{
2353 		if (streq(what, k_info_flags3[i]))
2354 		{
2355 			a_ptr->flags3 |= (1L << i);
2356 			return (0);
2357 		}
2358 	}
2359 
2360     /* Check flags4 */
2361     /*
2362     for (i = 0; i < 32; i++)
2363     {
2364         if (streq(what, k_info_flags4[i]))
2365         {
2366             a_ptr->flags4 |= (1L << i);
2367             return (0);
2368         }
2369     }
2370     */
2371 
2372 	/* Oops */
2373 	plog(format("Unknown artifact flag '%s'.", what));
2374 
2375 	/* Error */
2376 	return (1);
2377 }
2378 
2379 /*
2380  * Grab one activation from a textual string
2381  */
grab_one_activation(artifact_type * a_ptr,cptr what)2382 static errr grab_one_activation(artifact_type *a_ptr, cptr what)
2383 {
2384 	int i;
2385 
2386 	/* Scan activations */
2387 	for (i = 0; i < ACT_MAX; i++)
2388 	{
2389 		if (streq(what, a_info_act[i]))
2390 		{
2391 			a_ptr->activation = i;
2392 			return (0);
2393 		}
2394 	}
2395 
2396 	/* Oops */
2397 	plog(format("Unknown artifact activation '%s'.", what));
2398 
2399 	/* Error */
2400 	return (1);
2401 }
2402 
2403 /*
2404  * Initialize the "a_info" array, by parsing an ascii "template" file
2405  */
parse_a_info(char * buf,header * head)2406 errr parse_a_info(char *buf, header *head)
2407 {
2408 	int i;
2409 
2410 	char *s, *t;
2411 
2412 	/* Current entry */
2413 	static artifact_type *a_ptr = NULL;
2414 
2415 
2416 	/* Process 'N' for "New/Number/Name" */
2417 	if (buf[0] == 'N')
2418 	{
2419 		/* Find the colon before the name */
2420 		s = strchr(buf+2, ':');
2421 
2422 		/* Verify that colon */
2423 		if (!s) return (PARSE_ERROR_GENERIC);
2424 
2425 		/* Nuke the colon, advance to the name */
2426 		*s++ = '\0';
2427 
2428 		/* Paranoia -- require a name */
2429 		if (!*s) return (PARSE_ERROR_GENERIC);
2430 
2431 		/* Get the index */
2432 		i = atoi(buf+2);
2433 
2434 		/* Verify information */
2435 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
2436 
2437 		/* Verify information */
2438 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
2439 
2440 		/* Save the index */
2441 		error_idx = i;
2442 
2443 		/* Point at the "info" */
2444 		a_ptr = (artifact_type*)head->info_ptr + i;
2445 
2446 		/* Store the name */
2447 		if (!(a_ptr->name = add_name(head, s)))
2448 			return (PARSE_ERROR_OUT_OF_MEMORY);
2449 
2450 		/* Ignore everything */
2451 		a_ptr->flags3 |= (TR3_IGNORE_MASK);
2452 	}
2453 
2454 	/* Process 'I' for "Info" (one line only) */
2455 	else if (buf[0] == 'I')
2456 	{
2457 		int tval, sval, pval;
2458 
2459 		/* There better be a current a_ptr */
2460 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2461 
2462 		/* Scan for the values */
2463 		if (3 != sscanf(buf+2, "%d:%d:%d",
2464 			            &tval, &sval, &pval)) return (PARSE_ERROR_GENERIC);
2465 
2466 		/* Save the values */
2467 		a_ptr->tval = tval;
2468 		a_ptr->sval = sval;
2469 		a_ptr->pval = pval;
2470 	}
2471 
2472 	/* Process 'W' for "More Info" (one line only) */
2473 	else if (buf[0] == 'W')
2474 	{
2475 		int level, rarity, wgt;
2476 		long cost;
2477 
2478 		/* There better be a current a_ptr */
2479 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2480 
2481 		/* Scan for the values */
2482 		if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
2483 			            &level, &rarity, &wgt, &cost)) return (PARSE_ERROR_GENERIC);
2484 
2485 		/* Save the values */
2486 		a_ptr->level = level;
2487 		a_ptr->rarity = rarity;
2488 		a_ptr->weight = wgt;
2489 		a_ptr->cost = cost;
2490 	}
2491 
2492 	/* Process 'P' for "power" and such */
2493 	else if (buf[0] == 'P')
2494 	{
2495 		int ac, hd1, hd2, th, td, ta;
2496 
2497 		/* There better be a current a_ptr */
2498 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2499 
2500 		/* Scan for the values */
2501 		if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
2502 			            &ac, &hd1, &hd2, &th, &td, &ta)) return (PARSE_ERROR_GENERIC);
2503 
2504 		a_ptr->ac = ac;
2505 		a_ptr->dd = hd1;
2506 		a_ptr->ds = hd2;
2507 		a_ptr->to_h = th;
2508 		a_ptr->to_d = td;
2509 		a_ptr->to_a = ta;
2510 	}
2511 
2512 	/* Process 'F' for flags */
2513 	else if (buf[0] == 'F')
2514 	{
2515 		/* There better be a current a_ptr */
2516 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2517 
2518 		/* Parse every entry textually */
2519 		for (s = buf + 2; *s; )
2520 		{
2521 			/* Find the end of this entry */
2522 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2523 
2524 			/* Nuke and skip any dividers */
2525 			if (*t)
2526 			{
2527 				*t++ = '\0';
2528 				while ((*t == ' ') || (*t == '|')) t++;
2529 			}
2530 
2531 			/* Parse this entry */
2532 			if (0 != grab_one_artifact_flag(a_ptr, s)) return (PARSE_ERROR_INVALID_FLAG);
2533 
2534 			/* Start the next entry */
2535 			s = t;
2536 		}
2537 	}
2538 
2539 	/* Process 'A' for "Activation & time" */
2540 	else if (buf[0] == 'A')
2541 	{
2542 		int time, rand;
2543 
2544 		/* There better be a current a_ptr */
2545 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2546 
2547 		/* Find the colon before the name */
2548 		s = strchr(buf + 2, ':');
2549 
2550 		/* Verify that colon */
2551 		if (!s) return (PARSE_ERROR_GENERIC);
2552 
2553 		/* Nuke the colon, advance to the name */
2554 		*s++ = '\0';
2555 
2556 		/* Paranoia -- require a name */
2557 		if (!*s) return (PARSE_ERROR_GENERIC);
2558 
2559 		/* Get the activation */
2560 		if (grab_one_activation(a_ptr, buf + 2)) return (PARSE_ERROR_GENERIC);
2561 
2562 		/* Scan for the values */
2563 		if (2 != sscanf(s, "%d:%d",
2564 			            &time, &rand)) return (PARSE_ERROR_GENERIC);
2565 
2566 		/* Save the values */
2567 		a_ptr->time = time;
2568 		a_ptr->randtime = rand;
2569 	}
2570 
2571 	/* Process 'D' for "Description" */
2572 	else if (buf[0] == 'D')
2573 	{
2574 		/* There better be a current a_ptr */
2575 		if (!a_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2576 
2577 		/* Get the text */
2578 		s = buf+2;
2579 
2580 		/* Store the text */
2581 		if (!add_text(&a_ptr->text, head, s))
2582 			return (PARSE_ERROR_OUT_OF_MEMORY);
2583 	}
2584 
2585 	else
2586 	{
2587 		/* Oops */
2588 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
2589 	}
2590 
2591 	/* Success */
2592 	return (0);
2593 }
2594 
2595 
2596 
2597 /*
2598  * Grab one flag in a ego-item_type from a textual string
2599  */
grab_one_ego_item_flag(ego_item_type * e_ptr,cptr what)2600 static bool grab_one_ego_item_flag(ego_item_type *e_ptr, cptr what)
2601 {
2602 	int i;
2603 
2604 	/* Check flags1 */
2605 	for (i = 0; i < 32; i++)
2606 	{
2607 		if (streq(what, k_info_flags1[i]))
2608 		{
2609 			e_ptr->flags1 |= (1L << i);
2610 			return (0);
2611 		}
2612 	}
2613 
2614 	/* Check flags2 */
2615 	for (i = 0; i < 32; i++)
2616 	{
2617 		if (streq(what, k_info_flags2[i]))
2618 		{
2619 			e_ptr->flags2 |= (1L << i);
2620 			return (0);
2621 		}
2622 	}
2623 
2624 	/* Check flags3 */
2625 	for (i = 0; i < 32; i++)
2626 	{
2627 		if (streq(what, k_info_flags3[i]))
2628 		{
2629 			e_ptr->flags3 |= (1L << i);
2630 			return (0);
2631 		}
2632 	}
2633 
2634     /* Check flags4 */
2635     /*
2636     for (i = 0; i < 32; i++)
2637     {
2638         if (streq(what, k_info_flags4[i]))
2639         {
2640             e_ptr->flags4 |= (1L << i);
2641             return (0);
2642         }
2643     }
2644     */
2645 
2646 	/* Oops */
2647 	plog(format("Unknown ego-item flag '%s'.", what));
2648 
2649 	/* Error */
2650 	return (1);
2651 }
2652 
2653 /*
2654  * Initialize the "e_info" array, by parsing an ascii "template" file
2655  */
parse_e_info(char * buf,header * head)2656 errr parse_e_info(char *buf, header *head)
2657 {
2658 	int i;
2659 
2660 	char *s, *t;
2661 
2662 	/* Current entry */
2663 	static ego_item_type *e_ptr = NULL;
2664 
2665 	static int cur_t = 0;
2666 
2667 
2668 	/* Process 'N' for "New/Number/Name" */
2669 	if (buf[0] == 'N')
2670 	{
2671 		/* Find the colon before the name */
2672 		s = strchr(buf+2, ':');
2673 
2674 		/* Verify that colon */
2675 		if (!s) return (PARSE_ERROR_GENERIC);
2676 
2677 		/* Nuke the colon, advance to the name */
2678 		*s++ = '\0';
2679 
2680 		/* Paranoia -- require a name */
2681 		if (!*s) return (PARSE_ERROR_GENERIC);
2682 
2683 		/* Get the index */
2684 		i = atoi(buf+2);
2685 
2686 		/* Verify information */
2687 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
2688 
2689 		/* Verify information */
2690 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
2691 
2692 		/* Save the index */
2693 		error_idx = i;
2694 
2695 		/* Point at the "info" */
2696 		e_ptr = (ego_item_type*)head->info_ptr + i;
2697 
2698 		/* Store the name */
2699 		if (!(e_ptr->name = add_name(head, s)))
2700 			return (PARSE_ERROR_OUT_OF_MEMORY);
2701 
2702 		/* Start with the first of the tval indices */
2703 		cur_t = 0;
2704 	}
2705 
2706 	/* Process 'W' for "More Info" (one line only) */
2707 	else if (buf[0] == 'W')
2708 	{
2709 		int level, rarity, pad2;
2710 		long cost;
2711 
2712 		/* There better be a current e_ptr */
2713 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2714 
2715 		/* Scan for the values */
2716 		if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
2717 			            &level, &rarity, &pad2, &cost)) return (PARSE_ERROR_GENERIC);
2718 
2719 		/* Save the values */
2720 		e_ptr->level = level;
2721 		e_ptr->rarity = rarity;
2722 		/* e_ptr->weight = wgt; */
2723 		e_ptr->cost = cost;
2724 	}
2725 
2726 	/* Process 'X' for "Xtra" (one line only) */
2727 	else if (buf[0] == 'X')
2728 	{
2729 		int rating, xtra;
2730 
2731 		/* There better be a current e_ptr */
2732 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2733 
2734 		/* Scan for the values */
2735 		if (2 != sscanf(buf+2, "%d:%d", &rating, &xtra))
2736 			return (PARSE_ERROR_GENERIC);
2737 
2738 		/* Save the values */
2739 		e_ptr->rating = rating;
2740 		e_ptr->xtra = xtra;
2741 	}
2742 
2743 	/* Process 'T' for "Types allowed" (up to three lines) */
2744 	else if (buf[0] == 'T')
2745 	{
2746 		int tval, sval1, sval2;
2747 
2748 		/* There better be a current e_ptr */
2749 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2750 
2751 		/* Scan for the values */
2752 		if (3 != sscanf(buf+2, "%d:%d:%d",
2753 			            &tval, &sval1, &sval2)) return (PARSE_ERROR_GENERIC);
2754 
2755 		/* Save the values */
2756 		e_ptr->tval[cur_t] = (byte)tval;
2757 		e_ptr->min_sval[cur_t] = (byte)sval1;
2758 		e_ptr->max_sval[cur_t] = (byte)sval2;
2759 
2760 		/* Increase counter for 'possible tval' index */
2761 		cur_t++;
2762 
2763 		/* Allow only a limited number of T: lines */
2764 		if (cur_t > EGO_TVALS_MAX) return (PARSE_ERROR_GENERIC);
2765 	}
2766 
2767 	/* Hack -- Process 'C' for "creation" */
2768 	else if (buf[0] == 'C')
2769 	{
2770 		int th, td, ta, pv;
2771 
2772 		/* There better be a current e_ptr */
2773 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2774 
2775 		/* Scan for the values */
2776 		if (4 != sscanf(buf+2, "%d:%d:%d:%d",
2777 			            &th, &td, &ta, &pv)) return (PARSE_ERROR_GENERIC);
2778 
2779 		e_ptr->max_to_h = th;
2780 		e_ptr->max_to_d = td;
2781 		e_ptr->max_to_a = ta;
2782 		e_ptr->max_pval = pv;
2783 	}
2784 
2785 	/* Hack -- Process 'F' for flags */
2786 	else if (buf[0] == 'F')
2787 	{
2788 		/* There better be a current e_ptr */
2789 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2790 
2791 		/* Parse every entry textually */
2792 		for (s = buf + 2; *s; )
2793 		{
2794 			/* Find the end of this entry */
2795 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2796 
2797 			/* Nuke and skip any dividers */
2798 			if (*t)
2799 			{
2800 				*t++ = '\0';
2801 				while ((*t == ' ') || (*t == '|')) t++;
2802 			}
2803 
2804 			/* Parse this entry */
2805 			if (0 != grab_one_ego_item_flag(e_ptr, s)) return (PARSE_ERROR_INVALID_FLAG);
2806 
2807 			/* Start the next entry */
2808 			s = t;
2809 		}
2810 	}
2811 
2812 	/* Process 'D' for "Description" */
2813 	else if (buf[0] == 'D')
2814 	{
2815 		/* There better be a current e_ptr */
2816 		if (!e_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2817 
2818 		/* Get the text */
2819 		s = buf+2;
2820 
2821 		/* Store the text */
2822 		if (!add_text(&e_ptr->text, head, s))
2823 			return (PARSE_ERROR_OUT_OF_MEMORY);
2824 	}
2825 
2826 	else
2827 	{
2828 		/* Oops */
2829 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
2830 	}
2831 
2832 	/* Success */
2833 	return (0);
2834 }
2835 
2836 
2837 
2838 /*
2839  * Grab one (basic) flag in a monster_race from a textual string
2840  */
grab_one_basic_flag(monster_race * r_ptr,cptr what)2841 static errr grab_one_basic_flag(monster_race *r_ptr, cptr what)
2842 {
2843 	int i;
2844 
2845 	/* Scan flags1 */
2846 	for (i = 0; i < 32; i++)
2847 	{
2848 		if (streq(what, r_info_flags1[i]))
2849 		{
2850 			r_ptr->flags1 |= (1L << i);
2851 			return (0);
2852 		}
2853 	}
2854 
2855 	/* Scan flags2 */
2856 	for (i = 0; i < 32; i++)
2857 	{
2858 		if (streq(what, r_info_flags2[i]))
2859 		{
2860 			r_ptr->flags2 |= (1L << i);
2861 			return (0);
2862 		}
2863 	}
2864 
2865 	/* Scan flags1 */
2866 	for (i = 0; i < 32; i++)
2867 	{
2868 		if (streq(what, r_info_flags3[i]))
2869 		{
2870 			r_ptr->flags3 |= (1L << i);
2871 			return (0);
2872 		}
2873 	}
2874 
2875 	/* Oops */
2876 	plog(format("Unknown monster flag '%s'.", what));
2877 
2878 	/* Failure */
2879 	return (1);
2880 }
2881 
2882 /*
2883  * Grab one (spell) flag in a monster_race from a textual string
2884  */
grab_one_spell_flag(monster_race * r_ptr,cptr what)2885 static errr grab_one_spell_flag(monster_race *r_ptr, cptr what)
2886 {
2887 	int i;
2888 
2889 	/* Scan flags4 */
2890 	for (i = 0; i < 32; i++)
2891 	{
2892 		if (streq(what, r_info_flags4[i]))
2893 		{
2894 			r_ptr->flags4 |= (1L << i);
2895 			return (0);
2896 		}
2897 	}
2898 
2899 	/* Scan flags5 */
2900 	for (i = 0; i < 32; i++)
2901 	{
2902 		if (streq(what, r_info_flags5[i]))
2903 		{
2904 			r_ptr->flags5 |= (1L << i);
2905 			return (0);
2906 		}
2907 	}
2908 
2909 	/* Scan flags6 */
2910 	for (i = 0; i < 32; i++)
2911 	{
2912 		if (streq(what, r_info_flags6[i]))
2913 		{
2914 			r_ptr->flags6 |= (1L << i);
2915 			return (0);
2916 		}
2917 	}
2918 
2919 	/* Oops */
2920 	plog(format("Unknown monster flag '%s'.", what));
2921 
2922 	/* Failure */
2923 	return (1);
2924 }
2925 
2926 /*
2927  * Initialize the "r_info" array, by parsing an ascii "template" file
2928  */
parse_r_info(char * buf,header * head)2929 errr parse_r_info(char *buf, header *head)
2930 {
2931 	int i;
2932 
2933 	char *s, *t;
2934 
2935 	/* Current entry */
2936 	static monster_race *r_ptr = NULL;
2937 
2938 
2939 	/* Process 'N' for "New/Number/Name" */
2940 	if (buf[0] == 'N')
2941 	{
2942 		/* Find the colon before the name */
2943 		s = strchr(buf+2, ':');
2944 
2945 		/* Verify that colon */
2946 		if (!s) return (PARSE_ERROR_GENERIC);
2947 
2948 		/* Nuke the colon, advance to the name */
2949 		*s++ = '\0';
2950 
2951 		/* Paranoia -- require a name */
2952 		if (!*s) return (PARSE_ERROR_GENERIC);
2953 
2954 		/* Get the index */
2955 		i = atoi(buf+2);
2956 
2957 		/* Verify information */
2958 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
2959 
2960 		/* Verify information */
2961 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
2962 
2963 		/* Save the index */
2964 		error_idx = i;
2965 
2966 		/* Point at the "info" */
2967 		r_ptr = (monster_race*)head->info_ptr + i;
2968 
2969 		/* Store the name */
2970 		if (!(r_ptr->name = add_name(head, s)))
2971 			return (PARSE_ERROR_OUT_OF_MEMORY);
2972 	}
2973 
2974 	/* Process 'D' for "Description" */
2975 	else if (buf[0] == 'D')
2976 	{
2977 		/* There better be a current r_ptr */
2978 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2979 
2980 		/* Get the text */
2981 		s = buf+2;
2982 
2983 		/* Store the text */
2984 		if (!add_text(&(r_ptr->text), head, s))
2985 			return (PARSE_ERROR_OUT_OF_MEMORY);
2986 	}
2987 
2988 	/* Process 'G' for "Graphics" (one line only) */
2989 	else if (buf[0] == 'G')
2990 	{
2991 		char d_char;
2992 		int d_attr;
2993 
2994 		/* There better be a current r_ptr */
2995 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
2996 
2997 		/* Paranoia */
2998 		if (!buf[2]) return (PARSE_ERROR_GENERIC);
2999 		if (!buf[3]) return (PARSE_ERROR_GENERIC);
3000 		if (!buf[4]) return (PARSE_ERROR_GENERIC);
3001 
3002 		/* Extract d_char */
3003 		d_char = buf[2];
3004 
3005 		/* If we have a longer string than expected ... */
3006 		if (buf[5])
3007 		{
3008 			/* Advance "buf" on by 4 */
3009 			buf += 4;
3010 
3011 			/* Extract the colour */
3012 			d_attr = color_text_to_attr(buf);
3013 		}
3014 		else
3015 		{
3016 			/* Extract the attr */
3017 			d_attr = color_char_to_attr(buf[4]);
3018 		}
3019 
3020 		/* Paranoia */
3021 		if (d_attr < 0) return (PARSE_ERROR_GENERIC);
3022 
3023 		/* Save the values */
3024 		r_ptr->d_attr = d_attr;
3025 		r_ptr->d_char = d_char;
3026 	}
3027 
3028 	/* Process 'I' for "Info" (one line only) */
3029 	else if (buf[0] == 'I')
3030 	{
3031 		int spd, hp1, hp2, aaf, ac, slp;
3032 
3033 		/* There better be a current r_ptr */
3034 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3035 
3036 		/* Scan for the other values */
3037 		if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
3038 			            &spd, &hp1, &hp2, &aaf, &ac, &slp)) return (PARSE_ERROR_GENERIC);
3039 
3040 		/* Save the values */
3041 		r_ptr->speed = spd;
3042 		r_ptr->hdice = hp1;
3043 		r_ptr->hside = hp2;
3044 		r_ptr->aaf = aaf;
3045 		r_ptr->ac = ac;
3046 		r_ptr->sleep = slp;
3047 	}
3048 
3049 	/* Process 'W' for "More Info" (one line only) */
3050 	else if (buf[0] == 'W')
3051 	{
3052 		int lev, rar, pad;
3053 		long exp;
3054 
3055 		/* There better be a current r_ptr */
3056 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3057 
3058 		/* Scan for the values */
3059 		if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
3060 			            &lev, &rar, &pad, &exp)) return (PARSE_ERROR_GENERIC);
3061 
3062 		/* Save the values */
3063 		r_ptr->level = lev;
3064 		r_ptr->rarity = rar;
3065 		r_ptr->extra = pad;
3066 		r_ptr->mexp = exp;
3067 	}
3068 
3069 	/* Process 'B' for "Blows" */
3070 	else if (buf[0] == 'B')
3071 	{
3072 		int n1, n2;
3073 
3074 		/* There better be a current r_ptr */
3075 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3076 
3077 		/* Find the next empty blow slot (if any) */
3078 		for (i = 0; i < MONSTER_BLOW_MAX; i++) if (!r_ptr->blow[i].method) break;
3079 
3080 		/* Oops, no more slots */
3081 		if (i == MONSTER_BLOW_MAX) return (PARSE_ERROR_GENERIC);
3082 
3083 		/* Analyze the first field */
3084 		for (s = t = buf+2; *t && (*t != ':'); t++) /* loop */;
3085 
3086 		/* Terminate the field (if necessary) */
3087 		if (*t == ':') *t++ = '\0';
3088 
3089 		/* Analyze the method */
3090 		for (n1 = 0; r_info_blow_method[n1]; n1++)
3091 		{
3092 			if (streq(s, r_info_blow_method[n1])) break;
3093 		}
3094 
3095 		/* Invalid method */
3096 		if (!r_info_blow_method[n1]) return (PARSE_ERROR_GENERIC);
3097 
3098 		/* Analyze the second field */
3099 		for (s = t; *t && (*t != ':'); t++) /* loop */;
3100 
3101 		/* Terminate the field (if necessary) */
3102 		if (*t == ':') *t++ = '\0';
3103 
3104 		/* Analyze effect */
3105 		for (n2 = 0; r_info_blow_effect[n2]; n2++)
3106 		{
3107 			if (streq(s, r_info_blow_effect[n2])) break;
3108 		}
3109 
3110 		/* Invalid effect */
3111 		if (!r_info_blow_effect[n2]) return (PARSE_ERROR_GENERIC);
3112 
3113 		/* Analyze the third field */
3114 		for (s = t; *t && (*t != 'd'); t++) /* loop */;
3115 
3116 		/* Terminate the field (if necessary) */
3117 		if (*t == 'd') *t++ = '\0';
3118 
3119 		/* Save the method */
3120 		r_ptr->blow[i].method = n1;
3121 
3122 		/* Save the effect */
3123 		r_ptr->blow[i].effect = n2;
3124 
3125 		/* Extract the damage dice and sides */
3126 		r_ptr->blow[i].d_dice = atoi(s);
3127 		r_ptr->blow[i].d_side = atoi(t);
3128 	}
3129 
3130 	/* Process 'F' for "Basic Flags" (multiple lines) */
3131 	else if (buf[0] == 'F')
3132 	{
3133 		/* There better be a current r_ptr */
3134 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3135 
3136 		/* Parse every entry */
3137 		for (s = buf + 2; *s; )
3138 		{
3139 			/* Find the end of this entry */
3140 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
3141 
3142 			/* Nuke and skip any dividers */
3143 			if (*t)
3144 			{
3145 				*t++ = '\0';
3146 				while (*t == ' ' || *t == '|') t++;
3147 			}
3148 
3149 			/* Parse this entry */
3150 			if (0 != grab_one_basic_flag(r_ptr, s)) return (PARSE_ERROR_INVALID_FLAG);
3151 
3152 			/* Start the next entry */
3153 			s = t;
3154 		}
3155 	}
3156 
3157 	/* Process 'S' for "Spell Flags" (multiple lines) */
3158 	else if (buf[0] == 'S')
3159 	{
3160 		/* There better be a current r_ptr */
3161 		if (!r_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3162 
3163 		/* Parse every entry */
3164 		for (s = buf + 2; *s; )
3165 		{
3166 			/* Find the end of this entry */
3167 			for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
3168 
3169 			/* Nuke and skip any dividers */
3170 			if (*t)
3171 			{
3172 				*t++ = '\0';
3173 				while ((*t == ' ') || (*t == '|')) t++;
3174 			}
3175 
3176 			/* XXX Hack -- Read spell frequency */
3177 			if (1 == sscanf(s, "1_IN_%d", &i))
3178 			{
3179 				/* Sanity check */
3180 				if ((i < 1) || (i > 100))
3181 					return (PARSE_ERROR_INVALID_SPELL_FREQ);
3182 
3183 				/* Extract a "frequency" */
3184 				r_ptr->freq_spell = r_ptr->freq_innate = 100 / i;
3185 
3186 				/* Start at next entry */
3187 				s = t;
3188 
3189 				/* Continue */
3190 				continue;
3191 			}
3192 
3193 			/* Parse this entry */
3194 			if (0 != grab_one_spell_flag(r_ptr, s))
3195 				return (PARSE_ERROR_INVALID_FLAG);
3196 
3197 			/* Start the next entry */
3198 			s = t;
3199 		}
3200 	}
3201 	else
3202 	{
3203 		/* Oops */
3204 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
3205 	}
3206 
3207 #if 0
3208 	/* XXX XXX XXX The ghost is unused */
3209 
3210 	/* Mega-Hack -- acquire "ghost" */
3211 	r_ptr = &r_info[z_info->r_max-1];
3212 
3213 	/* Get the next index */
3214 	r_ptr->name = head->name_size;
3215 	r_ptr->text = head->text_size;
3216 
3217 	/* Save some space for the ghost info */
3218 	head->name_size += 64;
3219 	head->text_size += 64;
3220 
3221 	/* Hack -- Default name/text for the ghost */
3222 	strcpy(r_name + r_ptr->name, "Nobody, the Undefined Ghost");
3223 	strcpy(r_text + r_ptr->text, "It seems strangely familiar...");
3224 
3225 	/* Hack -- set the attr/char info */
3226 	r_ptr->d_attr = /* r_ptr->x_attr = */ TERM_WHITE;
3227 	r_ptr->d_char = /* r_ptr->x_attr = */ 'G';
3228 
3229 	/* Hack -- Try to prevent a few "potential" bugs */
3230 	r_ptr->flags1 |= (RF1_UNIQUE);
3231 
3232 	/* Hack -- Try to prevent a few "potential" bugs */
3233 	r_ptr->flags1 |= (RF1_NEVER_MOVE | RF1_NEVER_BLOW);
3234 
3235 	/* Hack -- Try to prevent a few "potential" bugs */
3236 	r_ptr->hdice = r_ptr->hside = 1;
3237 
3238 	/* Hack -- Try to prevent a few "potential" bugs */
3239 	r_ptr->mexp = 1L;
3240 #endif
3241 
3242 	/* Success */
3243 	return (0);
3244 }
3245 
3246 
3247 
3248 /*
3249  * Initialize the "flavor_info" array, by parsing an ascii "template" file
3250  */
parse_flavor_info(char * buf,header * head)3251 errr parse_flavor_info(char *buf, header *head)
3252 {
3253 	int i;
3254 
3255 	/* Current entry */
3256 	static flavor_type *flavor_ptr;
3257 
3258 
3259 	/* Process 'N' for "Number" */
3260 	if (buf[0] == 'N')
3261 	{
3262 		int tval, sval;
3263 		int result;
3264 
3265 		/* Scan the value */
3266 		result = sscanf(buf, "N:%d:%d:%d", &i, &tval, &sval);
3267 
3268 		/* Either two or three values */
3269 		if ((result != 2) && (result != 3)) return (PARSE_ERROR_GENERIC);
3270 
3271 		/* Verify information */
3272 		if (i <= error_idx) return (PARSE_ERROR_NON_SEQUENTIAL_RECORDS);
3273 
3274 		/* Verify information */
3275 		if (i >= head->info_num) return (PARSE_ERROR_TOO_MANY_ENTRIES);
3276 
3277 		/* Save the index */
3278 		error_idx = i;
3279 
3280 		/* Point at the "info" */
3281 		flavor_ptr = (flavor_type*)head->info_ptr + i;
3282 
3283 		/* Save the tval */
3284 		flavor_ptr->tval = (byte)tval;
3285 
3286 		/* Save the sval */
3287 		if (result == 2)
3288 		{
3289 			/* Megahack - unknown sval */
3290 			flavor_ptr->sval = SV_UNKNOWN;
3291 		}
3292 		else
3293 			flavor_ptr->sval = (byte)sval;
3294 	}
3295 
3296 	/* Process 'G' for "Graphics" */
3297 	else if (buf[0] == 'G')
3298 	{
3299 		char d_char;
3300 		int d_attr;
3301 
3302 		/* There better be a current flavor_ptr */
3303 		if (!flavor_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3304 
3305 		/* Paranoia */
3306 		if (!buf[2]) return (PARSE_ERROR_GENERIC);
3307 		if (!buf[3]) return (PARSE_ERROR_GENERIC);
3308 		if (!buf[4]) return (PARSE_ERROR_GENERIC);
3309 
3310 		/* Extract d_char */
3311 		d_char = buf[2];
3312 
3313 		/* If we have a longer string than expected ... */
3314 		if (buf[5])
3315 		{
3316 			/* Advance "buf" on by 4 */
3317 			buf += 4;
3318 
3319 			/* Extract the colour */
3320 			d_attr = color_text_to_attr(buf);
3321 		}
3322 		else
3323 		{
3324 			/* Extract the attr */
3325 			d_attr = color_char_to_attr(buf[4]);
3326 		}
3327 
3328 		/* Paranoia */
3329 		if (d_attr < 0) return (PARSE_ERROR_GENERIC);
3330 
3331 		/* Save the values */
3332 		flavor_ptr->d_attr = /* flavor_ptr->x_attr = */ d_attr;
3333 		flavor_ptr->d_char = /* flavor_ptr->d_char = */ d_char;
3334 	}
3335 
3336 	/* Process 'D' for "Description" */
3337 	else if (buf[0] == 'D')
3338 	{
3339 		/* There better be a current flavor_ptr */
3340 		if (!flavor_ptr) return (PARSE_ERROR_MISSING_RECORD_HEADER);
3341 
3342 		/* Paranoia */
3343 		if (!buf[1]) return (PARSE_ERROR_GENERIC);
3344 		if (!buf[2]) return (PARSE_ERROR_GENERIC);
3345 
3346 		/* Store the text */
3347 		if (!add_text(&flavor_ptr->text, head, buf + 2))
3348 			return (PARSE_ERROR_OUT_OF_MEMORY);
3349 	}
3350 
3351 	else
3352 	{
3353 		/* Oops */
3354 		return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
3355 	}
3356 
3357 	/* Success */
3358 	return (0);
3359 }
3360 
3361 
3362 #else	/* ALLOW_TEMPLATES */
3363 
3364 #ifdef MACINTOSH
3365 static int i = 0;
3366 #endif
3367 
3368 #endif	/* ALLOW_TEMPLATES */
3369