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