OSDN Git Service

[Refactor] #2651 get_random_line() の引数からchar *を削除し、返り値をstd::optional<std::string...
[hengbandforosx/hengbandosx.git] / src / flavor / object-flavor.cpp
1 /*!
2  *  @brief オブジェクトの記述処理 / Mbject flavor code
3  *  @date 2014/01/03
4  *  @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  *\n
7  * This software may be copied and distributed for educational, research,\n
8  * and not for profit purposes provided that this copyright and statement\n
9  * are included in all such copies.  Other copyrights may also apply.\n
10  */
11
12 #include "flavor/object-flavor.h"
13 #include "combat/shoot.h"
14 #include "flavor/flag-inscriptions-table.h"
15 #include "flavor/flavor-util.h"
16 #include "flavor/object-flavor-types.h"
17 #include "game-option/text-display-options.h"
18 #include "grid/trap.h"
19 #include "inventory/inventory-slot-types.h"
20 #include "io/files-util.h"
21 #include "locale/english.h"
22 #include "locale/japanese.h"
23 #include "mind/mind-sniper.h"
24 #include "mind/mind-weaponsmith.h"
25 #include "monster-race/monster-race.h"
26 #include "monster-race/race-flags1.h"
27 #include "object-enchant/object-ego.h"
28 #include "object-enchant/special-object-flags.h"
29 #include "object-enchant/tr-types.h"
30 #include "object-enchant/trg-types.h"
31 #include "object-hook/hook-quest.h"
32 #include "object/object-flags.h"
33 #include "object/object-info.h"
34 #include "perception/object-perception.h"
35 #include "player-info/class-info.h"
36 #include "player/player-status.h"
37 #include "sv-definition/sv-food-types.h"
38 #include "sv-definition/sv-lite-types.h"
39 #include "system/baseitem-info.h"
40 #include "util/bit-flags-calculator.h"
41 #include "util/quarks.h"
42 #include "util/string-processor.h"
43 #include "world/world.h"
44 #include <functional>
45 #include <sstream>
46 #include <utility>
47
48 /*!
49  * @brief 最初から簡易な名称が明らかになるベースアイテムの判定。 /  Certain items, if aware, are known instantly
50  * @param i ベースアイテムID
51  * @return 簡易名称を明らかにするならTRUEを返す。
52  * @details
53  * This function is used only by "flavor_init()"
54  */
55 static bool object_easy_know(int i)
56 {
57     const auto &baseitem = baseitems_info[i];
58     switch (baseitem.bi_key.tval()) {
59     case ItemKindType::LIFE_BOOK:
60     case ItemKindType::SORCERY_BOOK:
61     case ItemKindType::NATURE_BOOK:
62     case ItemKindType::CHAOS_BOOK:
63     case ItemKindType::DEATH_BOOK:
64     case ItemKindType::TRUMP_BOOK:
65     case ItemKindType::ARCANE_BOOK:
66     case ItemKindType::CRAFT_BOOK:
67     case ItemKindType::DEMON_BOOK:
68     case ItemKindType::CRUSADE_BOOK:
69     case ItemKindType::MUSIC_BOOK:
70     case ItemKindType::HISSATSU_BOOK:
71     case ItemKindType::HEX_BOOK:
72         return true;
73     case ItemKindType::FLASK:
74     case ItemKindType::JUNK:
75     case ItemKindType::BOTTLE:
76     case ItemKindType::SKELETON:
77     case ItemKindType::SPIKE:
78     case ItemKindType::WHISTLE:
79         return true;
80     case ItemKindType::FOOD:
81     case ItemKindType::POTION:
82     case ItemKindType::SCROLL:
83     case ItemKindType::ROD:
84         return true;
85
86     default:
87         break;
88     }
89
90     return false;
91 }
92
93 /*!
94  * @brief 各種語彙からランダムな名前を作成する
95  * @return std::string 作成した名前
96  * @details 日本語の場合 aname_j.txt 英語の場合確率に応じて
97  * syllables 配列と elvish.txt を組み合わせる
98  */
99 std::string get_table_name_aux()
100 {
101     std::stringstream ss;
102 #ifdef JP
103     ss << get_random_line("aname_j.txt", 1).value();
104     ss << get_random_line("aname_j.txt", 2).value();
105     return ss.str();
106 #else
107     static std::vector<std::string_view> syllables = {
108         "a", "ab", "ag", "aks", "ala", "an", "ankh", "app", "arg", "arze", "ash", "aus", "ban", "bar", "bat", "bek",
109         "bie", "bin", "bit", "bjor", "blu", "bot", "bu", "byt", "comp", "con", "cos", "cre", "dalf", "dan", "den", "der", "doe", "dok", "eep", "el", "eng",
110         "er", "ere", "erk", "esh", "evs", "fa", "fid", "flit", "for", "fri", "fu", "gan", "gar", "glen", "gop", "gre", "ha", "he", "hyd", "i", "ing", "ion",
111         "ip", "ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech", "man", "mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", "nag", "nej",
112         "nelg", "nep", "ner", "nes", "nis", "nih", "nin", "o", "od", "ood", "org", "orn", "ox", "oxy", "pay", "pet", "ple", "plu", "po", "pot", "prok", "re",
113         "rea", "rhov", "ri", "ro", "rog", "rok", "rol", "sa", "san", "sat", "see", "sef", "seh", "shu", "ski", "sna", "sne", "snik", "sno", "so", "sol", "sri",
114         "sta", "sun", "ta", "tab", "tem", "ther", "ti", "tox", "trol", "tue", "turs", "u", "ulk", "um", "un", "uni", "ur", "val", "viv", "vly", "vom", "wah",
115         "wed", "werg", "wex", "whon", "wun", "x", "yerg", "yp", "zun", "tri", "blaa", "jah", "bul", "on", "foo", "ju", "xuxu"
116     };
117
118     int testcounter = randint1(3) + 1;
119     if (randint1(3) == 2) {
120         while (testcounter--) {
121             ss << syllables[randint0(syllables.size())];
122         }
123     } else {
124         testcounter = randint1(2) + 1;
125         while (testcounter--) {
126             ss << get_random_line("elvish.txt", 0).value();
127         }
128     }
129
130     auto name = ss.str();
131     name[0] = toupper(name[0]);
132     return name;
133 #endif
134 }
135
136 /*!
137  * @brief ランダムな名前をアーティファクト銘として整形する。 / Create a name from random parts with quotes.
138  * @return std::string 作成した名前
139  * @details get_table_name_aux()ほぼ完全に実装を依存している。
140  */
141 std::string get_table_name()
142 {
143     return std::string(_("『", "'")).append(get_table_name_aux()).append(_("』", "'"));
144 }
145
146 /*!
147  * @brief ランダムなシンダリン銘を作成する / Make random Sindarin name
148  * @return std::string 作成した名前
149  * @details sname.txtが語幹の辞書となっている。
150  */
151 std::string get_table_sindarin_aux()
152 {
153     std::stringstream ss;
154     ss << get_random_line("sname.txt", 1).value();
155     ss << get_random_line("sname.txt", 2).value();
156     auto name = ss.str();
157     return _(sindarin_to_kana(name), name);
158 }
159
160 /*!
161  * @brief シンダリン銘をアーティファクト用に整形する。 / Make random Sindarin name with quotes
162  * @param out_string 作成した名を保管する参照ポインタ
163  * @return std::string 作成した名前
164  * @details get_table_sindarin_aux()ほぼ完全に実装を依存している。
165  */
166 std::string get_table_sindarin()
167 {
168     return std::string(_("『", "'")).append(get_table_sindarin_aux()).append(_("』", "'"));
169 }
170
171 /*!
172  * @brief ベースアイテムの未確定名を共通tval間でシャッフルする / Shuffle flavor indices of a group of objects with given tval
173  * @param tval シャッフルしたいtval
174  * @details 巻物、各種魔道具などに利用される。
175  */
176 static void shuffle_flavors(ItemKindType tval)
177 {
178     std::vector<std::reference_wrapper<IDX>> flavor_idx_ref_list;
179     for (const auto &baseitem : baseitems_info) {
180         if (baseitem.bi_key.tval() != tval) {
181             continue;
182         }
183
184         if (baseitem.flavor == 0) {
185             continue;
186         }
187
188         if (baseitem.flags.has(TR_FIXED_FLAVOR)) {
189             continue;
190         }
191
192         flavor_idx_ref_list.push_back(baseitems_info[baseitem.idx].flavor);
193     }
194
195     rand_shuffle(flavor_idx_ref_list.begin(), flavor_idx_ref_list.end());
196 }
197
198 /*!
199  * @brief ゲーム開始時に行われるベースアイテムの初期化ルーチン
200  * @param なし
201  */
202 void flavor_init(void)
203 {
204     const auto state_backup = w_ptr->rng.get_state();
205     w_ptr->rng.set_state(w_ptr->seed_flavor);
206     for (auto &baseitem : baseitems_info) {
207         if (baseitem.flavor_name.empty()) {
208             continue;
209         }
210
211         baseitem.flavor = baseitem.idx;
212     }
213
214     shuffle_flavors(ItemKindType::RING);
215     shuffle_flavors(ItemKindType::AMULET);
216     shuffle_flavors(ItemKindType::STAFF);
217     shuffle_flavors(ItemKindType::WAND);
218     shuffle_flavors(ItemKindType::ROD);
219     shuffle_flavors(ItemKindType::FOOD);
220     shuffle_flavors(ItemKindType::POTION);
221     shuffle_flavors(ItemKindType::SCROLL);
222     w_ptr->rng.set_state(state_backup);
223     for (auto &baseitem : baseitems_info) {
224         if (baseitem.idx == 0 || baseitem.name.empty()) {
225             continue;
226         }
227
228         if (!baseitem.flavor) {
229             baseitem.aware = true;
230         }
231
232         baseitem.easy_know = object_easy_know(baseitem.idx);
233     }
234 }
235
236 /*!
237  * @brief nameバッファ内からベースアイテム名を返す / Strip an "object name" into a buffer
238  * @param buf ベースアイテム格納先の参照ポインタ
239  * @param bi_id ベースアイテムID
240  */
241 std::string strip_name(short bi_id)
242 {
243     const auto &baseitem = baseitems_info[bi_id];
244     auto tok = str_split(baseitem.name, ' ');
245     std::stringstream name;
246     for (const auto &s : tok) {
247         if (s == "" || s == "~" || s == "&" || s == "#") {
248             continue;
249         }
250
251         auto offset = 0;
252         auto endpos = s.size();
253         auto is_kanji = false;
254
255         if (s[0] == '~' || s[0] == '#') {
256             offset++;
257         }
258 #ifdef JP
259         if (s.size() > 2) {
260             is_kanji = iskanji(s[endpos - 2]);
261         }
262
263 #endif
264         if (!is_kanji && (s[endpos - 1] == '~' || s[endpos - 1] == '#')) {
265             endpos--;
266         }
267
268         name << s.substr(offset, endpos);
269     }
270
271     name << " ";
272     return name.str();
273 }