OSDN Git Service

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