4 * Copyright (c) 1997 Ben Harrison
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
11 /* Purpose: Initialization (part 1) -BEN- */
18 static char *_strchr(const char *ptr, char ch)
20 for ( ; *ptr != '\0'; ++ptr)
22 if (*ptr == ch) return (char *)ptr;
23 if (iskanji(*ptr)) ++ptr;
28 #define strchr _strchr
31 * This file is used to initialize various variables and arrays for the
32 * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass
33 * the common limitation of "read()" and "write()" to only 32767 bytes
36 * Several of the arrays for Angband are built from "template" files in
37 * the "lib/file" directory, from which quick-load binary "image" files
38 * are constructed whenever they are not present in the "lib/data"
39 * directory, or if those files become obsolete, if we are allowed.
41 * Warning -- the "ascii" file parsers use a minor hack to collect the
42 * name and text information in a single pass. Thus, the game will not
43 * be able to load any template file with more than 20K of names or 60K
44 * of text, even though technically, up to 64K should be legal.
46 * Note that if "ALLOW_TEMPLATES" is not defined, then a lot of the code
47 * in this file is compiled out, and the game will not run unless valid
48 * "binary template files" already exist in "lib/data". Thus, one can
49 * compile Angband with ALLOW_TEMPLATES defined, run once to create the
50 * "*.raw" files in "lib/data", and then quit, and recompile without
51 * defining ALLOW_TEMPLATES, which will both save 20K and prevent people
52 * from changing the ascii template files in potentially dangerous ways.
54 * The code could actually be removed and placed into a "stand-alone"
55 * program, but that feels a little silly, especially considering some
56 * of the platforms that we currently support.
59 #ifdef ALLOW_TEMPLATES
64 /*** Helper arrays for parsing ascii template files ***/
67 * Monster Blow Methods
69 static cptr r_info_blow_method[] =
102 * Monster Blow Effects
104 static cptr r_info_blow_effect[] =
147 static cptr r_info_flags1[] =
186 static cptr r_info_flags2[] =
225 static cptr r_info_flags3[] =
264 static cptr r_info_flags4[] =
303 static cptr r_info_flags5[] =
342 static cptr r_info_flags6[] =
359 "ANIM_DEAD", /* ToDo: Implement ANIM_DEAD */
382 static cptr r_info_flags7[] =
421 static cptr r_info_flags8[] =
453 "WILD_SWAMP", /* ToDo: Implement Swamp */
459 * Monster race flags - Drops
461 static cptr r_info_flags9[] =
502 static cptr k_info_flags[] =
627 static cptr k_info_gen_flags[] =
667 static cptr d_info_flags1[] =
705 * Add a text to the text-storage and store offset to it.
707 * Returns FALSE when there isn't enough space available to store
710 static bool add_text(u32b *offset, header *head, cptr buf)
712 /* Hack -- Verify space */
713 if (head->text_size + strlen(buf) + 8 > FAKE_TEXT_SIZE)
719 /* Advance and save the text index */
720 *offset = ++head->text_size;
723 /* Append chars to the text */
724 strcpy(head->text_ptr + head->text_size, buf);
726 /* Advance the index */
727 head->text_size += strlen(buf);
735 * Add a name to the name-storage and return an offset to it.
737 * Returns FALSE when there isn't enough space available to store
740 static bool add_name(u32b *offset, header *head, cptr buf)
742 /* Hack -- Verify space */
743 if (head->name_size + strlen(buf) + 8 > FAKE_NAME_SIZE)
749 /* Advance and save the name index */
750 *offset = ++head->name_size;
753 /* Append chars to the names */
754 strcpy(head->name_ptr + head->name_size, buf);
756 /* Advance the index */
757 head->name_size += strlen(buf);
765 * Convert a "color letter" into an "actual" color
766 * The colors are: dwsorgbuDWvyRGBU, as shown below
768 byte color_char_to_attr(char c)
772 case 'd': return (TERM_DARK);
773 case 'w': return (TERM_WHITE);
774 case 's': return (TERM_SLATE);
775 case 'o': return (TERM_ORANGE);
776 case 'r': return (TERM_RED);
777 case 'g': return (TERM_GREEN);
778 case 'b': return (TERM_BLUE);
779 case 'u': return (TERM_UMBER);
781 case 'D': return (TERM_L_DARK);
782 case 'W': return (TERM_L_WHITE);
783 case 'v': return (TERM_VIOLET);
784 case 'y': return (TERM_YELLOW);
785 case 'R': return (TERM_L_RED);
786 case 'G': return (TERM_L_GREEN);
787 case 'B': return (TERM_L_BLUE);
788 case 'U': return (TERM_L_UMBER);
796 /*** Initialize from ascii template files ***/
800 * Initialize an "*_info" array, by parsing an ascii "template" file
802 errr init_info_txt(FILE *fp, char *buf, header *head,
803 parse_info_txt_func parse_info_txt_line)
807 /* Just before the first record */
810 /* Just before the first line */
814 /* Prepare the "fake" stuff */
819 while (0 == my_fgets(fp, buf, 1024))
821 /* Advance the line number */
824 /* Skip comments and blank lines */
825 if (!buf[0] || (buf[0] == '#')) continue;
827 /* Verify correct "colon" format */
828 if (buf[1] != ':') return (PARSE_ERROR_GENERIC);
831 /* Hack -- Process 'V' for "Version" */
838 /* Mega Hack -- Calculate Check Sum */
839 if (buf[0] != 'N' && buf[0] != 'D')
842 for (i = 0; buf[i]; i++)
844 head->v_extra += (byte)buf[i];
845 head->v_extra ^= (1 << (i % 8));
850 if ((err = (*parse_info_txt_line)(buf, head)) != 0)
855 /* Complete the "name" and "text" sizes */
856 if (head->name_size) head->name_size++;
857 if (head->text_size) head->text_size++;
865 * Initialize the "v_info" array, by parsing an ascii "template" file
867 errr parse_v_info(char *buf, header *head)
873 static vault_type *v_ptr = NULL;
875 /* Process 'N' for "New/Number/Name" */
878 /* Find the colon before the name */
879 s = strchr(buf+2, ':');
881 /* Verify that colon */
884 /* Nuke the colon, advance to the name */
887 /* Paranoia -- require a name */
893 /* Verify information */
894 if (i <= error_idx) return (4);
896 /* Verify information */
897 if (i >= head->info_num) return (2);
902 /* Point at the "info" */
906 if (!add_name(&v_ptr->name, head, s)) return (7);
909 /* There better be a current v_ptr */
910 else if (!v_ptr) return (3);
912 /* Process 'D' for "Description" */
913 else if (buf[0] == 'D')
915 /* Acquire the text */
919 if (!add_text(&v_ptr->text, head, s)) return (7);
922 /* Process 'X' for "Extra info" (one line only) */
923 else if (buf[0] == 'X')
925 int typ, rat, hgt, wid;
927 /* Scan for the values */
928 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
929 &typ, &rat, &hgt, &wid)) return (1);
931 /* Save the values */
948 * Initialize the "s_info" array, by parsing an ascii "template" file
950 errr parse_s_info(char *buf, header *head)
955 static skill_table *s_ptr = NULL;
958 /* Process 'N' for "New/Number/Name" */
964 /* Verify information */
965 if (i <= error_idx) return (4);
967 /* Verify information */
968 if (i >= head->info_num) return (2);
973 /* Point at the "info" */
977 /* There better be a current s_ptr */
978 else if (!s_ptr) return (3);
980 /* Process 'W' for "Weapon exp" */
981 else if (buf[0] == 'W')
983 int tval, sval, start, max;
984 const s16b exp_conv_table[] = { 0, 4000, 6000, 7000, 8000 };
986 /* Scan for the values */
987 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
988 &tval, &sval, &start, &max)) return (1);
990 if (start < 0 || start > 4 || max < 0 || max > 4) return (8);
992 /* Save the values */
993 s_ptr->w_start[tval][sval] = exp_conv_table[start];
994 s_ptr->w_max[tval][sval] = exp_conv_table[max];
997 /* Process 'S' for "Skill exp" */
998 else if (buf[0] == 'S')
1000 int num, start, max;
1002 /* Scan for the values */
1003 if (3 != sscanf(buf+2, "%d:%d:%d",
1004 &num, &start, &max)) return (1);
1006 if (start < 0 || start > 8000 || max < 0 || max > 8000) return (8);
1008 /* Save the values */
1009 s_ptr->s_start[num] = start;
1010 s_ptr->s_max[num] = max;
1023 * Initialize the "m_info" array, by parsing an ascii "template" file
1025 errr parse_m_info(char *buf, header *head)
1032 static player_magic *m_ptr = NULL;
1035 static int realm, magic_idx = 0, readable = 0;
1038 /* Process 'N' for "New/Number/Name" */
1044 /* Verify information */
1045 if (i <= error_idx) return (4);
1047 /* Verify information */
1048 if (i >= head->info_num) return (2);
1050 /* Save the index */
1053 /* Point at the "info" */
1057 /* There better be a current m_ptr */
1058 else if (!m_ptr) return (3);
1060 /* Process 'I' for "Info" (one line only) */
1061 else if (buf[0] == 'I')
1064 int xtra, type, first, weight;
1066 /* Find the colon before the name */
1067 s = strchr(buf+2, ':');
1069 /* Verify that colon */
1072 /* Nuke the colon, advance to the name */
1077 if (streq(book, "SORCERY")) m_ptr->spell_book = TV_SORCERY_BOOK;
1078 else if (streq(book, "LIFE")) m_ptr->spell_book = TV_LIFE_BOOK;
1079 else if (streq(book, "MUSIC")) m_ptr->spell_book = TV_MUSIC_BOOK;
1080 else if (streq(book, "HISSATSU")) m_ptr->spell_book = TV_HISSATSU_BOOK;
1081 else if (streq(book, "NONE")) m_ptr->spell_book = 0;
1086 /* Find the colon before the name */
1089 /* Verify that colon */
1092 /* Nuke the colon, advance to the name */
1095 if (streq(stat, "STR")) m_ptr->spell_stat = A_STR;
1096 else if (streq(stat, "INT")) m_ptr->spell_stat = A_INT;
1097 else if (streq(stat, "WIS")) m_ptr->spell_stat = A_WIS;
1098 else if (streq(stat, "DEX")) m_ptr->spell_stat = A_DEX;
1099 else if (streq(stat, "CON")) m_ptr->spell_stat = A_CON;
1100 else if (streq(stat, "CHR")) m_ptr->spell_stat = A_CHR;
1104 /* Scan for the values */
1105 if (4 != sscanf(s, "%x:%d:%d:%d",
1106 (uint *)&xtra, &type, &first, &weight)) return (1);
1108 m_ptr->spell_xtra = xtra;
1109 m_ptr->spell_type = type;
1110 m_ptr->spell_first = first;
1111 m_ptr->spell_weight = weight;
1115 /* Process 'R' for "Realm" (one line only) */
1116 else if (buf[0] == 'R')
1118 /* Scan for the values */
1119 if (2 != sscanf(buf+2, "%d:%d",
1120 &realm, &readable)) return (1);
1125 else if (buf[0] == 'T')
1127 int level, mana, fail, exp;
1129 if (!readable) return (1);
1130 /* Scan for the values */
1131 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1132 &level, &mana, &fail, &exp)) return (1);
1134 m_ptr->info[realm][magic_idx].slevel = level;
1135 m_ptr->info[realm][magic_idx].smana = mana;
1136 m_ptr->info[realm][magic_idx].sfail = fail;
1137 m_ptr->info[realm][magic_idx].sexp = exp;
1151 * Initialize the "f_info" array, by parsing an ascii "template" file
1153 errr parse_f_info(char *buf, header *head)
1160 static feature_type *f_ptr = NULL;
1163 /* Process 'N' for "New/Number/Name" */
1166 /* Find the colon before the name */
1167 s = strchr(buf+2, ':');
1169 /* Verify that colon */
1172 /* Nuke the colon, advance to the name */
1176 /* Paranoia -- require a name */
1177 if (!*s) return (1);
1183 /* Verify information */
1184 if (i <= error_idx) return (4);
1186 /* Verify information */
1187 if (i >= head->info_num) return (2);
1189 /* Save the index */
1192 /* Point at the "info" */
1196 /* Store the name */
1197 if (!add_name(&f_ptr->name, head, s)) return (7);
1199 /* Default "mimic" */
1203 /* There better be a current f_ptr */
1204 else if (!f_ptr) return (3);
1207 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1208 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1209 else if (buf[0] == 'E')
1214 else if (buf[0] == 'E')
1216 /* Acquire the Text */
1219 /* Store the name */
1220 if (!add_name(&f_ptr->name, head, s)) return (7);
1225 /* Process 'M' for "Mimic" (one line only) */
1226 else if (buf[0] == 'M')
1230 /* Scan for the values */
1231 if (1 != sscanf(buf+2, "%d",
1232 &mimic)) return (1);
1234 /* Save the values */
1235 f_ptr->mimic = mimic;
1240 /* Process 'G' for "Graphics" (one line only) */
1241 else if (buf[0] == 'G')
1246 if (!buf[2]) return (1);
1247 if (!buf[3]) return (1);
1248 if (!buf[4]) return (1);
1250 /* Extract the color */
1251 tmp = color_char_to_attr(buf[4]);
1254 if (tmp > 127) return (1);
1256 /* Save the values */
1257 f_ptr->d_attr = tmp;
1258 f_ptr->d_char = buf[2];
1271 * Grab one flag in an object_kind from a textual string
1273 static errr grab_one_kind_flag(object_kind *k_ptr, cptr what)
1278 for (i = 0; i < TR_FLAG_MAX; i++)
1280 if (streq(what, k_info_flags[i]))
1282 add_flag(k_ptr->flags, i);
1287 /* Check gen_flags */
1288 for (i = 0; i < 32; i++)
1290 if (streq(what, k_info_gen_flags[i]))
1292 k_ptr->gen_flags |= (1L << i);
1299 msg_format("̤ÃΤΥ¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1301 msg_format("Unknown object flag '%s'.", what);
1311 * Initialize the "k_info" array, by parsing an ascii "template" file
1313 errr parse_k_info(char *buf, header *head)
1320 static object_kind *k_ptr = NULL;
1323 /* Process 'N' for "New/Number/Name" */
1326 /* Find the colon before the name */
1327 s = strchr(buf+2, ':');
1329 /* Verify that colon */
1332 /* Nuke the colon, advance to the name */
1336 /* Paranoia -- require a name */
1337 if (!*s) return (1);
1342 /* Verify information */
1343 if (i <= error_idx) return (4);
1345 /* Verify information */
1346 if (i >= head->info_num) return (2);
1348 /* Save the index */
1351 /* Point at the "info" */
1355 /* Store the name */
1356 if (!add_name(&k_ptr->name, head, s)) return (7);
1360 /* There better be a current k_ptr */
1361 else if (!k_ptr) return (3);
1365 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1366 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1367 else if (buf[0] == 'E')
1372 else if (buf[0] == 'E')
1374 /* Acquire the Text */
1377 /* Store the name */
1378 if (!add_name(&k_ptr->name, head, s)) return (7);
1382 /* Process 'D' for "Description" */
1383 else if (buf[0] == 'D')
1388 /* Acquire the text */
1393 /* Acquire the text */
1397 /* Store the text */
1398 if (!add_text(&k_ptr->text, head, s)) return (7);
1401 /* Process 'G' for "Graphics" (one line only) */
1402 else if (buf[0] == 'G')
1408 if (!buf[2]) return (1);
1409 if (!buf[3]) return (1);
1410 if (!buf[4]) return (1);
1412 /* Extract the char */
1415 /* Extract the attr */
1416 tmp = color_char_to_attr(buf[4]);
1419 if (tmp > 127) return (1);
1421 /* Save the values */
1422 k_ptr->d_attr = tmp;
1423 k_ptr->d_char = sym;
1426 /* Process 'I' for "Info" (one line only) */
1427 else if (buf[0] == 'I')
1429 int tval, sval, pval;
1431 /* Scan for the values */
1432 if (3 != sscanf(buf+2, "%d:%d:%d",
1433 &tval, &sval, &pval)) return (1);
1435 /* Save the values */
1441 /* Process 'W' for "More Info" (one line only) */
1442 else if (buf[0] == 'W')
1444 int level, extra, wgt;
1447 /* Scan for the values */
1448 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1449 &level, &extra, &wgt, &cost)) return (1);
1451 /* Save the values */
1452 k_ptr->level = level;
1453 k_ptr->extra = extra;
1454 k_ptr->weight = wgt;
1458 /* Process 'A' for "Allocation" (one line only) */
1459 else if (buf[0] == 'A')
1463 /* XXX XXX XXX Simply read each number following a colon */
1464 for (i = 0, s = buf+1; s && (s[0] == ':') && s[1]; ++i)
1466 /* Default chance */
1467 k_ptr->chance[i] = 1;
1469 /* Store the attack damage index */
1470 k_ptr->locale[i] = atoi(s+1);
1472 /* Find the slash */
1473 t = strchr(s+1, '/');
1475 /* Find the next colon */
1476 s = strchr(s+1, ':');
1478 /* If the slash is "nearby", use it */
1479 if (t && (!s || t < s))
1481 int chance = atoi(t+1);
1482 if (chance > 0) k_ptr->chance[i] = chance;
1487 /* Hack -- Process 'P' for "power" and such */
1488 else if (buf[0] == 'P')
1490 int ac, hd1, hd2, th, td, ta;
1492 /* Scan for the values */
1493 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
1494 &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
1504 /* Hack -- Process 'F' for flags */
1505 else if (buf[0] == 'F')
1507 /* Parse every entry textually */
1508 for (s = buf + 2; *s; )
1510 /* Find the end of this entry */
1511 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1513 /* Nuke and skip any dividers */
1517 while (*t == ' ' || *t == '|') t++;
1520 /* Parse this entry */
1521 if (0 != grab_one_kind_flag(k_ptr, s)) return (5);
1523 /* Start the next entry */
1539 * Grab one flag in an artifact_type from a textual string
1541 static errr grab_one_artifact_flag(artifact_type *a_ptr, cptr what)
1546 for (i = 0; i < TR_FLAG_MAX; i++)
1548 if (streq(what, k_info_flags[i]))
1550 add_flag(a_ptr->flags, i);
1555 /* Check gen_flags */
1556 for (i = 0; i < 32; i++)
1558 if (streq(what, k_info_gen_flags[i]))
1560 a_ptr->gen_flags |= (1L << i);
1567 msg_format("̤ÃΤÎÅÁÀâ¤Î¥¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1569 msg_format("Unknown artifact flag '%s'.", what);
1581 * Initialize the "a_info" array, by parsing an ascii "template" file
1583 errr parse_a_info(char *buf, header *head)
1590 static artifact_type *a_ptr = NULL;
1593 /* Process 'N' for "New/Number/Name" */
1596 /* Find the colon before the name */
1597 s = strchr(buf+2, ':');
1599 /* Verify that colon */
1602 /* Nuke the colon, advance to the name */
1605 /* Paranoia -- require a name */
1606 if (!*s) return (1);
1611 /* Verify information */
1612 if (i < error_idx) return (4);
1614 /* Verify information */
1615 if (i >= head->info_num) return (2);
1617 /* Save the index */
1620 /* Point at the "info" */
1623 /* Ignore everything */
1624 add_flag(a_ptr->flags, TR_IGNORE_ACID);
1625 add_flag(a_ptr->flags, TR_IGNORE_ELEC);
1626 add_flag(a_ptr->flags, TR_IGNORE_FIRE);
1627 add_flag(a_ptr->flags, TR_IGNORE_COLD);
1629 /* Store the name */
1630 if (!add_name(&a_ptr->name, head, s)) return (7);
1634 /* There better be a current a_ptr */
1635 else if (!a_ptr) return (3);
1639 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1640 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1641 else if (buf[0] == 'E')
1646 else if (buf[0] == 'E')
1648 /* Acquire the Text */
1651 /* Store the name */
1652 if (!add_name(&a_ptr->name, head, s)) return (7);
1656 /* Process 'D' for "Description" */
1657 else if (buf[0] == 'D')
1662 /* Acquire the text */
1667 /* Acquire the text */
1671 /* Store the text */
1672 if (!add_text(&a_ptr->text, head, s)) return (7);
1676 /* Process 'I' for "Info" (one line only) */
1677 else if (buf[0] == 'I')
1679 int tval, sval, pval;
1681 /* Scan for the values */
1682 if (3 != sscanf(buf+2, "%d:%d:%d",
1683 &tval, &sval, &pval)) return (1);
1685 /* Save the values */
1691 /* Process 'W' for "More Info" (one line only) */
1692 else if (buf[0] == 'W')
1694 int level, rarity, wgt;
1697 /* Scan for the values */
1698 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1699 &level, &rarity, &wgt, &cost)) return (1);
1701 /* Save the values */
1702 a_ptr->level = level;
1703 a_ptr->rarity = rarity;
1704 a_ptr->weight = wgt;
1708 /* Hack -- Process 'P' for "power" and such */
1709 else if (buf[0] == 'P')
1711 int ac, hd1, hd2, th, td, ta;
1713 /* Scan for the values */
1714 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
1715 &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
1725 /* Hack -- Process 'F' for flags */
1726 else if (buf[0] == 'F')
1728 /* Parse every entry textually */
1729 for (s = buf + 2; *s; )
1731 /* Find the end of this entry */
1732 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1734 /* Nuke and skip any dividers */
1738 while ((*t == ' ') || (*t == '|')) t++;
1741 /* Parse this entry */
1742 if (0 != grab_one_artifact_flag(a_ptr, s)) return (5);
1744 /* Start the next entry */
1760 * Grab one flag in a ego-item_type from a textual string
1762 static bool grab_one_ego_item_flag(ego_item_type *e_ptr, cptr what)
1767 for (i = 0; i < TR_FLAG_MAX; i++)
1769 if (streq(what, k_info_flags[i]))
1771 add_flag(e_ptr->flags, i);
1776 /* Check gen_flags */
1777 for (i = 0; i < 32; i++)
1779 if (streq(what, k_info_gen_flags[i]))
1781 e_ptr->gen_flags |= (1L << i);
1788 msg_format("̤ÃΤÎ̾¤Î¤¢¤ë¥¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1790 msg_format("Unknown ego-item flag '%s'.", what);
1802 * Initialize the "e_info" array, by parsing an ascii "template" file
1804 errr parse_e_info(char *buf, header *head)
1811 static ego_item_type *e_ptr = NULL;
1814 /* Just before the first record */
1817 /* Just before the first line */
1821 /* Process 'N' for "New/Number/Name" */
1824 /* Find the colon before the name */
1825 s = strchr(buf+2, ':');
1827 /* Verify that colon */
1830 /* Nuke the colon, advance to the name */
1833 /* Paranoia -- require a name */
1834 if (!*s) return (1);
1839 /* Verify information */
1840 if (i < error_idx) return (4);
1842 /* Verify information */
1843 if (i >= head->info_num) return (2);
1845 /* Save the index */
1848 /* Point at the "info" */
1851 /* Store the name */
1852 if (!add_name(&e_ptr->name, head, s)) return (7);
1856 /* There better be a current e_ptr */
1857 else if (!e_ptr) return (3);
1861 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1862 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾ */
1863 else if (buf[0] == 'E')
1868 else if (buf[0] == 'E')
1870 /* Acquire the Text */
1873 /* Store the name */
1874 if (!add_name(&e_ptr->name, head, s)) return (7);
1879 /* Process 'D' for "Description" */
1880 else if (buf[0] == 'D')
1882 /* Acquire the text */
1885 /* Store the text */
1886 if (!add_text(&e_ptr->text, head, s)) return (7);
1891 /* Process 'X' for "Xtra" (one line only) */
1892 else if (buf[0] == 'X')
1896 /* Scan for the values */
1897 if (2 != sscanf(buf+2, "%d:%d",
1898 &slot, &rating)) return (1);
1900 /* Save the values */
1902 e_ptr->rating = rating;
1905 /* Process 'W' for "More Info" (one line only) */
1906 else if (buf[0] == 'W')
1908 int level, rarity, pad2;
1911 /* Scan for the values */
1912 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1913 &level, &rarity, &pad2, &cost)) return (1);
1915 /* Save the values */
1916 e_ptr->level = level;
1917 e_ptr->rarity = rarity;
1918 /* e_ptr->weight = wgt; */
1922 /* Hack -- Process 'C' for "creation" */
1923 else if (buf[0] == 'C')
1927 /* Scan for the values */
1928 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1929 &th, &td, &ta, &pv)) return (1);
1931 e_ptr->max_to_h = th;
1932 e_ptr->max_to_d = td;
1933 e_ptr->max_to_a = ta;
1934 e_ptr->max_pval = pv;
1937 /* Hack -- Process 'F' for flags */
1938 else if (buf[0] == 'F')
1940 /* Parse every entry textually */
1941 for (s = buf + 2; *s; )
1943 /* Find the end of this entry */
1944 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1946 /* Nuke and skip any dividers */
1950 while ((*t == ' ') || (*t == '|')) t++;
1953 /* Parse this entry */
1954 if (0 != grab_one_ego_item_flag(e_ptr, s)) return (5);
1956 /* Start the next entry */
1970 * Grab one (basic) flag in a monster_race from a textual string
1972 static errr grab_one_basic_flag(monster_race *r_ptr, cptr what)
1977 for (i = 0; i < 32; i++)
1979 if (streq(what, r_info_flags1[i]))
1981 r_ptr->flags1 |= (1L << i);
1987 for (i = 0; i < 32; i++)
1989 if (streq(what, r_info_flags2[i]))
1991 r_ptr->flags2 |= (1L << i);
1997 for (i = 0; i < 32; i++)
1999 if (streq(what, r_info_flags3[i]))
2001 r_ptr->flags3 |= (1L << i);
2007 for (i = 0; i < 32; i++)
2009 if (streq(what, r_info_flags7[i]))
2011 r_ptr->flags7 |= (1L << i);
2017 for (i = 0; i < 32; i++)
2019 if (streq(what, r_info_flags8[i]))
2021 r_ptr->flags8 |= (1L << i);
2027 for (i = 0; i < 32; i++)
2029 if (streq(what, r_info_flags9[i]))
2031 r_ptr->flags9 |= (1L << i);
2038 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2040 msg_format("Unknown monster flag '%s'.", what);
2050 * Grab one (spell) flag in a monster_race from a textual string
2052 static errr grab_one_spell_flag(monster_race *r_ptr, cptr what)
2057 for (i = 0; i < 32; i++)
2059 if (streq(what, r_info_flags4[i]))
2061 r_ptr->flags4 |= (1L << i);
2067 for (i = 0; i < 32; i++)
2069 if (streq(what, r_info_flags5[i]))
2071 r_ptr->flags5 |= (1L << i);
2077 for (i = 0; i < 32; i++)
2079 if (streq(what, r_info_flags6[i]))
2081 r_ptr->flags6 |= (1L << i);
2088 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2090 msg_format("Unknown monster flag '%s'.", what);
2102 * Initialize the "r_info" array, by parsing an ascii "template" file
2104 errr parse_r_info(char *buf, header *head)
2111 static monster_race *r_ptr = NULL;
2114 /* Process 'N' for "New/Number/Name" */
2117 /* Find the colon before the name */
2118 s = strchr(buf+2, ':');
2120 /* Verify that colon */
2123 /* Nuke the colon, advance to the name */
2126 /* Paranoia -- require a name */
2127 if (!*s) return (1);
2132 /* Verify information */
2133 if (i < error_idx) return (4);
2135 /* Verify information */
2136 if (i >= head->info_num) return (2);
2138 /* Save the index */
2141 /* Point at the "info" */
2144 /* Store the name */
2145 if (!add_name(&r_ptr->name, head, s)) return (7);
2149 /* There better be a current r_ptr */
2150 else if (!r_ptr) return (3);
2154 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
2155 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾ */
2156 else if (buf[0] == 'E')
2158 /* Acquire the Text */
2161 /* Store the name */
2162 if (!add_name(&r_ptr->E_name, head, s)) return (7);
2165 else if (buf[0] == 'E')
2167 /* Acquire the Text */
2170 /* Store the name */
2171 if (!add_name(&r_ptr->name, head, s)) return (7);
2174 /* Process 'D' for "Description" */
2175 else if (buf[0] == 'D')
2180 /* Acquire the text */
2185 /* Acquire the text */
2189 /* Store the text */
2190 if (!add_text(&r_ptr->text, head, s)) return (7);
2193 /* Process 'G' for "Graphics" (one line only) */
2194 else if (buf[0] == 'G')
2200 if (!buf[2]) return (1);
2201 if (!buf[3]) return (1);
2202 if (!buf[4]) return (1);
2204 /* Extract the char */
2207 /* Extract the attr */
2208 tmp = color_char_to_attr(buf[4]);
2211 if (tmp > 127) return (1);
2213 /* Save the values */
2214 r_ptr->d_char = sym;
2215 r_ptr->d_attr = tmp;
2218 /* Process 'I' for "Info" (one line only) */
2219 else if (buf[0] == 'I')
2221 int spd, hp1, hp2, aaf, ac, slp;
2223 /* Scan for the other values */
2224 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
2225 &spd, &hp1, &hp2, &aaf, &ac, &slp)) return (1);
2227 /* Save the values */
2236 /* Process 'W' for "More Info" (one line only) */
2237 else if (buf[0] == 'W')
2244 /* Scan for the values */
2245 if (6 != sscanf(buf+2, "%d:%d:%d:%ld:%ld:%d",
2246 &lev, &rar, &pad, &exp, &nextexp, &nextmon)) return (1);
2248 /* Save the values */
2250 r_ptr->rarity = rar;
2253 r_ptr->next_exp = nextexp;
2254 r_ptr->next_r_idx = nextmon;
2257 /* Process 'B' for "Blows" (up to four lines) */
2258 else if (buf[0] == 'B')
2262 /* Find the next empty blow slot (if any) */
2263 for (i = 0; i < 4; i++) if (!r_ptr->blow[i].method) break;
2265 /* Oops, no more slots */
2266 if (i == 4) return (1);
2268 /* Analyze the first field */
2269 for (s = t = buf+2; *t && (*t != ':'); t++) /* loop */;
2271 /* Terminate the field (if necessary) */
2272 if (*t == ':') *t++ = '\0';
2274 /* Analyze the method */
2275 for (n1 = 0; r_info_blow_method[n1]; n1++)
2277 if (streq(s, r_info_blow_method[n1])) break;
2280 /* Invalid method */
2281 if (!r_info_blow_method[n1]) return (1);
2283 /* Analyze the second field */
2284 for (s = t; *t && (*t != ':'); t++) /* loop */;
2286 /* Terminate the field (if necessary) */
2287 if (*t == ':') *t++ = '\0';
2289 /* Analyze effect */
2290 for (n2 = 0; r_info_blow_effect[n2]; n2++)
2292 if (streq(s, r_info_blow_effect[n2])) break;
2295 /* Invalid effect */
2296 if (!r_info_blow_effect[n2]) return (1);
2298 /* Analyze the third field */
2299 for (s = t; *t && (*t != 'd'); t++) /* loop */;
2301 /* Terminate the field (if necessary) */
2302 if (*t == 'd') *t++ = '\0';
2304 /* Save the method */
2305 r_ptr->blow[i].method = n1;
2307 /* Save the effect */
2308 r_ptr->blow[i].effect = n2;
2310 /* Extract the damage dice and sides */
2311 r_ptr->blow[i].d_dice = atoi(s);
2312 r_ptr->blow[i].d_side = atoi(t);
2315 /* Process 'F' for "Basic Flags" (multiple lines) */
2316 else if (buf[0] == 'F')
2318 /* Parse every entry */
2319 for (s = buf + 2; *s; )
2321 /* Find the end of this entry */
2322 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2324 /* Nuke and skip any dividers */
2328 while (*t == ' ' || *t == '|') t++;
2331 /* Parse this entry */
2332 if (0 != grab_one_basic_flag(r_ptr, s)) return (5);
2334 /* Start the next entry */
2339 /* Process 'S' for "Spell Flags" (multiple lines) */
2340 else if (buf[0] == 'S')
2342 /* Parse every entry */
2343 for (s = buf + 2; *s; )
2345 /* Find the end of this entry */
2346 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2348 /* Nuke and skip any dividers */
2352 while ((*t == ' ') || (*t == '|')) t++;
2355 /* XXX XXX XXX Hack -- Read spell frequency */
2356 if (1 == sscanf(s, "1_IN_%d", &i))
2358 /* Extract a "frequency" */
2359 r_ptr->freq_spell = 100 / i;
2361 /* Start at next entry */
2368 /* Parse this entry */
2369 if (0 != grab_one_spell_flag(r_ptr, s)) return (5);
2371 /* Start the next entry */
2386 * Grab one flag for a dungeon type from a textual string
2388 static errr grab_one_dungeon_flag(dungeon_info_type *d_ptr, cptr what)
2393 for (i = 0; i < 32; i++)
2395 if (streq(what, d_info_flags1[i]))
2397 d_ptr->flags1 |= (1L << i);
2404 msg_format("̤ÃΤΥÀ¥ó¥¸¥ç¥ó¡¦¥Õ¥é¥° '%s'¡£", what);
2406 msg_format("Unknown dungeon type flag '%s'.", what);
2414 * Grab one (basic) flag in a monster_race from a textual string
2416 static errr grab_one_basic_monster_flag(dungeon_info_type *d_ptr, cptr what)
2421 for (i = 0; i < 32; i++)
2423 if (streq(what, r_info_flags1[i]))
2425 d_ptr->mflags1 |= (1L << i);
2431 for (i = 0; i < 32; i++)
2433 if (streq(what, r_info_flags2[i]))
2435 d_ptr->mflags2 |= (1L << i);
2441 for (i = 0; i < 32; i++)
2443 if (streq(what, r_info_flags3[i]))
2445 d_ptr->mflags3 |= (1L << i);
2451 for (i = 0; i < 32; i++)
2453 if (streq(what, r_info_flags7[i]))
2455 d_ptr->mflags7 |= (1L << i);
2461 for (i = 0; i < 32; i++)
2463 if (streq(what, r_info_flags8[i]))
2465 d_ptr->mflags8 |= (1L << i);
2471 for (i = 0; i < 32; i++)
2473 if (streq(what, r_info_flags9[i]))
2475 d_ptr->mflags9 |= (1L << i);
2482 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2484 msg_format("Unknown monster flag '%s'.", what);
2492 * Grab one (spell) flag in a monster_race from a textual string
2494 static errr grab_one_spell_monster_flag(dungeon_info_type *d_ptr, cptr what)
2499 for (i = 0; i < 32; i++)
2501 if (streq(what, r_info_flags4[i]))
2503 d_ptr->mflags4 |= (1L << i);
2509 for (i = 0; i < 32; i++)
2511 if (streq(what, r_info_flags5[i]))
2513 d_ptr->mflags5 |= (1L << i);
2519 for (i = 0; i < 32; i++)
2521 if (streq(what, r_info_flags6[i]))
2523 d_ptr->mflags6 |= (1L << i);
2530 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2532 msg_format("Unknown monster flag '%s'.", what);
2540 * Initialize the "d_info" array, by parsing an ascii "template" file
2542 errr parse_d_info(char *buf, header *head)
2549 static dungeon_info_type *d_ptr = NULL;
2552 /* Process 'N' for "New/Number/Name" */
2555 /* Find the colon before the name */
2556 s = strchr(buf+2, ':');
2558 /* Verify that colon */
2561 /* Nuke the colon, advance to the name */
2564 /* Paranoia -- require a name */
2565 if (!*s) return (1);
2570 /* Verify information */
2571 if (i < error_idx) return (4);
2573 /* Verify information */
2574 if (i >= head->info_num) return (2);
2576 /* Save the index */
2579 /* Point at the "info" */
2582 /* Store the name */
2583 if (!add_name(&d_ptr->name, head, s)) return (7);
2588 else if (buf[0] == 'E') return (0);
2590 else if (buf[0] == 'E')
2592 /* Acquire the Text */
2595 /* Store the name */
2596 if (!add_name(&d_ptr->name, head, s)) return (7);
2600 /* Process 'D' for "Description */
2601 else if (buf[0] == 'D')
2606 /* Acquire the text */
2611 /* Acquire the text */
2615 /* Store the text */
2616 if (!add_text(&d_ptr->text, head, s)) return (7);
2619 /* Process 'W' for "More Info" (one line only) */
2620 else if (buf[0] == 'W')
2622 int min_lev, max_lev;
2624 int min_alloc, max_chance;
2625 int obj_good, obj_great;
2628 /* Scan for the values */
2629 if (10 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d:%x:%x",
2630 &min_lev, &max_lev, &min_plev, &mode, &min_alloc, &max_chance, &obj_good, &obj_great, (unsigned int *)&pit, (unsigned int *)&nest)) return (1);
2632 /* Save the values */
2633 d_ptr->mindepth = min_lev;
2634 d_ptr->maxdepth = max_lev;
2635 d_ptr->min_plev = min_plev;
2637 d_ptr->min_m_alloc_level = min_alloc;
2638 d_ptr->max_m_alloc_chance = max_chance;
2639 d_ptr->obj_good = obj_good;
2640 d_ptr->obj_great = obj_great;
2645 /* Process 'P' for "Place Info" */
2646 else if (buf[0] == 'P')
2650 /* Scan for the values */
2651 if (2 != sscanf(buf+2, "%d:%d", &dy, &dx)) return (1);
2653 /* Save the values */
2658 /* Process 'L' for "fLoor type" (one line only) */
2659 else if (buf[0] == 'L')
2665 /* Scan for the values */
2666 if (7 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d",
2667 &f1, &p1, &f2, &p2, &f3, &p3, &tunnel)) return (1);
2669 /* Save the values */
2671 d_ptr->floor_percent1 = p1;
2673 d_ptr->floor_percent2 = p2;
2675 d_ptr->floor_percent3 = p3;
2676 d_ptr->tunnel_percent = tunnel;
2679 /* Process 'A' for "wAll type" (one line only) */
2680 else if (buf[0] == 'A')
2682 int w1, w2, w3, outer, inner, stream1, stream2;
2685 /* Scan for the values */
2686 if (10 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
2687 &w1, &p1, &w2, &p2, &w3, &p3, &outer, &inner, &stream1, &stream2)) return (1);
2689 /* Save the values */
2690 d_ptr->fill_type1 = w1;
2691 d_ptr->fill_percent1 = p1;
2692 d_ptr->fill_type2 = w2;
2693 d_ptr->fill_percent2 = p2;
2694 d_ptr->fill_type3 = w3;
2695 d_ptr->fill_percent3 = p3;
2696 d_ptr->outer_wall = outer;
2697 d_ptr->inner_wall = inner;
2698 d_ptr->stream1 = stream1;
2699 d_ptr->stream2 = stream2;
2702 /* Process 'F' for "Dungeon Flags" (multiple lines) */
2703 else if (buf[0] == 'F')
2705 int artif = 0, monst = 0;
2707 /* Parse every entry */
2708 for (s = buf + 2; *s; )
2710 /* Find the end of this entry */
2711 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2713 /* Nuke and skip any dividers */
2717 while (*t == ' ' || *t == '|') t++;
2720 /* XXX XXX XXX Hack -- Read Final Artifact */
2721 if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif))
2723 /* Extract a "Final Artifact" */
2724 d_ptr->final_artifact = artif;
2726 /* Start at next entry */
2733 /* XXX XXX XXX Hack -- Read Final Object */
2734 if (1 == sscanf(s, "FINAL_OBJECT_%d", &artif))
2736 /* Extract a "Final Artifact" */
2737 d_ptr->final_object = artif;
2739 /* Start at next entry */
2746 /* XXX XXX XXX Hack -- Read Artifact Guardian */
2747 if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst))
2749 /* Extract a "Artifact Guardian" */
2750 d_ptr->final_guardian = monst;
2752 /* Start at next entry */
2759 /* XXX XXX XXX Hack -- Read Special Percentage */
2760 if (1 == sscanf(s, "MONSTER_DIV_%d", &monst))
2762 /* Extract a "Special %" */
2763 d_ptr->special_div = monst;
2765 /* Start at next entry */
2772 /* Parse this entry */
2773 if (0 != grab_one_dungeon_flag(d_ptr, s)) return (5);
2775 /* Start the next entry */
2780 /* Process 'M' for "Basic Flags" (multiple lines) */
2781 else if (buf[0] == 'M')
2783 /* Parse every entry */
2784 for (s = buf + 2; *s; )
2786 /* Find the end of this entry */
2787 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2789 /* Nuke and skip any dividers */
2793 while (*t == ' ' || *t == '|') t++;
2796 /* Hack -- Read monster symbols */
2797 if (!strncmp(s, "R_CHAR_", 7))
2799 /* Skip "R_CHAR_" */
2803 strncpy(d_ptr->r_char, s, sizeof(d_ptr->r_char));
2805 /* Start at next entry */
2812 /* Parse this entry */
2813 if (0 != grab_one_basic_monster_flag(d_ptr, s)) return (5);
2815 /* Start the next entry */
2820 /* Process 'S' for "Spell Flags" (multiple lines) */
2821 else if (buf[0] == 'S')
2823 /* Parse every entry */
2824 for (s = buf + 2; *s; )
2826 /* Find the end of this entry */
2827 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2829 /* Nuke and skip any dividers */
2833 while ((*t == ' ') || (*t == '|')) t++;
2836 /* XXX XXX XXX Hack -- Read spell frequency */
2837 if (1 == sscanf(s, "1_IN_%d", &i))
2839 /* Start at next entry */
2846 /* Parse this entry */
2847 if (0 != grab_one_spell_monster_flag(d_ptr, s)) return (5);
2849 /* Start the next entry */
2862 #else /* ALLOW_TEMPLATES */
2868 #endif /* ALLOW_TEMPLATES */
2871 /* Random dungeon grid effects */
2872 #define RANDOM_NONE 0x00
2873 #define RANDOM_FEATURE 0x01
2874 #define RANDOM_MONSTER 0x02
2875 #define RANDOM_OBJECT 0x04
2876 #define RANDOM_EGO 0x08
2877 #define RANDOM_ARTIFACT 0x10
2878 #define RANDOM_TRAP 0x20
2881 typedef struct dungeon_grid dungeon_grid;
2885 int feature; /* Terrain feature */
2886 int monster; /* Monster */
2887 int object; /* Object */
2888 int ego; /* Ego-Item */
2889 int artifact; /* Artifact */
2890 int trap; /* Trap */
2891 int cave_info; /* Flags for CAVE_MARK, CAVE_GLOW, CAVE_ICKY, CAVE_ROOM */
2892 int special; /* Reserved for special terrain info */
2893 int random; /* Number of the random effect */
2897 static dungeon_grid letter[255];
2901 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
2903 static errr parse_line_feature(char *buf)
2909 if (init_flags & INIT_ONLY_BUILDINGS) return (0);
2911 /* Tokenize the line */
2912 if ((num = tokenize(buf+2, 9, zz, 0)) > 1)
2914 /* Letter to assign */
2915 int index = zz[0][0];
2917 /* Reset the info for the letter */
2918 letter[index].feature = 0;
2919 letter[index].monster = 0;
2920 letter[index].object = 0;
2921 letter[index].ego = 0;
2922 letter[index].artifact = 0;
2923 letter[index].trap = 0;
2924 letter[index].cave_info = 0;
2925 letter[index].special = 0;
2926 letter[index].random = 0;
2932 letter[index].special = atoi(zz[8]);
2936 if (zz[7][0] == '*')
2938 letter[index].random |= RANDOM_TRAP;
2943 letter[index].trap = atoi(zz[7]);
2948 letter[index].trap = atoi(zz[7]);
2953 if (zz[6][0] == '*')
2955 letter[index].random |= RANDOM_ARTIFACT;
2960 letter[index].artifact = atoi(zz[6]);
2965 letter[index].artifact = atoi(zz[6]);
2970 if (zz[5][0] == '*')
2972 letter[index].random |= RANDOM_EGO;
2977 letter[index].ego = atoi(zz[5]);
2982 letter[index].ego = atoi(zz[5]);
2987 if (zz[4][0] == '*')
2989 letter[index].random |= RANDOM_OBJECT;
2994 letter[index].object = atoi(zz[4]);
2999 letter[index].object = atoi(zz[4]);
3004 if (zz[3][0] == '*')
3006 letter[index].random |= RANDOM_MONSTER;
3010 letter[index].monster = atoi(zz[3]);
3013 else if (zz[3][0] == 'c')
3015 letter[index].monster = - atoi(zz[3]+1);
3019 letter[index].monster = atoi(zz[3]);
3024 letter[index].cave_info = atoi(zz[2]);
3028 if (zz[1][0] == '*')
3030 letter[index].random |= RANDOM_FEATURE;
3034 letter[index].feature = atoi(zz[1]);
3039 letter[index].feature = atoi(zz[1]);
3052 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
3054 static errr parse_line_building(char *buf)
3070 /* Get the building number */
3073 /* Find the colon after the building number */
3076 /* Verify that colon */
3079 /* Nuke the colon, advance to the sub-index */
3082 /* Paranoia -- require a sub-index */
3083 if (!*s) return (1);
3085 /* Building definition sub-index */
3088 /* Building name, owner, race */
3091 if (tokenize(s + 2, 3, zz, 0) == 3)
3093 /* Name of the building */
3094 strcpy(building[index].name, zz[0]);
3096 /* Name of the owner */
3097 strcpy(building[index].owner_name, zz[1]);
3099 /* Race of the owner */
3100 strcpy(building[index].owner_race, zz[2]);
3105 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3108 /* Building Action */
3111 if (tokenize(s + 2, 8, zz, 0) >= 7)
3113 /* Index of the action */
3114 int action_index = atoi(zz[0]);
3116 /* Name of the action */
3117 strcpy(building[index].act_names[action_index], zz[1]);
3119 /* Cost of the action for members */
3120 building[index].member_costs[action_index] = atoi(zz[2]);
3122 /* Cost of the action for non-members */
3123 building[index].other_costs[action_index] = atoi(zz[3]);
3125 /* Letter assigned to the action */
3126 building[index].letters[action_index] = zz[4][0];
3129 building[index].actions[action_index] = atoi(zz[5]);
3131 /* Action restriction */
3132 building[index].action_restr[action_index] = atoi(zz[6]);
3137 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3140 /* Building Classes */
3143 if (tokenize(s + 2, MAX_CLASS, zz, 0) == MAX_CLASS)
3145 for (i = 0; i < MAX_CLASS; i++)
3147 building[index].member_class[i] = atoi(zz[i]);
3153 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3156 /* Building Races */
3159 if (tokenize(s+2, MAX_RACES, zz, 0) == MAX_RACES)
3161 for (i = 0; i < MAX_RACES; i++)
3163 building[index].member_race[i] = atoi(zz[i]);
3169 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3172 /* Building Realms */
3175 if (tokenize(s+2, MAX_MAGIC, zz, 0) == MAX_MAGIC)
3177 for (i = 0; i < MAX_MAGIC; i++)
3179 building[index].member_realm[i+1] = atoi(zz[i]);
3185 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3190 /* Ignore scripts */
3196 return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
3205 * Parse a sub-file of the "extra info"
3207 static errr process_dungeon_file_aux(char *buf, int ymin, int xmin, int ymax, int xmax, int *y, int *x)
3214 /* Skip "empty" lines */
3215 if (!buf[0]) return (0);
3217 /* Skip "blank" lines */
3218 if (isspace(buf[0])) return (0);
3221 if (buf[0] == '#') return (0);
3223 /* Require "?:*" format */
3224 if (buf[1] != ':') return (1);
3227 /* Process "%:<fname>" */
3230 /* Attempt to Process the given file */
3231 return (process_dungeon_file(buf + 2, ymin, xmin, ymax, xmax));
3234 /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid */
3237 return parse_line_feature(buf);
3240 /* Process "D:<dungeon>" -- info for the cave grids */
3241 else if (buf[0] == 'D')
3243 object_type object_type_body;
3245 /* Acquire the text */
3248 /* Length of the text */
3249 int len = strlen(s);
3251 if (init_flags & INIT_ONLY_BUILDINGS) return (0);
3253 for (*x = xmin, i = 0; ((*x < xmax) && (i < len)); (*x)++, s++, i++)
3255 /* Access the grid */
3256 cave_type *c_ptr = &cave[*y][*x];
3260 int object_index = letter[idx].object;
3261 int monster_index = letter[idx].monster;
3262 int random = letter[idx].random;
3263 int artifact_index = letter[idx].artifact;
3265 /* Lay down a floor */
3266 c_ptr->feat = letter[idx].feature;
3268 /* Only the features */
3269 if (init_flags & INIT_ONLY_FEATURES) continue;
3272 c_ptr->info = letter[idx].cave_info;
3274 /* Create a monster */
3275 if (random & RANDOM_MONSTER)
3277 monster_level = base_level + monster_index;
3279 place_monster(*y, *x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
3281 monster_level = base_level;
3283 else if (monster_index)
3285 int old_cur_num, old_max_num;
3288 if (monster_index < 0)
3290 monster_index = -monster_index;
3293 old_cur_num = r_info[monster_index].cur_num;
3294 old_max_num = r_info[monster_index].max_num;
3296 /* Make alive again */
3297 if (r_info[monster_index].flags1 & RF1_UNIQUE)
3299 r_info[monster_index].cur_num = 0;
3300 r_info[monster_index].max_num = 1;
3303 /* Make alive again */
3304 if (r_info[monster_index].flags7 & RF7_UNIQUE_7)
3306 if (r_info[monster_index].cur_num == r_info[monster_index].max_num)
3308 r_info[monster_index].max_num++;
3313 place_monster_aux(0, *y, *x, monster_index, (PM_ALLOW_SLEEP | PM_NO_KAGE));
3317 m_list[hack_m_idx_ii].smart |= SM_CLONED;
3319 /* Make alive again for real unique monster */
3320 r_info[monster_index].cur_num = old_cur_num;
3321 r_info[monster_index].max_num = old_max_num;
3325 /* Object (and possible trap) */
3326 if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP))
3328 object_level = base_level + object_index;
3331 * Random trap and random treasure defined
3332 * 25% chance for trap and 75% chance for object
3334 if (randint0(100) < 75)
3336 place_object(*y, *x, FALSE, FALSE);
3343 object_level = base_level;
3345 else if (random & RANDOM_OBJECT)
3347 object_level = base_level + object_index;
3349 /* Create an out of deep object */
3350 if (randint0(100) < 75)
3351 place_object(*y, *x, FALSE, FALSE);
3352 else if (randint0(100) < 80)
3353 place_object(*y, *x, TRUE, FALSE);
3355 place_object(*y, *x, TRUE, TRUE);
3357 object_level = base_level;
3360 else if (random & RANDOM_TRAP)
3364 /* Hidden trap (or door) */
3365 else if (letter[idx].trap)
3367 c_ptr->mimic = c_ptr->feat;
3368 c_ptr->feat = letter[idx].trap;
3370 else if (object_index)
3372 /* Get local object */
3373 object_type *o_ptr = &object_type_body;
3375 /* Create the item */
3376 object_prep(o_ptr, object_index);
3378 if (o_ptr->tval == TV_GOLD)
3380 coin_type = object_index - OBJ_GOLD_LIST;
3385 /* Apply magic (no messages, no artifacts) */
3386 apply_magic(o_ptr, base_level, FALSE, TRUE, FALSE, FALSE);
3388 (void)drop_near(o_ptr, -1, *y, *x);
3394 if (a_info[artifact_index].cur_num)
3398 object_type *q_ptr = &forge;
3400 object_prep(q_ptr, k_idx);
3402 /* Drop it in the dungeon */
3403 (void)drop_near(q_ptr, -1, *y, *x);
3407 /* Create the artifact */
3408 create_named_art(artifact_index, *y, *x);
3410 a_info[artifact_index].cur_num = 1;
3414 /* Terrain special */
3415 c_ptr->special = letter[idx].special;
3423 /* Process "Q:<number>:<command>:... -- quest info */
3424 else if (buf[0] == 'Q')
3431 num = tokenize(buf + 2, 33, zz, 0);
3435 num = tokenize(buf + 3, 33, zz, 0);
3438 /* Have we enough parameters? */
3439 if (num < 3) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3442 q_ptr = &(quest[atoi(zz[0])]);
3444 /* Process "Q:<q_index>:Q:<type>:<num_mon>:<cur_num>:<max_num>:<level>:<r_idx>:<k_idx>:<flags>" -- quest info */
3445 if (zz[1][0] == 'Q')
3447 if (init_flags & INIT_ASSIGN)
3449 monster_race *r_ptr;
3450 artifact_type *a_ptr;
3452 if (num < 9) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3454 q_ptr->type = atoi(zz[2]);
3455 q_ptr->num_mon = atoi(zz[3]);
3456 q_ptr->cur_num = atoi(zz[4]);
3457 q_ptr->max_num = atoi(zz[5]);
3458 q_ptr->level = atoi(zz[6]);
3459 q_ptr->r_idx = atoi(zz[7]);
3460 q_ptr->k_idx = atoi(zz[8]);
3461 q_ptr->dungeon = atoi(zz[9]);
3464 q_ptr->flags = atoi(zz[10]);
3466 r_ptr = &r_info[q_ptr->r_idx];
3467 if (r_ptr->flags1 & RF1_UNIQUE)
3468 r_ptr->flags1 |= RF1_QUESTOR;
3470 a_ptr = &a_info[q_ptr->k_idx];
3471 a_ptr->gen_flags |= TRG_QUESTITEM;
3476 /* Process "Q:<q_index>:N:<name>" -- quest name */
3477 else if (zz[1][0] == 'N')
3479 if (init_flags & (INIT_ASSIGN | INIT_SHOW_TEXT))
3481 strcpy(q_ptr->name, zz[2]);
3487 /* Process "Q:<q_index>:T:<text>" -- quest description line */
3488 else if (zz[1][0] == 'T')
3490 if (init_flags & INIT_SHOW_TEXT)
3492 strcpy(quest_text[quest_text_line], zz[2]);
3500 /* Process "W:<command>: ..." -- info for the wilderness */
3501 else if (buf[0] == 'W')
3503 return parse_line_wilderness(buf, ymin, xmin, ymax, xmax, y, x);
3506 /* Process "P:<y>:<x>" -- player position */
3507 else if (buf[0] == 'P')
3509 if (init_flags & INIT_CREATE_DUNGEON)
3511 if (tokenize(buf + 2, 2, zz, 0) == 2)
3513 int panels_x, panels_y;
3515 /* Hack - Set the dungeon size */
3516 panels_y = (*y / SCREEN_HGT);
3517 if (*y % SCREEN_HGT) panels_y++;
3518 cur_hgt = panels_y * SCREEN_HGT;
3520 panels_x = (*x / SCREEN_WID);
3521 if (*x % SCREEN_WID) panels_x++;
3522 cur_wid = panels_x * SCREEN_WID;
3524 /* Assume illegal panel */
3525 panel_row_min = cur_hgt;
3526 panel_col_min = cur_wid;
3528 /* Place player in a quest level */
3529 if (p_ptr->inside_quest)
3533 /* Delete the monster (if any) */
3534 delete_monster(py, px);
3542 /* Place player in the town */
3543 else if (!p_ptr->oldpx && !p_ptr->oldpy)
3545 p_ptr->oldpy = atoi(zz[0]);
3546 p_ptr->oldpx = atoi(zz[1]);
3554 /* Process "B:<Index>:<Command>:..." -- Building definition */
3555 else if (buf[0] == 'B')
3557 return parse_line_building(buf);
3560 /* Process "M:<type>:<maximum>" -- set maximum values */
3561 else if (buf[0] == 'M')
3563 if (tokenize(buf+2, 2, zz, 0) == 2)
3566 if (zz[0][0] == 'T')
3568 max_towns = atoi(zz[1]);
3571 /* Maximum quests */
3572 else if (zz[0][0] == 'Q')
3574 max_quests = atoi(zz[1]);
3578 else if (zz[0][0] == 'R')
3580 max_r_idx = atoi(zz[1]);
3584 else if (zz[0][0] == 'K')
3586 max_k_idx = atoi(zz[1]);
3590 else if (zz[0][0] == 'V')
3592 max_v_idx = atoi(zz[1]);
3596 else if (zz[0][0] == 'F')
3598 max_f_idx = atoi(zz[1]);
3602 else if (zz[0][0] == 'A')
3604 max_a_idx = atoi(zz[1]);
3608 else if (zz[0][0] == 'E')
3610 max_e_idx = atoi(zz[1]);
3614 else if (zz[0][0] == 'D')
3616 max_d_idx = atoi(zz[1]);
3620 else if (zz[0][0] == 'O')
3622 max_o_idx = atoi(zz[1]);
3626 else if (zz[0][0] == 'M')
3628 max_m_idx = atoi(zz[1]);
3631 /* Wilderness size */
3632 else if (zz[0][0] == 'W')
3634 /* Maximum wild_x_size */
3635 if (zz[0][1] == 'X')
3636 max_wild_x = atoi(zz[1]);
3637 /* Maximum wild_y_size */
3638 if (zz[0][1] == 'Y')
3639 max_wild_y = atoi(zz[1]);
3653 static cptr variant = "ZANGBAND";
3657 * Helper function for "process_dungeon_file()"
3659 static cptr process_dungeon_file_expr(char **sp, char *fp)
3675 while (isspace(*s)) s++;
3693 t = process_dungeon_file_expr(&s, &f);
3702 else if (streq(t, "IOR"))
3705 while (*s && (f != b2))
3707 t = process_dungeon_file_expr(&s, &f);
3708 if (*t && !streq(t, "0")) v = "1";
3713 else if (streq(t, "AND"))
3716 while (*s && (f != b2))
3718 t = process_dungeon_file_expr(&s, &f);
3719 if (*t && streq(t, "0")) v = "0";
3724 else if (streq(t, "NOT"))
3727 while (*s && (f != b2))
3729 t = process_dungeon_file_expr(&s, &f);
3730 if (*t && streq(t, "1")) v = "0";
3735 else if (streq(t, "EQU"))
3738 if (*s && (f != b2))
3740 t = process_dungeon_file_expr(&s, &f);
3742 while (*s && (f != b2))
3745 t = process_dungeon_file_expr(&s, &f);
3746 if (*t && !streq(p, t)) v = "0";
3751 else if (streq(t, "LEQ"))
3754 if (*s && (f != b2))
3756 t = process_dungeon_file_expr(&s, &f);
3758 while (*s && (f != b2))
3761 t = process_dungeon_file_expr(&s, &f);
3762 if (*t && (strcmp(p, t) > 0)) v = "0";
3767 else if (streq(t, "GEQ"))
3770 if (*s && (f != b2))
3772 t = process_dungeon_file_expr(&s, &f);
3774 while (*s && (f != b2))
3777 t = process_dungeon_file_expr(&s, &f);
3778 if (*t && (strcmp(p, t) < 0)) v = "0";
3785 while (*s && (f != b2))
3787 t = process_dungeon_file_expr(&s, &f);
3792 if (f != b2) v = "?x?x?";
3794 /* Extract final and Terminate */
3795 if ((f = *s) != '\0') *s++ = '\0';
3801 /* Accept all printables except spaces and brackets */
3802 while (isprint(*s) && !strchr(" []", *s)) ++s;
3804 /* Extract final and Terminate */
3805 if ((f = *s) != '\0') *s++ = '\0';
3811 if (streq(b+1, "SYS"))
3817 else if (streq(b+1, "GRAF"))
3822 else if (streq(b+1, "MONOCHROME"))
3831 else if (streq(b+1, "RACE"))
3834 v = rp_ptr->E_title;
3841 else if (streq(b+1, "CLASS"))
3844 v = cp_ptr->E_title;
3851 else if (streq(b+1, "REALM1"))
3854 v = E_realm_names[p_ptr->realm1];
3856 v = realm_names[p_ptr->realm1];
3861 else if (streq(b+1, "REALM2"))
3864 v = E_realm_names[p_ptr->realm2];
3866 v = realm_names[p_ptr->realm2];
3871 else if (streq(b+1, "PLAYER"))
3877 else if (streq(b+1, "TOWN"))
3879 sprintf(tmp, "%d", p_ptr->town_num);
3884 else if (streq(b+1, "LEVEL"))
3886 sprintf(tmp, "%d", p_ptr->lev);
3890 /* Current quest number */
3891 else if (streq(b+1, "QUEST_NUMBER"))
3893 sprintf(tmp, "%d", p_ptr->inside_quest);
3897 /* Number of last quest */
3898 else if (streq(b+1, "LEAVING_QUEST"))
3900 sprintf(tmp, "%d", leaving_quest);
3905 else if (prefix(b+1, "QUEST"))
3907 /* "QUEST" uses a special parameter to determine the number of the quest */
3908 sprintf(tmp, "%d", quest[atoi(b+6)].status);
3913 else if (prefix(b+1, "RANDOM"))
3915 /* "RANDOM" uses a special parameter to determine the number of the quest */
3916 sprintf(tmp, "%d", (int)(seed_town%atoi(b+7)));
3921 else if (streq(b+1, "VARIANT"))
3927 else if (streq(b+1, "WILDERNESS"))
3930 sprintf(tmp, "NONE");
3932 sprintf(tmp, "LITE");
3934 sprintf(tmp, "NORMAL");
3957 errr process_dungeon_file(cptr name, int ymin, int xmin, int ymax, int xmax)
3967 bool bypass = FALSE;
3969 int x = xmin, y = ymin;
3972 /* Build the filename */
3973 path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, name);
3976 fp = my_fopen(buf, "r");
3979 if (!fp) return (-1);
3982 /* Process the file */
3983 while (0 == my_fgets(fp, buf, sizeof(buf)))
3989 /* Skip "empty" lines */
3990 if (!buf[0]) continue;
3992 /* Skip "blank" lines */
3993 if (isspace(buf[0])) continue;
3996 if (buf[0] == '#') continue;
3999 /* Process "?:<expr>" */
4000 if ((buf[0] == '?') && (buf[1] == ':'))
4009 /* Parse the expr */
4010 v = process_dungeon_file_expr(&s, &f);
4013 bypass = (streq(v, "0") ? TRUE : FALSE);
4019 /* Apply conditionals */
4020 if (bypass) continue;
4022 /* Process the line */
4023 err = process_dungeon_file_aux(buf, ymin, xmin, ymax, xmax, &y, &x);
4035 oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
4038 msg_format("Error %d (%s) at line %d of '%s'.", err, oops, num, name);
4040 msg_format("'%s'¤ò²òÀÏÃæ¡£", buf);
4042 msg_format("Parsing '%s'.", buf);
4049 /* Close the file */
4059 void write_r_info_txt(void)
4061 int i, j, z, fc, bc;
4069 monster_race *r_ptr;
4071 monster_blow *b_ptr;
4073 FILE *fff = fopen("output.txt", "wt");
4081 fprintf(fff, "# File: r_info.txt (autogenerated)\n\n");
4083 fprintf(fff, "# Version stamp (required)\n\n");
4086 fprintf(fff, "V:%d.%d.%d\n\n\n", r_head->v_major, r_head->v_minor, r_head->v_patch);
4089 fprintf(fff, "##### The Player #####\n\n");
4091 for (z = -1; z < alloc_race_size; z++)
4093 /* Output the monsters in order */
4094 i = (z >= 0) ? alloc_race_table[z].index : 0;
4096 /* Acquire the monster */
4099 /* Ignore empty monsters */
4100 if (!strlen(r_name + r_ptr->name)) continue;
4102 /* Ignore useless monsters */
4103 if (i && !r_ptr->speed) continue;
4105 /* Write a note if necessary */
4106 if (i && (!r_ptr->level != !mode))
4111 fprintf(fff, "\n##### Town monsters #####\n\n");
4113 /* Note the dungeon */
4116 fprintf(fff, "\n##### Normal monsters #####\n\n");
4119 /* Record the change */
4120 mode = r_ptr->level;
4123 /* Acquire the flags */
4124 f_ptr[0] = r_ptr->flags1; n_ptr[0] = r_info_flags1;
4125 f_ptr[1] = r_ptr->flags2; n_ptr[1] = r_info_flags2;
4126 f_ptr[2] = r_ptr->flags3; n_ptr[2] = r_info_flags3;
4127 f_ptr[3] = r_ptr->flags4; n_ptr[3] = r_info_flags4;
4128 f_ptr[4] = r_ptr->flags5; n_ptr[4] = r_info_flags5;
4129 f_ptr[5] = r_ptr->flags6; n_ptr[5] = r_info_flags6;
4130 f_ptr[6] = r_ptr->flags7; n_ptr[6] = r_info_flags7;
4131 f_ptr[7] = r_ptr->flags8; n_ptr[7] = r_info_flags8;
4132 f_ptr[8] = r_ptr->flags9; n_ptr[8] = r_info_flags9;
4134 /* Write New/Number/Name */
4135 fprintf(fff, "N:%d:%s\n", z + 1, r_name + r_ptr->name);
4138 fprintf(fff, "G:%c:%c\n", r_ptr->d_char, color_char[r_ptr->d_attr]);
4140 /* Write Information */
4141 fprintf(fff, "I:%d:%dd%d:%d:%d:%d\n", r_ptr->speed, r_ptr->hdice, r_ptr->hside,
4142 r_ptr->aaf, r_ptr->ac, r_ptr->sleep);
4144 /* Write more information */
4145 fprintf(fff, "W:%d:%d:%d:%ld\n", r_ptr->level, r_ptr->rarity, r_ptr->extra, r_ptr->mexp);
4148 for(j = 0; j < 4; j++)
4150 b_ptr = &(r_ptr->blow[j]);
4152 /* Stop when done */
4153 if (!b_ptr->method) break;
4155 /* Write the blows */
4156 fprintf(fff, "B:%s:%s:%dd%d\n", r_info_blow_method[b_ptr->method],
4157 r_info_blow_effect[b_ptr->effect],
4158 b_ptr->d_dice, b_ptr->d_side);
4161 /* Extract the flags */
4162 for (fc = 0, j = 0; j < 96; j++)
4164 /* Check this flag */
4165 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4168 /* Extract the extra flags */
4169 for (j = 192; j < 288; j++)
4171 /* Check this flag */
4172 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4175 /* Write the flags */
4176 for (j = 0; j < fc;)
4180 /* Start the line */
4183 for (bc = 0; (bc < 60) && (j < fc); j++)
4187 /* Format the flag */
4188 sprintf(t, "%s%s", flags[j], (j < fc - 1) ? " | " : "");
4190 /* Add it to the buffer */
4193 /* Note the length */
4197 /* Done with this line; write it */
4198 fprintf(fff, "%s\n", buf);
4201 /* Write Spells if applicable */
4202 if (r_ptr->freq_spell)
4204 /* Write the frequency */
4205 fprintf(fff, "S:1_IN_%d | \n", 100 / r_ptr->freq_spell);
4207 /* Extract the spell flags */
4208 for (fc = 0, j = 96; j < 192; j++)
4210 /* Check this flag */
4211 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4214 /* Write the flags */
4215 for (j = 0; j < fc;)
4219 /* Start the line */
4222 for (bc = 0, t = buf + 2; (bc < 60) && (j < fc); j++)
4226 /* Format the flag */
4227 sprintf(t, "%s%s", flags[j], (j < fc - 1) ? " | " : "");
4231 /* Note the length */
4238 /* Done with this line; write it */
4239 fprintf(fff, "%s\n", buf);
4243 /* Acquire the description */
4244 desc = r_text + r_ptr->text;
4245 dlen = strlen(desc);
4247 /* Write Description */
4248 for (j = 0; j < dlen;)
4252 /* Start the line */
4255 for (bc = 0, t = buf + 2; ((bc < 60) || !isspace(desc[j])) && (j < dlen); j++, bc++, t++)
4263 /* Done with this line; write it */
4264 fprintf(fff, "%s\n", buf);
4267 /* Space between entries */