OSDN Git Service

[Refactor] #2233 name2をego_idxに改名した
[hengbandforosx/hengbandosx.git] / src / wizard / wizard-item-modifier.cpp
1 #include "wizard/wizard-item-modifier.h"
2 #include "artifact/fixed-art-generator.h"
3 #include "artifact/random-art-effects.h"
4 #include "artifact/random-art-generator.h"
5 #include "core/asking-player.h"
6 #include "core/show-file.h"
7 #include "core/player-update-types.h"
8 #include "core/window-redrawer.h"
9 #include "core/stuff-handler.h"
10 #include "flavor/flavor-describer.h"
11 #include "flavor/object-flavor-types.h"
12 #include "floor/floor-object.h"
13 #include "game-option/cheat-options.h"
14 #include "inventory/inventory-slot-types.h"
15 #include "io/input-key-acceptor.h"
16 #include "io/input-key-requester.h"
17 #include "object-enchant/apply-magic.h"
18 #include "object-enchant/item-apply-magic.h"
19 #include "object-enchant/object-ego.h"
20 #include "object-enchant/special-object-flags.h"
21 #include "object-enchant/tr-types.h"
22 #include "object/item-use-flags.h"
23 #include "object/object-flags.h"
24 #include "object/object-info.h"
25 #include "object/object-kind.h"
26 #include "object/object-kind-hook.h"
27 #include "object/object-mark-types.h"
28 #include "object/object-value.h"
29 #include "util/bit-flags-calculator.h"
30 #include "util/string-processor.h"
31 #include "spell-kind/spells-perception.h"
32 #include "spell/spells-object.h"
33 #include "system/alloc-entries.h"
34 #include "system/artifact-type-definition.h"
35 #include "system/floor-type-definition.h"
36 #include "system/object-type-definition.h"
37 #include "system/player-type-definition.h"
38 #include "system/system-variables.h"
39 #include "term/screen-processor.h"
40 #include "term/term-color-types.h"
41 #include "view/display-messages.h"
42 #include "util/bit-flags-calculator.h"
43 #include "util/int-char-converter.h"
44 #include "wizard/wizard-special-process.h"
45 #include "world/world.h"
46 #include <algorithm>
47 #include <limits>
48 #include <sstream>
49 #include <tuple>
50 #include <vector>
51
52 #define K_MAX_DEPTH 110 /*!< アイテムの階層毎生成率を表示する最大階 */
53
54 namespace {
55 /*!
56  * @brief アイテム設定コマンド一覧表
57  */
58 constexpr std::array wizard_sub_menu_table = {
59     std::make_tuple('a', _("アーティファクト出現フラグリセット", "Restore aware flag of fixed artifact")),
60     std::make_tuple('A', _("アーティファクトを出現済みにする", "Make a fixed artifact awared")),
61     std::make_tuple('e', _("高級品獲得ドロップ", "Drop excellent object")),
62     std::make_tuple('f', _("*鑑定*", "*Idenfity*")),
63     std::make_tuple('i', _("鑑定", "Idenfity")),
64     std::make_tuple('I', _("インベントリ全*鑑定*", "Idenfity all objects fully in inventory")),
65     std::make_tuple('l', _("指定アイテム番号まで一括鑑定", "Make objects awared to target object id")),
66     std::make_tuple('g', _("上質なアイテムドロップ", "Drop good object")),
67     std::make_tuple('s', _("特別品獲得ドロップ", "Drop special object")),
68     std::make_tuple('w', _("願い", "Wishing")),
69     std::make_tuple('U', _("発動を変更する", "Modify item activation")),
70 };
71
72 /*!
73  * @brief ゲーム設定コマンドの一覧を表示する
74  */
75 void display_wizard_sub_menu()
76 {
77     for (auto y = 1U; y <= wizard_sub_menu_table.size(); y++)
78         term_erase(14, y, 64);
79
80     int r = 1;
81     int c = 15;
82     for (const auto &[symbol, desc] : wizard_sub_menu_table) {
83         std::stringstream ss;
84         ss << symbol << ") " << desc;
85         put_str(ss.str().c_str(), r++, c);
86     }
87 }
88 }
89
90 /*!
91  * @brief キャスト先の型の最小値、最大値でclampする。
92  */
93 template <typename T>
94 T clamp_cast(int val)
95 {
96     return static_cast<T>(std::clamp(val,
97         static_cast<int>(std::numeric_limits<T>::min()),
98         static_cast<int>(std::numeric_limits<T>::max())));
99 }
100
101 void wiz_restore_aware_flag_of_fixed_arfifact(ARTIFACT_IDX a_idx, bool aware = false);
102 void wiz_modify_item_activation(PlayerType *player_ptr);
103 void wiz_identify_full_inventory(PlayerType *player_ptr);
104
105 /*!
106     * @brief ゲーム設定コマンドの入力を受け付ける
107     * @param player_ptr プレイヤーの情報へのポインタ
108        */
109 void wizard_item_modifier(PlayerType *player_ptr)
110 {
111     screen_save();
112     display_wizard_sub_menu();
113
114     char cmd;
115     get_com("Player Command: ", &cmd, false);
116     screen_load();
117
118     switch (cmd) {
119     case ESCAPE:
120     case ' ':
121     case '\n':
122     case '\r':
123         break;
124     case 'a':
125         wiz_restore_aware_flag_of_fixed_arfifact(command_arg);
126         break;
127     case 'A':
128         wiz_restore_aware_flag_of_fixed_arfifact(command_arg, true);
129         break;
130     case 'e':
131         if (command_arg <= 0)
132             command_arg = 1;
133
134         acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, true, false, true);
135         break;
136     case 'f':
137         identify_fully(player_ptr, false);
138         break;
139     case 'g':
140         if (command_arg <= 0)
141             command_arg = 1;
142
143         acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, false, false, true);
144         break;
145     case 'i':
146         (void)ident_spell(player_ptr, false);
147         break;
148     case 'I':
149         wiz_identify_full_inventory(player_ptr);
150         break;
151     case 'l':
152         wiz_learn_items_all(player_ptr);
153         break;
154     case 's':
155         if (command_arg <= 0)
156             command_arg = 1;
157
158         acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, true, true, true);
159         break;
160     case 'U':
161         wiz_modify_item_activation(player_ptr);
162         break;
163     case 'w':
164         do_cmd_wishing(player_ptr, -1, true, true, true);
165         break;
166     }
167 }
168
169 /*!
170  * @brief 固定アーティファクトの出現フラグをリセットする
171  * @param a_idx 指定したアーティファクトID
172  */
173 void wiz_restore_aware_flag_of_fixed_arfifact(ARTIFACT_IDX a_idx, bool aware)
174 {
175     if (a_idx <= 0) {
176         char tmp[80] = "";
177         sprintf(tmp, "Artifact ID (1-%d): ", static_cast<int>(a_info.size()) - 1);
178         char tmp_val[10] = "";
179         if (!get_string(tmp, tmp_val, 3))
180             return;
181
182         a_idx = (ARTIFACT_IDX)atoi(tmp_val);
183     }
184
185     if (a_idx <= 0 || a_idx >= static_cast<ARTIFACT_IDX>(a_info.size())) {
186         msg_format(_("番号は1から%dの間で指定して下さい。", "ID must be between 1 to %d."), a_info.size() - 1);
187         return;
188     }
189
190     auto *a_ptr = &a_info[a_idx];
191     a_ptr->cur_num = aware ? 1 : 0;
192     msg_print(aware ? "Modified." : "Restored.");
193 }
194
195 /*!
196  * @brief オブジェクトに発動を追加する/変更する
197  * @param catser_ptr プレイヤー情報への参照ポインタ
198  */
199 void wiz_modify_item_activation(PlayerType *player_ptr)
200 {
201     auto q = _("どのアイテムの発動を変更しますか? ", "Which object? ");
202     auto s = _("発動を変更するアイテムがない。", "Nothing to do with.");
203     OBJECT_IDX item;
204     auto *o_ptr = choose_object(player_ptr, &item, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
205     if (!o_ptr) {
206         return;
207     }
208
209     int val;
210     if (!get_value("Activation ID", enum2i(RandomArtActType::NONE), enum2i(RandomArtActType::MAX) - 1, &val)) {
211         return;
212     }
213
214     auto act_idx = i2enum<RandomArtActType>(val);
215     o_ptr->art_flags.set(TR_ACTIVATE);
216     o_ptr->activation_id = act_idx;
217 }
218
219 /*!
220  * @brief インベントリ内のアイテムを全て*鑑定*済みにする
221  * @param catser_ptr プレイヤー情報への参照ポインタ
222  */
223 void wiz_identify_full_inventory(PlayerType *player_ptr)
224 {
225     for (int i = 0; i < INVEN_TOTAL; i++) {
226         auto *o_ptr = &player_ptr->inventory_list[i];
227         if (!o_ptr->k_idx)
228             continue;
229
230         auto k_ptr = &k_info[o_ptr->k_idx];
231         k_ptr->aware = true; //!< @note 記録には残さないためTRUEを立てるのみ
232         set_bits(o_ptr->ident, IDENT_KNOWN | IDENT_FULL_KNOWN);
233         set_bits(o_ptr->marked, OM_TOUCHED);
234     }
235
236     /* Refrect item informaiton onto subwindows without updating inventory */
237     reset_bits(player_ptr->update, PU_COMBINE | PU_REORDER);
238     handle_stuff(player_ptr);
239     set_bits(player_ptr->update, PU_COMBINE | PU_REORDER);
240     set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP);
241 }
242
243 /*!
244  * @brief アイテムの階層毎生成率を表示する / Output a rarity graph for a type of object.
245  * @param tval ベースアイテムの大項目ID
246  * @param sval ベースアイテムの小項目ID
247  * @param row 表示列
248  * @param col 表示行
249  */
250 static void prt_alloc(ItemKindType tval, OBJECT_SUBTYPE_VALUE sval, TERM_LEN row, TERM_LEN col)
251 {
252     uint32_t rarity[K_MAX_DEPTH] = {};
253     uint32_t total[K_MAX_DEPTH] = {};
254     int32_t display[22] = {};
255
256     int home = 0;
257     for (int i = 0; i < K_MAX_DEPTH; i++) {
258         int total_frac = 0;
259         object_kind *k_ptr;
260         for (const auto &entry : alloc_kind_table) {
261             PERCENTAGE prob = 0;
262
263             if (entry.level <= i) {
264                 prob = entry.prob1 * GREAT_OBJ * K_MAX_DEPTH;
265             } else if (entry.level - 1 > 0) {
266                 prob = entry.prob1 * i * K_MAX_DEPTH / (entry.level - 1);
267             }
268
269             k_ptr = &k_info[entry.index];
270
271             total[i] += prob / (GREAT_OBJ * K_MAX_DEPTH);
272             total_frac += prob % (GREAT_OBJ * K_MAX_DEPTH);
273
274             if ((k_ptr->tval == tval) && (k_ptr->sval == sval)) {
275                 home = k_ptr->level;
276                 rarity[i] += prob / (GREAT_OBJ * K_MAX_DEPTH);
277             }
278         }
279
280         total[i] += total_frac / (GREAT_OBJ * K_MAX_DEPTH);
281     }
282
283     for (int i = 0; i < 22; i++) {
284         int possibility = 0;
285         for (int j = i * K_MAX_DEPTH / 22; j < (i + 1) * K_MAX_DEPTH / 22; j++)
286             possibility += rarity[j] * 100000 / total[j];
287
288         display[i] = possibility / 5;
289     }
290
291     for (int i = 0; i < 22; i++) {
292         term_putch(col, row + i + 1, TERM_WHITE, '|');
293         prt(format("%2dF", (i * 5)), row + i + 1, col);
294         if ((i * K_MAX_DEPTH / 22 <= home) && (home < (i + 1) * K_MAX_DEPTH / 22))
295             c_prt(TERM_RED, format("%3d.%04d%%", display[i] / 1000, display[i] % 1000), row + i + 1, col + 3);
296         else
297             c_prt(TERM_WHITE, format("%3d.%04d%%", display[i] / 1000, display[i] % 1000), row + i + 1, col + 3);
298     }
299
300     concptr r = "+---Rate---+";
301     prt(r, row, col);
302 }
303
304 /*!
305  * @brief 32ビット変数のビット配列を並べて描画する / Output a long int in binary format.
306  */
307 static void prt_binary(BIT_FLAGS flags, const int row, int col)
308 {
309     uint32_t bitmask;
310     for (int i = bitmask = 1; i <= 32; i++, bitmask *= 2)
311         if (flags & bitmask)
312             term_putch(col++, row, TERM_BLUE, '*');
313         else
314             term_putch(col++, row, TERM_WHITE, '-');
315 }
316
317 /*!
318  * @brief アイテムの詳細ステータスを表示する /
319  * Change various "permanent" player variables.
320  * @param player_ptr プレイヤーへの参照ポインタ
321  * @param o_ptr 詳細を表示するアイテム情報の参照ポインタ
322  */
323 static void wiz_display_item(PlayerType *player_ptr, ObjectType *o_ptr)
324 {
325     auto flgs = object_flags(o_ptr);
326     auto get_seq_32bits = [](const TrFlags &flgs, uint start) {
327         BIT_FLAGS result = 0U;
328         for (auto i = 0U; i < 32 && start + i < flgs.size(); i++) {
329             if (flgs.has(i2enum<tr_type>(start + i))) {
330                 result |= 1U << i;
331             }
332         }
333         return result;
334     };
335     int j = 13;
336     for (int i = 1; i <= 23; i++)
337         prt("", i, j - 2);
338
339     prt_alloc(o_ptr->tval, o_ptr->sval, 1, 0);
340     char buf[256];
341     describe_flavor(player_ptr, buf, o_ptr, OD_STORE);
342     prt(buf, 2, j);
343
344     auto line = 4;
345     prt(format("kind = %-5d  level = %-4d  tval = %-5d  sval = %-5d", o_ptr->k_idx, k_info[o_ptr->k_idx].level, o_ptr->tval, o_ptr->sval), line, j);
346     prt(format("number = %-3d  wgt = %-6d  ac = %-5d    damage = %dd%d", o_ptr->number, o_ptr->weight, o_ptr->ac, o_ptr->dd, o_ptr->ds), ++line, j);
347     prt(format("pval = %-5d  toac = %-5d  tohit = %-4d  todam = %-4d", o_ptr->pval, o_ptr->to_a, o_ptr->to_h, o_ptr->to_d), ++line, j);
348     prt(format("name1 = %-4d  name2 = %-4d  cost = %ld", o_ptr->fixed_artifact_idx, o_ptr->ego_idx, (long)object_value_real(o_ptr)), ++line, j);
349     prt(format("ident = %04x  activation_id = %-4d  timeout = %-d", o_ptr->ident, o_ptr->activation_id, o_ptr->timeout), ++line, j);
350     prt(format("chest_level = %-4d  fuel = %-d", o_ptr->chest_level, o_ptr->fuel), ++line, j);
351     prt(format("smith_hit = %-4d  smith_damage = %-4d", o_ptr->smith_hit, o_ptr->smith_damage), ++line, j);
352     prt(format("cursed  = %-d  captured_monster_speed = %-4d", o_ptr->curse_flags, o_ptr->captured_monster_speed), ++line, j);
353     prt(format("captured_monster_max_hp = %-4d  captured_monster_max_hp = %-4d", o_ptr->captured_monster_current_hp, o_ptr->captured_monster_max_hp), ++line, j);
354
355     prt("+------------FLAGS1------------+", ++line, j);
356     prt("AFFECT........SLAY........BRAND.", ++line, j);
357     prt("      mf      cvae      xsqpaefc", ++line, j);
358     prt("siwdccsossidsahanvudotgddhuoclio", ++line, j);
359     prt("tnieohtctrnipttmiinmrrnrrraiierl", ++line, j);
360     prt("rtsxnarelcfgdkcpmldncltggpksdced", ++line, j);
361     prt_binary(get_seq_32bits(flgs, 32 * 0), ++line, j);
362
363     prt("+------------FLAGS2------------+", ++line, j);
364     prt("SUST....IMMUN.RESIST............", ++line, j);
365     prt("      reaefctrpsaefcpfldbc sn   ", ++line, j);
366     prt("siwdcciaclioheatcliooeialoshtncd", ++line, j);
367     prt("tnieohdsierlrfraierliatrnnnrhehi", ++line, j);
368     prt("rtsxnaeydcedwlatdcedsrekdfddrxss", ++line, j);
369     prt_binary(get_seq_32bits(flgs, 32 * 1), ++line, j);
370
371     line = 10;
372     prt("+------------FLAGS3------------+", line, j + 32);
373     prt("fe cnn t      stdrmsiiii d ab   ", ++line, j + 32);
374     prt("aa aoomywhs lleeieihgggg rtgl   ", ++line, j + 32);
375     prt("uu utmacaih eielgggonnnnaaere   ", ++line, j + 32);
376     prt("rr reanurdo vtieeehtrrrrcilas   ", ++line, j + 32);
377     prt("aa algarnew ienpsntsaefctnevs   ", ++line, j + 32);
378     prt_binary(get_seq_32bits(flgs, 32 * 2), ++line, j + 32);
379
380     prt("+------------FLAGS4------------+", ++line, j + 32);
381     prt("KILL....ESP.........            ", ++line, j + 32);
382     prt("aeud tghaud tgdhegnu            ", ++line, j + 32);
383     prt("nvneoriunneoriruvoon            ", ++line, j + 32);
384     prt("iidmroamidmroagmionq            ", ++line, j + 32);
385     prt("mlenclnmmenclnnnldlu            ", ++line, j + 32);
386     prt_binary(get_seq_32bits(flgs, 32 * 3), ++line, j + 32);
387 }
388
389 /*!
390  * @brief 検査対象のアイテムを基準とした生成テストを行う /
391  * Try to create an item again. Output some statistics.    -Bernd-
392  * @param player_ptr プレイヤーへの参照ポインタ
393  * @param o_ptr 生成テストの基準となるアイテム情報の参照ポインタ
394  * The statistics are correct now.  We acquire a clean grid, and then
395  * repeatedly place an object in this grid, copying it into an item
396  * holder, and then deleting the object.  We fiddle with the artifact
397  * counter flags to prevent weirdness.  We use the items to collect
398  * statistics on item creation relative to the initial item.
399  */
400 static void wiz_statistics(PlayerType *player_ptr, ObjectType *o_ptr)
401 {
402     concptr q = "Rolls: %ld  Correct: %ld  Matches: %ld  Better: %ld  Worse: %ld  Other: %ld";
403     concptr p = "Enter number of items to roll: ";
404     char tmp_val[80];
405
406     if (o_ptr->is_fixed_artifact())
407         a_info[o_ptr->fixed_artifact_idx].cur_num = 0;
408
409     uint32_t i, matches, better, worse, other, correct;
410     uint32_t test_roll = 1000000;
411     char ch;
412     concptr quality;
413     BIT_FLAGS mode;
414     while (true) {
415         concptr pmt = "Roll for [n]ormal, [g]ood, or [e]xcellent treasure? ";
416         wiz_display_item(player_ptr, o_ptr);
417         if (!get_com(pmt, &ch, false))
418             break;
419
420         if (ch == 'n' || ch == 'N') {
421             mode = 0L;
422             quality = "normal";
423         } else if (ch == 'g' || ch == 'G') {
424             mode = AM_GOOD;
425             quality = "good";
426         } else if (ch == 'e' || ch == 'E') {
427             mode = AM_GOOD | AM_GREAT;
428             quality = "excellent";
429         } else {
430             break;
431         }
432
433         sprintf(tmp_val, "%ld", (long int)test_roll);
434         if (get_string(p, tmp_val, 10))
435             test_roll = atol(tmp_val);
436         test_roll = std::max<uint>(1, test_roll);
437         msg_format("Creating a lot of %s items. Base level = %d.", quality, player_ptr->current_floor_ptr->dun_level);
438         msg_print(nullptr);
439
440         correct = matches = better = worse = other = 0;
441         for (i = 0; i <= test_roll; i++) {
442             if ((i < 100) || (i % 100 == 0)) {
443                 inkey_scan = true;
444                 if (inkey()) {
445                     flush();
446                     break; // stop rolling
447                 }
448
449                 prt(format(q, i, correct, matches, better, worse, other), 0, 0);
450                 term_fresh();
451             }
452
453             ObjectType forge;
454             auto *q_ptr = &forge;
455             q_ptr->wipe();
456             make_object(player_ptr, q_ptr, mode);
457             if (q_ptr->is_fixed_artifact())
458                 a_info[q_ptr->fixed_artifact_idx].cur_num = 0;
459
460             if ((o_ptr->tval != q_ptr->tval) || (o_ptr->sval != q_ptr->sval))
461                 continue;
462
463             correct++;
464             if ((q_ptr->pval == o_ptr->pval) && (q_ptr->to_a == o_ptr->to_a) && (q_ptr->to_h == o_ptr->to_h) && (q_ptr->to_d == o_ptr->to_d)
465                 && (q_ptr->fixed_artifact_idx == o_ptr->fixed_artifact_idx)) {
466                 matches++;
467             } else if ((q_ptr->pval >= o_ptr->pval) && (q_ptr->to_a >= o_ptr->to_a) && (q_ptr->to_h >= o_ptr->to_h) && (q_ptr->to_d >= o_ptr->to_d)) {
468                 better++;
469             } else if ((q_ptr->pval <= o_ptr->pval) && (q_ptr->to_a <= o_ptr->to_a) && (q_ptr->to_h <= o_ptr->to_h) && (q_ptr->to_d <= o_ptr->to_d)) {
470                 worse++;
471             } else {
472                 other++;
473             }
474         }
475
476         msg_format(q, i, correct, matches, better, worse, other);
477         msg_print(nullptr);
478     }
479
480     if (o_ptr->is_fixed_artifact())
481         a_info[o_ptr->fixed_artifact_idx].cur_num = 1;
482 }
483
484 /*!
485  * @brief アイテムの質を選択して再生成する /
486  * Apply magic to an item or turn it into an artifact. -Bernd-
487  * @param o_ptr 再生成の対象となるアイテム情報の参照ポインタ
488  */
489 static void wiz_reroll_item(PlayerType *player_ptr, ObjectType *o_ptr)
490 {
491     if (o_ptr->is_artifact())
492         return;
493
494     ObjectType forge;
495     ObjectType *q_ptr;
496     q_ptr = &forge;
497     q_ptr->copy_from(o_ptr);
498
499     char ch;
500     bool changed = false;
501     while (true) {
502         wiz_display_item(player_ptr, q_ptr);
503         if (!get_com("[a]ccept, [w]orthless, [c]ursed, [n]ormal, [g]ood, [e]xcellent, [s]pecial? ", &ch, false)) {
504             if (q_ptr->is_fixed_artifact()) {
505                 a_info[q_ptr->fixed_artifact_idx].cur_num = 0;
506                 q_ptr->fixed_artifact_idx = 0;
507             }
508
509             changed = false;
510             break;
511         }
512
513         if (ch == 'A' || ch == 'a') {
514             changed = true;
515             break;
516         }
517
518         if (q_ptr->is_fixed_artifact()) {
519             a_info[q_ptr->fixed_artifact_idx].cur_num = 0;
520             q_ptr->fixed_artifact_idx = 0;
521         }
522
523         switch (tolower(ch)) {
524         /* Apply bad magic, but first clear object */
525         case 'w':
526             q_ptr->prep(o_ptr->k_idx);
527             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_NO_FIXED_ART | AM_GOOD | AM_GREAT | AM_CURSED);
528             break;
529         /* Apply bad magic, but first clear object */
530         case 'c':
531             q_ptr->prep(o_ptr->k_idx);
532             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_NO_FIXED_ART | AM_GOOD | AM_CURSED);
533             break;
534         /* Apply normal magic, but first clear object */
535         case 'n':
536             q_ptr->prep(o_ptr->k_idx);
537             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_NO_FIXED_ART);
538             break;
539         /* Apply good magic, but first clear object */
540         case 'g':
541             q_ptr->prep(o_ptr->k_idx);
542             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_NO_FIXED_ART | AM_GOOD);
543             break;
544         /* Apply great magic, but first clear object */
545         case 'e':
546             q_ptr->prep(o_ptr->k_idx);
547             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_NO_FIXED_ART | AM_GOOD | AM_GREAT);
548             break;
549         /* Apply special magic, but first clear object */
550         case 's':
551             q_ptr->prep(o_ptr->k_idx);
552             apply_magic_to_object(player_ptr, q_ptr, player_ptr->current_floor_ptr->dun_level, AM_GOOD | AM_GREAT | AM_SPECIAL);
553             if (!q_ptr->is_artifact())
554                 become_random_artifact(player_ptr, q_ptr, false);
555
556             break;
557         default:
558             break;
559         }
560
561         q_ptr->iy = o_ptr->iy;
562         q_ptr->ix = o_ptr->ix;
563         q_ptr->marked = o_ptr->marked;
564     }
565
566     if (!changed)
567         return;
568
569     o_ptr->copy_from(q_ptr);
570     set_bits(player_ptr->update, PU_BONUS | PU_COMBINE | PU_REORDER);
571     set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_SPELL | PW_PLAYER | PW_FLOOR_ITEM_LIST);
572 }
573
574 /*!
575  * @briefアイテムの基礎能力値を調整する / Tweak an item
576  * @param player_ptr プレイヤーへの参照ポインタ
577  * @param o_ptr 調整するアイテムの参照ポインタ
578  */
579 static void wiz_tweak_item(PlayerType *player_ptr, ObjectType *o_ptr)
580 {
581     if (o_ptr->is_artifact())
582         return;
583
584     concptr p = "Enter new 'pval' setting: ";
585     char tmp_val[80];
586     sprintf(tmp_val, "%d", o_ptr->pval);
587     if (!get_string(p, tmp_val, 5))
588         return;
589
590     o_ptr->pval = clamp_cast<int16_t>(atoi(tmp_val));
591     wiz_display_item(player_ptr, o_ptr);
592     p = "Enter new 'to_a' setting: ";
593     sprintf(tmp_val, "%d", o_ptr->to_a);
594     if (!get_string(p, tmp_val, 5))
595         return;
596
597     o_ptr->to_a = clamp_cast<int16_t>(atoi(tmp_val));
598     wiz_display_item(player_ptr, o_ptr);
599     p = "Enter new 'to_h' setting: ";
600     sprintf(tmp_val, "%d", o_ptr->to_h);
601     if (!get_string(p, tmp_val, 5))
602         return;
603
604     o_ptr->to_h = clamp_cast<int16_t>(atoi(tmp_val));
605     wiz_display_item(player_ptr, o_ptr);
606     p = "Enter new 'to_d' setting: ";
607     sprintf(tmp_val, "%d", (int)o_ptr->to_d);
608     if (!get_string(p, tmp_val, 5))
609         return;
610
611     o_ptr->to_d = clamp_cast<int16_t>(atoi(tmp_val));
612     wiz_display_item(player_ptr, o_ptr);
613 }
614
615 /*!
616  * @brief 検査対象のアイテムの数を変更する /
617  * Change the quantity of a the item
618  * @param player_ptr プレイヤーへの参照ポインタ
619  * @param o_ptr 変更するアイテム情報構造体の参照ポインタ
620  */
621 static void wiz_quantity_item(ObjectType *o_ptr)
622 {
623     if (o_ptr->is_artifact())
624         return;
625
626     int tmp_qnt = o_ptr->number;
627     char tmp_val[100];
628     sprintf(tmp_val, "%d", (int)o_ptr->number);
629     if (get_string("Quantity: ", tmp_val, 2)) {
630         int tmp_int = atoi(tmp_val);
631         if (tmp_int < 1)
632             tmp_int = 1;
633
634         if (tmp_int > 99)
635             tmp_int = 99;
636
637         o_ptr->number = (byte)tmp_int;
638     }
639
640     if (o_ptr->tval == ItemKindType::ROD)
641         o_ptr->pval = o_ptr->pval * o_ptr->number / tmp_qnt;
642 }
643
644 /*!
645  * @brief アイテムを弄るデバッグコマンド
646  * Play with an item. Options include:
647  * @details
648  *   - Output statistics (via wiz_roll_item)<br>
649  *   - Reroll item (via wiz_reroll_item)<br>
650  *   - Change properties (via wiz_tweak_item)<br>
651  *   - Change the number of items (via wiz_quantity_item)<br>
652  */
653 void wiz_modify_item(PlayerType *player_ptr)
654 {
655     concptr q = "Play with which object? ";
656     concptr s = "You have nothing to play with.";
657     OBJECT_IDX item;
658     ObjectType *o_ptr;
659     o_ptr = choose_object(player_ptr, &item, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
660     if (!o_ptr)
661         return;
662
663     screen_save();
664
665     ObjectType forge;
666     ObjectType *q_ptr;
667     q_ptr = &forge;
668     q_ptr->copy_from(o_ptr);
669     char ch;
670     bool changed = false;
671     while (true) {
672         wiz_display_item(player_ptr, q_ptr);
673         if (!get_com("[a]ccept [s]tatistics [r]eroll [t]weak [q]uantity? ", &ch, false)) {
674             changed = false;
675             break;
676         }
677
678         if (ch == 'A' || ch == 'a') {
679             changed = true;
680             break;
681         }
682
683         if (ch == 's' || ch == 'S') {
684             wiz_statistics(player_ptr, q_ptr);
685         }
686
687         if (ch == 'r' || ch == 'R') {
688             wiz_reroll_item(player_ptr, q_ptr);
689         }
690
691         if (ch == 't' || ch == 'T') {
692             wiz_tweak_item(player_ptr, q_ptr);
693         }
694
695         if (ch == 'q' || ch == 'Q') {
696             wiz_quantity_item(q_ptr);
697         }
698     }
699
700     screen_load();
701     if (changed) {
702         msg_print("Changes accepted.");
703
704         o_ptr->copy_from(q_ptr);
705         set_bits(player_ptr->update, PU_BONUS | PU_COMBINE | PU_REORDER);
706         set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_SPELL | PW_PLAYER | PW_FLOOR_ITEM_LIST);
707     } else {
708         msg_print("Changes ignored.");
709     }
710 }
711
712 /*!
713  * @brief オブジェクトの装備スロットがエゴが有効なスロットかどうか判定
714  */
715 static int is_slot_able_to_be_ego(PlayerType *player_ptr, ObjectType *o_ptr)
716 {
717     int slot = wield_slot(player_ptr, o_ptr);
718
719     if (slot > -1)
720         return slot;
721
722     if ((o_ptr->tval == ItemKindType::SHOT) || (o_ptr->tval == ItemKindType::ARROW) || (o_ptr->tval == ItemKindType::BOLT))
723         return INVEN_AMMO;
724
725     return -1;
726 }
727
728 /*!
729  * @brief 願ったが消えてしまった場合のメッセージ 
730  */
731 static void wishing_puff_of_smoke(void)
732 {
733     msg_print(_("何かが足下に転がってきたが、煙のように消えてしまった。",
734         "You feel something roll beneath your feet, but it disappears in a puff of smoke!"));
735 }
736
737 /*!
738  * @brief 願ったが消えてしまった場合のメッセージ
739  * @param player_ptr 願ったプレイヤー情報への参照ポインタ
740  * @param prob ★などを願った場合の生成確率
741  * @param art_ok アーティファクトの生成を許すならTRUE
742  * @param ego_ok エゴの生成を許すならTRUE
743  * @param confirm 願わない場合に確認するかどうか
744  * @return 願った結果
745  */
746 WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art, bool allow_ego, bool confirm)
747 {
748     concptr fixed_str[] = {
749 #ifdef JP
750         "燃えない",
751         "錆びない",
752         "腐食しない",
753         "安定した",
754 #else
755         "rotproof",
756         "fireproof",
757         "rustproof",
758         "erodeproof",
759         "corrodeproof",
760         "fixed",
761 #endif
762         nullptr,
763     };
764
765     char buf[MAX_NLEN] = "\0";
766     char *str = buf;
767     ObjectType forge;
768     auto *o_ptr = &forge;
769     char o_name[MAX_NLEN];
770
771     bool wish_art = false;
772     bool wish_randart = false;
773     bool wish_ego = false;
774     bool exam_base = true;
775     bool ok_art = randint0(100) < prob;
776     bool ok_ego = randint0(100) < 50 + prob;
777     bool must = prob < 0;
778     bool blessed = false;
779     bool fixed = true;
780
781     while (1) {
782         if (get_string(_("何をお望み? ", "For what do you wish?"), buf, (MAX_NLEN - 1)))
783             break;
784         if (confirm) {
785             if (!get_check(_("何も願いません。本当によろしいですか?", "Do you wish nothing, really? ")))
786                 continue;
787         }
788         return WishResultType::NOTHING;
789     }
790
791 #ifndef JP
792     str_tolower(str);
793
794     /* remove 'a' */
795     if (!strncmp(buf, "a ", 2))
796         str = ltrim(str + 1);
797     else if (!strncmp(buf, "an ", 3))
798         str = ltrim(str + 2);
799 #endif // !JP
800
801     str = rtrim(str);
802
803     if (!strncmp(str, _("祝福された", "blessed"), _(10, 7))) {
804         str = ltrim(str + _(10, 7));
805         blessed = true;
806     }
807
808     for (int i = 0; fixed_str[i] != nullptr; i++) {
809         int len = strlen(fixed_str[i]);
810         if (!strncmp(str, fixed_str[i], len)) {
811             str = ltrim(str + len);
812             fixed = true;
813             break;
814         }
815     }
816
817 #ifdef JP
818     if (!strncmp(str, "★", 2)) {
819         str = ltrim(str + 2);
820         wish_art = true;
821         exam_base = false;
822     } else
823 #endif
824
825     if (!strncmp(str, _("☆", "The "), _(2, 4))) {
826         str = ltrim(str + _(2, 4));
827         wish_art = true;
828         wish_randart = true;
829     }
830
831     /* wishing random ego ? */
832     else if (!strncmp(str, _("高級な", "excellent "), _(6, 9))) {
833         str = ltrim(str + _(6, 9));
834         wish_ego = true;
835     }
836
837     if (strlen(str) < 1) {
838         msg_print(_("名前がない!", "What?"));
839         return WishResultType::NOTHING;
840     }
841
842     if (!allow_art && wish_art) {
843         msg_print(_("アーティファクトは願えない!", "You can not wish artifacts!"));
844         return WishResultType::NOTHING;
845     }
846
847     if (cheat_xtra)
848         msg_format("Wishing %s....", buf);
849
850     std::vector<KIND_OBJECT_IDX> k_ids;
851     std::vector<EgoType> e_ids;
852     if (exam_base) {
853         int len;
854         int max_len = 0;
855         for (const auto &k_ref : k_info) {
856             if (k_ref.idx == 0 || k_ref.name.empty())
857                 continue;
858
859             o_ptr->prep(k_ref.idx);
860             describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY | OD_STORE));
861 #ifndef JP
862             str_tolower(o_name);
863 #endif
864             if (cheat_xtra)
865                 msg_format("Matching object No.%d %s", k_ref.idx, o_name);
866
867             len = strlen(o_name);
868
869             if (_(!strrncmp(str, o_name, len), !strncmp(str, o_name, len))) {
870                 if (len > max_len) {
871                     k_ids.push_back(k_ref.idx);
872                     max_len = len;
873                 }
874             }
875         }
876
877         if (allow_ego && k_ids.size() == 1) {
878             KIND_OBJECT_IDX k_idx = k_ids.back();
879             o_ptr->prep(k_idx);
880
881             for (const auto &[e_idx, e_ref] : e_info) {
882                 if (e_ref.idx == EgoType::NONE || e_ref.name.empty())
883                     continue;
884
885                 strcpy(o_name, e_ref.name.c_str());
886 #ifndef JP
887                 str_tolower(o_name);
888 #endif
889                 if (cheat_xtra)
890                     msg_format("matching ego no.%d %s...", e_ref.idx, o_name);
891
892                 if (_(!strncmp(str, o_name, strlen(o_name)), !strrncmp(str, o_name, strlen(o_name)))) {
893                     if (is_slot_able_to_be_ego(player_ptr, o_ptr) != e_ref.slot)
894                         continue;
895
896                     e_ids.push_back(e_ref.idx);
897                 }
898             }
899         }
900     }
901
902     std::vector<ARTIFACT_IDX> a_ids;
903
904     if (allow_art) {
905         char a_desc[MAX_NLEN] = "\0";
906         char *a_str = a_desc;
907
908         int len;
909         int mlen = 0;
910         for (const auto &a_ref : a_info) {
911             if (a_ref.idx == 0 || a_ref.name.empty())
912                 continue;
913
914             KIND_OBJECT_IDX k_idx = lookup_kind(a_ref.tval, a_ref.sval);
915             if (!k_idx)
916                 continue;
917
918             o_ptr->prep(k_idx);
919             o_ptr->fixed_artifact_idx = a_ref.idx;
920
921             describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY | OD_STORE));
922 #ifndef JP
923             str_tolower(o_name);
924 #endif
925             a_str = a_desc;
926             strcpy(a_desc, a_ref.name.c_str());
927
928             if (*a_str == '$')
929                 a_str++;
930 #ifdef JP
931             /* remove quotes */
932             if (!strncmp(a_str, "『", 2)) {
933                 a_str += 2;
934                 char *s = strstr(a_str, "』");
935                 *s = '\0';
936             }
937             /* remove 'of' */
938             else {
939                 int l = strlen(a_str);
940                 if (!strrncmp(a_str, "の", 2)) {
941                     a_str[l - 2] = '\0';
942                 }
943             }
944 #else
945             /* remove quotes */
946             if (a_str[0] == '\'') {
947                 a_str += 1;
948                 char *s = strchr(a_desc, '\'');
949                 *s = '\0';
950             }
951             /* remove 'of ' */
952             else if (!strncmp(a_str, (const char *)"of ", 3)) {
953                 a_str += 3;
954             }
955
956             str_tolower(a_str);
957 #endif
958
959             if (cheat_xtra)
960                 msg_format("Matching artifact No.%d %s(%s)", a_ref.idx, a_desc, _(&o_name[2], o_name));
961
962             std::vector<const char *> l = { a_str, a_ref.name.c_str(), _(&o_name[2], o_name) };
963             for (size_t c = 0; c < l.size(); c++) {
964                 if (!strcmp(str, l.at(c))) {
965                     len = strlen(l.at(c));
966                     if (len > mlen) {
967                         a_ids.push_back(a_ref.idx);
968                         mlen = len;
969                     }
970                 }
971             }
972         }
973     }
974
975     if (w_ptr->wizard && (a_ids.size() > 1 || e_ids.size() > 1)) {
976         msg_print(_("候補が多すぎる!", "Too many matches!"));
977         return WishResultType::FAIL;
978     }
979     
980     if (a_ids.size() == 1) {
981         ARTIFACT_IDX a_idx = a_ids.back();
982         if (must || (ok_art && !a_info[a_idx].cur_num)) {
983             create_named_art(player_ptr, a_idx, player_ptr->y, player_ptr->x);
984             if (!w_ptr->wizard)
985                 a_info[a_idx].cur_num = 1;
986         }
987         else
988             wishing_puff_of_smoke();
989
990         return WishResultType::ARTIFACT;
991     }
992     
993     if (!allow_ego && (wish_ego || e_ids.size() > 0)) {
994         msg_print(_("エゴアイテムは願えない!", "Can not wish ego item."));
995         return WishResultType::NOTHING;
996     }
997     
998     if (k_ids.size() == 1) {
999         KIND_OBJECT_IDX k_idx = k_ids.back();
1000         auto *k_ptr = &k_info[k_idx];
1001
1002         artifact_type *a_ptr;
1003         ARTIFACT_IDX a_idx = 0;
1004         if (k_ptr->gen_flags.has(ItemGenerationTraitType::INSTA_ART)) {
1005             for (const auto &a_ref : a_info) {
1006                 if (a_ref.idx == 0 || a_ref.tval != k_ptr->tval || a_ref.sval != k_ptr->sval)
1007                     continue;
1008                 a_idx = a_ref.idx;
1009                 break;
1010             }
1011         }
1012
1013         if (a_idx > 0) {
1014             a_ptr = &a_info[a_idx];
1015             if (must || (ok_art && !a_ptr->cur_num)) {
1016                 create_named_art(player_ptr, a_idx, player_ptr->y, player_ptr->x);
1017                 if (!w_ptr->wizard)
1018                     a_info[a_idx].cur_num = 1;
1019             }
1020             else
1021                 wishing_puff_of_smoke();
1022
1023             return WishResultType::ARTIFACT;
1024         }
1025
1026         if (wish_randart) {
1027             if (must || ok_art) {
1028                 do {
1029                     o_ptr->prep(k_idx);
1030                     apply_magic_to_object(player_ptr, o_ptr, k_ptr->level, (AM_SPECIAL | AM_NO_FIXED_ART));
1031                 } while (!o_ptr->art_name || o_ptr->fixed_artifact_idx || o_ptr->is_ego() || o_ptr->is_cursed());
1032
1033                 if (o_ptr->art_name)
1034                     drop_near(player_ptr, o_ptr, -1, player_ptr->y, player_ptr->x);
1035             } else {
1036                 wishing_puff_of_smoke();
1037             }
1038             return WishResultType::ARTIFACT;
1039         }
1040
1041         WishResultType res = WishResultType::NOTHING;
1042         if (allow_ego && (wish_ego || e_ids.size() > 0)) {
1043             if (must || ok_ego) {
1044                 if (e_ids.size() > 0) {
1045                     o_ptr->prep(k_idx);
1046                     o_ptr->ego_idx = e_ids[0];
1047                     apply_ego(o_ptr, player_ptr->current_floor_ptr->base_level);
1048                 } else {
1049                     int max_roll = 1000;
1050                     int i = 0;
1051                     for (i = 0; i < max_roll; i++) {
1052                         o_ptr->prep(k_idx);
1053                         (void)apply_magic_to_object(player_ptr, o_ptr, k_ptr->level, (AM_GREAT | AM_NO_FIXED_ART));
1054
1055                         if (o_ptr->fixed_artifact_idx || o_ptr->art_name)
1056                             continue;
1057
1058                         if (wish_ego)
1059                             break;
1060
1061                         EgoType e_idx = EgoType::NONE;
1062                         for (auto e : e_ids) {
1063                             if (o_ptr->ego_idx == e) {
1064                                 e_idx = e;
1065                                 break;
1066                             }
1067                         }
1068
1069                         if (e_idx != EgoType::NONE)
1070                             break;
1071                     }
1072
1073                     if (i == max_roll) {
1074                         msg_print(_("失敗!もう一度願ってみてください。", "Failed! Try again."));
1075                         return WishResultType::FAIL;
1076                     }
1077                 }
1078             } else {
1079                 wishing_puff_of_smoke();
1080             }
1081             
1082             res = WishResultType::EGO;
1083         } else {
1084             for (int i = 0; i < 100; i++) {
1085                 o_ptr->prep(k_idx);
1086                 apply_magic_to_object(player_ptr, o_ptr, 0, (AM_NO_FIXED_ART));
1087                 if (!o_ptr->is_cursed())
1088                     break;
1089             }
1090             res = WishResultType::NORMAL;
1091         }
1092
1093         if (blessed && wield_slot(player_ptr, o_ptr) != -1)
1094             o_ptr->art_flags.set(TR_BLESSED);
1095
1096         if (fixed && wield_slot(player_ptr, o_ptr) != -1) {
1097             o_ptr->art_flags.set(TR_IGNORE_ACID);
1098             o_ptr->art_flags.set(TR_IGNORE_FIRE);
1099         }
1100
1101         (void)drop_near(player_ptr, o_ptr, -1, player_ptr->y, player_ptr->x);
1102
1103         return res;
1104     }
1105
1106     msg_print(_("うーん、そんなものは存在しないようだ。", "Ummmm, that is not existing..."));
1107     return WishResultType::FAIL;
1108 }