OSDN Git Service

[Fix] mutation-flag-types.h のインクルード関係
[hengbandforosx/hengbandosx.git] / src / inventory / inventory-util.cpp
1 /*!
2  * @brief インベントリ関係のユーティリティ
3  * @date 2020/07/02
4  * @author Hourier
5  * @details 少々雑多なので後で整理を検討する
6  */
7
8 #include "inventory/inventory-util.h"
9 #include "core/asking-player.h"
10 #include "flavor/flavor-describer.h"
11 #include "inventory/inventory-slot-types.h"
12 #include "io/input-key-requester.h"
13 #include "object/item-tester-hooker.h"
14 #include "object/item-use-flags.h"
15 #include "system/floor-type-definition.h"
16 #include "system/object-type-definition.h"
17 #include "system/player-type-definition.h"
18 #include "util/int-char-converter.h"
19 #include "util/quarks.h"
20 #include "util/string-processor.h"
21
22 /*!
23  * @brief プレイヤーの所持/装備オブジェクトIDが指輪枠かを返す /
24  * @param i プレイヤーの所持/装備オブジェクトID
25  * @return 指輪枠ならばTRUEを返す。
26  */
27 bool is_ring_slot(int i) { return (i == INVEN_MAIN_RING) || (i == INVEN_SUB_RING); }
28
29 /*!
30  * @brief 床オブジェクトに選択タグを与える/タグに該当するオブジェクトがあるかを返す /
31  * Find the "first" inventory object with the given "tag".
32  * @param cp 対応するタグIDを与える参照ポインタ
33  * @param tag 該当するオブジェクトがあるかを調べたいタグ
34  * @param floor_list 床上アイテムの配列
35  * @param floor_num  床上アイテムの配列ID
36  * @return タグに該当するオブジェクトがあるならTRUEを返す
37  * @details
38  * A "tag" is a numeral "n" appearing as "@n" anywhere in the\n
39  * inscription of an object.  Alphabetical characters don't work as a\n
40  * tag in this form.\n
41  *\n
42  * Also, the tag "@xn" will work as well, where "n" is a any tag-char,\n
43  * and "x" is the "current" command_cmd code.\n
44  */
45 bool get_tag_floor(floor_type *floor_ptr, COMMAND_CODE *cp, char tag, FLOOR_IDX floor_list[], ITEM_NUMBER floor_num)
46 {
47     for (COMMAND_CODE i = 0; i < floor_num && i < 23; i++) {
48         object_type *o_ptr = &floor_ptr->o_list[floor_list[i]];
49         if (!o_ptr->inscription)
50             continue;
51
52         concptr s = angband_strchr(quark_str(o_ptr->inscription), '@');
53         while (s) {
54             if ((s[1] == command_cmd) && (s[2] == tag)) {
55                 *cp = i;
56                 return TRUE;
57             }
58
59             s = angband_strchr(s + 1, '@');
60         }
61     }
62
63     if (tag < '0' || '9' < tag) {
64         return FALSE;
65     }
66
67     for (COMMAND_CODE i = 0; i < floor_num && i < 23; i++) {
68         object_type *o_ptr = &floor_ptr->o_list[floor_list[i]];
69         if (!o_ptr->inscription)
70             continue;
71
72         concptr s = angband_strchr(quark_str(o_ptr->inscription), '@');
73         while (s) {
74             if (s[1] == tag) {
75                 *cp = i;
76                 return TRUE;
77             }
78
79             s = angband_strchr(s + 1, '@');
80         }
81     }
82
83     return FALSE;
84 }
85
86 /*!
87  * @brief 所持/装備オブジェクトに選択タグを与える/タグに該当するオブジェクトがあるかを返す /
88  * Find the "first" inventory object with the given "tag".
89  * @param owner_ptr プレーヤーへの参照ポインタ
90  * @param cp 対応するタグIDを与える参照ポインタ
91  * @param tag 該当するオブジェクトがあるかを調べたいタグ
92  * @param mode 所持、装備の切り替え
93  * @return タグに該当するオブジェクトがあるならTRUEを返す
94  * @details
95  * A "tag" is a numeral "n" appearing as "@n" anywhere in the\n
96  * inscription of an object.  Alphabetical characters don't work as a\n
97  * tag in this form.\n
98  *\n
99  * Also, the tag "@xn" will work as well, where "n" is a any tag-char,\n
100  * and "x" is the "current" command_cmd code.\n
101  */
102 bool get_tag(player_type *owner_ptr, COMMAND_CODE *cp, char tag, BIT_FLAGS mode, tval_type tval)
103 {
104     COMMAND_CODE start, end;
105     switch (mode) {
106     case USE_EQUIP:
107         start = INVEN_MAIN_HAND;
108         end = INVEN_TOTAL - 1;
109         break;
110
111     case USE_INVEN:
112         start = 0;
113         end = INVEN_PACK - 1;
114         break;
115
116     default:
117         return FALSE;
118     }
119
120     for (COMMAND_CODE i = start; i <= end; i++) {
121         object_type *o_ptr = &owner_ptr->inventory_list[i];
122         if ((o_ptr->k_idx == 0) || (o_ptr->inscription == 0))
123             continue;
124
125         if (!item_tester_okay(owner_ptr, o_ptr, tval) && !(mode & USE_FULL))
126             continue;
127
128         concptr s = angband_strchr(quark_str(o_ptr->inscription), '@');
129         while (s) {
130             if ((s[1] == command_cmd) && (s[2] == tag)) {
131                 *cp = i;
132                 return TRUE;
133             }
134
135             s = angband_strchr(s + 1, '@');
136         }
137     }
138
139     if (tag < '0' || '9' < tag)
140         return FALSE;
141
142     for (COMMAND_CODE i = start; i <= end; i++) {
143         object_type *o_ptr = &owner_ptr->inventory_list[i];
144         if ((o_ptr->k_idx == 0) || (o_ptr->inscription == 0))
145             continue;
146
147         if (!item_tester_okay(owner_ptr, o_ptr, tval) && !(mode & USE_FULL))
148             continue;
149
150         concptr s = angband_strchr(quark_str(o_ptr->inscription), '@');
151         while (s) {
152             if (s[1] == tag) {
153                 *cp = i;
154                 return TRUE;
155             }
156
157             s = angband_strchr(s + 1, '@');
158         }
159     }
160
161     return FALSE;
162 }
163
164 /*!
165  * @brief プレイヤーの所持/装備オブジェクトが正規のものかを返す /
166  * Auxiliary function for "get_item()" -- test an index
167  * @param i 選択アイテムID
168  * @return 正規のIDならばTRUEを返す。
169  */
170 bool get_item_okay(player_type *owner_ptr, OBJECT_IDX i, tval_type item_tester_tval)
171 {
172     if ((i < 0) || (i >= INVEN_TOTAL))
173         return FALSE;
174
175     if (owner_ptr->select_ring_slot)
176         return is_ring_slot(i);
177
178     return item_tester_okay(owner_ptr, &owner_ptr->inventory_list[i], item_tester_tval);
179 }
180
181 /*!
182  * @brief 選択したアイテムの確認処理のメインルーチン /
183  * @param owner_ptr プレーヤーへの参照ポインタ
184  * @param item 選択アイテムID
185  * @return 確認がYesならTRUEを返す。
186  * @details The item can be negative to mean "item on floor".
187  * Hack -- allow user to "prevent" certain choices
188  */
189 bool get_item_allow(player_type *owner_ptr, INVENTORY_IDX item)
190 {
191     if (!command_cmd)
192         return TRUE;
193
194     object_type *o_ptr;
195     if (item >= 0)
196         o_ptr = &owner_ptr->inventory_list[item];
197     else
198         o_ptr = &owner_ptr->current_floor_ptr->o_list[0 - item];
199
200     if (!o_ptr->inscription)
201         return TRUE;
202
203     concptr s = angband_strchr(quark_str(o_ptr->inscription), '!');
204     while (s) {
205         if ((s[1] == command_cmd) || (s[1] == '*'))
206             if (!verify(owner_ptr, _("本当に", "Really try"), item))
207                 return FALSE;
208
209         s = angband_strchr(s + 1, '!');
210     }
211
212     return TRUE;
213 }
214
215 /*!
216  * @brief 選択アルファベットラベルからプレイヤーの装備オブジェクトIDを返す /
217  * @param owner_ptr プレーヤーへの参照ポインタ
218  * Convert a label into the index of a item in the "equip"
219  * @return 対応するID。該当スロットにオブジェクトが存在しなかった場合-1を返す / Return "-1" if the label does not indicate a real item
220  */
221 INVENTORY_IDX label_to_equipment(player_type *owner_ptr, int c)
222 {
223     INVENTORY_IDX i = (INVENTORY_IDX)(islower(c) ? A2I(c) : -1) + INVEN_MAIN_HAND;
224
225     if ((i < INVEN_MAIN_HAND) || (i >= INVEN_TOTAL))
226         return -1;
227
228     if (owner_ptr->select_ring_slot)
229         return is_ring_slot(i) ? i : -1;
230
231     if (!owner_ptr->inventory_list[i].k_idx)
232         return -1;
233
234     return i;
235 }
236
237 /*!
238  * @brief 選択アルファベットラベルからプレイヤーの所持オブジェクトIDを返す /
239  * Convert a label into the index of an item in the "inven"
240  * @param owner_ptr プレーヤーへの参照ポインタ
241  * @param c 選択されたアルファベット
242  * @return 対応するID。該当スロットにオブジェクトが存在しなかった場合-1を返す / Return "-1" if the label does not indicate a real item
243  * @details Note that the label does NOT distinguish inven/equip.
244  */
245 INVENTORY_IDX label_to_inventory(player_type *owner_ptr, int c)
246 {
247     INVENTORY_IDX i = (INVENTORY_IDX)(islower(c) ? A2I(c) : -1);
248
249     if ((i < 0) || (i > INVEN_PACK) || (owner_ptr->inventory_list[i].k_idx == 0))
250         return -1;
251
252     return i;
253 }
254
255 /*!
256  * @brief 選択したアイテムの確認処理の補助 /
257  * Verify the choice of an item.
258  * @param owner_ptr プレーヤーへの参照ポインタ
259  * @param prompt メッセージ表示の一部
260  * @param item 選択アイテムID
261  * @return 確認がYesならTRUEを返す。
262  * @details The item can be negative to mean "item on floor".
263  */
264 bool verify(player_type *owner_ptr, concptr prompt, INVENTORY_IDX item)
265 {
266     GAME_TEXT o_name[MAX_NLEN];
267     char out_val[MAX_NLEN + 20];
268     object_type *o_ptr;
269     if (item >= 0)
270         o_ptr = &owner_ptr->inventory_list[item];
271     else
272         o_ptr = &owner_ptr->current_floor_ptr->o_list[0 - item];
273
274     describe_flavor(owner_ptr, o_name, o_ptr, 0);
275     (void)sprintf(out_val, _("%s%sですか? ", "%s %s? "), prompt, o_name);
276     return get_check(out_val);
277 }
278
279 /*!
280  * @brief タグIDにあわせてタグアルファベットのリストを返す /
281  * Move around label characters with correspond tags
282  * @param owner_ptr プレーヤーへの参照ポインタ
283  * @param label ラベルリストを取得する文字列参照ポインタ
284  * @param mode 所持品リストか装備品リストかの切り替え
285  */
286 void prepare_label_string(player_type *owner_ptr, char *label, BIT_FLAGS mode, tval_type tval)
287 {
288     concptr alphabet_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
289     int offset = (mode == USE_EQUIP) ? INVEN_MAIN_HAND : 0;
290     strcpy(label, alphabet_chars);
291     for (int i = 0; i < 52; i++) {
292         COMMAND_CODE index;
293         SYMBOL_CODE c = alphabet_chars[i];
294         if (!get_tag(owner_ptr, &index, c, mode, tval))
295             continue;
296
297         if (label[i] == c)
298             label[i] = ' ';
299
300         label[index - offset] = c;
301     }
302 }