OSDN Git Service

Merge pull request #3814 from Slimebreath6078/feature/Add_Laffey_II
[hengbandforosx/hengbandosx.git] / src / realm / realm-hex.cpp
1 /*!
2  * @brief 呪術の処理実装 / Hex code
3  * @date 2014/01/14
4  * @author
5  * 2014 Deskull rearranged comment for Doxygen.\n
6  */
7
8 #include "realm/realm-hex.h"
9 #include "cmd-action/cmd-spell.h"
10 #include "cmd-item/cmd-quaff.h"
11 #include "core/asking-player.h"
12 #include "effect/attribute-types.h"
13 #include "effect/effect-characteristics.h"
14 #include "effect/effect-processor.h"
15 #include "flavor/flavor-describer.h"
16 #include "flavor/object-flavor-types.h"
17 #include "floor/cave.h"
18 #include "floor/floor-object.h"
19 #include "floor/geometry.h"
20 #include "inventory/inventory-slot-types.h"
21 #include "io/input-key-requester.h"
22 #include "monster-race/monster-race.h"
23 #include "object-enchant/object-curse.h"
24 #include "object-enchant/tr-types.h"
25 #include "object-enchant/trc-types.h"
26 #include "object-hook/hook-armor.h"
27 #include "object/item-tester-hooker.h"
28 #include "object/item-use-flags.h"
29 #include "player/attack-defense-types.h"
30 #include "player/player-skill.h"
31 #include "player/player-status.h"
32 #include "spell-kind/magic-item-recharger.h"
33 #include "spell-kind/spells-launcher.h"
34 #include "spell-kind/spells-neighbor.h"
35 #include "spell-kind/spells-sight.h"
36 #include "spell-kind/spells-teleport.h"
37 #include "spell-realm/spells-hex.h"
38 #include "spell/spells-execution.h"
39 #include "spell/spells-status.h"
40 #include "spell/technic-info-table.h"
41 #include "status/action-setter.h"
42 #include "system/floor-type-definition.h"
43 #include "system/grid-type-definition.h"
44 #include "system/item-entity.h"
45 #include "system/player-type-definition.h"
46 #include "system/redrawing-flags-updater.h"
47 #include "target/grid-selector.h"
48 #include "target/target-getter.h"
49 #include "term/screen-processor.h"
50 #include "util/bit-flags-calculator.h"
51 #include "view/display-messages.h"
52 #include "world/world.h"
53 #ifdef JP
54 #else
55 #include "player-info/equipment-info.h"
56 #endif
57
58 /*!
59  * @brief 呪術領域魔法の各処理を行う
60  * @param spell 魔法ID
61  * @param mode 処理内容 (SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO / SpellProcessType::CAST / SPELL_CONT / SpellProcessType::STOP)
62  * @return SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO 時には文字列を返す。SpellProcessType::CAST / SPELL_CONT / SpellProcessType::STOP 時は std::nullopt を返す。
63  */
64 std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type spell, SpellProcessType mode)
65 {
66     auto name = mode == SpellProcessType::NAME;
67     auto description = mode == SpellProcessType::DESCRIPTION;
68     auto info = mode == SpellProcessType::INFO;
69     auto cast = mode == SpellProcessType::CAST;
70     auto continuation = mode == SpellProcessType::CONTNUATION;
71     auto stop = mode == SpellProcessType::STOP;
72     auto should_continue = true;
73     int power;
74     switch (spell) {
75         /*** 1st book (0-7) ***/
76     case HEX_BLESS:
77         if (name) {
78             return _("邪なる祝福", "Evily blessing");
79         }
80         if (description) {
81             return _("祝福により攻撃精度と防御力が上がる。", "Attempts to increase +to_hit of a weapon and AC");
82         }
83         if (cast) {
84             if (!player_ptr->blessed) {
85                 msg_print(_("高潔な気分になった!", "You feel righteous!"));
86             }
87         }
88         if (stop) {
89             if (!player_ptr->blessed) {
90                 msg_print(_("高潔な気分が消え失せた。", "The prayer has expired."));
91             }
92         }
93         break;
94
95     case HEX_CURE_LIGHT:
96         if (name) {
97             return _("軽傷の治癒", "Cure light wounds");
98         }
99         if (description) {
100             return _("HPや傷を少し回復させる。", "Heals cuts and HP a little.");
101         }
102         if (info) {
103             return info_heal(1, 10, 0);
104         }
105         if (cast) {
106             msg_print(_("気分が良くなってくる。", "You feel a little better."));
107         }
108         if (cast || continuation) {
109             (void)cure_light_wounds(player_ptr, 1, 10);
110         }
111         break;
112
113     case HEX_DEMON_AURA:
114         if (name) {
115             return _("悪魔のオーラ", "Demonic aura");
116         }
117         if (description) {
118             return _("炎のオーラを身にまとい、回復速度が速くなる。", "Gives fire aura and regeneration.");
119         }
120         if (cast) {
121             msg_print(_("体が炎のオーラで覆われた。", "You are enveloped by a fiery aura!"));
122         }
123         if (stop) {
124             msg_print(_("炎のオーラが消え去った。", "The fiery aura disappeared."));
125         }
126         break;
127
128     case HEX_STINKING_MIST:
129         if (name) {
130             return _("悪臭霧", "Stinking mist");
131         }
132         if (description) {
133             return _("視界内のモンスターに微弱量の毒のダメージを与える。", "Deals a little poison damage to all monsters in your sight.");
134         }
135         power = player_ptr->lev / 2 + 5;
136         if (info) {
137             return info_damage(1, power, 0);
138         }
139         if (cast || continuation) {
140             project_all_los(player_ptr, AttributeType::POIS, randint1(power));
141         }
142         break;
143
144     case HEX_XTRA_MIGHT:
145         if (name) {
146             return _("腕力強化", "Extra might");
147         }
148         if (description) {
149             return _("術者の腕力を上昇させる。", "Attempts to increase your strength.");
150         }
151         if (cast) {
152             msg_print(_("何だか力が湧いて来る。", "You feel stronger."));
153         }
154         break;
155
156     case HEX_CURSE_WEAPON:
157         if (name) {
158             return _("武器呪縛", "Curse weapon");
159         }
160
161         if (description) {
162             return _("装備している武器を呪う。", "Curses your weapon.");
163         }
164
165         if (cast) {
166             constexpr auto q = _("どれを呪いますか?", "Which weapon do you curse?");
167             constexpr auto s = _("武器を装備していない。", "You're not wielding a weapon.");
168             short i_idx;
169             auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_melee_weapon));
170             if (o_ptr == nullptr) {
171                 return "";
172             }
173
174             const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
175             if (!input_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
176                 return "";
177             }
178
179             if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || o_ptr->get_flags().has(TR_BLESSED))) {
180                 msg_format(_("%s は呪いを跳ね返した。", "%s resists the effect."), item_name.data());
181                 if (one_in_(3)) {
182                     if (o_ptr->to_d > 0) {
183                         o_ptr->to_d -= randint1(3) % 2;
184                         if (o_ptr->to_d < 0) {
185                             o_ptr->to_d = 0;
186                         }
187                     }
188                     if (o_ptr->to_h > 0) {
189                         o_ptr->to_h -= randint1(3) % 2;
190                         if (o_ptr->to_h < 0) {
191                             o_ptr->to_h = 0;
192                         }
193                     }
194                     if (o_ptr->to_a > 0) {
195                         o_ptr->to_a -= randint1(3) % 2;
196                         if (o_ptr->to_a < 0) {
197                             o_ptr->to_a = 0;
198                         }
199                     }
200                     msg_format(_("%s は劣化してしまった。", "Your %s was disenchanted!"), item_name.data());
201                 }
202             } else {
203                 int curse_rank = 0;
204                 msg_format(_("恐怖の暗黒オーラがあなたの%sを包み込んだ!", "A terrible black aura blasts your %s!"), item_name.data());
205                 o_ptr->curse_flags.set(CurseTraitType::CURSED);
206
207                 if (o_ptr->is_fixed_or_random_artifact() || o_ptr->is_ego()) {
208
209                     if (one_in_(3)) {
210                         o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
211                     }
212                     if (one_in_(666)) {
213                         o_ptr->curse_flags.set(CurseTraitType::TY_CURSE);
214                         if (one_in_(666)) {
215                             o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
216                         }
217
218                         o_ptr->art_flags.set(TR_AGGRAVATE);
219                         o_ptr->art_flags.set(TR_VORPAL);
220                         o_ptr->art_flags.set(TR_VAMPIRIC);
221                         msg_print(_("血だ!血だ!血だ!", "Blood, Blood, Blood!"));
222                         curse_rank = 2;
223                     }
224                 }
225
226                 o_ptr->curse_flags.set(get_curse(curse_rank, o_ptr));
227             }
228
229             RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
230             should_continue = false;
231         }
232         break;
233
234     case HEX_DETECT_EVIL:
235         if (name) {
236             return _("邪悪感知", "Evil detection");
237         }
238         if (description) {
239             return _("周囲の邪悪なモンスターを感知する。", "Detects evil monsters.");
240         }
241         if (info) {
242             return info_range(MAX_PLAYER_SIGHT);
243         }
244         if (cast) {
245             msg_print(_("邪悪な生物の存在を感じ取ろうとした。", "You sense the presence of evil creatures."));
246         }
247         break;
248
249     case HEX_PATIENCE: {
250         if (name) {
251             return _("我慢", "Patience");
252         }
253
254         if (description) {
255             return _("数ターン攻撃を耐えた後、受けたダメージを地獄の業火として周囲に放出する。", "Bursts hell fire strongly after enduring damage for a few turns.");
256         }
257
258         SpellHex spell_hex(player_ptr);
259         power = std::min(200, spell_hex.get_revenge_power() * 2);
260         if (info) {
261             return info_damage(0, 0, power);
262         }
263
264         if (cast) {
265             int a = 3 - (player_ptr->pspeed - 100) / 10;
266             byte r = 3 + randint1(3) + std::max(0, std::min(3, a));
267
268             if (spell_hex.get_revenge_turn() > 0) {
269                 msg_print(_("すでに我慢をしている。", "You are already biding your time for vengeance."));
270                 return std::nullopt;
271             }
272
273             spell_hex.set_revenge_type(SpellHexRevengeType::PATIENCE);
274             spell_hex.set_revenge_turn(r, true);
275             spell_hex.set_revenge_power(0, true);
276             msg_print(_("じっと耐えることにした。", "You decide to endure damage for future retribution."));
277             should_continue = false;
278         }
279
280         if (continuation) {
281             POSITION rad = 2 + (power / 50);
282             spell_hex.set_revenge_turn(1, false);
283             if ((spell_hex.get_revenge_turn() == 0) || (power >= 200)) {
284                 msg_print(_("我慢が解かれた!", "My patience is at an end!"));
285                 if (power) {
286                     project(player_ptr, 0, rad, player_ptr->y, player_ptr->x, power, AttributeType::HELL_FIRE, (PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
287                 }
288
289                 if (w_ptr->wizard) {
290                     msg_format(_("%d点のダメージを返した。", "You return %d damage."), power);
291                 }
292
293                 spell_hex.set_revenge_type(SpellHexRevengeType::NONE);
294                 spell_hex.set_revenge_turn(0, true);
295                 spell_hex.set_revenge_power(0, true);
296             }
297         }
298         break;
299     }
300
301         /*** 2nd book (8-15) ***/
302     case HEX_ICE_ARMOR:
303         if (name) {
304             return _("氷の鎧", "Armor of ice");
305         }
306         if (description) {
307             return _("氷のオーラを身にまとい、防御力が上昇する。", "Surrounds you with an icy aura and gives a bonus to AC.");
308         }
309         if (cast) {
310             msg_print(_("体が氷の鎧で覆われた。", "You are enveloped by icy armor!"));
311         }
312         if (stop) {
313             msg_print(_("氷の鎧が消え去った。", "The icy armor disappeared."));
314         }
315         break;
316
317     case HEX_CURE_SERIOUS:
318         if (name) {
319             return _("重傷の治癒", "Cure serious wounds");
320         }
321         if (description) {
322             return _("体力や傷を多少回復させる。", "Heals cuts and HP.");
323         }
324         if (info) {
325             return info_heal(2, 10, 0);
326         }
327         if (cast) {
328             msg_print(_("気分が良くなってくる。", "You feel better."));
329         }
330         if (cast || continuation) {
331             (void)cure_serious_wounds(player_ptr, 2, 10);
332         }
333         break;
334
335     case HEX_INHALE: {
336         if (name) {
337             return _("薬品吸入", "Inhale potion");
338         }
339
340         if (description) {
341             return _("呪文詠唱を中止することなく、薬の効果を得ることができる。", "Quaffs a potion without canceling spell casting.");
342         }
343
344         SpellHex spell_hex(player_ptr);
345         if (cast) {
346             spell_hex.set_casting_flag(HEX_INHALE);
347             do_cmd_quaff_potion(player_ptr);
348             spell_hex.reset_casting_flag(HEX_INHALE);
349             should_continue = false;
350         }
351
352         break;
353     }
354     case HEX_VAMP_MIST:
355         if (name) {
356             return _("衰弱の霧", "Hypodynamic mist");
357         }
358         if (description) {
359             return _("視界内のモンスターに微弱量の衰弱属性のダメージを与える。", "Deals a little life-draining damage to all monsters in your sight.");
360         }
361         power = (player_ptr->lev / 2) + 5;
362         if (info) {
363             return info_damage(1, power, 0);
364         }
365         if (cast || continuation) {
366             project_all_los(player_ptr, AttributeType::HYPODYNAMIA, randint1(power));
367         }
368         break;
369
370     case HEX_RUNESWORD:
371         if (name) {
372             return _("魔剣化", "Swords to runeswords");
373         }
374         if (description) {
375             return _("武器の攻撃力を上げる。切れ味を得、呪いに応じて与えるダメージが上昇し、善良なモンスターに対するダメージが2倍になる。",
376                 "Gives vorpal ability to your weapon. Increases damage from your weapon acccording to curse of your weapon.");
377         }
378         if (cast) {
379 #ifdef JP
380             msg_print("あなたの武器が黒く輝いた。");
381 #else
382             if (!empty_hands(player_ptr, false)) {
383                 msg_print("Your weapons glow bright black.");
384             } else {
385                 msg_print("Your weapon glows bright black.");
386             }
387 #endif
388         }
389         if (stop) {
390 #ifdef JP
391             msg_print("武器の輝きが消え去った。");
392 #else
393             msg_format("Your weapon%s.", (empty_hands(player_ptr, false)) ? " no longer glows" : "s no longer glow");
394 #endif
395         }
396         break;
397
398     case HEX_CONFUSION:
399         if (name) {
400             return _("混乱の手", "Touch of confusion");
401         }
402         if (description) {
403             return _("攻撃した際モンスターを混乱させる。", "Confuses a monster when you attack.");
404         }
405         if (cast) {
406             msg_print(_("あなたの手が赤く輝き始めた。", "Your hands glow bright red."));
407         }
408         if (stop) {
409             msg_print(_("手の輝きがなくなった。", "Your hands no longer glow."));
410         }
411         break;
412
413     case HEX_BUILDING:
414         if (name) {
415             return _("肉体強化", "Building up");
416         }
417         if (description) {
418             return _(
419                 "術者の腕力、器用さ、耐久力を上昇させる。攻撃回数の上限を 1 増加させる。", "Attempts to increases your strength, dexterity and constitusion.");
420         }
421         if (cast) {
422             msg_print(_("身体が強くなった気がした。", "You feel your body is more developed now."));
423         }
424         break;
425
426     case HEX_ANTI_TELE:
427         if (name) {
428             return _("反テレポート結界", "Anti teleport barrier");
429         }
430         if (description) {
431             return _("視界内のモンスターのテレポートを阻害するバリアを張る。", "Obstructs all teleportations by monsters in your sight.");
432         }
433         power = player_ptr->lev * 3 / 2;
434         if (info) {
435             return info_power(power);
436         }
437         if (cast) {
438             msg_print(_("テレポートを防ぐ呪いをかけた。", "You feel anyone can not teleport except you."));
439         }
440         break;
441
442         /*** 3rd book (16-23) ***/
443     case HEX_SHOCK_CLOAK:
444         if (name) {
445             return _("衝撃のクローク", "Cloak of shock");
446         }
447         if (description) {
448             return _("電気のオーラを身にまとい、動きが速くなる。", "Gives lightning aura and a bonus to speed.");
449         }
450         if (cast) {
451             msg_print(_("体が稲妻のオーラで覆われた。", "You are enveloped by an electrical aura!"));
452         }
453         if (stop) {
454             msg_print(_("稲妻のオーラが消え去った。", "The electrical aura disappeared."));
455         }
456         break;
457
458     case HEX_CURE_CRITICAL:
459         if (name) {
460             return _("致命傷の治癒", "Cure critical wounds");
461         }
462         if (description) {
463             return _("体力や傷を回復させる。", "Heals cuts and HP greatly.");
464         }
465         if (info) {
466             return info_heal(4, 10, 0);
467         }
468         if (cast) {
469             msg_print(_("気分が良くなってくる。", "You feel much better."));
470         }
471         if (cast || continuation) {
472             (void)cure_critical_wounds(player_ptr, damroll(4, 10));
473         }
474         break;
475
476     case HEX_RECHARGE:
477         if (name) {
478             return _("呪力封入", "Recharging");
479         }
480         if (description) {
481             return _("魔法の道具に魔力を再充填する。", "Recharges a magic device.");
482         }
483         power = player_ptr->lev * 2;
484         if (info) {
485             return info_power(power);
486         }
487         if (cast) {
488             if (!recharge(player_ptr, power)) {
489                 return std::nullopt;
490             }
491             should_continue = false;
492         }
493         break;
494
495     case HEX_RAISE_DEAD:
496         if (name) {
497             return _("死者復活", "Animate Dead");
498         }
499         if (description) {
500             return _("死体を蘇らせてペットにする。", "Raises corpses and skeletons from dead.");
501         }
502         if (cast) {
503             msg_print(_("死者への呼びかけを始めた。", "You start to call the dead.!"));
504         }
505         if (cast || continuation) {
506             animate_dead(player_ptr, 0, player_ptr->y, player_ptr->x);
507         }
508         break;
509
510     case HEX_CURSE_ARMOUR:
511         if (name) {
512             return _("防具呪縛", "Curse armor");
513         }
514         if (description) {
515             return _("装備している防具に呪いをかける。", "Curse a piece of armour that you are wielding.");
516         }
517         if (cast) {
518             constexpr auto q = _("どれを呪いますか?", "Which piece of armour do you curse?");
519             constexpr auto s = _("防具を装備していない。", "You're not wearing any armor.");
520             short i_idx;
521             auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_protector));
522             if (!o_ptr) {
523                 return "";
524             }
525
526             o_ptr = &player_ptr->inventory_list[i_idx];
527             const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
528             if (!input_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
529                 return "";
530             }
531
532             if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || o_ptr->get_flags().has(TR_BLESSED))) {
533                 msg_format(_("%s は呪いを跳ね返した。", "%s resists the effect."), item_name.data());
534                 if (one_in_(3)) {
535                     if (o_ptr->to_d > 0) {
536                         o_ptr->to_d -= randint1(3) % 2;
537                         if (o_ptr->to_d < 0) {
538                             o_ptr->to_d = 0;
539                         }
540                     }
541                     if (o_ptr->to_h > 0) {
542                         o_ptr->to_h -= randint1(3) % 2;
543                         if (o_ptr->to_h < 0) {
544                             o_ptr->to_h = 0;
545                         }
546                     }
547                     if (o_ptr->to_a > 0) {
548                         o_ptr->to_a -= randint1(3) % 2;
549                         if (o_ptr->to_a < 0) {
550                             o_ptr->to_a = 0;
551                         }
552                     }
553                     msg_format(_("%s は劣化してしまった。", "Your %s was disenchanted!"), item_name.data());
554                 }
555             } else {
556                 int curse_rank = 0;
557                 msg_format(_("恐怖の暗黒オーラがあなたの%sを包み込んだ!", "A terrible black aura blasts your %s!"), item_name.data());
558                 o_ptr->curse_flags.set(CurseTraitType::CURSED);
559
560                 if (o_ptr->is_fixed_or_random_artifact() || o_ptr->is_ego()) {
561
562                     if (one_in_(3)) {
563                         o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
564                     }
565                     if (one_in_(666)) {
566                         o_ptr->curse_flags.set(CurseTraitType::TY_CURSE);
567                         if (one_in_(666)) {
568                             o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
569                         }
570
571                         o_ptr->art_flags.set(TR_AGGRAVATE);
572                         o_ptr->art_flags.set(TR_RES_POIS);
573                         o_ptr->art_flags.set(TR_RES_DARK);
574                         o_ptr->art_flags.set(TR_RES_NETHER);
575                         msg_print(_("血だ!血だ!血だ!", "Blood, Blood, Blood!"));
576                         curse_rank = 2;
577                     }
578                 }
579
580                 o_ptr->curse_flags.set(get_curse(curse_rank, o_ptr));
581             }
582
583             RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
584             should_continue = false;
585         }
586         break;
587
588     case HEX_SHADOW_CLOAK:
589         if (name) {
590             return _("影のクローク", "Cloak of shadow");
591         }
592         if (description) {
593             return _("影のオーラを身にまとい、敵に影のダメージを与える。", "Gives aura of shadow.");
594         }
595         if (cast) {
596             auto *o_ptr = &player_ptr->inventory_list[INVEN_OUTER];
597
598             if (!o_ptr->is_valid()) {
599                 msg_print(_("クロークを身につけていない!", "You are not wearing a cloak."));
600                 return std::nullopt;
601             } else if (!o_ptr->is_cursed()) {
602                 msg_print(_("クロークは呪われていない!", "Your cloak is not cursed."));
603                 return std::nullopt;
604             } else {
605                 msg_print(_("影のオーラを身にまとった。", "You are enveloped by a shadowy aura!"));
606             }
607         }
608         if (continuation) {
609             auto *o_ptr = &player_ptr->inventory_list[INVEN_OUTER];
610
611             if ((!o_ptr->is_valid()) || (!o_ptr->is_cursed())) {
612                 exe_spell(player_ptr, REALM_HEX, spell, SpellProcessType::STOP);
613                 SpellHex spell_hex(player_ptr);
614                 spell_hex.reset_casting_flag(spell);
615                 if (!spell_hex.is_spelling_any()) {
616                     set_action(player_ptr, ACTION_NONE);
617                 }
618             }
619         }
620         if (stop) {
621             msg_print(_("影のオーラが消え去った。", "The shadowy aura disappeared."));
622         }
623         break;
624
625     case HEX_PAIN_TO_MANA:
626         if (name) {
627             return _("苦痛を魔力に", "Pain to mana");
628         }
629         if (description) {
630             return _("視界内のモンスターに精神ダメージ与え、魔力を吸い取る。", "Deals psychic damage to all monsters in sight and drains some mana.");
631         }
632         power = player_ptr->lev * 3 / 2;
633         if (info) {
634             return info_damage(1, power, 0);
635         }
636         if (cast || continuation) {
637             project_all_los(player_ptr, AttributeType::PSI_DRAIN, randint1(power));
638         }
639         break;
640
641     case HEX_EYE_FOR_EYE:
642         if (name) {
643             return _("目には目を", "Eye for an eye");
644         }
645         if (description) {
646             return _("打撃や魔法で受けたダメージを、攻撃元のモンスターにも与える。", "Returns same damage which you got to the monster which damaged you.");
647         }
648         if (cast) {
649             msg_print(_("復讐したい欲望にかられた。", "You feel very vengeful."));
650         }
651         break;
652
653         /*** 4th book (24-31) ***/
654     case HEX_ANTI_MULTI:
655         if (name) {
656             return _("反増殖結界", "Anti multiply barrier");
657         }
658         if (description) {
659             return _("その階の増殖するモンスターの増殖を阻止する。", "Obstructs all multiplying by monsters on entire floor.");
660         }
661         if (cast) {
662             msg_print(_("増殖を阻止する呪いをかけた。", "You feel anyone can not multiply."));
663         }
664         break;
665
666     case HEX_RESTORE:
667         if (name) {
668             return _("全復活", "Restoration");
669         }
670         if (description) {
671             return _("経験値を徐々に復活し、減少した能力値を回復させる。", "Restores experience and status.");
672         }
673         if (cast) {
674             msg_print(_("体が元の活力を取り戻し始めた。", "You feel your lost status starting to return."));
675         }
676         if (cast || continuation) {
677             bool flag = false;
678             int d = (player_ptr->max_exp - player_ptr->exp);
679             int r = (player_ptr->exp / 20);
680             int i;
681
682             if (d > 0) {
683                 if (d < r) {
684                     player_ptr->exp = player_ptr->max_exp;
685                 } else {
686                     player_ptr->exp += r;
687                 }
688
689                 /* Check the experience */
690                 check_experience(player_ptr);
691
692                 flag = true;
693             }
694
695             auto &rfu = RedrawingFlagsUpdater::get_instance();
696             for (i = A_STR; i < A_MAX; i++) {
697                 if (player_ptr->stat_cur[i] < player_ptr->stat_max[i]) {
698                     if (player_ptr->stat_cur[i] < 18) {
699                         player_ptr->stat_cur[i]++;
700                     } else {
701                         player_ptr->stat_cur[i] += 10;
702                     }
703
704                     if (player_ptr->stat_cur[i] > player_ptr->stat_max[i]) {
705                         player_ptr->stat_cur[i] = player_ptr->stat_max[i];
706                     }
707
708                     rfu.set_flag(StatusRecalculatingFlag::BONUS);
709                     flag = true;
710                 }
711             }
712
713             if (!flag) {
714                 const auto spell_name = exe_spell(player_ptr, REALM_HEX, HEX_RESTORE, SpellProcessType::NAME);
715                 msg_format(_("%sの呪文の詠唱をやめた。", "Finish casting '%s^'."), spell_name->data());
716                 SpellHex spell_hex(player_ptr);
717                 spell_hex.reset_casting_flag(HEX_RESTORE);
718                 if (!spell_hex.is_spelling_any()) {
719                     set_action(player_ptr, ACTION_NONE);
720                 }
721
722                 static constexpr auto flags = {
723                     StatusRecalculatingFlag::BONUS,
724                     StatusRecalculatingFlag::HP,
725                     StatusRecalculatingFlag::MP,
726                     StatusRecalculatingFlag::SPELLS,
727                 };
728                 rfu.set_flags(flags);
729                 rfu.set_flag(MainWindowRedrawingFlag::EXTRA);
730                 return "";
731             }
732         }
733         break;
734
735     case HEX_DRAIN_CURSE:
736         if (name) {
737             return _("呪力吸収", "Drain curse power");
738         }
739         if (description) {
740             return _("呪われた装備品の呪いを吸収して魔力を回復する。", "Drains curse on your equipment and heals SP a little.");
741         }
742         if (cast) {
743             constexpr auto q = _("どの装備品から吸収しますか?", "Which cursed equipment do you drain mana from?");
744             constexpr auto s = _("呪われたアイテムを装備していない。", "You have no cursed equipment.");
745             short i_idx;
746             auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_cursed));
747             if (!o_ptr) {
748                 return "";
749             }
750
751             player_ptr->csp += (player_ptr->lev / 5) + randint1(player_ptr->lev / 5);
752             if (o_ptr->get_flags().has(TR_TY_CURSE) || o_ptr->curse_flags.has(CurseTraitType::TY_CURSE)) {
753                 player_ptr->csp += randint1(5);
754             }
755             if (player_ptr->csp > player_ptr->msp) {
756                 player_ptr->csp = player_ptr->msp;
757             }
758
759             if (o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE)) {
760                 /* Nothing */
761             } else if (o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE)) {
762                 if (one_in_(7)) {
763                     msg_print(_("呪いを全て吸い取った。", "A heavy curse vanished."));
764                     o_ptr->curse_flags.clear();
765                 }
766             } else if (o_ptr->curse_flags.has(CurseTraitType::CURSED) && one_in_(3)) {
767                 msg_print(_("呪いを全て吸い取った。", "A curse vanished."));
768                 o_ptr->curse_flags.clear();
769             }
770
771             should_continue = false;
772         }
773         break;
774
775     case HEX_VAMP_BLADE:
776         if (name) {
777             return _("吸血の刃", "Swords to vampires");
778         }
779         if (description) {
780             return _("吸血属性で攻撃する。", "Gives vampiric ability to your weapon.");
781         }
782         if (cast) {
783 #ifdef JP
784             msg_print("あなたの武器が血を欲している。");
785 #else
786             if (!empty_hands(player_ptr, false)) {
787                 msg_print("Your weapons want more blood now.");
788             } else {
789                 msg_print("Your weapon wants more blood now.");
790             }
791 #endif
792         }
793         if (stop) {
794 #ifdef JP
795             msg_print("武器の渇望が消え去った。");
796 #else
797             msg_format("Your weapon%s less thirsty now.", (empty_hands(player_ptr, false)) ? " is" : "s are");
798 #endif
799         }
800         break;
801
802     case HEX_STUN_MONSTERS:
803         if (name) {
804             return _("朦朧の言葉", "Word of stun");
805         }
806         if (description) {
807             return _("視界内のモンスターを朦朧とさせる。", "Stuns all monsters in your sight.");
808         }
809         power = player_ptr->lev * 4;
810         if (info) {
811             return info_power(power);
812         }
813         if (cast || continuation) {
814             stun_monsters(player_ptr, power);
815         }
816         break;
817
818     case HEX_SHADOW_MOVE:
819         if (name) {
820             return _("影移動", "Moving into shadow");
821         }
822         if (description) {
823             return _("モンスターの隣のマスに瞬間移動する。", "Teleports you close to a monster.");
824         }
825         if (cast) {
826             int i, dir;
827             POSITION y, x;
828             bool flag;
829
830             for (i = 0; i < 3; i++) {
831                 if (!tgt_pt(player_ptr, &x, &y)) {
832                     return "";
833                 }
834
835                 flag = false;
836
837                 const auto *floor_ptr = player_ptr->current_floor_ptr;
838                 for (dir = 0; dir < 8; dir++) {
839                     int dy = y + ddy_ddd[dir];
840                     int dx = x + ddx_ddd[dir];
841                     if (dir == 5) {
842                         continue;
843                     }
844                     if (floor_ptr->grid_array[dy][dx].has_monster()) {
845                         flag = true;
846                     }
847                 }
848
849                 const auto dist = distance(y, x, player_ptr->y, player_ptr->x);
850                 if (!is_cave_empty_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].is_icky() || (dist > player_ptr->lev + 2)) {
851                     msg_print(_("そこには移動できない。", "Can not teleport to there."));
852                     continue;
853                 }
854                 break;
855             }
856
857             if (flag && randint0(player_ptr->lev * player_ptr->lev / 2)) {
858                 teleport_player_to(player_ptr, y, x, TELEPORT_SPONTANEOUS);
859             } else {
860                 msg_print(_("おっと!", "Oops!"));
861                 teleport_player(player_ptr, 30, TELEPORT_SPONTANEOUS);
862             }
863
864             should_continue = false;
865         }
866         break;
867
868     case HEX_ANTI_MAGIC:
869         if (name) {
870             return _("反魔法結界", "Anti magic barrier");
871         }
872         if (description) {
873             return _("視界内のモンスターの魔法を阻害するバリアを張る。", "Obstructs all magic spells of monsters in your sight.");
874         }
875         power = player_ptr->lev * 3 / 2;
876         if (info) {
877             return info_power(power);
878         }
879         if (cast) {
880             msg_print(_("魔法を防ぐ呪いをかけた。", "You feel anyone can not cast spells except you."));
881         }
882         break;
883
884     case HEX_REVENGE: {
885         if (name) {
886             return _("復讐の宣告", "Revenge sentence");
887         }
888
889         if (description) {
890             return _("数ターン後にそれまで受けたダメージに応じた威力の地獄の劫火の弾を放つ。", "Fires a ball of hell fire to try avenging damage from a few turns.");
891         }
892
893         SpellHex spell_hex(player_ptr);
894         power = spell_hex.get_revenge_power();
895         if (info) {
896             return info_damage(0, 0, power);
897         }
898
899         if (cast) {
900             byte r;
901             int a = 3 - (player_ptr->pspeed - 100) / 10;
902             r = 1 + randint1(2) + std::max(0, std::min(3, a));
903
904             if (spell_hex.get_revenge_turn() > 0) {
905                 msg_print(_("すでに復讐は宣告済みだ。", "You've already declared your revenge."));
906                 return std::nullopt;
907             }
908
909             spell_hex.set_revenge_type(SpellHexRevengeType::REVENGE);
910             spell_hex.set_revenge_turn(r, true);
911             msg_format(_("あなたは復讐を宣告した。あと %d ターン。", "You declare your revenge. %d turns left."), r);
912             should_continue = false;
913         }
914
915         if (continuation) {
916             spell_hex.set_revenge_turn(1, false);
917             if (spell_hex.get_revenge_turn() == 0) {
918                 DIRECTION dir;
919
920                 if (power) {
921                     command_dir = 0;
922
923                     do {
924                         msg_print(_("復讐の時だ!", "Time for revenge!"));
925                     } while (!get_aim_dir(player_ptr, &dir));
926
927                     fire_ball(player_ptr, AttributeType::HELL_FIRE, dir, power, 1);
928
929                     if (w_ptr->wizard) {
930                         msg_format(_("%d点のダメージを返した。", "You return %d damage."), power);
931                     }
932                 } else {
933                     msg_print(_("復讐する気が失せた。", "You are not in the mood for revenge."));
934                 }
935
936                 spell_hex.set_revenge_power(0, true);
937             }
938         }
939
940         break;
941     }
942     case HEX_MAX:
943         break;
944     }
945
946     if (cast && should_continue) {
947         SpellHex spell_hex(player_ptr);
948         spell_hex.set_casting_flag(spell);
949         if (player_ptr->action != ACTION_SPELL) {
950             set_action(player_ptr, ACTION_SPELL);
951         }
952     }
953
954     if (!info) {
955         auto &rfu = RedrawingFlagsUpdater::get_instance();
956         static constexpr auto flags_srf = {
957             StatusRecalculatingFlag::BONUS,
958             StatusRecalculatingFlag::HP,
959             StatusRecalculatingFlag::MP,
960             StatusRecalculatingFlag::SPELLS,
961         };
962         rfu.set_flags(flags_srf);
963         static constexpr auto flags_mwrf = {
964             MainWindowRedrawingFlag::EXTRA,
965             MainWindowRedrawingFlag::HP,
966             MainWindowRedrawingFlag::MP,
967         };
968         rfu.set_flags(flags_mwrf);
969     }
970
971     return "";
972 }