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[] =
500 * Monster race flags - Resistances
502 static cptr r_info_flagsr[] =
542 static cptr k_info_flags[] =
667 static cptr k_info_gen_flags[] =
707 static cptr d_info_flags1[] =
745 * Add a text to the text-storage and store offset to it.
747 * Returns FALSE when there isn't enough space available to store
750 static bool add_text(u32b *offset, header *head, cptr buf)
752 /* Hack -- Verify space */
753 if (head->text_size + strlen(buf) + 8 > FAKE_TEXT_SIZE)
759 /* Advance and save the text index */
760 *offset = ++head->text_size;
763 /* Append chars to the text */
764 strcpy(head->text_ptr + head->text_size, buf);
766 /* Advance the index */
767 head->text_size += strlen(buf);
775 * Add a name to the name-storage and return an offset to it.
777 * Returns FALSE when there isn't enough space available to store
780 static bool add_name(u32b *offset, header *head, cptr buf)
782 /* Hack -- Verify space */
783 if (head->name_size + strlen(buf) + 8 > FAKE_NAME_SIZE)
789 /* Advance and save the name index */
790 *offset = ++head->name_size;
793 /* Append chars to the names */
794 strcpy(head->name_ptr + head->name_size, buf);
796 /* Advance the index */
797 head->name_size += strlen(buf);
805 * Convert a "color letter" into an "actual" color
806 * The colors are: dwsorgbuDWvyRGBU, as shown below
808 byte color_char_to_attr(char c)
812 case 'd': return (TERM_DARK);
813 case 'w': return (TERM_WHITE);
814 case 's': return (TERM_SLATE);
815 case 'o': return (TERM_ORANGE);
816 case 'r': return (TERM_RED);
817 case 'g': return (TERM_GREEN);
818 case 'b': return (TERM_BLUE);
819 case 'u': return (TERM_UMBER);
821 case 'D': return (TERM_L_DARK);
822 case 'W': return (TERM_L_WHITE);
823 case 'v': return (TERM_VIOLET);
824 case 'y': return (TERM_YELLOW);
825 case 'R': return (TERM_L_RED);
826 case 'G': return (TERM_L_GREEN);
827 case 'B': return (TERM_L_BLUE);
828 case 'U': return (TERM_L_UMBER);
836 /*** Initialize from ascii template files ***/
840 * Initialize an "*_info" array, by parsing an ascii "template" file
842 errr init_info_txt(FILE *fp, char *buf, header *head,
843 parse_info_txt_func parse_info_txt_line)
847 /* Just before the first record */
850 /* Just before the first line */
854 /* Prepare the "fake" stuff */
859 while (0 == my_fgets(fp, buf, 1024))
861 /* Advance the line number */
864 /* Skip comments and blank lines */
865 if (!buf[0] || (buf[0] == '#')) continue;
867 /* Verify correct "colon" format */
868 if (buf[1] != ':') return (PARSE_ERROR_GENERIC);
871 /* Hack -- Process 'V' for "Version" */
878 /* Mega Hack -- Calculate Check Sum */
879 if (buf[0] != 'N' && buf[0] != 'D')
882 for (i = 0; buf[i]; i++)
884 head->v_extra += (byte)buf[i];
885 head->v_extra ^= (1 << (i % 8));
890 if ((err = (*parse_info_txt_line)(buf, head)) != 0)
895 /* Complete the "name" and "text" sizes */
896 if (head->name_size) head->name_size++;
897 if (head->text_size) head->text_size++;
905 * Initialize the "v_info" array, by parsing an ascii "template" file
907 errr parse_v_info(char *buf, header *head)
913 static vault_type *v_ptr = NULL;
915 /* Process 'N' for "New/Number/Name" */
918 /* Find the colon before the name */
919 s = strchr(buf+2, ':');
921 /* Verify that colon */
924 /* Nuke the colon, advance to the name */
927 /* Paranoia -- require a name */
933 /* Verify information */
934 if (i <= error_idx) return (4);
936 /* Verify information */
937 if (i >= head->info_num) return (2);
942 /* Point at the "info" */
946 if (!add_name(&v_ptr->name, head, s)) return (7);
949 /* There better be a current v_ptr */
950 else if (!v_ptr) return (3);
952 /* Process 'D' for "Description" */
953 else if (buf[0] == 'D')
955 /* Acquire the text */
959 if (!add_text(&v_ptr->text, head, s)) return (7);
962 /* Process 'X' for "Extra info" (one line only) */
963 else if (buf[0] == 'X')
965 int typ, rat, hgt, wid;
967 /* Scan for the values */
968 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
969 &typ, &rat, &hgt, &wid)) return (1);
971 /* Save the values */
988 * Initialize the "s_info" array, by parsing an ascii "template" file
990 errr parse_s_info(char *buf, header *head)
995 static skill_table *s_ptr = NULL;
998 /* Process 'N' for "New/Number/Name" */
1004 /* Verify information */
1005 if (i <= error_idx) return (4);
1007 /* Verify information */
1008 if (i >= head->info_num) return (2);
1010 /* Save the index */
1013 /* Point at the "info" */
1017 /* There better be a current s_ptr */
1018 else if (!s_ptr) return (3);
1020 /* Process 'W' for "Weapon exp" */
1021 else if (buf[0] == 'W')
1023 int tval, sval, start, max;
1024 const s16b exp_conv_table[] =
1026 WEAPON_EXP_UNSKILLED, WEAPON_EXP_BEGINNER, WEAPON_EXP_SKILLED,
1027 WEAPON_EXP_EXPERT, WEAPON_EXP_MASTER
1030 /* Scan for the values */
1031 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1032 &tval, &sval, &start, &max)) return (1);
1034 if (start < EXP_LEVEL_UNSKILLED || start > EXP_LEVEL_MASTER
1035 || max < EXP_LEVEL_UNSKILLED || max > EXP_LEVEL_MASTER) return (8);
1037 /* Save the values */
1038 s_ptr->w_start[tval][sval] = exp_conv_table[start];
1039 s_ptr->w_max[tval][sval] = exp_conv_table[max];
1042 /* Process 'S' for "Skill exp" */
1043 else if (buf[0] == 'S')
1045 int num, start, max;
1047 /* Scan for the values */
1048 if (3 != sscanf(buf+2, "%d:%d:%d",
1049 &num, &start, &max)) return (1);
1051 if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER
1052 || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER) return (8);
1054 /* Save the values */
1055 s_ptr->s_start[num] = start;
1056 s_ptr->s_max[num] = max;
1069 * Initialize the "m_info" array, by parsing an ascii "template" file
1071 errr parse_m_info(char *buf, header *head)
1078 static player_magic *m_ptr = NULL;
1081 static int realm, magic_idx = 0, readable = 0;
1084 /* Process 'N' for "New/Number/Name" */
1090 /* Verify information */
1091 if (i <= error_idx) return (4);
1093 /* Verify information */
1094 if (i >= head->info_num) return (2);
1096 /* Save the index */
1099 /* Point at the "info" */
1103 /* There better be a current m_ptr */
1104 else if (!m_ptr) return (3);
1106 /* Process 'I' for "Info" (one line only) */
1107 else if (buf[0] == 'I')
1110 int xtra, type, first, weight;
1112 /* Find the colon before the name */
1113 s = strchr(buf+2, ':');
1115 /* Verify that colon */
1118 /* Nuke the colon, advance to the name */
1123 if (streq(book, "SORCERY")) m_ptr->spell_book = TV_SORCERY_BOOK;
1124 else if (streq(book, "LIFE")) m_ptr->spell_book = TV_LIFE_BOOK;
1125 else if (streq(book, "MUSIC")) m_ptr->spell_book = TV_MUSIC_BOOK;
1126 else if (streq(book, "HISSATSU")) m_ptr->spell_book = TV_HISSATSU_BOOK;
1127 else if (streq(book, "NONE")) m_ptr->spell_book = 0;
1132 /* Find the colon before the name */
1135 /* Verify that colon */
1138 /* Nuke the colon, advance to the name */
1141 if (streq(stat, "STR")) m_ptr->spell_stat = A_STR;
1142 else if (streq(stat, "INT")) m_ptr->spell_stat = A_INT;
1143 else if (streq(stat, "WIS")) m_ptr->spell_stat = A_WIS;
1144 else if (streq(stat, "DEX")) m_ptr->spell_stat = A_DEX;
1145 else if (streq(stat, "CON")) m_ptr->spell_stat = A_CON;
1146 else if (streq(stat, "CHR")) m_ptr->spell_stat = A_CHR;
1150 /* Scan for the values */
1151 if (4 != sscanf(s, "%x:%d:%d:%d",
1152 (uint *)&xtra, &type, &first, &weight)) return (1);
1154 m_ptr->spell_xtra = xtra;
1155 m_ptr->spell_type = type;
1156 m_ptr->spell_first = first;
1157 m_ptr->spell_weight = weight;
1161 /* Process 'R' for "Realm" (one line only) */
1162 else if (buf[0] == 'R')
1164 /* Scan for the values */
1165 if (2 != sscanf(buf+2, "%d:%d",
1166 &realm, &readable)) return (1);
1171 else if (buf[0] == 'T')
1173 int level, mana, fail, exp;
1175 if (!readable) return (1);
1176 /* Scan for the values */
1177 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1178 &level, &mana, &fail, &exp)) return (1);
1180 m_ptr->info[realm][magic_idx].slevel = level;
1181 m_ptr->info[realm][magic_idx].smana = mana;
1182 m_ptr->info[realm][magic_idx].sfail = fail;
1183 m_ptr->info[realm][magic_idx].sexp = exp;
1197 * Initialize the "f_info" array, by parsing an ascii "template" file
1199 errr parse_f_info(char *buf, header *head)
1206 static feature_type *f_ptr = NULL;
1209 /* Process 'N' for "New/Number/Name" */
1212 /* Find the colon before the name */
1213 s = strchr(buf+2, ':');
1215 /* Verify that colon */
1218 /* Nuke the colon, advance to the name */
1222 /* Paranoia -- require a name */
1223 if (!*s) return (1);
1229 /* Verify information */
1230 if (i <= error_idx) return (4);
1232 /* Verify information */
1233 if (i >= head->info_num) return (2);
1235 /* Save the index */
1238 /* Point at the "info" */
1242 /* Store the name */
1243 if (!add_name(&f_ptr->name, head, s)) return (7);
1245 /* Default "mimic" */
1249 /* There better be a current f_ptr */
1250 else if (!f_ptr) return (3);
1253 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1254 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1255 else if (buf[0] == 'E')
1260 else if (buf[0] == 'E')
1262 /* Acquire the Text */
1265 /* Store the name */
1266 if (!add_name(&f_ptr->name, head, s)) return (7);
1271 /* Process 'M' for "Mimic" (one line only) */
1272 else if (buf[0] == 'M')
1276 /* Scan for the values */
1277 if (1 != sscanf(buf+2, "%d",
1278 &mimic)) return (1);
1280 /* Save the values */
1281 f_ptr->mimic = mimic;
1286 /* Process 'G' for "Graphics" (one line only) */
1287 else if (buf[0] == 'G')
1292 if (!buf[2]) return (1);
1293 if (!buf[3]) return (1);
1294 if (!buf[4]) return (1);
1296 /* Extract the color */
1297 tmp = color_char_to_attr(buf[4]);
1300 if (tmp > 127) return (1);
1302 /* Save the values */
1303 f_ptr->d_attr = tmp;
1304 f_ptr->d_char = buf[2];
1317 * Grab one flag in an object_kind from a textual string
1319 static errr grab_one_kind_flag(object_kind *k_ptr, cptr what)
1324 for (i = 0; i < TR_FLAG_MAX; i++)
1326 if (streq(what, k_info_flags[i]))
1328 add_flag(k_ptr->flags, i);
1333 /* Check gen_flags */
1334 for (i = 0; i < 32; i++)
1336 if (streq(what, k_info_gen_flags[i]))
1338 k_ptr->gen_flags |= (1L << i);
1345 msg_format("̤ÃΤΥ¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1347 msg_format("Unknown object flag '%s'.", what);
1357 * Initialize the "k_info" array, by parsing an ascii "template" file
1359 errr parse_k_info(char *buf, header *head)
1366 static object_kind *k_ptr = NULL;
1369 /* Process 'N' for "New/Number/Name" */
1372 /* Find the colon before the name */
1373 s = strchr(buf+2, ':');
1375 /* Verify that colon */
1378 /* Nuke the colon, advance to the name */
1382 /* Paranoia -- require a name */
1383 if (!*s) return (1);
1388 /* Verify information */
1389 if (i <= error_idx) return (4);
1391 /* Verify information */
1392 if (i >= head->info_num) return (2);
1394 /* Save the index */
1397 /* Point at the "info" */
1401 /* Store the name */
1402 if (!add_name(&k_ptr->name, head, s)) return (7);
1406 /* There better be a current k_ptr */
1407 else if (!k_ptr) return (3);
1411 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1412 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1413 else if (buf[0] == 'E')
1418 else if (buf[0] == 'E')
1420 /* Acquire the Text */
1423 /* Store the name */
1424 if (!add_name(&k_ptr->name, head, s)) return (7);
1428 /* Process 'D' for "Description" */
1429 else if (buf[0] == 'D')
1434 /* Acquire the text */
1439 /* Acquire the text */
1443 /* Store the text */
1444 if (!add_text(&k_ptr->text, head, s)) return (7);
1447 /* Process 'G' for "Graphics" (one line only) */
1448 else if (buf[0] == 'G')
1454 if (!buf[2]) return (1);
1455 if (!buf[3]) return (1);
1456 if (!buf[4]) return (1);
1458 /* Extract the char */
1461 /* Extract the attr */
1462 tmp = color_char_to_attr(buf[4]);
1465 if (tmp > 127) return (1);
1467 /* Save the values */
1468 k_ptr->d_attr = tmp;
1469 k_ptr->d_char = sym;
1472 /* Process 'I' for "Info" (one line only) */
1473 else if (buf[0] == 'I')
1475 int tval, sval, pval;
1477 /* Scan for the values */
1478 if (3 != sscanf(buf+2, "%d:%d:%d",
1479 &tval, &sval, &pval)) return (1);
1481 /* Save the values */
1487 /* Process 'W' for "More Info" (one line only) */
1488 else if (buf[0] == 'W')
1490 int level, extra, wgt;
1493 /* Scan for the values */
1494 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1495 &level, &extra, &wgt, &cost)) return (1);
1497 /* Save the values */
1498 k_ptr->level = level;
1499 k_ptr->extra = extra;
1500 k_ptr->weight = wgt;
1504 /* Process 'A' for "Allocation" (one line only) */
1505 else if (buf[0] == 'A')
1509 /* XXX XXX XXX Simply read each number following a colon */
1510 for (i = 0, s = buf+1; s && (s[0] == ':') && s[1]; ++i)
1512 /* Default chance */
1513 k_ptr->chance[i] = 1;
1515 /* Store the attack damage index */
1516 k_ptr->locale[i] = atoi(s+1);
1518 /* Find the slash */
1519 t = strchr(s+1, '/');
1521 /* Find the next colon */
1522 s = strchr(s+1, ':');
1524 /* If the slash is "nearby", use it */
1525 if (t && (!s || t < s))
1527 int chance = atoi(t+1);
1528 if (chance > 0) k_ptr->chance[i] = chance;
1533 /* Hack -- Process 'P' for "power" and such */
1534 else if (buf[0] == 'P')
1536 int ac, hd1, hd2, th, td, ta;
1538 /* Scan for the values */
1539 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
1540 &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
1550 /* Hack -- Process 'F' for flags */
1551 else if (buf[0] == 'F')
1553 /* Parse every entry textually */
1554 for (s = buf + 2; *s; )
1556 /* Find the end of this entry */
1557 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1559 /* Nuke and skip any dividers */
1563 while (*t == ' ' || *t == '|') t++;
1566 /* Parse this entry */
1567 if (0 != grab_one_kind_flag(k_ptr, s)) return (5);
1569 /* Start the next entry */
1585 * Grab one flag in an artifact_type from a textual string
1587 static errr grab_one_artifact_flag(artifact_type *a_ptr, cptr what)
1592 for (i = 0; i < TR_FLAG_MAX; i++)
1594 if (streq(what, k_info_flags[i]))
1596 add_flag(a_ptr->flags, i);
1601 /* Check gen_flags */
1602 for (i = 0; i < 32; i++)
1604 if (streq(what, k_info_gen_flags[i]))
1606 a_ptr->gen_flags |= (1L << i);
1613 msg_format("̤ÃΤÎÅÁÀâ¤Î¥¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1615 msg_format("Unknown artifact flag '%s'.", what);
1627 * Initialize the "a_info" array, by parsing an ascii "template" file
1629 errr parse_a_info(char *buf, header *head)
1636 static artifact_type *a_ptr = NULL;
1639 /* Process 'N' for "New/Number/Name" */
1642 /* Find the colon before the name */
1643 s = strchr(buf+2, ':');
1645 /* Verify that colon */
1648 /* Nuke the colon, advance to the name */
1651 /* Paranoia -- require a name */
1652 if (!*s) return (1);
1657 /* Verify information */
1658 if (i < error_idx) return (4);
1660 /* Verify information */
1661 if (i >= head->info_num) return (2);
1663 /* Save the index */
1666 /* Point at the "info" */
1669 /* Ignore everything */
1670 add_flag(a_ptr->flags, TR_IGNORE_ACID);
1671 add_flag(a_ptr->flags, TR_IGNORE_ELEC);
1672 add_flag(a_ptr->flags, TR_IGNORE_FIRE);
1673 add_flag(a_ptr->flags, TR_IGNORE_COLD);
1675 /* Store the name */
1676 if (!add_name(&a_ptr->name, head, s)) return (7);
1680 /* There better be a current a_ptr */
1681 else if (!a_ptr) return (3);
1685 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1686 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾¤È¤·¤Æ¤¤¤ë */
1687 else if (buf[0] == 'E')
1692 else if (buf[0] == 'E')
1694 /* Acquire the Text */
1697 /* Store the name */
1698 if (!add_name(&a_ptr->name, head, s)) return (7);
1702 /* Process 'D' for "Description" */
1703 else if (buf[0] == 'D')
1708 /* Acquire the text */
1713 /* Acquire the text */
1717 /* Store the text */
1718 if (!add_text(&a_ptr->text, head, s)) return (7);
1722 /* Process 'I' for "Info" (one line only) */
1723 else if (buf[0] == 'I')
1725 int tval, sval, pval;
1727 /* Scan for the values */
1728 if (3 != sscanf(buf+2, "%d:%d:%d",
1729 &tval, &sval, &pval)) return (1);
1731 /* Save the values */
1737 /* Process 'W' for "More Info" (one line only) */
1738 else if (buf[0] == 'W')
1740 int level, rarity, wgt;
1743 /* Scan for the values */
1744 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1745 &level, &rarity, &wgt, &cost)) return (1);
1747 /* Save the values */
1748 a_ptr->level = level;
1749 a_ptr->rarity = rarity;
1750 a_ptr->weight = wgt;
1754 /* Hack -- Process 'P' for "power" and such */
1755 else if (buf[0] == 'P')
1757 int ac, hd1, hd2, th, td, ta;
1759 /* Scan for the values */
1760 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
1761 &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
1771 /* Hack -- Process 'F' for flags */
1772 else if (buf[0] == 'F')
1774 /* Parse every entry textually */
1775 for (s = buf + 2; *s; )
1777 /* Find the end of this entry */
1778 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1780 /* Nuke and skip any dividers */
1784 while ((*t == ' ') || (*t == '|')) t++;
1787 /* Parse this entry */
1788 if (0 != grab_one_artifact_flag(a_ptr, s)) return (5);
1790 /* Start the next entry */
1806 * Grab one flag in a ego-item_type from a textual string
1808 static bool grab_one_ego_item_flag(ego_item_type *e_ptr, cptr what)
1813 for (i = 0; i < TR_FLAG_MAX; i++)
1815 if (streq(what, k_info_flags[i]))
1817 add_flag(e_ptr->flags, i);
1822 /* Check gen_flags */
1823 for (i = 0; i < 32; i++)
1825 if (streq(what, k_info_gen_flags[i]))
1827 e_ptr->gen_flags |= (1L << i);
1834 msg_format("̤ÃΤÎ̾¤Î¤¢¤ë¥¢¥¤¥Æ¥à¡¦¥Õ¥é¥° '%s'¡£", what);
1836 msg_format("Unknown ego-item flag '%s'.", what);
1848 * Initialize the "e_info" array, by parsing an ascii "template" file
1850 errr parse_e_info(char *buf, header *head)
1857 static ego_item_type *e_ptr = NULL;
1860 /* Just before the first record */
1863 /* Just before the first line */
1867 /* Process 'N' for "New/Number/Name" */
1870 /* Find the colon before the name */
1871 s = strchr(buf+2, ':');
1873 /* Verify that colon */
1876 /* Nuke the colon, advance to the name */
1879 /* Paranoia -- require a name */
1880 if (!*s) return (1);
1885 /* Verify information */
1886 if (i < error_idx) return (4);
1888 /* Verify information */
1889 if (i >= head->info_num) return (2);
1891 /* Save the index */
1894 /* Point at the "info" */
1897 /* Store the name */
1898 if (!add_name(&e_ptr->name, head, s)) return (7);
1902 /* There better be a current e_ptr */
1903 else if (!e_ptr) return (3);
1907 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
1908 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾ */
1909 else if (buf[0] == 'E')
1914 else if (buf[0] == 'E')
1916 /* Acquire the Text */
1919 /* Store the name */
1920 if (!add_name(&e_ptr->name, head, s)) return (7);
1925 /* Process 'D' for "Description" */
1926 else if (buf[0] == 'D')
1928 /* Acquire the text */
1931 /* Store the text */
1932 if (!add_text(&e_ptr->text, head, s)) return (7);
1937 /* Process 'X' for "Xtra" (one line only) */
1938 else if (buf[0] == 'X')
1942 /* Scan for the values */
1943 if (2 != sscanf(buf+2, "%d:%d",
1944 &slot, &rating)) return (1);
1946 /* Save the values */
1948 e_ptr->rating = rating;
1951 /* Process 'W' for "More Info" (one line only) */
1952 else if (buf[0] == 'W')
1954 int level, rarity, pad2;
1957 /* Scan for the values */
1958 if (4 != sscanf(buf+2, "%d:%d:%d:%ld",
1959 &level, &rarity, &pad2, &cost)) return (1);
1961 /* Save the values */
1962 e_ptr->level = level;
1963 e_ptr->rarity = rarity;
1964 /* e_ptr->weight = wgt; */
1968 /* Hack -- Process 'C' for "creation" */
1969 else if (buf[0] == 'C')
1973 /* Scan for the values */
1974 if (4 != sscanf(buf+2, "%d:%d:%d:%d",
1975 &th, &td, &ta, &pv)) return (1);
1977 e_ptr->max_to_h = th;
1978 e_ptr->max_to_d = td;
1979 e_ptr->max_to_a = ta;
1980 e_ptr->max_pval = pv;
1983 /* Hack -- Process 'F' for flags */
1984 else if (buf[0] == 'F')
1986 /* Parse every entry textually */
1987 for (s = buf + 2; *s; )
1989 /* Find the end of this entry */
1990 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
1992 /* Nuke and skip any dividers */
1996 while ((*t == ' ') || (*t == '|')) t++;
1999 /* Parse this entry */
2000 if (0 != grab_one_ego_item_flag(e_ptr, s)) return (5);
2002 /* Start the next entry */
2016 * Grab one (basic) flag in a monster_race from a textual string
2018 static errr grab_one_basic_flag(monster_race *r_ptr, cptr what)
2023 for (i = 0; i < 32; i++)
2025 if (streq(what, r_info_flags1[i]))
2027 r_ptr->flags1 |= (1L << i);
2033 for (i = 0; i < 32; i++)
2035 if (streq(what, r_info_flags2[i]))
2037 r_ptr->flags2 |= (1L << i);
2043 for (i = 0; i < 32; i++)
2045 if (streq(what, r_info_flags3[i]))
2047 r_ptr->flags3 |= (1L << i);
2053 for (i = 0; i < 32; i++)
2055 if (streq(what, r_info_flags7[i]))
2057 r_ptr->flags7 |= (1L << i);
2063 for (i = 0; i < 32; i++)
2065 if (streq(what, r_info_flags8[i]))
2067 r_ptr->flags8 |= (1L << i);
2073 for (i = 0; i < 32; i++)
2075 if (streq(what, r_info_flags9[i]))
2077 r_ptr->flags9 |= (1L << i);
2082 /* Scan flagsr (resistance) */
2083 for (i = 0; i < 32; i++)
2085 if (streq(what, r_info_flagsr[i]))
2087 r_ptr->flagsr |= (1L << i);
2094 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2096 msg_format("Unknown monster flag '%s'.", what);
2106 * Grab one (spell) flag in a monster_race from a textual string
2108 static errr grab_one_spell_flag(monster_race *r_ptr, cptr what)
2113 for (i = 0; i < 32; i++)
2115 if (streq(what, r_info_flags4[i]))
2117 r_ptr->flags4 |= (1L << i);
2123 for (i = 0; i < 32; i++)
2125 if (streq(what, r_info_flags5[i]))
2127 r_ptr->flags5 |= (1L << i);
2133 for (i = 0; i < 32; i++)
2135 if (streq(what, r_info_flags6[i]))
2137 r_ptr->flags6 |= (1L << i);
2144 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2146 msg_format("Unknown monster flag '%s'.", what);
2158 * Initialize the "r_info" array, by parsing an ascii "template" file
2160 errr parse_r_info(char *buf, header *head)
2167 static monster_race *r_ptr = NULL;
2170 /* Process 'N' for "New/Number/Name" */
2173 /* Find the colon before the name */
2174 s = strchr(buf+2, ':');
2176 /* Verify that colon */
2179 /* Nuke the colon, advance to the name */
2182 /* Paranoia -- require a name */
2183 if (!*s) return (1);
2188 /* Verify information */
2189 if (i < error_idx) return (4);
2191 /* Verify information */
2192 if (i >= head->info_num) return (2);
2194 /* Save the index */
2197 /* Point at the "info" */
2200 /* Store the name */
2201 if (!add_name(&r_ptr->name, head, s)) return (7);
2205 /* There better be a current r_ptr */
2206 else if (!r_ptr) return (3);
2210 /* ±Ñ¸ì̾¤òÆɤà¥ë¡¼¥Á¥ó¤òÄɲà */
2211 /* 'E' ¤«¤é»Ï¤Þ¤ë¹Ô¤Ï±Ñ¸ì̾ */
2212 else if (buf[0] == 'E')
2214 /* Acquire the Text */
2217 /* Store the name */
2218 if (!add_name(&r_ptr->E_name, head, s)) return (7);
2221 else if (buf[0] == 'E')
2223 /* Acquire the Text */
2226 /* Store the name */
2227 if (!add_name(&r_ptr->name, head, s)) return (7);
2230 /* Process 'D' for "Description" */
2231 else if (buf[0] == 'D')
2236 /* Acquire the text */
2241 /* Acquire the text */
2245 /* Store the text */
2246 if (!add_text(&r_ptr->text, head, s)) return (7);
2249 /* Process 'G' for "Graphics" (one line only) */
2250 else if (buf[0] == 'G')
2256 if (!buf[2]) return (1);
2257 if (!buf[3]) return (1);
2258 if (!buf[4]) return (1);
2260 /* Extract the char */
2263 /* Extract the attr */
2264 tmp = color_char_to_attr(buf[4]);
2267 if (tmp > 127) return (1);
2269 /* Save the values */
2270 r_ptr->d_char = sym;
2271 r_ptr->d_attr = tmp;
2274 /* Process 'I' for "Info" (one line only) */
2275 else if (buf[0] == 'I')
2277 int spd, hp1, hp2, aaf, ac, slp;
2279 /* Scan for the other values */
2280 if (6 != sscanf(buf+2, "%d:%dd%d:%d:%d:%d",
2281 &spd, &hp1, &hp2, &aaf, &ac, &slp)) return (1);
2283 /* Save the values */
2292 /* Process 'W' for "More Info" (one line only) */
2293 else if (buf[0] == 'W')
2300 /* Scan for the values */
2301 if (6 != sscanf(buf+2, "%d:%d:%d:%ld:%ld:%d",
2302 &lev, &rar, &pad, &exp, &nextexp, &nextmon)) return (1);
2304 /* Save the values */
2306 r_ptr->rarity = rar;
2309 r_ptr->next_exp = nextexp;
2310 r_ptr->next_r_idx = nextmon;
2313 /* Process 'B' for "Blows" (up to four lines) */
2314 else if (buf[0] == 'B')
2318 /* Find the next empty blow slot (if any) */
2319 for (i = 0; i < 4; i++) if (!r_ptr->blow[i].method) break;
2321 /* Oops, no more slots */
2322 if (i == 4) return (1);
2324 /* Analyze the first field */
2325 for (s = t = buf+2; *t && (*t != ':'); t++) /* loop */;
2327 /* Terminate the field (if necessary) */
2328 if (*t == ':') *t++ = '\0';
2330 /* Analyze the method */
2331 for (n1 = 0; r_info_blow_method[n1]; n1++)
2333 if (streq(s, r_info_blow_method[n1])) break;
2336 /* Invalid method */
2337 if (!r_info_blow_method[n1]) return (1);
2339 /* Analyze the second field */
2340 for (s = t; *t && (*t != ':'); t++) /* loop */;
2342 /* Terminate the field (if necessary) */
2343 if (*t == ':') *t++ = '\0';
2345 /* Analyze effect */
2346 for (n2 = 0; r_info_blow_effect[n2]; n2++)
2348 if (streq(s, r_info_blow_effect[n2])) break;
2351 /* Invalid effect */
2352 if (!r_info_blow_effect[n2]) return (1);
2354 /* Analyze the third field */
2355 for (s = t; *t && (*t != 'd'); t++) /* loop */;
2357 /* Terminate the field (if necessary) */
2358 if (*t == 'd') *t++ = '\0';
2360 /* Save the method */
2361 r_ptr->blow[i].method = n1;
2363 /* Save the effect */
2364 r_ptr->blow[i].effect = n2;
2366 /* Extract the damage dice and sides */
2367 r_ptr->blow[i].d_dice = atoi(s);
2368 r_ptr->blow[i].d_side = atoi(t);
2371 /* Process 'F' for "Basic Flags" (multiple lines) */
2372 else if (buf[0] == 'F')
2374 /* Parse every entry */
2375 for (s = buf + 2; *s; )
2377 /* Find the end of this entry */
2378 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2380 /* Nuke and skip any dividers */
2384 while (*t == ' ' || *t == '|') t++;
2387 /* Parse this entry */
2388 if (0 != grab_one_basic_flag(r_ptr, s)) return (5);
2390 /* Start the next entry */
2395 /* Process 'S' for "Spell Flags" (multiple lines) */
2396 else if (buf[0] == 'S')
2398 /* Parse every entry */
2399 for (s = buf + 2; *s; )
2401 /* Find the end of this entry */
2402 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2404 /* Nuke and skip any dividers */
2408 while ((*t == ' ') || (*t == '|')) t++;
2411 /* XXX XXX XXX Hack -- Read spell frequency */
2412 if (1 == sscanf(s, "1_IN_%d", &i))
2414 /* Extract a "frequency" */
2415 r_ptr->freq_spell = 100 / i;
2417 /* Start at next entry */
2424 /* Parse this entry */
2425 if (0 != grab_one_spell_flag(r_ptr, s)) return (5);
2427 /* Start the next entry */
2442 * Grab one flag for a dungeon type from a textual string
2444 static errr grab_one_dungeon_flag(dungeon_info_type *d_ptr, cptr what)
2449 for (i = 0; i < 32; i++)
2451 if (streq(what, d_info_flags1[i]))
2453 d_ptr->flags1 |= (1L << i);
2460 msg_format("̤ÃΤΥÀ¥ó¥¸¥ç¥ó¡¦¥Õ¥é¥° '%s'¡£", what);
2462 msg_format("Unknown dungeon type flag '%s'.", what);
2470 * Grab one (basic) flag in a monster_race from a textual string
2472 static errr grab_one_basic_monster_flag(dungeon_info_type *d_ptr, cptr what)
2477 for (i = 0; i < 32; i++)
2479 if (streq(what, r_info_flags1[i]))
2481 d_ptr->mflags1 |= (1L << i);
2487 for (i = 0; i < 32; i++)
2489 if (streq(what, r_info_flags2[i]))
2491 d_ptr->mflags2 |= (1L << i);
2497 for (i = 0; i < 32; i++)
2499 if (streq(what, r_info_flags3[i]))
2501 d_ptr->mflags3 |= (1L << i);
2507 for (i = 0; i < 32; i++)
2509 if (streq(what, r_info_flags7[i]))
2511 d_ptr->mflags7 |= (1L << i);
2517 for (i = 0; i < 32; i++)
2519 if (streq(what, r_info_flags8[i]))
2521 d_ptr->mflags8 |= (1L << i);
2527 for (i = 0; i < 32; i++)
2529 if (streq(what, r_info_flags9[i]))
2531 d_ptr->mflags9 |= (1L << i);
2536 /* Scan flagsr (resistance) */
2537 for (i = 0; i < 32; i++)
2539 if (streq(what, r_info_flagsr[i]))
2541 d_ptr->mflagsr |= (1L << i);
2548 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2550 msg_format("Unknown monster flag '%s'.", what);
2558 * Grab one (spell) flag in a monster_race from a textual string
2560 static errr grab_one_spell_monster_flag(dungeon_info_type *d_ptr, cptr what)
2565 for (i = 0; i < 32; i++)
2567 if (streq(what, r_info_flags4[i]))
2569 d_ptr->mflags4 |= (1L << i);
2575 for (i = 0; i < 32; i++)
2577 if (streq(what, r_info_flags5[i]))
2579 d_ptr->mflags5 |= (1L << i);
2585 for (i = 0; i < 32; i++)
2587 if (streq(what, r_info_flags6[i]))
2589 d_ptr->mflags6 |= (1L << i);
2596 msg_format("̤ÃΤΥâ¥ó¥¹¥¿¡¼¡¦¥Õ¥é¥° '%s'¡£", what);
2598 msg_format("Unknown monster flag '%s'.", what);
2606 * Initialize the "d_info" array, by parsing an ascii "template" file
2608 errr parse_d_info(char *buf, header *head)
2615 static dungeon_info_type *d_ptr = NULL;
2618 /* Process 'N' for "New/Number/Name" */
2621 /* Find the colon before the name */
2622 s = strchr(buf+2, ':');
2624 /* Verify that colon */
2627 /* Nuke the colon, advance to the name */
2630 /* Paranoia -- require a name */
2631 if (!*s) return (1);
2636 /* Verify information */
2637 if (i < error_idx) return (4);
2639 /* Verify information */
2640 if (i >= head->info_num) return (2);
2642 /* Save the index */
2645 /* Point at the "info" */
2648 /* Store the name */
2649 if (!add_name(&d_ptr->name, head, s)) return (7);
2654 else if (buf[0] == 'E') return (0);
2656 else if (buf[0] == 'E')
2658 /* Acquire the Text */
2661 /* Store the name */
2662 if (!add_name(&d_ptr->name, head, s)) return (7);
2666 /* Process 'D' for "Description */
2667 else if (buf[0] == 'D')
2672 /* Acquire the text */
2677 /* Acquire the text */
2681 /* Store the text */
2682 if (!add_text(&d_ptr->text, head, s)) return (7);
2685 /* Process 'W' for "More Info" (one line only) */
2686 else if (buf[0] == 'W')
2688 int min_lev, max_lev;
2690 int min_alloc, max_chance;
2691 int obj_good, obj_great;
2694 /* Scan for the values */
2695 if (10 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d:%x:%x",
2696 &min_lev, &max_lev, &min_plev, &mode, &min_alloc, &max_chance, &obj_good, &obj_great, (unsigned int *)&pit, (unsigned int *)&nest)) return (1);
2698 /* Save the values */
2699 d_ptr->mindepth = min_lev;
2700 d_ptr->maxdepth = max_lev;
2701 d_ptr->min_plev = min_plev;
2703 d_ptr->min_m_alloc_level = min_alloc;
2704 d_ptr->max_m_alloc_chance = max_chance;
2705 d_ptr->obj_good = obj_good;
2706 d_ptr->obj_great = obj_great;
2711 /* Process 'P' for "Place Info" */
2712 else if (buf[0] == 'P')
2716 /* Scan for the values */
2717 if (2 != sscanf(buf+2, "%d:%d", &dy, &dx)) return (1);
2719 /* Save the values */
2724 /* Process 'L' for "fLoor type" (one line only) */
2725 else if (buf[0] == 'L')
2731 /* Scan for the values */
2732 if (7 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d",
2733 &f1, &p1, &f2, &p2, &f3, &p3, &tunnel)) return (1);
2735 /* Save the values */
2737 d_ptr->floor_percent1 = p1;
2739 d_ptr->floor_percent2 = p2;
2741 d_ptr->floor_percent3 = p3;
2742 d_ptr->tunnel_percent = tunnel;
2745 /* Process 'A' for "wAll type" (one line only) */
2746 else if (buf[0] == 'A')
2748 int w1, w2, w3, outer, inner, stream1, stream2;
2751 /* Scan for the values */
2752 if (10 != sscanf(buf+2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
2753 &w1, &p1, &w2, &p2, &w3, &p3, &outer, &inner, &stream1, &stream2)) return (1);
2755 /* Save the values */
2756 d_ptr->fill_type1 = w1;
2757 d_ptr->fill_percent1 = p1;
2758 d_ptr->fill_type2 = w2;
2759 d_ptr->fill_percent2 = p2;
2760 d_ptr->fill_type3 = w3;
2761 d_ptr->fill_percent3 = p3;
2762 d_ptr->outer_wall = outer;
2763 d_ptr->inner_wall = inner;
2764 d_ptr->stream1 = stream1;
2765 d_ptr->stream2 = stream2;
2768 /* Process 'F' for "Dungeon Flags" (multiple lines) */
2769 else if (buf[0] == 'F')
2771 int artif = 0, monst = 0;
2773 /* Parse every entry */
2774 for (s = buf + 2; *s; )
2776 /* Find the end of this entry */
2777 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2779 /* Nuke and skip any dividers */
2783 while (*t == ' ' || *t == '|') t++;
2786 /* XXX XXX XXX Hack -- Read Final Artifact */
2787 if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif))
2789 /* Extract a "Final Artifact" */
2790 d_ptr->final_artifact = artif;
2792 /* Start at next entry */
2799 /* XXX XXX XXX Hack -- Read Final Object */
2800 if (1 == sscanf(s, "FINAL_OBJECT_%d", &artif))
2802 /* Extract a "Final Artifact" */
2803 d_ptr->final_object = artif;
2805 /* Start at next entry */
2812 /* XXX XXX XXX Hack -- Read Artifact Guardian */
2813 if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst))
2815 /* Extract a "Artifact Guardian" */
2816 d_ptr->final_guardian = monst;
2818 /* Start at next entry */
2825 /* XXX XXX XXX Hack -- Read Special Percentage */
2826 if (1 == sscanf(s, "MONSTER_DIV_%d", &monst))
2828 /* Extract a "Special %" */
2829 d_ptr->special_div = monst;
2831 /* Start at next entry */
2838 /* Parse this entry */
2839 if (0 != grab_one_dungeon_flag(d_ptr, s)) return (5);
2841 /* Start the next entry */
2846 /* Process 'M' for "Basic Flags" (multiple lines) */
2847 else if (buf[0] == 'M')
2849 /* Parse every entry */
2850 for (s = buf + 2; *s; )
2852 /* Find the end of this entry */
2853 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2855 /* Nuke and skip any dividers */
2859 while (*t == ' ' || *t == '|') t++;
2862 /* Hack -- Read monster symbols */
2863 if (!strncmp(s, "R_CHAR_", 7))
2865 /* Skip "R_CHAR_" */
2869 strncpy(d_ptr->r_char, s, sizeof(d_ptr->r_char));
2871 /* Start at next entry */
2878 /* Parse this entry */
2879 if (0 != grab_one_basic_monster_flag(d_ptr, s)) return (5);
2881 /* Start the next entry */
2886 /* Process 'S' for "Spell Flags" (multiple lines) */
2887 else if (buf[0] == 'S')
2889 /* Parse every entry */
2890 for (s = buf + 2; *s; )
2892 /* Find the end of this entry */
2893 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
2895 /* Nuke and skip any dividers */
2899 while ((*t == ' ') || (*t == '|')) t++;
2902 /* XXX XXX XXX Hack -- Read spell frequency */
2903 if (1 == sscanf(s, "1_IN_%d", &i))
2905 /* Start at next entry */
2912 /* Parse this entry */
2913 if (0 != grab_one_spell_monster_flag(d_ptr, s)) return (5);
2915 /* Start the next entry */
2928 #else /* ALLOW_TEMPLATES */
2934 #endif /* ALLOW_TEMPLATES */
2937 /* Random dungeon grid effects */
2938 #define RANDOM_NONE 0x00
2939 #define RANDOM_FEATURE 0x01
2940 #define RANDOM_MONSTER 0x02
2941 #define RANDOM_OBJECT 0x04
2942 #define RANDOM_EGO 0x08
2943 #define RANDOM_ARTIFACT 0x10
2944 #define RANDOM_TRAP 0x20
2947 typedef struct dungeon_grid dungeon_grid;
2951 int feature; /* Terrain feature */
2952 int monster; /* Monster */
2953 int object; /* Object */
2954 int ego; /* Ego-Item */
2955 int artifact; /* Artifact */
2956 int trap; /* Trap */
2957 int cave_info; /* Flags for CAVE_MARK, CAVE_GLOW, CAVE_ICKY, CAVE_ROOM */
2958 int special; /* Reserved for special terrain info */
2959 int random; /* Number of the random effect */
2963 static dungeon_grid letter[255];
2967 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
2969 static errr parse_line_feature(char *buf)
2975 if (init_flags & INIT_ONLY_BUILDINGS) return (0);
2977 /* Tokenize the line */
2978 if ((num = tokenize(buf+2, 9, zz, 0)) > 1)
2980 /* Letter to assign */
2981 int index = zz[0][0];
2983 /* Reset the info for the letter */
2984 letter[index].feature = 0;
2985 letter[index].monster = 0;
2986 letter[index].object = 0;
2987 letter[index].ego = 0;
2988 letter[index].artifact = 0;
2989 letter[index].trap = 0;
2990 letter[index].cave_info = 0;
2991 letter[index].special = 0;
2992 letter[index].random = 0;
2998 letter[index].special = atoi(zz[8]);
3002 if (zz[7][0] == '*')
3004 letter[index].random |= RANDOM_TRAP;
3009 letter[index].trap = atoi(zz[7]);
3014 letter[index].trap = atoi(zz[7]);
3019 if (zz[6][0] == '*')
3021 letter[index].random |= RANDOM_ARTIFACT;
3026 letter[index].artifact = atoi(zz[6]);
3031 letter[index].artifact = atoi(zz[6]);
3036 if (zz[5][0] == '*')
3038 letter[index].random |= RANDOM_EGO;
3043 letter[index].ego = atoi(zz[5]);
3048 letter[index].ego = atoi(zz[5]);
3053 if (zz[4][0] == '*')
3055 letter[index].random |= RANDOM_OBJECT;
3060 letter[index].object = atoi(zz[4]);
3065 letter[index].object = atoi(zz[4]);
3070 if (zz[3][0] == '*')
3072 letter[index].random |= RANDOM_MONSTER;
3076 letter[index].monster = atoi(zz[3]);
3079 else if (zz[3][0] == 'c')
3081 letter[index].monster = - atoi(zz[3]+1);
3085 letter[index].monster = atoi(zz[3]);
3090 letter[index].cave_info = atoi(zz[2]);
3094 if (zz[1][0] == '*')
3096 letter[index].random |= RANDOM_FEATURE;
3100 letter[index].feature = atoi(zz[1]);
3105 letter[index].feature = atoi(zz[1]);
3118 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
3120 static errr parse_line_building(char *buf)
3136 /* Get the building number */
3139 /* Find the colon after the building number */
3142 /* Verify that colon */
3145 /* Nuke the colon, advance to the sub-index */
3148 /* Paranoia -- require a sub-index */
3149 if (!*s) return (1);
3151 /* Building definition sub-index */
3154 /* Building name, owner, race */
3157 if (tokenize(s + 2, 3, zz, 0) == 3)
3159 /* Name of the building */
3160 strcpy(building[index].name, zz[0]);
3162 /* Name of the owner */
3163 strcpy(building[index].owner_name, zz[1]);
3165 /* Race of the owner */
3166 strcpy(building[index].owner_race, zz[2]);
3171 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3174 /* Building Action */
3177 if (tokenize(s + 2, 8, zz, 0) >= 7)
3179 /* Index of the action */
3180 int action_index = atoi(zz[0]);
3182 /* Name of the action */
3183 strcpy(building[index].act_names[action_index], zz[1]);
3185 /* Cost of the action for members */
3186 building[index].member_costs[action_index] = atoi(zz[2]);
3188 /* Cost of the action for non-members */
3189 building[index].other_costs[action_index] = atoi(zz[3]);
3191 /* Letter assigned to the action */
3192 building[index].letters[action_index] = zz[4][0];
3195 building[index].actions[action_index] = atoi(zz[5]);
3197 /* Action restriction */
3198 building[index].action_restr[action_index] = atoi(zz[6]);
3203 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3206 /* Building Classes */
3209 if (tokenize(s + 2, MAX_CLASS, zz, 0) == MAX_CLASS)
3211 for (i = 0; i < MAX_CLASS; i++)
3213 building[index].member_class[i] = atoi(zz[i]);
3219 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3222 /* Building Races */
3225 if (tokenize(s+2, MAX_RACES, zz, 0) == MAX_RACES)
3227 for (i = 0; i < MAX_RACES; i++)
3229 building[index].member_race[i] = atoi(zz[i]);
3235 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3238 /* Building Realms */
3241 if (tokenize(s+2, MAX_MAGIC, zz, 0) == MAX_MAGIC)
3243 for (i = 0; i < MAX_MAGIC; i++)
3245 building[index].member_realm[i+1] = atoi(zz[i]);
3251 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3256 /* Ignore scripts */
3262 return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
3271 * Parse a sub-file of the "extra info"
3273 static errr process_dungeon_file_aux(char *buf, int ymin, int xmin, int ymax, int xmax, int *y, int *x)
3280 /* Skip "empty" lines */
3281 if (!buf[0]) return (0);
3283 /* Skip "blank" lines */
3284 if (isspace(buf[0])) return (0);
3287 if (buf[0] == '#') return (0);
3289 /* Require "?:*" format */
3290 if (buf[1] != ':') return (1);
3293 /* Process "%:<fname>" */
3296 /* Attempt to Process the given file */
3297 return (process_dungeon_file(buf + 2, ymin, xmin, ymax, xmax));
3300 /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid */
3303 return parse_line_feature(buf);
3306 /* Process "D:<dungeon>" -- info for the cave grids */
3307 else if (buf[0] == 'D')
3309 object_type object_type_body;
3311 /* Acquire the text */
3314 /* Length of the text */
3315 int len = strlen(s);
3317 if (init_flags & INIT_ONLY_BUILDINGS) return (0);
3319 for (*x = xmin, i = 0; ((*x < xmax) && (i < len)); (*x)++, s++, i++)
3321 /* Access the grid */
3322 cave_type *c_ptr = &cave[*y][*x];
3326 int object_index = letter[idx].object;
3327 int monster_index = letter[idx].monster;
3328 int random = letter[idx].random;
3329 int artifact_index = letter[idx].artifact;
3331 /* Lay down a floor */
3332 c_ptr->feat = letter[idx].feature;
3334 /* Only the features */
3335 if (init_flags & INIT_ONLY_FEATURES) continue;
3338 c_ptr->info = letter[idx].cave_info;
3340 /* Create a monster */
3341 if (random & RANDOM_MONSTER)
3343 monster_level = base_level + monster_index;
3345 place_monster(*y, *x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
3347 monster_level = base_level;
3349 else if (monster_index)
3351 int old_cur_num, old_max_num;
3354 if (monster_index < 0)
3356 monster_index = -monster_index;
3359 old_cur_num = r_info[monster_index].cur_num;
3360 old_max_num = r_info[monster_index].max_num;
3362 /* Make alive again */
3363 if (r_info[monster_index].flags1 & RF1_UNIQUE)
3365 r_info[monster_index].cur_num = 0;
3366 r_info[monster_index].max_num = 1;
3369 /* Make alive again */
3370 if (r_info[monster_index].flags7 & RF7_UNIQUE_7)
3372 if (r_info[monster_index].cur_num == r_info[monster_index].max_num)
3374 r_info[monster_index].max_num++;
3379 place_monster_aux(0, *y, *x, monster_index, (PM_ALLOW_SLEEP | PM_NO_KAGE));
3383 m_list[hack_m_idx_ii].smart |= SM_CLONED;
3385 /* Make alive again for real unique monster */
3386 r_info[monster_index].cur_num = old_cur_num;
3387 r_info[monster_index].max_num = old_max_num;
3391 /* Object (and possible trap) */
3392 if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP))
3394 object_level = base_level + object_index;
3397 * Random trap and random treasure defined
3398 * 25% chance for trap and 75% chance for object
3400 if (randint0(100) < 75)
3402 place_object(*y, *x, 0L);
3409 object_level = base_level;
3411 else if (random & RANDOM_OBJECT)
3413 object_level = base_level + object_index;
3415 /* Create an out of deep object */
3416 if (randint0(100) < 75)
3417 place_object(*y, *x, 0L);
3418 else if (randint0(100) < 80)
3419 place_object(*y, *x, AM_GOOD);
3421 place_object(*y, *x, AM_GOOD | AM_GREAT);
3423 object_level = base_level;
3426 else if (random & RANDOM_TRAP)
3430 /* Hidden trap (or door) */
3431 else if (letter[idx].trap)
3433 c_ptr->mimic = f_info[c_ptr->feat].mimic;
3434 c_ptr->feat = letter[idx].trap;
3436 else if (object_index)
3438 /* Get local object */
3439 object_type *o_ptr = &object_type_body;
3441 /* Create the item */
3442 object_prep(o_ptr, object_index);
3444 if (o_ptr->tval == TV_GOLD)
3446 coin_type = object_index - OBJ_GOLD_LIST;
3451 /* Apply magic (no messages, no artifacts) */
3452 apply_magic(o_ptr, base_level, AM_NO_FIXED_ART | AM_GOOD);
3454 (void)drop_near(o_ptr, -1, *y, *x);
3460 if (a_info[artifact_index].cur_num)
3462 int k_idx = lookup_kind(TV_SCROLL, SV_SCROLL_ACQUIREMENT);
3464 object_type *q_ptr = &forge;
3466 object_prep(q_ptr, k_idx);
3468 /* Drop it in the dungeon */
3469 (void)drop_near(q_ptr, -1, *y, *x);
3473 /* Create the artifact */
3474 create_named_art(artifact_index, *y, *x);
3476 a_info[artifact_index].cur_num = 1;
3480 /* Terrain special */
3481 c_ptr->special = letter[idx].special;
3489 /* Process "Q:<number>:<command>:... -- quest info */
3490 else if (buf[0] == 'Q')
3497 num = tokenize(buf + 2, 33, zz, 0);
3501 num = tokenize(buf + 3, 33, zz, 0);
3504 /* Have we enough parameters? */
3505 if (num < 3) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3508 q_ptr = &(quest[atoi(zz[0])]);
3510 /* Process "Q:<q_index>:Q:<type>:<num_mon>:<cur_num>:<max_num>:<level>:<r_idx>:<k_idx>:<flags>" -- quest info */
3511 if (zz[1][0] == 'Q')
3513 if (init_flags & INIT_ASSIGN)
3515 monster_race *r_ptr;
3516 artifact_type *a_ptr;
3518 if (num < 9) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3520 q_ptr->type = atoi(zz[2]);
3521 q_ptr->num_mon = atoi(zz[3]);
3522 q_ptr->cur_num = atoi(zz[4]);
3523 q_ptr->max_num = atoi(zz[5]);
3524 q_ptr->level = atoi(zz[6]);
3525 q_ptr->r_idx = atoi(zz[7]);
3526 q_ptr->k_idx = atoi(zz[8]);
3527 q_ptr->dungeon = atoi(zz[9]);
3530 q_ptr->flags = atoi(zz[10]);
3532 r_ptr = &r_info[q_ptr->r_idx];
3533 if (r_ptr->flags1 & RF1_UNIQUE)
3534 r_ptr->flags1 |= RF1_QUESTOR;
3536 a_ptr = &a_info[q_ptr->k_idx];
3537 a_ptr->gen_flags |= TRG_QUESTITEM;
3542 /* Process "Q:<q_index>:N:<name>" -- quest name */
3543 else if (zz[1][0] == 'N')
3545 if (init_flags & (INIT_ASSIGN | INIT_SHOW_TEXT))
3547 strcpy(q_ptr->name, zz[2]);
3553 /* Process "Q:<q_index>:T:<text>" -- quest description line */
3554 else if (zz[1][0] == 'T')
3556 if (init_flags & INIT_SHOW_TEXT)
3558 strcpy(quest_text[quest_text_line], zz[2]);
3566 /* Process "W:<command>: ..." -- info for the wilderness */
3567 else if (buf[0] == 'W')
3569 return parse_line_wilderness(buf, ymin, xmin, ymax, xmax, y, x);
3572 /* Process "P:<y>:<x>" -- player position */
3573 else if (buf[0] == 'P')
3575 if (init_flags & INIT_CREATE_DUNGEON)
3577 if (tokenize(buf + 2, 2, zz, 0) == 2)
3579 int panels_x, panels_y;
3581 /* Hack - Set the dungeon size */
3582 panels_y = (*y / SCREEN_HGT);
3583 if (*y % SCREEN_HGT) panels_y++;
3584 cur_hgt = panels_y * SCREEN_HGT;
3586 panels_x = (*x / SCREEN_WID);
3587 if (*x % SCREEN_WID) panels_x++;
3588 cur_wid = panels_x * SCREEN_WID;
3590 /* Assume illegal panel */
3591 panel_row_min = cur_hgt;
3592 panel_col_min = cur_wid;
3594 /* Place player in a quest level */
3595 if (p_ptr->inside_quest)
3599 /* Delete the monster (if any) */
3600 delete_monster(py, px);
3608 /* Place player in the town */
3609 else if (!p_ptr->oldpx && !p_ptr->oldpy)
3611 p_ptr->oldpy = atoi(zz[0]);
3612 p_ptr->oldpx = atoi(zz[1]);
3620 /* Process "B:<Index>:<Command>:..." -- Building definition */
3621 else if (buf[0] == 'B')
3623 return parse_line_building(buf);
3626 /* Process "M:<type>:<maximum>" -- set maximum values */
3627 else if (buf[0] == 'M')
3629 if (tokenize(buf+2, 2, zz, 0) == 2)
3632 if (zz[0][0] == 'T')
3634 max_towns = atoi(zz[1]);
3637 /* Maximum quests */
3638 else if (zz[0][0] == 'Q')
3640 max_quests = atoi(zz[1]);
3644 else if (zz[0][0] == 'R')
3646 max_r_idx = atoi(zz[1]);
3650 else if (zz[0][0] == 'K')
3652 max_k_idx = atoi(zz[1]);
3656 else if (zz[0][0] == 'V')
3658 max_v_idx = atoi(zz[1]);
3662 else if (zz[0][0] == 'F')
3664 max_f_idx = atoi(zz[1]);
3668 else if (zz[0][0] == 'A')
3670 max_a_idx = atoi(zz[1]);
3674 else if (zz[0][0] == 'E')
3676 max_e_idx = atoi(zz[1]);
3680 else if (zz[0][0] == 'D')
3682 max_d_idx = atoi(zz[1]);
3686 else if (zz[0][0] == 'O')
3688 max_o_idx = atoi(zz[1]);
3692 else if (zz[0][0] == 'M')
3694 max_m_idx = atoi(zz[1]);
3697 /* Wilderness size */
3698 else if (zz[0][0] == 'W')
3700 /* Maximum wild_x_size */
3701 if (zz[0][1] == 'X')
3702 max_wild_x = atoi(zz[1]);
3703 /* Maximum wild_y_size */
3704 if (zz[0][1] == 'Y')
3705 max_wild_y = atoi(zz[1]);
3719 static cptr variant = "ZANGBAND";
3723 * Helper function for "process_dungeon_file()"
3725 static cptr process_dungeon_file_expr(char **sp, char *fp)
3741 while (isspace(*s)) s++;
3759 t = process_dungeon_file_expr(&s, &f);
3768 else if (streq(t, "IOR"))
3771 while (*s && (f != b2))
3773 t = process_dungeon_file_expr(&s, &f);
3774 if (*t && !streq(t, "0")) v = "1";
3779 else if (streq(t, "AND"))
3782 while (*s && (f != b2))
3784 t = process_dungeon_file_expr(&s, &f);
3785 if (*t && streq(t, "0")) v = "0";
3790 else if (streq(t, "NOT"))
3793 while (*s && (f != b2))
3795 t = process_dungeon_file_expr(&s, &f);
3796 if (*t && streq(t, "1")) v = "0";
3801 else if (streq(t, "EQU"))
3804 if (*s && (f != b2))
3806 t = process_dungeon_file_expr(&s, &f);
3808 while (*s && (f != b2))
3811 t = process_dungeon_file_expr(&s, &f);
3812 if (*t && !streq(p, t)) v = "0";
3817 else if (streq(t, "LEQ"))
3820 if (*s && (f != b2))
3822 t = process_dungeon_file_expr(&s, &f);
3824 while (*s && (f != b2))
3827 t = process_dungeon_file_expr(&s, &f);
3828 if (*t && (strcmp(p, t) > 0)) v = "0";
3833 else if (streq(t, "GEQ"))
3836 if (*s && (f != b2))
3838 t = process_dungeon_file_expr(&s, &f);
3840 while (*s && (f != b2))
3843 t = process_dungeon_file_expr(&s, &f);
3844 if (*t && (strcmp(p, t) < 0)) v = "0";
3851 while (*s && (f != b2))
3853 t = process_dungeon_file_expr(&s, &f);
3858 if (f != b2) v = "?x?x?";
3860 /* Extract final and Terminate */
3861 if ((f = *s) != '\0') *s++ = '\0';
3867 /* Accept all printables except spaces and brackets */
3868 while (isprint(*s) && !strchr(" []", *s)) ++s;
3870 /* Extract final and Terminate */
3871 if ((f = *s) != '\0') *s++ = '\0';
3877 if (streq(b+1, "SYS"))
3883 else if (streq(b+1, "GRAF"))
3888 else if (streq(b+1, "MONOCHROME"))
3897 else if (streq(b+1, "RACE"))
3900 v = rp_ptr->E_title;
3907 else if (streq(b+1, "CLASS"))
3910 v = cp_ptr->E_title;
3917 else if (streq(b+1, "REALM1"))
3920 v = E_realm_names[p_ptr->realm1];
3922 v = realm_names[p_ptr->realm1];
3927 else if (streq(b+1, "REALM2"))
3930 v = E_realm_names[p_ptr->realm2];
3932 v = realm_names[p_ptr->realm2];
3937 else if (streq(b+1, "PLAYER"))
3943 else if (streq(b+1, "TOWN"))
3945 sprintf(tmp, "%d", p_ptr->town_num);
3950 else if (streq(b+1, "LEVEL"))
3952 sprintf(tmp, "%d", p_ptr->lev);
3956 /* Current quest number */
3957 else if (streq(b+1, "QUEST_NUMBER"))
3959 sprintf(tmp, "%d", p_ptr->inside_quest);
3963 /* Number of last quest */
3964 else if (streq(b+1, "LEAVING_QUEST"))
3966 sprintf(tmp, "%d", leaving_quest);
3971 else if (prefix(b+1, "QUEST"))
3973 /* "QUEST" uses a special parameter to determine the number of the quest */
3974 sprintf(tmp, "%d", quest[atoi(b+6)].status);
3979 else if (prefix(b+1, "RANDOM"))
3981 /* "RANDOM" uses a special parameter to determine the number of the quest */
3982 sprintf(tmp, "%d", (int)(seed_town%atoi(b+7)));
3987 else if (streq(b+1, "VARIANT"))
3993 else if (streq(b+1, "WILDERNESS"))
3996 sprintf(tmp, "NONE");
3998 sprintf(tmp, "LITE");
4000 sprintf(tmp, "NORMAL");
4023 errr process_dungeon_file(cptr name, int ymin, int xmin, int ymax, int xmax)
4033 bool bypass = FALSE;
4035 int x = xmin, y = ymin;
4038 /* Build the filename */
4039 path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, name);
4042 fp = my_fopen(buf, "r");
4045 if (!fp) return (-1);
4048 /* Process the file */
4049 while (0 == my_fgets(fp, buf, sizeof(buf)))
4055 /* Skip "empty" lines */
4056 if (!buf[0]) continue;
4058 /* Skip "blank" lines */
4059 if (isspace(buf[0])) continue;
4062 if (buf[0] == '#') continue;
4065 /* Process "?:<expr>" */
4066 if ((buf[0] == '?') && (buf[1] == ':'))
4075 /* Parse the expr */
4076 v = process_dungeon_file_expr(&s, &f);
4079 bypass = (streq(v, "0") ? TRUE : FALSE);
4085 /* Apply conditionals */
4086 if (bypass) continue;
4088 /* Process the line */
4089 err = process_dungeon_file_aux(buf, ymin, xmin, ymax, xmax, &y, &x);
4101 oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
4104 msg_format("Error %d (%s) at line %d of '%s'.", err, oops, num, name);
4106 msg_format("'%s'¤ò²òÀÏÃæ¡£", buf);
4108 msg_format("Parsing '%s'.", buf);
4115 /* Close the file */
4125 void write_r_info_txt(void)
4127 int i, j, z, fc, bc;
4130 cptr flags[32 * 10];
4135 monster_race *r_ptr;
4137 monster_blow *b_ptr;
4139 FILE *fff = fopen("output.txt", "wt");
4147 fprintf(fff, "# File: r_info.txt (autogenerated)\n\n");
4149 fprintf(fff, "# Version stamp (required)\n\n");
4152 fprintf(fff, "V:%d.%d.%d\n\n\n", r_head->v_major, r_head->v_minor, r_head->v_patch);
4155 fprintf(fff, "##### The Player #####\n\n");
4157 for (z = -1; z < alloc_race_size; z++)
4159 /* Output the monsters in order */
4160 i = (z >= 0) ? alloc_race_table[z].index : 0;
4162 /* Acquire the monster */
4165 /* Ignore empty monsters */
4166 if (!strlen(r_name + r_ptr->name)) continue;
4168 /* Ignore useless monsters */
4169 if (i && !r_ptr->speed) continue;
4171 /* Write a note if necessary */
4172 if (i && (!r_ptr->level != !mode))
4177 fprintf(fff, "\n##### Town monsters #####\n\n");
4179 /* Note the dungeon */
4182 fprintf(fff, "\n##### Normal monsters #####\n\n");
4185 /* Record the change */
4186 mode = r_ptr->level;
4189 /* Acquire the flags */
4190 f_ptr[0] = r_ptr->flags1; n_ptr[0] = r_info_flags1;
4191 f_ptr[1] = r_ptr->flags2; n_ptr[1] = r_info_flags2;
4192 f_ptr[2] = r_ptr->flags3; n_ptr[2] = r_info_flags3;
4193 f_ptr[3] = r_ptr->flags4; n_ptr[3] = r_info_flags4;
4194 f_ptr[4] = r_ptr->flags5; n_ptr[4] = r_info_flags5;
4195 f_ptr[5] = r_ptr->flags6; n_ptr[5] = r_info_flags6;
4196 f_ptr[6] = r_ptr->flags7; n_ptr[6] = r_info_flags7;
4197 f_ptr[7] = r_ptr->flags8; n_ptr[7] = r_info_flags8;
4198 f_ptr[8] = r_ptr->flags9; n_ptr[8] = r_info_flags9;
4199 f_ptr[9] = r_ptr->flagsr; n_ptr[9] = r_info_flagsr;
4201 /* Write New/Number/Name */
4202 fprintf(fff, "N:%d:%s\n", z + 1, r_name + r_ptr->name);
4205 fprintf(fff, "G:%c:%c\n", r_ptr->d_char, color_char[r_ptr->d_attr]);
4207 /* Write Information */
4208 fprintf(fff, "I:%d:%dd%d:%d:%d:%d\n", r_ptr->speed, r_ptr->hdice, r_ptr->hside,
4209 r_ptr->aaf, r_ptr->ac, r_ptr->sleep);
4211 /* Write more information */
4212 fprintf(fff, "W:%d:%d:%d:%ld\n", r_ptr->level, r_ptr->rarity, r_ptr->extra, r_ptr->mexp);
4215 for(j = 0; j < 4; j++)
4217 b_ptr = &(r_ptr->blow[j]);
4219 /* Stop when done */
4220 if (!b_ptr->method) break;
4222 /* Write the blows */
4223 fprintf(fff, "B:%s:%s:%dd%d\n", r_info_blow_method[b_ptr->method],
4224 r_info_blow_effect[b_ptr->effect],
4225 b_ptr->d_dice, b_ptr->d_side);
4228 /* Extract the flags */
4229 for (fc = 0, j = 0; j < 32 * 3; j++)
4231 /* Check this flag */
4232 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4235 /* Extract the extra flags */
4236 for (j = 32 * 6; j < 32 * 10; j++)
4238 /* Check this flag */
4239 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4242 /* Write the flags */
4243 for (j = 0; j < fc;)
4247 /* Start the line */
4250 for (bc = 0; (bc < 60) && (j < fc); j++)
4254 /* Format the flag */
4255 sprintf(t, "%s%s", flags[j], (j < fc - 1) ? " | " : "");
4257 /* Add it to the buffer */
4260 /* Note the length */
4264 /* Done with this line; write it */
4265 fprintf(fff, "%s\n", buf);
4268 /* Write Spells if applicable */
4269 if (r_ptr->freq_spell)
4271 /* Write the frequency */
4272 fprintf(fff, "S:1_IN_%d | \n", 100 / r_ptr->freq_spell);
4274 /* Extract the spell flags */
4275 for (fc = 0, j = 96; j < 192; j++)
4277 /* Check this flag */
4278 if (f_ptr[j / 32] & (1L << (j % 32))) flags[fc++] = n_ptr[j / 32][j % 32];
4281 /* Write the flags */
4282 for (j = 0; j < fc;)
4286 /* Start the line */
4289 for (bc = 0, t = buf + 2; (bc < 60) && (j < fc); j++)
4293 /* Format the flag */
4294 sprintf(t, "%s%s", flags[j], (j < fc - 1) ? " | " : "");
4298 /* Note the length */
4305 /* Done with this line; write it */
4306 fprintf(fff, "%s\n", buf);
4310 /* Acquire the description */
4311 desc = r_text + r_ptr->text;
4312 dlen = strlen(desc);
4314 /* Write Description */
4315 for (j = 0; j < dlen;)
4319 /* Start the line */
4322 for (bc = 0, t = buf + 2; ((bc < 60) || !isspace(desc[j])) && (j < dlen); j++, bc++, t++)
4330 /* Done with this line; write it */
4331 fprintf(fff, "%s\n", buf);
4334 /* Space between entries */