OSDN Git Service

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