3 * @brief ゲームデータ初期化1 / Initialization (part 1) -BEN-
7 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8 * This software may be copied and distributed for educational, research,
9 * and not for profit purposes provided that this copyright and statement
10 * are included in all such copies. Other copyrights may also apply.
11 * 2014 Deskull rearranged comment for Doxygen.\n
15 * This file is used to initialize various variables and arrays for the
16 * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass
17 * the common limitation of "read()" and "write()" to only 32767 bytes
19 * Several of the arrays for Angband are built from "template" files in
20 * the "lib/file" directory, from which quick-load binary "image" files
21 * are constructed whenever they are not present in the "lib/data"
22 * directory, or if those files become obsolete, if we are allowed.
23 * Warning -- the "ascii" file parsers use a minor hack to collect the
24 * name and text information in a single pass. Thus, the game will not
25 * be able to load any template file with more than 20K of names or 60K
26 * of text, even though technically, up to 64K should be legal.
28 * The code could actually be removed and placed into a "stand-alone"
29 * program, but that feels a little silly, especially considering some
30 * of the platforms that we currently support.
38 #include "io/tokenizer.h"
40 #include "dungeon-file.h"
41 #include "rooms-vault.h"
47 #include "player-skill.h"
48 #include "player-race.h"
53 #include "rooms-vault.h"
54 #include "objectkind.h"
55 #include "object-ego.h"
56 #include "monsterrace.h"
57 #include "floor-town.h"
62 #include "cmd-activate.h"
65 #include "view-mainwindow.h"
66 #include "player-class.h"
70 dungeon_grid letter[255];
72 /*** Helper arrays for parsing ascii template files ***/
76 * Monster Blow Methods
78 static concptr r_info_blow_method[] =
110 * モンスターの打撃属性トークンの定義 /
111 * Monster Blow Effects
113 static concptr r_info_blow_effect[] =
158 static concptr f_info_flags[] =
282 static concptr r_info_flags1[] =
322 static concptr r_info_flags2[] =
362 static concptr r_info_flags3[] =
402 static concptr r_info_flags4[] =
439 * モンスター特性トークン(発動型能力1) /
442 static concptr r_a_ability_flags1[] =
479 * モンスター特性トークン(発動型能力2) /
482 static concptr r_a_ability_flags2[] =
499 "ANIM_DEAD", /* ToDo: Implement ANIM_DEAD */
522 static concptr r_info_flags7[] =
562 static concptr r_info_flags8[] =
594 "WILD_SWAMP", /* ToDo: Implement Swamp */
602 static concptr r_info_flags9[] =
640 * モンスター特性トークンの定義R(耐性) /
643 static concptr r_info_flagsr[] =
680 * オブジェクト基本特性トークンの定義 /
683 static concptr k_info_flags[] =
780 "XXX3", /* Fake flag for Smith */
781 "XXX4", /* Fake flag for Smith */
831 * オブジェクト生成特性トークンの定義 /
834 static concptr k_info_gen_flags[] =
874 static concptr d_info_flags1[] =
911 * @brief データの可変文字列情報をテキストとして保管する /
912 * Add a text to the text-storage and store offset to it.
913 * @param offset 文字列保管ポインタからのオフセット
914 * @param head テキスト保管ヘッダ情報の構造体参照ポインタ
916 * @param normal_text テキストの正規化を行う
919 * Returns FALSE when there isn't enough space available to store
922 static bool add_text(u32b *offset, header *head, concptr buf, bool normal_text)
924 if (head->text_size + strlen(buf) + 8 > FAKE_TEXT_SIZE)
929 *offset = ++head->text_size;
931 else if (normal_text)
934 * If neither the end of the last line nor
935 * the beginning of current line is not a space,
936 * fill up a space as a correct separator of two words.
938 if (head->text_size > 0 &&
940 (*(head->text_ptr + head->text_size - 1) != ' ') &&
941 ((head->text_size == 1) || !iskanji(*(head->text_ptr + head->text_size - 2))) &&
942 (buf[0] != ' ') && !iskanji(buf[0])
944 (*(head->text_ptr + head->text_size - 1) != ' ') &&
949 *(head->text_ptr + head->text_size) = ' ';
954 strcpy(head->text_ptr + head->text_size, buf);
955 head->text_size += strlen(buf);
961 * @brief データの可変文字列情報を名前として保管する /
962 * Add a name to the name-storage and return an offset to it.
963 * @param offset 文字列保管ポインタからのオフセット
964 * @param head テキスト保管ヘッダ情報の構造体参照ポインタ
968 * Returns FALSE when there isn't enough space available to store
971 static bool add_name(u32b *offset, header *head, concptr buf)
973 if (head->name_size + strlen(buf) + 8 > FAKE_NAME_SIZE)
978 *offset = ++head->name_size;
981 strcpy(head->name_ptr + head->name_size, buf);
982 head->name_size += strlen(buf);
988 * @brief データの可変文字列情報をタグとして保管する /
989 * Add a tag to the tag-storage and return an offset to it.
990 * @param offset 文字列保管ポインタからのオフセット
991 * @param head テキスト保管ヘッダ情報の構造体参照ポインタ
995 * Returns FALSE when there isn't enough space available to store
998 static bool add_tag(STR_OFFSET *offset, header *head, concptr buf)
1001 for (i = 1; i < head->tag_size; i += strlen(&head->tag_ptr[i]) + 1)
1003 if (streq(&head->tag_ptr[i], buf)) break;
1006 if (i >= head->tag_size)
1008 if (head->tag_size + strlen(buf) + 8 > FAKE_TAG_SIZE)
1011 strcpy(head->tag_ptr + head->tag_size, buf);
1013 head->tag_size += strlen(buf) + 1;
1022 * @brief パース関数に基づいてデータファイルからデータを読み取る /
1023 * Initialize an "*_info" array, by parsing an ascii "template" file
1024 * @param fp 読み取りに使うファイルポインタ
1025 * @param buf 読み取りに使うバッファ領域
1026 * @param head ヘッダ構造体
1027 * @param parse_info_txt_line パース関数
1030 errr init_info_txt(FILE *fp, char *buf, header *head, parse_info_txt_func parse_info_txt_line)
1035 head->name_size = 0;
1036 head->text_size = 0;
1040 while (my_fgets(fp, buf, 1024) == 0)
1043 if (!buf[0] || (buf[0] == '#')) continue;
1045 if (buf[1] != ':') return (PARSE_ERROR_GENERIC);
1052 if (buf[0] != 'N' && buf[0] != 'D')
1055 for (i = 0; buf[i]; i++)
1057 head->v_extra += (byte)buf[i];
1058 head->v_extra ^= (1 << (i % 8));
1062 if ((err = (*parse_info_txt_line)(buf, head)) != 0)
1066 if (head->name_size) head->name_size++;
1067 if (head->text_size) head->text_size++;
1074 * @brief Vault情報(v_info)のパース関数 /
1075 * Initialize the "v_info" array, by parsing an ascii "template" file
1077 * @param head ヘッダ構造体
1080 errr parse_v_info(char *buf, header *head)
1083 static vault_type *v_ptr = NULL;
1087 s = my_strchr(buf + 2, ':');
1093 int i = atoi(buf + 2);
1094 if (i <= error_idx) return 4;
1095 if (i >= head->info_num) return 2;
1099 if (!add_name(&v_ptr->name, head, s)) return 7;
1101 else if (!v_ptr) return 3;
1102 else if (buf[0] == 'D')
1105 if (!add_text(&v_ptr->text, head, s, FALSE)) return 7;
1107 else if (buf[0] == 'X')
1109 EFFECT_ID typ, rat, hgt, wid;
1110 if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
1111 &typ, &rat, &hgt, &wid)) return 1;
1113 v_ptr->typ = (ROOM_IDX)typ;
1114 v_ptr->rat = (PROB)rat;
1115 v_ptr->hgt = (POSITION)hgt;
1116 v_ptr->wid = (POSITION)wid;
1126 * @brief 職業技能情報(s_info)のパース関数 /
1127 * Initialize the "s_info" array, by parsing an ascii "template" file
1129 * @param head ヘッダ構造体
1132 errr parse_s_info(char *buf, header *head)
1134 static skill_table *s_ptr = NULL;
1137 int i = atoi(buf + 2);
1138 if (i <= error_idx) return 4;
1139 if (i >= head->info_num) return 2;
1148 else if (buf[0] == 'W')
1150 int tval, sval, start, max;
1151 const s16b exp_conv_table[] =
1153 WEAPON_EXP_UNSKILLED, WEAPON_EXP_BEGINNER, WEAPON_EXP_SKILLED,
1154 WEAPON_EXP_EXPERT, WEAPON_EXP_MASTER
1157 if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
1158 &tval, &sval, &start, &max)) return 1;
1160 if (start < EXP_LEVEL_UNSKILLED || start > EXP_LEVEL_MASTER
1161 || max < EXP_LEVEL_UNSKILLED || max > EXP_LEVEL_MASTER) return 8;
1163 s_ptr->w_start[tval][sval] = exp_conv_table[start];
1164 s_ptr->w_max[tval][sval] = exp_conv_table[max];
1166 else if (buf[0] == 'S')
1168 int num, start, max;
1169 if (3 != sscanf(buf + 2, "%d:%d:%d",
1170 &num, &start, &max)) return 1;
1172 if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER
1173 || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER) return 8;
1175 s_ptr->s_start[num] = (SUB_EXP)start;
1176 s_ptr->s_max[num] = (SUB_EXP)max;
1186 * @brief 職業魔法情報(m_info)のパース関数 /
1187 * Initialize the "m_info" array, by parsing an ascii "template" file
1189 * @param head ヘッダ構造体
1192 errr parse_m_info(char *buf, header *head)
1194 static player_magic *m_ptr = NULL;
1195 static int realm, magic_idx = 0, readable = 0;
1199 int i = atoi(buf + 2);
1201 if (i <= error_idx) return 4;
1202 if (i >= head->info_num) return 2;
1211 else if (buf[0] == 'I')
1214 int xtra, type, first, weight;
1216 s = my_strchr(buf + 2, ':');
1218 /* Verify that colon */
1221 /* Nuke the colon, advance to the name */
1226 if (streq(book, "SORCERY")) m_ptr->spell_book = TV_SORCERY_BOOK;
1227 else if (streq(book, "LIFE")) m_ptr->spell_book = TV_LIFE_BOOK;
1228 else if (streq(book, "MUSIC")) m_ptr->spell_book = TV_MUSIC_BOOK;
1229 else if (streq(book, "HISSATSU")) m_ptr->spell_book = TV_HISSATSU_BOOK;
1230 else if (streq(book, "NONE")) m_ptr->spell_book = 0;
1234 s = my_strchr(s, ':');
1238 if (streq(stat, "STR")) m_ptr->spell_stat = A_STR;
1239 else if (streq(stat, "INT")) m_ptr->spell_stat = A_INT;
1240 else if (streq(stat, "WIS")) m_ptr->spell_stat = A_WIS;
1241 else if (streq(stat, "DEX")) m_ptr->spell_stat = A_DEX;
1242 else if (streq(stat, "CON")) m_ptr->spell_stat = A_CON;
1243 else if (streq(stat, "CHR")) m_ptr->spell_stat = A_CHR;
1246 if (4 != sscanf(s, "%x:%d:%d:%d",
1247 (uint *)&xtra, &type, &first, &weight)) return 1;
1249 m_ptr->spell_xtra = xtra;
1250 m_ptr->spell_type = type;
1251 m_ptr->spell_first = first;
1252 m_ptr->spell_weight = weight;
1254 else if (buf[0] == 'R')
1256 if (2 != sscanf(buf + 2, "%d:%d",
1257 &realm, &readable)) return 1;
1261 else if (buf[0] == 'T')
1263 int level, mana, fail, exp;
1265 if (!readable) return 1;
1266 if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
1267 &level, &mana, &fail, &exp)) return 1;
1269 m_ptr->info[realm][magic_idx].slevel = (PLAYER_LEVEL)level;
1270 m_ptr->info[realm][magic_idx].smana = (MANA_POINT)mana;
1271 m_ptr->info[realm][magic_idx].sfail = (PERCENTAGE)fail;
1272 m_ptr->info[realm][magic_idx].sexp = (EXP)exp;
1283 * @brief テキストトークンを走査してフラグを一つ得る(汎用) /
1284 * Grab one flag from a textual string
1285 * @param flags ビットフラグを追加する先の参照ポインタ
1286 * @param names トークン定義配列
1287 * @param what 参照元の文字列ポインタ
1290 static errr grab_one_flag(u32b *flags, concptr names[], concptr what)
1292 for (int i = 0; i < 32; i++)
1294 if (streq(what, names[i]))
1296 *flags |= (1L << i);
1306 * @brief テキストトークンを走査してフラグを一つ得る(地形情報向け) /
1307 * Grab one flag in an feature_type from a textual string
1308 * @param f_ptr 地形情報を保管する先の構造体参照ポインタ
1309 * @param what 参照元の文字列ポインタ
1312 static errr grab_one_feat_flag(feature_type *f_ptr, concptr what)
1314 for (int i = 0; i < FF_FLAG_MAX; i++)
1316 if (streq(what, f_info_flags[i]))
1318 add_flag(f_ptr->flags, i);
1323 msg_format(_("未知の地形フラグ '%s'。", "Unknown feature flag '%s'."), what);
1324 return PARSE_ERROR_GENERIC;
1329 * @brief テキストトークンを走査してフラグ(ステート)を一つ得る(地形情報向け2) /
1330 * Grab an action in an feature_type from a textual string
1331 * @param f_ptr 地形情報を保管する先の構造体参照ポインタ
1332 * @param what 参照元の文字列ポインタ
1333 * @param count ステートの保存先ID
1336 static errr grab_one_feat_action(feature_type *f_ptr, concptr what, int count)
1338 for (FF_FLAGS_IDX i = 0; i < FF_FLAG_MAX; i++)
1340 if (streq(what, f_info_flags[i]))
1342 f_ptr->state[count].action = i;
1347 msg_format(_("未知の地形アクション '%s'。", "Unknown feature action '%s'."), what);
1348 return PARSE_ERROR_GENERIC;
1353 * @brief 地形情報(f_info)のパース関数 /
1354 * Initialize the "f_info" array, by parsing an ascii "template" file
1356 * @param head ヘッダ構造体
1359 errr parse_f_info(char *buf, header *head)
1361 static feature_type *f_ptr = NULL;
1366 s = my_strchr(buf + 2, ':');
1374 if (i <= error_idx) return 4;
1375 if (i >= head->info_num) return 2;
1381 if (!add_tag(&f_ptr->tag, head, s)) return 7;
1384 f_ptr->mimic = (FEAT_IDX)i;
1385 f_ptr->destroyed = (FEAT_IDX)i;
1386 for (i = 0; i < MAX_FEAT_STATES; i++)
1387 f_ptr->state[i].action = FF_FLAG_MAX;
1394 else if (buf[0] == 'J')
1396 if (!add_name(&f_ptr->name, head, buf + 2)) return 7;
1398 else if (buf[0] == 'E')
1402 else if (buf[0] == 'J')
1405 else if (buf[0] == 'E')
1408 if (!add_name(&f_ptr->name, head, s)) return 7;
1411 else if (buf[0] == 'M')
1414 if (!add_tag(&offset, head, buf + 2))
1415 return PARSE_ERROR_OUT_OF_MEMORY;
1417 f_ptr->mimic_tag = offset;
1419 else if (buf[0] == 'G')
1423 char char_tmp[F_LIT_MAX];
1424 if (buf[1] != ':') return 1;
1425 if (!buf[2]) return 1;
1426 if (buf[3] != ':') return 1;
1427 if (!buf[4]) return 1;
1429 char_tmp[F_LIT_STANDARD] = buf[2];
1430 s_attr = color_char_to_attr(buf[4]);
1431 if (s_attr > 127) return 1;
1433 f_ptr->d_attr[F_LIT_STANDARD] = s_attr;
1434 f_ptr->d_char[F_LIT_STANDARD] = char_tmp[F_LIT_STANDARD];
1437 apply_default_feat_lighting(f_ptr->d_attr, f_ptr->d_char);
1438 if (!streq(buf + 6, "LIT"))
1440 char attr_lite_tmp[F_LIT_MAX - F_LIT_NS_BEGIN];
1442 if ((F_LIT_MAX - F_LIT_NS_BEGIN) * 2 != sscanf(buf + 6, "%c:%c:%c:%c",
1443 &char_tmp[F_LIT_LITE], &attr_lite_tmp[F_LIT_LITE - F_LIT_NS_BEGIN],
1444 &char_tmp[F_LIT_DARK], &attr_lite_tmp[F_LIT_DARK - F_LIT_NS_BEGIN])) return 1;
1445 if (buf[F_LIT_MAX * 4 + 1]) return 1;
1447 for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
1449 switch (attr_lite_tmp[j - F_LIT_NS_BEGIN])
1452 /* Use default lighting */
1455 /* No lighting support */
1456 f_ptr->d_attr[j] = f_ptr->d_attr[F_LIT_STANDARD];
1459 /* Extract the color */
1460 f_ptr->d_attr[j] = color_char_to_attr(attr_lite_tmp[j - F_LIT_NS_BEGIN]);
1461 if (f_ptr->d_attr[j] > 127) return 1;
1464 f_ptr->d_char[j] = char_tmp[j];
1470 for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
1472 f_ptr->d_attr[j] = s_attr;
1473 f_ptr->d_char[j] = char_tmp[F_LIT_STANDARD];
1478 else if (buf[0] == 'F')
1480 for (s = buf + 2; *s; )
1483 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
1488 while (*t == ' ' || *t == '|') t++;
1491 if (1 == sscanf(s, "SUBTYPE_%d", &i))
1493 f_ptr->subtype = (FEAT_SUBTYPE)i;
1499 if (1 == sscanf(s, "POWER_%d", &i))
1501 f_ptr->power = (FEAT_POWER)i;
1506 if (0 != grab_one_feat_flag(f_ptr, s))
1507 return (PARSE_ERROR_INVALID_FLAG);
1512 else if (buf[0] == 'W')
1515 if (1 != sscanf(buf + 2, "%d", &priority))
1516 return (PARSE_ERROR_GENERIC);
1517 f_ptr->priority = (FEAT_PRIORITY)priority;
1519 else if (buf[0] == 'K')
1522 for (i = 0; i < MAX_FEAT_STATES; i++)
1523 if (f_ptr->state[i].action == FF_FLAG_MAX) break;
1525 if (i == MAX_FEAT_STATES) return PARSE_ERROR_GENERIC;
1528 for (s = t = buf + 2; *t && (*t != ':'); t++);
1530 if (*t == ':') *t++ = '\0';
1532 if (streq(s, "DESTROYED"))
1534 if (!add_tag(&offset, head, t)) return PARSE_ERROR_OUT_OF_MEMORY;
1536 f_ptr->destroyed_tag = offset;
1540 f_ptr->state[i].action = 0;
1541 if (0 != grab_one_feat_action(f_ptr, s, i)) return PARSE_ERROR_INVALID_FLAG;
1542 if (!add_tag(&offset, head, t)) return PARSE_ERROR_OUT_OF_MEMORY;
1544 f_ptr->state[i].result_tag = offset;
1557 * @brief 地形タグからIDを得る /
1558 * Convert a fake tag to a real feat index
1562 s16b f_tag_to_index(concptr str)
1564 for (u16b i = 0; i < f_head.info_num; i++)
1566 if (streq(f_tag + f_info[i].tag, str))
1577 * @brief 地形タグからIDを得る /
1578 * Search for real index corresponding to this fake tag
1579 * @param feat タグ文字列のオフセット
1580 * @return 地形ID。該当がないなら-1
1582 static FEAT_IDX search_real_feat(STR_OFFSET feat)
1589 for (FEAT_IDX i = 0; i < f_head.info_num; i++)
1591 if (feat == f_info[i].tag)
1597 msg_format(_("未定義のタグ '%s'。", "%s is undefined."), f_tag + feat);
1603 * @brief 地形情報の各種タグからIDへ変換して結果を収める /
1604 * Retouch fake tags of f_info
1605 * @param head ヘッダ構造体
1608 void retouch_f_info(header *head)
1610 for (int i = 0; i < head->info_num; i++)
1612 feature_type *f_ptr = &f_info[i];
1613 FEAT_IDX k = search_real_feat(f_ptr->mimic_tag);
1614 f_ptr->mimic = k < 0 ? f_ptr->mimic : k;
1615 k = search_real_feat(f_ptr->destroyed_tag);
1616 f_ptr->destroyed = k < 0 ? f_ptr->destroyed : k;
1617 for (FEAT_IDX j = 0; j < MAX_FEAT_STATES; j++)
1619 k = search_real_feat(f_ptr->state[j].result_tag);
1620 f_ptr->state[j].result = k < 0 ? f_ptr->state[j].result : k;
1627 * @brief テキストトークンを走査してフラグを一つ得る(ベースアイテム用) /
1628 * Grab one flag in an object_kind from a textual string
1629 * @param k_ptr 保管先のベースアイテム構造体参照ポインタ
1630 * @param what 参照元の文字列ポインタ
1633 static errr grab_one_kind_flag(object_kind *k_ptr, concptr what)
1635 for (int i = 0; i < TR_FLAG_MAX; i++)
1637 if (streq(what, k_info_flags[i]))
1639 add_flag(k_ptr->flags, i);
1644 if (grab_one_flag(&k_ptr->gen_flags, k_info_gen_flags, what) == 0)
1647 msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what);
1653 * @brief テキストトークンを走査してフラグを一つ得る(発動能力用) /
1654 * Grab one activation index flag
1655 * @param what 参照元の文字列ポインタ
1658 static byte grab_one_activation_flag(concptr what)
1660 for (int i = 0; ; i++)
1662 if (activation_info[i].flag == NULL) break;
1664 if (streq(what, activation_info[i].flag))
1666 return activation_info[i].index;
1676 msg_format(_("未知の発動・フラグ '%s'。", "Unknown activation flag '%s'."), what);
1682 * @brief ベースアイテム(k_info)のパース関数 /
1683 * Initialize the "k_info" array, by parsing an ascii "template" file
1685 * @param head ヘッダ構造体
1688 errr parse_k_info(char *buf, header *head)
1690 static object_kind *k_ptr = NULL;
1698 s = my_strchr(buf + 2, ':');
1702 int i = atoi(buf + 2);
1704 if (i <= error_idx) return 4;
1705 if (i >= head->info_num) return 2;
1713 flavor = my_strchr(s, ':');
1717 if (!add_name(&k_ptr->flavor_name, head, flavor)) return 7;
1720 if (!add_name(&k_ptr->name, head, s)) return 7;
1729 /* 'E' から始まる行は英語名としている */
1730 else if (buf[0] == 'E')
1735 else if (buf[0] == 'E')
1739 flavor = my_strchr(s, ':');
1743 if (!add_name(&k_ptr->flavor_name, head, flavor)) return 7;
1746 if (!add_name(&k_ptr->name, head, s)) return 7;
1749 else if (buf[0] == 'D')
1760 if (!add_text(&k_ptr->text, head, s, TRUE)) return 7;
1762 else if (buf[0] == 'G')
1766 if (buf[1] != ':') return 1;
1767 if (!buf[2]) return 1;
1768 if (buf[3] != ':') return 1;
1769 if (!buf[4]) return 1;
1772 tmp = color_char_to_attr(buf[4]);
1773 if (tmp > 127) return 1;
1775 k_ptr->d_attr = tmp;
1776 k_ptr->d_char = sym;
1778 else if (buf[0] == 'I')
1780 int tval, sval, pval;
1781 if (3 != sscanf(buf + 2, "%d:%d:%d",
1782 &tval, &sval, &pval)) return 1;
1784 k_ptr->tval = (OBJECT_TYPE_VALUE)tval;
1785 k_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval;
1786 k_ptr->pval = (PARAMETER_VALUE)pval;
1788 else if (buf[0] == 'W')
1790 int level, extra, wgt;
1792 if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
1793 &level, &extra, &wgt, &cost)) return 1;
1795 k_ptr->level = (DEPTH)level;
1796 k_ptr->extra = (BIT_FLAGS8)extra;
1797 k_ptr->weight = (WEIGHT)wgt;
1798 k_ptr->cost = (PRICE)cost;
1800 else if (buf[0] == 'A')
1803 for (s = buf + 1; s && (s[0] == ':') && s[1]; ++i)
1805 k_ptr->chance[i] = 1;
1806 k_ptr->locale[i] = atoi(s + 1);
1807 t = my_strchr(s + 1, '/');
1808 s = my_strchr(s + 1, ':');
1809 if (t && (!s || t < s))
1811 int chance = atoi(t + 1);
1812 if (chance > 0) k_ptr->chance[i] = (PROB)chance;
1816 else if (buf[0] == 'P')
1818 int ac, hd1, hd2, th, td, ta;
1819 if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
1820 &ac, &hd1, &hd2, &th, &td, &ta)) return 1;
1822 k_ptr->ac = (ARMOUR_CLASS)ac;
1823 k_ptr->dd = (DICE_NUMBER)hd1;
1824 k_ptr->ds = (DICE_SID)hd2;
1825 k_ptr->to_h = (HIT_PROB)th;
1826 k_ptr->to_d = (HIT_POINT)td;
1827 k_ptr->to_a = (ARMOUR_CLASS)ta;
1829 else if (buf[0] == 'U')
1832 n = grab_one_activation_flag(buf + 2);
1842 else if (buf[0] == 'F')
1844 for (s = buf + 2; *s; )
1847 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
1852 while (*t == ' ' || *t == '|') t++;
1855 if (0 != grab_one_kind_flag(k_ptr, s)) return 5;
1869 * @brief テキストトークンを走査してフラグを一つ得る(アーティファクト用) /
1870 * Grab one activation index flag
1871 * @param a_ptr 保管先のアーティファクト構造体参照ポインタ
1872 * @param what 参照元の文字列ポインタ
1873 * @return エラーがあった場合1、エラーがない場合0を返す
1875 static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what)
1877 for (int i = 0; i < TR_FLAG_MAX; i++)
1879 if (streq(what, k_info_flags[i]))
1881 add_flag(a_ptr->flags, i);
1886 if (grab_one_flag(&a_ptr->gen_flags, k_info_gen_flags, what) == 0)
1889 msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what);
1895 * @brief 固定アーティファクト情報(a_info)のパース関数 /
1896 * Initialize the "a_info" array, by parsing an ascii "template" file
1898 * @param head ヘッダ構造体
1901 errr parse_a_info(char *buf, header *head)
1903 static artifact_type *a_ptr = NULL;
1907 s = my_strchr(buf + 2, ':');
1914 int i = atoi(buf + 2);
1915 if (i < error_idx) return 4;
1916 if (i >= head->info_num) return 2;
1920 add_flag(a_ptr->flags, TR_IGNORE_ACID);
1921 add_flag(a_ptr->flags, TR_IGNORE_ELEC);
1922 add_flag(a_ptr->flags, TR_IGNORE_FIRE);
1923 add_flag(a_ptr->flags, TR_IGNORE_COLD);
1925 if (!add_name(&a_ptr->name, head, s)) return 7;
1934 /* 'E' から始まる行は英語名としている */
1935 else if (buf[0] == 'E')
1940 else if (buf[0] == 'E')
1943 if (!add_name(&a_ptr->name, head, s)) return 7;
1946 else if (buf[0] == 'D')
1957 if (!add_text(&a_ptr->text, head, s, TRUE)) return 7;
1959 else if (buf[0] == 'I')
1961 int tval, sval, pval;
1962 if (3 != sscanf(buf + 2, "%d:%d:%d",
1963 &tval, &sval, &pval)) return 1;
1965 a_ptr->tval = (OBJECT_TYPE_VALUE)tval;
1966 a_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval;
1967 a_ptr->pval = (PARAMETER_VALUE)pval;
1969 else if (buf[0] == 'W')
1971 int level, rarity, wgt;
1973 if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
1974 &level, &rarity, &wgt, &cost)) return 1;
1976 a_ptr->level = (DEPTH)level;
1977 a_ptr->rarity = (RARITY)rarity;
1978 a_ptr->weight = (WEIGHT)wgt;
1979 a_ptr->cost = (PRICE)cost;
1981 else if (buf[0] == 'P')
1983 int ac, hd1, hd2, th, td, ta;
1984 if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
1985 &ac, &hd1, &hd2, &th, &td, &ta)) return 1;
1987 a_ptr->ac = (ARMOUR_CLASS)ac;
1988 a_ptr->dd = (DICE_NUMBER)hd1;
1989 a_ptr->ds = (DICE_SID)hd2;
1990 a_ptr->to_h = (HIT_PROB)th;
1991 a_ptr->to_d = (HIT_POINT)td;
1992 a_ptr->to_a = (ARMOUR_CLASS)ta;
1994 else if (buf[0] == 'U')
1997 n = grab_one_activation_flag(buf + 2);
2007 else if (buf[0] == 'F')
2009 for (s = buf + 2; *s; )
2012 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2017 while ((*t == ' ') || (*t == '|')) t++;
2020 if (0 != grab_one_artifact_flag(a_ptr, s)) return 5;
2035 * @brief テキストトークンを走査してフラグを一つ得る(アーティファクト用) /
2036 * Grab one flag in a ego-item_type from a textual string
2037 * @param e_ptr 保管先のエゴ構造体参照ポインタ
2038 * @param what 参照元の文字列ポインタ
2039 * @return エラーがあった場合1、エラーがない場合0を返す
2041 static bool grab_one_ego_item_flag(ego_item_type *e_ptr, concptr what)
2043 for (int i = 0; i < TR_FLAG_MAX; i++)
2045 if (streq(what, k_info_flags[i]))
2047 add_flag(e_ptr->flags, i);
2052 if (grab_one_flag(&e_ptr->gen_flags, k_info_gen_flags, what) == 0)
2055 msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what);
2061 * @brief アイテムエゴ情報(e_info)のパース関数 /
2062 * Initialize the "e_info" array, by parsing an ascii "template" file
2064 * @param head ヘッダ構造体
2067 errr parse_e_info(char *buf, header *head)
2069 static ego_item_type *e_ptr = NULL;
2075 s = my_strchr(buf + 2, ':');
2082 int i = atoi(buf + 2);
2083 if (i < error_idx) return 4;
2084 if (i >= head->info_num) return 2;
2089 if (!add_name(&e_ptr->name, head, s)) return 7;
2098 /* 'E' から始まる行は英語名 */
2099 else if (buf[0] == 'E')
2104 else if (buf[0] == 'E')
2107 if (!add_name(&e_ptr->name, head, s)) return 7;
2110 else if (buf[0] == 'X')
2113 if (2 != sscanf(buf + 2, "%d:%d",
2114 &slot, &rating)) return 1;
2116 e_ptr->slot = (INVENTORY_IDX)slot;
2117 e_ptr->rating = (PRICE)rating;
2119 else if (buf[0] == 'W')
2121 int level, rarity, pad2;
2124 if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
2125 &level, &rarity, &pad2, &cost)) return 1;
2127 e_ptr->level = level;
2128 e_ptr->rarity = (RARITY)rarity;
2131 else if (buf[0] == 'C')
2133 int th, td, ta, pval;
2135 if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
2136 &th, &td, &ta, &pval)) return 1;
2138 e_ptr->max_to_h = (HIT_PROB)th;
2139 e_ptr->max_to_d = (HIT_POINT)td;
2140 e_ptr->max_to_a = (ARMOUR_CLASS)ta;
2141 e_ptr->max_pval = (PARAMETER_VALUE)pval;
2143 else if (buf[0] == 'U')
2146 n = grab_one_activation_flag(buf + 2);
2156 else if (buf[0] == 'F')
2158 for (s = buf + 2; *s; )
2161 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2166 while ((*t == ' ') || (*t == '|')) t++;
2169 if (0 != grab_one_ego_item_flag(e_ptr, s)) return 5;
2184 * @brief テキストトークンを走査してフラグを一つ得る(モンスター用1) /
2185 * Grab one (basic) flag in a monster_race from a textual string
2186 * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
2187 * @param what 参照元の文字列ポインタ
2190 static errr grab_one_basic_flag(monster_race *r_ptr, concptr what)
2192 if (grab_one_flag(&r_ptr->flags1, r_info_flags1, what) == 0)
2195 if (grab_one_flag(&r_ptr->flags2, r_info_flags2, what) == 0)
2198 if (grab_one_flag(&r_ptr->flags3, r_info_flags3, what) == 0)
2201 if (grab_one_flag(&r_ptr->flags7, r_info_flags7, what) == 0)
2204 if (grab_one_flag(&r_ptr->flags8, r_info_flags8, what) == 0)
2207 if (grab_one_flag(&r_ptr->flags9, r_info_flags9, what) == 0)
2210 if (grab_one_flag(&r_ptr->flagsr, r_info_flagsr, what) == 0)
2213 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
2219 * @brief テキストトークンを走査してフラグを一つ得る(モンスター用2) /
2220 * Grab one (spell) flag in a monster_race from a textual string
2221 * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
2222 * @param what 参照元の文字列ポインタ
2225 static errr grab_one_spell_flag(monster_race *r_ptr, concptr what)
2227 if (grab_one_flag(&r_ptr->flags4, r_info_flags4, what) == 0)
2230 if (grab_one_flag(&r_ptr->a_ability_flags1, r_a_ability_flags1, what) == 0)
2233 if (grab_one_flag(&r_ptr->a_ability_flags2, r_a_ability_flags2, what) == 0)
2236 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
2242 * @brief モンスター種族情報(r_info)のパース関数 /
2243 * Initialize the "r_info" array, by parsing an ascii "template" file
2245 * @param head ヘッダ構造体
2248 errr parse_r_info(char *buf, header *head)
2250 static monster_race *r_ptr = NULL;
2254 s = my_strchr(buf + 2, ':');
2262 int i = atoi(buf + 2);
2263 if (i < error_idx) return 4;
2264 if (i >= head->info_num) return 2;
2269 if (!add_name(&r_ptr->name, head, s)) return 7;
2278 /* 'E' から始まる行は英語名 */
2279 else if (buf[0] == 'E')
2282 if (!add_name(&r_ptr->E_name, head, s)) return 7;
2285 else if (buf[0] == 'E')
2288 if (!add_name(&r_ptr->name, head, s)) return 7;
2291 else if (buf[0] == 'D')
2302 if (!add_text(&r_ptr->text, head, s, TRUE)) return 7;
2304 else if (buf[0] == 'G')
2306 if (buf[1] != ':') return 1;
2307 if (!buf[2]) return 1;
2308 if (buf[3] != ':') return 1;
2309 if (!buf[4]) return 1;
2312 byte tmp = color_char_to_attr(buf[4]);
2313 if (tmp > 127) return 1;
2315 r_ptr->d_char = sym;
2316 r_ptr->d_attr = tmp;
2318 else if (buf[0] == 'I')
2320 int spd, hp1, hp2, aaf, ac, slp;
2322 if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
2323 &spd, &hp1, &hp2, &aaf, &ac, &slp)) return 1;
2325 r_ptr->speed = (SPEED)spd;
2326 r_ptr->hdice = (DICE_NUMBER)MAX(hp1, 1);
2327 r_ptr->hside = (DICE_SID)MAX(hp2, 1);
2328 r_ptr->aaf = (POSITION)aaf;
2329 r_ptr->ac = (ARMOUR_CLASS)ac;
2330 r_ptr->sleep = (SLEEP_DEGREE)slp;
2332 else if (buf[0] == 'W')
2338 if (6 != sscanf(buf + 2, "%d:%d:%d:%ld:%ld:%d",
2339 &lev, &rar, &pad, &exp, &nextexp, &nextmon)) return 1;
2341 r_ptr->level = (DEPTH)lev;
2342 r_ptr->rarity = (RARITY)rar;
2343 r_ptr->extra = (BIT_FLAGS16)pad;
2344 r_ptr->mexp = (EXP)exp;
2345 r_ptr->next_exp = (EXP)nextexp;
2346 r_ptr->next_r_idx = (MONRACE_IDX)nextmon;
2348 else if (buf[0] == 'R')
2352 for (; i < A_MAX; i++) if (r_ptr->reinforce_id[i] == 0) break;
2354 if (i == 6) return 1;
2356 if (3 != sscanf(buf + 2, "%d:%dd%d", &id, &dd, &ds)) return 1;
2357 r_ptr->reinforce_id[i] = (MONRACE_IDX)id;
2358 r_ptr->reinforce_dd[i] = (DICE_NUMBER)dd;
2359 r_ptr->reinforce_ds[i] = (DICE_SID)ds;
2361 else if (buf[0] == 'B')
2365 for (i = 0; i < 4; i++) if (!r_ptr->blow[i].method) break;
2367 if (i == 4) return 1;
2370 for (s = t = buf + 2; *t && (*t != ':'); t++);
2372 if (*t == ':') *t++ = '\0';
2374 for (n1 = 0; r_info_blow_method[n1]; n1++)
2376 if (streq(s, r_info_blow_method[n1])) break;
2379 if (!r_info_blow_method[n1]) return 1;
2382 for (s = t; *t && (*t != ':'); t++);
2384 if (*t == ':') *t++ = '\0';
2386 for (n2 = 0; r_info_blow_effect[n2]; n2++)
2388 if (streq(s, r_info_blow_effect[n2])) break;
2391 if (!r_info_blow_effect[n2]) return 1;
2394 for (s = t; *t && (*t != 'd'); t++);
2396 if (*t == 'd') *t++ = '\0';
2398 r_ptr->blow[i].method = (BLOW_METHOD)n1;
2399 r_ptr->blow[i].effect = (BLOW_EFFECT)n2;
2400 r_ptr->blow[i].d_dice = atoi(s);
2401 r_ptr->blow[i].d_side = atoi(t);
2403 else if (buf[0] == 'F')
2405 for (s = buf + 2; *s; )
2408 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2413 while (*t == ' ' || *t == '|') t++;
2416 if (0 != grab_one_basic_flag(r_ptr, s)) return 5;
2421 else if (buf[0] == 'S')
2423 for (s = buf + 2; *s; )
2427 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2432 while ((*t == ' ') || (*t == '|')) t++;
2436 if (1 == sscanf(s, "1_IN_%d", &i))
2438 r_ptr->freq_spell = 100 / i;
2443 if (0 != grab_one_spell_flag(r_ptr, s)) return 5;
2448 else if (buf[0] == 'A')
2450 int id, per, rarity;
2452 for (i = 0; i < 4; i++) if (!r_ptr->artifact_id[i]) break;
2454 if (i == 4) return 1;
2456 if (3 != sscanf(buf + 2, "%d:%d:%d", &id, &rarity, &per)) return 1;
2457 r_ptr->artifact_id[i] = (ARTIFACT_IDX)id;
2458 r_ptr->artifact_rarity[i] = (RARITY)rarity;
2459 r_ptr->artifact_percent[i] = (PERCENTAGE)per;
2461 else if (buf[0] == 'V')
2464 if (3 != sscanf(buf + 2, "%d", &val)) return 1;
2465 r_ptr->arena_ratio = (PERCENTAGE)val;
2477 * @brief テキストトークンを走査してフラグを一つ得る(ダンジョン用) /
2478 * Grab one flag for a dungeon type from a textual string
2479 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
2480 * @param what 参照元の文字列ポインタ
2483 static errr grab_one_dungeon_flag(dungeon_type *d_ptr, concptr what)
2485 if (grab_one_flag(&d_ptr->flags1, d_info_flags1, what) == 0)
2488 msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what);
2494 * @brief テキストトークンを走査してフラグを一つ得る(モンスターのダンジョン出現条件用1) /
2495 * Grab one (basic) flag in a monster_race from a textual string
2496 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
2497 * @param what 参照元の文字列ポインタ
2500 static errr grab_one_basic_monster_flag(dungeon_type *d_ptr, concptr what)
2502 if (grab_one_flag(&d_ptr->mflags1, r_info_flags1, what) == 0)
2505 if (grab_one_flag(&d_ptr->mflags2, r_info_flags2, what) == 0)
2508 if (grab_one_flag(&d_ptr->mflags3, r_info_flags3, what) == 0)
2511 if (grab_one_flag(&d_ptr->mflags7, r_info_flags7, what) == 0)
2514 if (grab_one_flag(&d_ptr->mflags8, r_info_flags8, what) == 0)
2517 if (grab_one_flag(&d_ptr->mflags9, r_info_flags9, what) == 0)
2520 if (grab_one_flag(&d_ptr->mflagsr, r_info_flagsr, what) == 0)
2523 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
2529 * @brief テキストトークンを走査してフラグを一つ得る(モンスターのダンジョン出現条件用2) /
2530 * Grab one (spell) flag in a monster_race from a textual string
2531 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
2532 * @param what 参照元の文字列ポインタ
2535 static errr grab_one_spell_monster_flag(dungeon_type *d_ptr, concptr what)
2537 if (grab_one_flag(&d_ptr->mflags4, r_info_flags4, what) == 0)
2540 if (grab_one_flag(&d_ptr->m_a_ability_flags1, r_a_ability_flags1, what) == 0)
2543 if (grab_one_flag(&d_ptr->m_a_ability_flags2, r_a_ability_flags2, what) == 0)
2546 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
2552 * @brief ダンジョン情報(d_info)のパース関数 /
2553 * Initialize the "d_info" array, by parsing an ascii "template" file
2555 * @param head ヘッダ構造体
2558 errr parse_d_info(char *buf, header *head)
2560 static dungeon_type *d_ptr = NULL;
2564 s = my_strchr(buf + 2, ':');
2572 int i = atoi(buf + 2);
2573 if (i < error_idx) return 4;
2574 if (i >= head->info_num) return 2;
2579 if (!add_name(&d_ptr->name, head, s)) return 7;
2583 else if (buf[0] == 'E') return 0;
2585 else if (buf[0] == 'E')
2587 /* Acquire the Text */
2590 /* Store the name */
2591 if (!add_name(&d_ptr->name, head, s)) return 7;
2594 else if (buf[0] == 'D')
2605 if (!add_text(&d_ptr->text, head, s, TRUE)) return 7;
2607 else if (buf[0] == 'W')
2609 int min_lev, max_lev;
2611 int min_alloc, max_chance;
2612 int obj_good, obj_great;
2615 if (10 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%x:%x",
2616 &min_lev, &max_lev, &min_plev, &mode, &min_alloc, &max_chance, &obj_good, &obj_great, (unsigned int *)&pit, (unsigned int *)&nest)) return 1;
2618 d_ptr->mindepth = (DEPTH)min_lev;
2619 d_ptr->maxdepth = (DEPTH)max_lev;
2620 d_ptr->min_plev = (PLAYER_LEVEL)min_plev;
2621 d_ptr->mode = (BIT_FLAGS8)mode;
2622 d_ptr->min_m_alloc_level = min_alloc;
2623 d_ptr->max_m_alloc_chance = max_chance;
2624 d_ptr->obj_good = obj_good;
2625 d_ptr->obj_great = obj_great;
2626 d_ptr->pit = (BIT_FLAGS16)pit;
2627 d_ptr->nest = (BIT_FLAGS16)nest;
2629 else if (buf[0] == 'P')
2632 if (2 != sscanf(buf + 2, "%d:%d", &dy, &dx)) return 1;
2637 else if (buf[0] == 'L')
2640 if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 1, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 1)) return 1;
2642 for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++)
2644 d_ptr->floor[i].feat = f_tag_to_index(zz[i * 2]);
2645 if (d_ptr->floor[i].feat < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2647 d_ptr->floor[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]);
2650 d_ptr->tunnel_percent = atoi(zz[DUNGEON_FEAT_PROB_NUM * 2]);
2652 else if (buf[0] == 'A')
2655 if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 4, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 4)) return 1;
2657 for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++)
2659 d_ptr->fill[i].feat = f_tag_to_index(zz[i * 2]);
2660 if (d_ptr->fill[i].feat < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2662 d_ptr->fill[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]);
2665 d_ptr->outer_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2]);
2666 if (d_ptr->outer_wall < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2668 d_ptr->inner_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 1]);
2669 if (d_ptr->inner_wall < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2671 d_ptr->stream1 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 2]);
2672 if (d_ptr->stream1 < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2674 d_ptr->stream2 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 3]);
2675 if (d_ptr->stream2 < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2677 else if (buf[0] == 'F')
2679 int artif = 0, monst = 0;
2681 for (s = buf + 2; *s; )
2684 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2689 while (*t == ' ' || *t == '|') t++;
2692 if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif))
2694 d_ptr->final_artifact = (ARTIFACT_IDX)artif;
2699 if (1 == sscanf(s, "FINAL_OBJECT_%d", &artif))
2701 d_ptr->final_object = (KIND_OBJECT_IDX)artif;
2706 if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst))
2708 d_ptr->final_guardian = (MONRACE_IDX)monst;
2713 if (1 == sscanf(s, "MONSTER_DIV_%d", &monst))
2715 d_ptr->special_div = (PROB)monst;
2720 if (0 != grab_one_dungeon_flag(d_ptr, s)) return 5;
2725 else if (buf[0] == 'M')
2727 for (s = buf + 2; *s; )
2730 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2735 while (*t == ' ' || *t == '|') t++;
2738 if (!strncmp(s, "R_CHAR_", 7))
2741 strncpy(d_ptr->r_char, s, sizeof(d_ptr->r_char));
2746 if (0 != grab_one_basic_monster_flag(d_ptr, s)) return 5;
2751 else if (buf[0] == 'S')
2753 for (s = buf + 2; *s; )
2756 for (t = s; *t && (*t != ' ') && (*t != '|'); ++t);
2761 while ((*t == ' ') || (*t == '|')) t++;
2765 if (1 == sscanf(s, "1_IN_%d", &i))
2771 if (0 != grab_one_spell_monster_flag(d_ptr, s)) return 5;
2786 * @brief 地形情報の「F:」情報をパースする
2787 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
2788 * @param floor_ptr 現在フロアへの参照ポインタ
2792 static errr parse_line_feature(floor_type *floor_ptr, char *buf)
2794 if (init_flags & INIT_ONLY_BUILDINGS) return 0;
2797 int num = tokenize(buf + 2, 9, zz, 0);
2798 if (num <= 1) return 1;
2800 int index = zz[0][0];
2801 letter[index].feature = feat_none;
2802 letter[index].monster = 0;
2803 letter[index].object = 0;
2804 letter[index].ego = 0;
2805 letter[index].artifact = 0;
2806 letter[index].trap = feat_none;
2807 letter[index].cave_info = 0;
2808 letter[index].special = 0;
2809 letter[index].random = RANDOM_NONE;
2814 letter[index].special = (s16b)atoi(zz[8]);
2817 if ((zz[7][0] == '*') && !zz[7][1])
2819 letter[index].random |= RANDOM_TRAP;
2823 letter[index].trap = f_tag_to_index(zz[7]);
2824 if (letter[index].trap < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2828 if (zz[6][0] == '*')
2830 letter[index].random |= RANDOM_ARTIFACT;
2831 if (zz[6][1]) letter[index].artifact = (ARTIFACT_IDX)atoi(zz[6] + 1);
2833 else if (zz[6][0] == '!')
2835 if (floor_ptr->inside_quest)
2837 letter[index].artifact = quest[floor_ptr->inside_quest].k_idx;
2842 letter[index].artifact = (ARTIFACT_IDX)atoi(zz[6]);
2846 if (zz[5][0] == '*')
2848 letter[index].random |= RANDOM_EGO;
2849 if (zz[5][1]) letter[index].ego = (EGO_IDX)atoi(zz[5] + 1);
2853 letter[index].ego = (EGO_IDX)atoi(zz[5]);
2857 if (zz[4][0] == '*')
2859 letter[index].random |= RANDOM_OBJECT;
2860 if (zz[4][1]) letter[index].object = (OBJECT_IDX)atoi(zz[4] + 1);
2862 else if (zz[4][0] == '!')
2864 if (floor_ptr->inside_quest)
2866 ARTIFACT_IDX a_idx = quest[floor_ptr->inside_quest].k_idx;
2869 artifact_type *a_ptr = &a_info[a_idx];
2870 if (!(a_ptr->gen_flags & TRG_INSTA_ART))
2872 letter[index].object = lookup_kind(a_ptr->tval, a_ptr->sval);
2879 letter[index].object = (IDX)atoi(zz[4]);
2883 if (zz[3][0] == '*')
2885 letter[index].random |= RANDOM_MONSTER;
2886 if (zz[3][1]) letter[index].monster = (IDX)atoi(zz[3] + 1);
2888 else if (zz[3][0] == 'c')
2890 if (!zz[3][1]) return PARSE_ERROR_GENERIC;
2891 letter[index].monster = -atoi(zz[3] + 1);
2895 letter[index].monster = (IDX)atoi(zz[3]);
2899 letter[index].cave_info = atoi(zz[2]);
2902 if ((zz[1][0] == '*') && !zz[1][1])
2904 letter[index].random |= RANDOM_FEATURE;
2908 letter[index].feature = f_tag_to_index(zz[1]);
2909 if (letter[index].feature < 0) return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
2920 * @brief 地形情報の「B:」情報をパースする
2921 * Process "B:<Index>:<Command>:..." -- Building definition
2925 static errr parse_line_building(char *buf)
2939 int index = atoi(s);
2940 s = my_strchr(s, ':');
2950 if (tokenize(s + 2, 3, zz, 0) == 3)
2952 strcpy(building[index].name, zz[0]);
2953 strcpy(building[index].owner_name, zz[1]);
2954 strcpy(building[index].owner_race, zz[2]);
2958 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
2962 if (tokenize(s + 2, 8, zz, 0) >= 7)
2964 int action_index = atoi(zz[0]);
2965 strcpy(building[index].act_names[action_index], zz[1]);
2966 building[index].member_costs[action_index] = (PRICE)atoi(zz[2]);
2967 building[index].other_costs[action_index] = (PRICE)atoi(zz[3]);
2968 building[index].letters[action_index] = zz[4][0];
2969 building[index].actions[action_index] = (BACT_IDX)atoi(zz[5]);
2970 building[index].action_restr[action_index] = (BACT_RESTRICT_IDX)atoi(zz[6]);
2974 return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
2979 n = tokenize(s + 2, MAX_CLASS, zz, 0);
2980 for (int i = 0; i < MAX_CLASS; i++)
2982 building[index].member_class[i] = ((i < n) ? (CLASS_IDX)atoi(zz[i]) : 1);
2990 n = tokenize(s + 2, MAX_RACES, zz, 0);
2991 for (int i = 0; i < MAX_RACES; i++)
2993 building[index].member_race[i] = ((i < n) ? (RACE_IDX)atoi(zz[i]) : 1);
3001 n = tokenize(s + 2, MAX_MAGIC, zz, 0);
3002 for (int i = 0; i < MAX_MAGIC; i++)
3004 building[index].member_realm[i + 1] = ((i < n) ? (REALM_IDX)atoi(zz[i]) : 1);
3015 return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
3024 * @brief フロアの所定のマスにオブジェクトを配置する
3025 * Place the object j_ptr to a grid
3026 * @param floor_ptr 現在フロアへの参照ポインタ
3027 * @param j_ptr オブジェクト構造体の参照ポインタ
3032 static void drop_here(floor_type *floor_ptr, object_type *j_ptr, POSITION y, POSITION x)
3034 OBJECT_IDX o_idx = o_pop(floor_ptr);
3036 o_ptr = &floor_ptr->o_list[o_idx];
3037 object_copy(o_ptr, j_ptr);
3040 o_ptr->held_m_idx = 0;
3041 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
3042 o_ptr->next_o_idx = g_ptr->o_idx;
3043 g_ptr->o_idx = o_idx;
3048 * todo yminとymaxは本当に使われているのか?
3049 * @brief クエスト用固定ダンジョンをフロアに生成する
3050 * Parse a sub-file of the "extra info"
3051 * @param player_ptr プレーヤーへの参照ポインタ
3061 static errr process_dungeon_file_aux(player_type *player_ptr, char *buf, int ymin, int xmin, int ymax, int xmax, int *y, int *x)
3065 if (!buf[0]) return 0;
3066 if (iswspace(buf[0])) return 0;
3067 if (buf[0] == '#') return 0;
3068 if (buf[1] != ':') return 1;
3072 return process_dungeon_file(player_ptr, buf + 2, ymin, xmin, ymax, xmax);
3075 floor_type *floor_ptr = player_ptr->current_floor_ptr;
3076 /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid */
3079 return parse_line_feature(player_ptr->current_floor_ptr, buf);
3081 else if (buf[0] == 'D')
3083 object_type object_type_body;
3085 int len = strlen(s);
3086 if (init_flags & INIT_ONLY_BUILDINGS) return 0;
3089 for (int i = 0; ((*x < xmax) && (i < len)); (*x)++, s++, i++)
3091 grid_type *g_ptr = &floor_ptr->grid_array[*y][*x];
3093 OBJECT_IDX object_index = letter[idx].object;
3094 MONSTER_IDX monster_index = letter[idx].monster;
3095 int random = letter[idx].random;
3096 ARTIFACT_IDX artifact_index = letter[idx].artifact;
3097 g_ptr->feat = conv_dungeon_feat(floor_ptr, letter[idx].feature);
3098 if (init_flags & INIT_ONLY_FEATURES) continue;
3100 g_ptr->info = letter[idx].cave_info;
3101 if (random & RANDOM_MONSTER)
3103 floor_ptr->monster_level = floor_ptr->base_level + monster_index;
3105 place_monster(player_ptr, *y, *x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
3107 floor_ptr->monster_level = floor_ptr->base_level;
3109 else if (monster_index)
3111 int old_cur_num, old_max_num;
3114 if (monster_index < 0)
3116 monster_index = -monster_index;
3120 old_cur_num = r_info[monster_index].cur_num;
3121 old_max_num = r_info[monster_index].max_num;
3123 if (r_info[monster_index].flags1 & RF1_UNIQUE)
3125 r_info[monster_index].cur_num = 0;
3126 r_info[monster_index].max_num = 1;
3128 else if (r_info[monster_index].flags7 & RF7_NAZGUL)
3130 if (r_info[monster_index].cur_num == r_info[monster_index].max_num)
3132 r_info[monster_index].max_num++;
3136 place_monster_aux(player_ptr, 0, *y, *x, monster_index, (PM_ALLOW_SLEEP | PM_NO_KAGE));
3139 floor_ptr->m_list[hack_m_idx_ii].smart |= SM_CLONED;
3140 r_info[monster_index].cur_num = old_cur_num;
3141 r_info[monster_index].max_num = old_max_num;
3145 if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP))
3147 floor_ptr->object_level = floor_ptr->base_level + object_index;
3150 * Random trap and random treasure defined
3151 * 25% chance for trap and 75% chance for object
3153 if (randint0(100) < 75)
3155 place_object(player_ptr, *y, *x, 0L);
3159 place_trap(player_ptr, *y, *x);
3162 floor_ptr->object_level = floor_ptr->base_level;
3164 else if (random & RANDOM_OBJECT)
3166 floor_ptr->object_level = floor_ptr->base_level + object_index;
3167 if (randint0(100) < 75)
3168 place_object(player_ptr, *y, *x, 0L);
3169 else if (randint0(100) < 80)
3170 place_object(player_ptr, *y, *x, AM_GOOD);
3172 place_object(player_ptr, *y, *x, AM_GOOD | AM_GREAT);
3174 floor_ptr->object_level = floor_ptr->base_level;
3176 else if (random & RANDOM_TRAP)
3178 place_trap(player_ptr, *y, *x);
3180 else if (letter[idx].trap)
3182 g_ptr->mimic = g_ptr->feat;
3183 g_ptr->feat = conv_dungeon_feat(floor_ptr, letter[idx].trap);
3185 else if (object_index)
3187 object_type *o_ptr = &object_type_body;
3188 object_prep(o_ptr, object_index);
3189 if (o_ptr->tval == TV_GOLD)
3191 coin_type = object_index - OBJ_GOLD_LIST;
3192 make_gold(floor_ptr, o_ptr);
3196 apply_magic(player_ptr, o_ptr, floor_ptr->base_level, AM_NO_FIXED_ART | AM_GOOD);
3197 drop_here(floor_ptr, o_ptr, *y, *x);
3202 if (a_info[artifact_index].cur_num)
3204 KIND_OBJECT_IDX k_idx = lookup_kind(TV_SCROLL, SV_SCROLL_ACQUIREMENT);
3206 object_type *q_ptr = &forge;
3208 object_prep(q_ptr, k_idx);
3209 drop_here(floor_ptr, q_ptr, *y, *x);
3213 if (create_named_art(player_ptr, artifact_index, *y, *x))
3214 a_info[artifact_index].cur_num = 1;
3218 g_ptr->special = letter[idx].special;
3224 else if (buf[0] == 'Q')
3231 num = tokenize(buf + 2, 33, zz, 0);
3235 num = tokenize(buf + 3, 33, zz, 0);
3238 if (num < 3) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3240 q_ptr = &(quest[atoi(zz[0])]);
3241 if (zz[1][0] == 'Q')
3243 if (init_flags & INIT_ASSIGN)
3245 monster_race *r_ptr;
3246 artifact_type *a_ptr;
3248 if (num < 9) return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
3250 q_ptr->type = (QUEST_TYPE)atoi(zz[2]);
3251 q_ptr->num_mon = (MONSTER_NUMBER)atoi(zz[3]);
3252 q_ptr->cur_num = (MONSTER_NUMBER)atoi(zz[4]);
3253 q_ptr->max_num = (MONSTER_NUMBER)atoi(zz[5]);
3254 q_ptr->level = (DEPTH)atoi(zz[6]);
3255 q_ptr->r_idx = (IDX)atoi(zz[7]);
3256 q_ptr->k_idx = (IDX)atoi(zz[8]);
3257 q_ptr->dungeon = (DUNGEON_IDX)atoi(zz[9]);
3259 if (num > 10) q_ptr->flags = atoi(zz[10]);
3261 r_ptr = &r_info[q_ptr->r_idx];
3262 if (r_ptr->flags1 & RF1_UNIQUE)
3263 r_ptr->flags1 |= RF1_QUESTOR;
3265 a_ptr = &a_info[q_ptr->k_idx];
3266 a_ptr->gen_flags |= TRG_QUESTITEM;
3271 else if (zz[1][0] == 'R')
3273 if (init_flags & INIT_ASSIGN)
3276 IDX idx, reward_idx = 0;
3278 for (idx = 2; idx < num; idx++)
3280 IDX a_idx = (IDX)atoi(zz[idx]);
3281 if (a_idx < 1) continue;
3282 if (a_info[a_idx].cur_num > 0) continue;
3284 if (one_in_(count)) reward_idx = a_idx;
3289 q_ptr->k_idx = reward_idx;
3290 a_info[reward_idx].gen_flags |= TRG_QUESTITEM;
3294 q_ptr->type = QUEST_TYPE_KILL_ALL;
3300 else if (zz[1][0] == 'N')
3302 if (init_flags & (INIT_ASSIGN | INIT_SHOW_TEXT | INIT_NAME_ONLY))
3304 strcpy(q_ptr->name, zz[2]);
3309 else if (zz[1][0] == 'T')
3311 if (init_flags & INIT_SHOW_TEXT)
3313 strcpy(quest_text[quest_text_line], zz[2]);
3320 else if (buf[0] == 'W')
3322 return parse_line_wilderness(player_ptr, buf, xmin, xmax, y, x);
3324 else if (buf[0] == 'P')
3326 if (init_flags & INIT_CREATE_DUNGEON)
3328 if (tokenize(buf + 2, 2, zz, 0) == 2)
3330 int panels_x, panels_y;
3332 panels_y = (*y / SCREEN_HGT);
3333 if (*y % SCREEN_HGT) panels_y++;
3334 floor_ptr->height = panels_y * SCREEN_HGT;
3336 panels_x = (*x / SCREEN_WID);
3337 if (*x % SCREEN_WID) panels_x++;
3338 floor_ptr->width = panels_x * SCREEN_WID;
3340 panel_row_min = floor_ptr->height;
3341 panel_col_min = floor_ptr->width;
3343 if (floor_ptr->inside_quest)
3345 delete_monster(player_ptr, player_ptr->y, player_ptr->x);
3347 POSITION py = atoi(zz[0]);
3348 POSITION px = atoi(zz[1]);
3353 else if (!player_ptr->oldpx && !player_ptr->oldpy)
3355 player_ptr->oldpy = atoi(zz[0]);
3356 player_ptr->oldpx = atoi(zz[1]);
3363 else if (buf[0] == 'B')
3365 return parse_line_building(buf);
3367 else if (buf[0] == 'M')
3369 if (tokenize(buf + 2, 2, zz, 0) == 2)
3371 if (zz[0][0] == 'T')
3373 max_towns = (TOWN_IDX)atoi(zz[1]);
3375 else if (zz[0][0] == 'Q')
3377 max_q_idx = (QUEST_IDX)atoi(zz[1]);
3379 else if (zz[0][0] == 'R')
3381 max_r_idx = (RACE_IDX)atoi(zz[1]);
3383 else if (zz[0][0] == 'K')
3385 max_k_idx = (KIND_OBJECT_IDX)atoi(zz[1]);
3387 else if (zz[0][0] == 'V')
3389 max_v_idx = (VAULT_IDX)atoi(zz[1]);
3391 else if (zz[0][0] == 'F')
3393 max_f_idx = (FEAT_IDX)atoi(zz[1]);
3395 else if (zz[0][0] == 'A')
3397 max_a_idx = (ARTIFACT_IDX)atoi(zz[1]);
3399 else if (zz[0][0] == 'E')
3401 max_e_idx = (EGO_IDX)atoi(zz[1]);
3403 else if (zz[0][0] == 'D')
3405 current_world_ptr->max_d_idx = (DUNGEON_IDX)atoi(zz[1]);
3407 else if (zz[0][0] == 'O')
3409 current_world_ptr->max_o_idx = (OBJECT_IDX)atoi(zz[1]);
3411 else if (zz[0][0] == 'M')
3413 current_world_ptr->max_m_idx = (MONSTER_IDX)atoi(zz[1]);
3415 else if (zz[0][0] == 'W')
3417 if (zz[0][1] == 'X')
3418 current_world_ptr->max_wild_x = (POSITION)atoi(zz[1]);
3420 if (zz[0][1] == 'Y')
3421 current_world_ptr->max_wild_y = (POSITION)atoi(zz[1]);
3432 * todo ここから先頭に移すとコンパイル警告が出る……
3435 static concptr variant = "ZANGBAND";
3438 * @brief クエスト用固定ダンジョン生成時の分岐処理
3439 * Helper function for "process_dungeon_file()"
3440 * @param player_ptr プレーヤーへの参照ポインタ
3445 static concptr process_dungeon_file_expr(player_type *player_ptr, char **sp, char *fp)
3455 while (iswspace(*s)) s++;
3459 concptr v = "?o?o?";
3465 t = process_dungeon_file_expr(player_ptr, &s, &f);
3470 else if (streq(t, "IOR"))
3473 while (*s && (f != b2))
3475 t = process_dungeon_file_expr(player_ptr, &s, &f);
3476 if (*t && !streq(t, "0")) v = "1";
3479 else if (streq(t, "AND"))
3482 while (*s && (f != b2))
3484 t = process_dungeon_file_expr(player_ptr, &s, &f);
3485 if (*t && streq(t, "0")) v = "0";
3488 else if (streq(t, "NOT"))
3491 while (*s && (f != b2))
3493 t = process_dungeon_file_expr(player_ptr, &s, &f);
3494 if (*t && streq(t, "1")) v = "0";
3497 else if (streq(t, "EQU"))
3500 if (*s && (f != b2))
3502 t = process_dungeon_file_expr(player_ptr, &s, &f);
3505 while (*s && (f != b2))
3507 p = process_dungeon_file_expr(player_ptr, &s, &f);
3508 if (streq(t, p)) v = "1";
3511 else if (streq(t, "LEQ"))
3514 if (*s && (f != b2))
3516 t = process_dungeon_file_expr(player_ptr, &s, &f);
3519 while (*s && (f != b2))
3522 t = process_dungeon_file_expr(player_ptr, &s, &f);
3523 if (*t && atoi(p) > atoi(t)) v = "0";
3526 else if (streq(t, "GEQ"))
3529 if (*s && (f != b2))
3531 t = process_dungeon_file_expr(player_ptr, &s, &f);
3534 while (*s && (f != b2))
3537 t = process_dungeon_file_expr(player_ptr, &s, &f);
3538 if (*t && atoi(p) < atoi(t)) v = "0";
3543 while (*s && (f != b2))
3545 t = process_dungeon_file_expr(player_ptr, &s, &f);
3549 if (f != b2) v = "?x?x?";
3550 if ((f = *s) != '\0') *s++ = '\0';
3558 while (iskanji(*s) || (isprint(*s) && !my_strchr(" []", *s)))
3560 if (iskanji(*s)) s++;
3564 while (isprint(*s) && !my_strchr(" []", *s)) ++s;
3566 if ((f = *s) != '\0') *s++ = '\0';
3576 if (streq(b + 1, "SYS"))
3580 else if (streq(b + 1, "GRAF"))
3584 else if (streq(b + 1, "MONOCHROME"))
3591 else if (streq(b + 1, "RACE"))
3593 v = _(rp_ptr->E_title, rp_ptr->title);
3595 else if (streq(b + 1, "CLASS"))
3597 v = _(cp_ptr->E_title, cp_ptr->title);
3599 else if (streq(b + 1, "REALM1"))
3601 v = _(E_realm_names[player_ptr->realm1], realm_names[player_ptr->realm1]);
3603 else if (streq(b + 1, "REALM2"))
3605 v = _(E_realm_names[player_ptr->realm2], realm_names[player_ptr->realm2]);
3607 else if (streq(b + 1, "PLAYER"))
3609 static char tmp_player_name[32];
3611 for (pn = player_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++)
3621 *tpn = my_strchr(" []", *pn) ? '_' : *pn;
3625 v = tmp_player_name;
3627 else if (streq(b + 1, "TOWN"))
3629 sprintf(tmp, "%d", player_ptr->town_num);
3632 else if (streq(b + 1, "LEVEL"))
3634 sprintf(tmp, "%d", player_ptr->lev);
3637 else if (streq(b + 1, "QUEST_NUMBER"))
3639 sprintf(tmp, "%d", player_ptr->current_floor_ptr->inside_quest);
3642 else if (streq(b + 1, "LEAVING_QUEST"))
3644 sprintf(tmp, "%d", leaving_quest);
3647 else if (prefix(b + 1, "QUEST_TYPE"))
3649 sprintf(tmp, "%d", quest[atoi(b + 11)].type);
3652 else if (prefix(b + 1, "QUEST"))
3654 sprintf(tmp, "%d", quest[atoi(b + 6)].status);
3657 else if (prefix(b + 1, "RANDOM"))
3659 sprintf(tmp, "%d", (int)(current_world_ptr->seed_town%atoi(b + 7)));
3662 else if (streq(b + 1, "VARIANT"))
3666 else if (streq(b + 1, "WILDERNESS"))
3669 sprintf(tmp, "NONE");
3671 sprintf(tmp, "LITE");
3673 sprintf(tmp, "NORMAL");
3684 * @brief クエスト用固定ダンジョン生成時のメインルーチン
3685 * Helper function for "process_dungeon_file()"
3686 * @param player_ptr プレーヤーへの参照ポインタ
3694 errr process_dungeon_file(player_type *player_ptr, concptr name, int ymin, int xmin, int ymax, int xmax)
3697 path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, name);
3699 fp = my_fopen(buf, "r");
3705 bool bypass = FALSE;
3706 int x = xmin, y = ymin;
3707 while (my_fgets(fp, buf, sizeof(buf)) == 0)
3710 if (!buf[0]) continue;
3711 if (iswspace(buf[0])) continue;
3712 if (buf[0] == '#') continue;
3713 if ((buf[0] == '?') && (buf[1] == ':'))
3718 concptr v = process_dungeon_file_expr(player_ptr, &s, &f);
3719 bypass = (streq(v, "0") ? TRUE : FALSE);
3723 if (bypass) continue;
3725 err = process_dungeon_file_aux(player_ptr, buf, ymin, xmin, ymax, xmax, &y, &x);
3731 concptr oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
3732 msg_format("Error %d (%s) at line %d of '%s'.", err, oops, num, name);
3733 msg_format(_("'%s'を解析中。", "Parsing '%s'."), buf);