OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / realm / realm-death.cpp
1 #include "realm/realm-death.h"
2 #include "avatar/avatar.h"
3 #include "cmd-action/cmd-spell.h"
4 #include "effect/effect-characteristics.h"
5 #include "effect/effect-processor.h"
6 #include "hpmp/hp-mp-processor.h"
7 #include "player-base/player-class.h"
8 #include "player-info/race-info.h"
9 #include "player/digestion-processor.h"
10 #include "player/player-damage.h"
11 #include "spell-kind/spells-charm.h"
12 #include "spell-kind/spells-detection.h"
13 #include "spell-kind/spells-genocide.h"
14 #include "spell-kind/spells-launcher.h"
15 #include "spell-kind/spells-neighbor.h"
16 #include "spell-kind/spells-perception.h"
17 #include "spell-kind/spells-sight.h"
18 #include "spell-kind/spells-specific-bolt.h"
19 #include "spell/spells-diceroll.h"
20 #include "spell/spells-object.h"
21 #include "spell/spells-status.h"
22 #include "spell/spells-summon.h"
23 #include "status/buff-setter.h"
24 #include "status/element-resistance.h"
25 #include "status/experience.h"
26 #include "status/shape-changer.h"
27 #include "system/player-type-definition.h"
28 #include "target/target-getter.h"
29
30 /*!
31  * @brief 暗黒領域魔法の各処理を行う
32  * @param player_ptr プレイヤーへの参照ポインタ
33  * @param spell 魔法ID
34  * @param mode 処理内容 (SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO / SpellProcessType::CAST)
35  * @return SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO 時には文字列を返す。SpellProcessType::CAST時は std::nullopt を返す。
36  */
37 std::optional<std::string> do_death_spell(PlayerType *player_ptr, SPELL_IDX spell, SpellProcessType mode)
38 {
39     bool name = mode == SpellProcessType::NAME;
40     bool desc = mode == SpellProcessType::DESCRIPTION;
41     bool info = mode == SpellProcessType::INFO;
42     bool cast = mode == SpellProcessType::CAST;
43
44     DIRECTION dir;
45     PLAYER_LEVEL plev = player_ptr->lev;
46
47     switch (spell) {
48     case 0:
49         if (name) {
50             return _("無生命感知", "Detect Unlife");
51         }
52         if (desc) {
53             return _("近くの生命のないモンスターを感知する。", "Detects all nonliving monsters in your vicinity.");
54         }
55
56         {
57             POSITION rad = DETECT_RAD_DEFAULT;
58
59             if (info) {
60                 return info_radius(rad);
61             }
62
63             if (cast) {
64                 detect_monsters_nonliving(player_ptr, rad);
65             }
66         }
67         break;
68
69     case 1:
70         if (name) {
71             return _("呪殺弾", "Malediction");
72         }
73         if (desc) {
74             return _("ごく小さな邪悪な力を持つボールを放つ。善良なモンスターには大きなダメージを与える。",
75                 "Fires a tiny ball of evil power which hurts good monsters greatly.");
76         }
77
78         {
79             DICE_NUMBER dice = 3 + (plev - 1) / 5;
80             DICE_SID sides = 4;
81             POSITION rad = 0;
82
83             if (info) {
84                 return info_damage(dice, sides, 0);
85             }
86
87             if (cast) {
88                 if (!get_aim_dir(player_ptr, &dir)) {
89                     return std::nullopt;
90                 }
91
92                 /*
93                  * A radius-0 ball may (1) be aimed at
94                  * objects etc., and will affect them;
95                  * (2) may be aimed at ANY visible
96                  * monster, unlike a 'bolt' which must
97                  * travel to the monster.
98                  */
99
100                 fire_ball(player_ptr, AttributeType::HELL_FIRE, dir, damroll(dice, sides), rad);
101
102                 if (one_in_(5)) {
103                     /* Special effect first */
104                     int effect = randint1(1000);
105
106                     if (effect == 666) {
107                         fire_ball_hide(player_ptr, AttributeType::DEATH_RAY, dir, plev * 200, 0);
108                     } else if (effect < 500) {
109                         fire_ball_hide(player_ptr, AttributeType::TURN_ALL, dir, plev, 0);
110                     } else if (effect < 800) {
111                         fire_ball_hide(player_ptr, AttributeType::OLD_CONF, dir, plev, 0);
112                     } else {
113                         fire_ball_hide(player_ptr, AttributeType::STUN, dir, plev, 0);
114                     }
115                 }
116             }
117         }
118         break;
119
120     case 2:
121         if (name) {
122             return _("邪悪感知", "Detect Evil");
123         }
124         if (desc) {
125             return _("近くの邪悪なモンスターを感知する。", "Detects all evil monsters in your vicinity.");
126         }
127
128         {
129             POSITION rad = DETECT_RAD_DEFAULT;
130
131             if (info) {
132                 return info_radius(rad);
133             }
134
135             if (cast) {
136                 detect_monsters_evil(player_ptr, rad);
137             }
138         }
139         break;
140
141     case 3:
142         if (name) {
143             return _("悪臭雲", "Stinking Cloud");
144         }
145         if (desc) {
146             return _("毒の球を放つ。", "Fires a ball of poison.");
147         }
148
149         {
150             int dam = 10 + plev / 2;
151             POSITION rad = 2;
152
153             if (info) {
154                 return info_damage(0, 0, dam);
155             }
156
157             if (cast) {
158                 if (!get_aim_dir(player_ptr, &dir)) {
159                     return std::nullopt;
160                 }
161
162                 fire_ball(player_ptr, AttributeType::POIS, dir, dam, rad);
163             }
164         }
165         break;
166
167     case 4:
168         if (name) {
169             return _("黒い眠り", "Black Sleep");
170         }
171         if (desc) {
172             return _("1体のモンスターを眠らせる。抵抗されると無効。", "Attempts to put a monster to sleep.");
173         }
174
175         {
176             int power = plev;
177
178             if (info) {
179                 return info_power(power);
180             }
181
182             if (cast) {
183                 if (!get_aim_dir(player_ptr, &dir)) {
184                     return std::nullopt;
185                 }
186
187                 sleep_monster(player_ptr, dir, plev);
188             }
189         }
190         break;
191
192     case 5:
193         if (name) {
194             return _("耐毒", "Resist Poison");
195         }
196         if (desc) {
197             return _("一定時間、毒への耐性を得る。装備による耐性に累積する。",
198                 "Gives resistance to poison. This resistance can be added to that from equipment for more powerful resistance.");
199         }
200
201         {
202             int base = 20;
203
204             if (info) {
205                 return info_duration(base, base);
206             }
207
208             if (cast) {
209                 set_oppose_pois(player_ptr, randint1(base) + base, false);
210             }
211         }
212         break;
213
214     case 6:
215         if (name) {
216             return _("恐慌", "Horrify");
217         }
218         if (desc) {
219             return _("モンスター1体を恐怖させ、朦朧させる。抵抗されると無効。", "Attempts to scare and stun a monster.");
220         }
221
222         {
223             int power = plev;
224
225             if (info) {
226                 return info_power(power);
227             }
228
229             if (cast) {
230                 if (!get_aim_dir(player_ptr, &dir)) {
231                     return std::nullopt;
232                 }
233
234                 fear_monster(player_ptr, dir, plev);
235                 stun_monster(player_ptr, dir, plev);
236             }
237         }
238         break;
239
240     case 7:
241         if (name) {
242             return _("アンデッド従属", "Enslave Undead");
243         }
244         if (desc) {
245             return _("アンデッド1体を魅了する。抵抗されると無効。", "Attempts to charm an undead monster.");
246         }
247
248         {
249             int power = plev;
250
251             if (info) {
252                 return info_power(power);
253             }
254
255             if (cast) {
256                 if (!get_aim_dir(player_ptr, &dir)) {
257                     return std::nullopt;
258                 }
259
260                 control_one_undead(player_ptr, dir, plev);
261             }
262         }
263         break;
264
265     case 8:
266         if (name) {
267             return _("エントロピーの球", "Orb of Entropy");
268         }
269         if (desc) {
270             return _("生命のある者のHPと最大HP双方にダメージを与える効果のある球を放つ。", "Fires a ball which reduces both HP and MaxHP of living monsters.");
271         }
272
273         {
274             DICE_NUMBER dice = 3;
275             DICE_SID sides = 6;
276             POSITION rad = (plev < 30) ? 2 : 3;
277             int base;
278
279             if (PlayerClass(player_ptr).is_wizard()) {
280                 base = plev + plev / 2;
281             } else {
282                 base = plev + plev / 4;
283             }
284
285             if (info) {
286                 return info_damage(dice, sides, base);
287             }
288
289             if (cast) {
290                 if (!get_aim_dir(player_ptr, &dir)) {
291                     return std::nullopt;
292                 }
293
294                 fire_ball(player_ptr, AttributeType::HYPODYNAMIA, dir, damroll(dice, sides) + base, rad);
295             }
296         }
297         break;
298
299     case 9:
300         if (name) {
301             return _("地獄の矢", "Nether Bolt");
302         }
303         if (desc) {
304             return _("地獄のボルトもしくはビームを放つ。", "Fires a bolt or beam of nether.");
305         }
306
307         {
308             DICE_NUMBER dice = 8 + (plev - 5) / 4;
309             DICE_SID sides = 8;
310
311             if (info) {
312                 return info_damage(dice, sides, 0);
313             }
314
315             if (cast) {
316                 if (!get_aim_dir(player_ptr, &dir)) {
317                     return std::nullopt;
318                 }
319
320                 fire_bolt_or_beam(player_ptr, beam_chance(player_ptr), AttributeType::NETHER, dir, damroll(dice, sides));
321             }
322         }
323         break;
324
325     case 10:
326         if (name) {
327             return _("殺戮雲", "Cloud kill");
328         }
329         if (desc) {
330             return _("自分を中心とした毒の球を発生させる。", "Generates a ball of poison centered on you.");
331         }
332
333         {
334             int dam = (30 + plev) * 2;
335             POSITION rad = plev / 10 + 2;
336
337             if (info) {
338                 return info_damage(0, 0, dam / 2);
339             }
340
341             if (cast) {
342                 project(player_ptr, 0, rad, player_ptr->y, player_ptr->x, dam, AttributeType::POIS, PROJECT_KILL | PROJECT_ITEM);
343             }
344         }
345         break;
346
347     case 11:
348         if (name) {
349             return _("モンスター消滅", "Genocide One");
350         }
351         if (desc) {
352             return _("モンスター1体を消し去る。経験値やアイテムは手に入らない。抵抗されると無効。", "Attempts to eradicate one monster.");
353         }
354
355         {
356             int power = plev + 50;
357
358             if (info) {
359                 return info_power(power);
360             }
361
362             if (cast) {
363                 if (!get_aim_dir(player_ptr, &dir)) {
364                     return std::nullopt;
365                 }
366
367                 fire_ball_hide(player_ptr, AttributeType::GENOCIDE, dir, power, 0);
368             }
369         }
370         break;
371
372     case 12:
373         if (name) {
374             return _("毒の刃", "Poison Branding");
375         }
376         if (desc) {
377             return _("武器に毒の属性をつける。", "Makes current weapon poison branded.");
378         }
379
380         {
381             if (cast) {
382                 brand_weapon(player_ptr, 3);
383             }
384         }
385         break;
386
387     case 13:
388         if (name) {
389             return _("吸血の矢", "Vampiric Bolt");
390         }
391         if (desc) {
392             return _("ボルトによりモンスター1体から生命力を吸いとる。吸いとった生命力によって満腹度が上がる。",
393                 "Fires a bolt which transfers HP from a monster to you. You will also gain nutritional sustenance from this.");
394         }
395
396         {
397             DICE_NUMBER dice = 1;
398             DICE_SID sides = plev * 2;
399             int base = plev * 2;
400
401             if (info) {
402                 return info_damage(dice, sides, base);
403             }
404
405             if (cast) {
406                 int dam = base + damroll(dice, sides);
407
408                 if (!get_aim_dir(player_ptr, &dir)) {
409                     return std::nullopt;
410                 }
411
412                 if (hypodynamic_bolt(player_ptr, dir, dam)) {
413                     chg_virtue(player_ptr, Virtue::SACRIFICE, -1);
414                     chg_virtue(player_ptr, Virtue::VITALITY, -1);
415
416                     hp_player(player_ptr, dam);
417
418                     /*
419                      * Gain nutritional sustenance:
420                      * 150/hp drained
421                      *
422                      * A Food ration gives 5000
423                      * food points (by contrast)
424                      * Don't ever get more than
425                      * "Full" this way But if we
426                      * ARE Gorged, it won't cure
427                      * us
428                      */
429                     dam = player_ptr->food + std::min(5000, 100 * dam);
430
431                     /* Not gorged already */
432                     if (player_ptr->food < PY_FOOD_MAX) {
433                         set_food(player_ptr, dam >= PY_FOOD_MAX ? PY_FOOD_MAX - 1 : dam);
434                     }
435                 }
436             }
437         }
438         break;
439
440     case 14:
441         if (name) {
442             return _("反魂の術", "Animate dead");
443         }
444         if (desc) {
445             return _("周囲の死体や骨を生き返す。", "Resurrects nearby corpses and skeletons. And makes them your pets.");
446         }
447
448         {
449             if (cast) {
450                 animate_dead(player_ptr, 0, player_ptr->y, player_ptr->x);
451             }
452         }
453         break;
454
455     case 15:
456         if (name) {
457             return _("抹殺", "Genocide");
458         }
459         if (desc) {
460             return _("指定した文字のモンスターを現在の階から消し去る。抵抗されると無効。",
461                 "Eliminates an entire class of monster, exhausting you. Powerful or unique monsters may resist.");
462         }
463
464         {
465             int power = plev + 50;
466
467             if (info) {
468                 return info_power(power);
469             }
470
471             if (cast) {
472                 symbol_genocide(player_ptr, power, true);
473             }
474         }
475         break;
476
477     case 16:
478         if (name) {
479             return _("狂戦士化", "Berserk");
480         }
481         if (desc) {
482             return _("狂戦士化し、恐怖を除去する。", "Gives a bonus to hit and HP, immunity to fear for a while. But decreases AC.");
483         }
484
485         {
486             int base = 25;
487
488             if (info) {
489                 return info_duration(base, base);
490             }
491
492             if (cast) {
493                 (void)berserk(player_ptr, base + randint1(base));
494             }
495         }
496         break;
497
498     case 17:
499         if (name) {
500             return _("悪霊召喚", "Invoke Spirits");
501         }
502         if (desc) {
503             return _("ランダムで様々な効果が起こる。", "Causes random effects.");
504         }
505
506         {
507             if (info) {
508                 return KWD_RANDOM;
509             }
510
511             if (cast) {
512                 if (!get_aim_dir(player_ptr, &dir)) {
513                     return std::nullopt;
514                 }
515
516                 cast_invoke_spirits(player_ptr, dir);
517             }
518         }
519         break;
520
521     case 18:
522         if (name) {
523             return _("暗黒の矢", "Dark Bolt");
524         }
525         if (desc) {
526             return _("暗黒のボルトもしくはビームを放つ。", "Fires a bolt or beam of darkness.");
527         }
528
529         {
530             DICE_NUMBER dice = 4 + (plev - 5) / 4;
531             DICE_SID sides = 8;
532
533             if (info) {
534                 return info_damage(dice, sides, 0);
535             }
536
537             if (cast) {
538                 if (!get_aim_dir(player_ptr, &dir)) {
539                     return std::nullopt;
540                 }
541
542                 fire_bolt_or_beam(player_ptr, beam_chance(player_ptr), AttributeType::DARK, dir, damroll(dice, sides));
543             }
544         }
545         break;
546
547     case 19:
548         if (name) {
549             return _("狂乱戦士", "Battle Frenzy");
550         }
551         if (desc) {
552             return _("狂戦士化し、恐怖を除去し、加速する。", "Gives another bonus to hit and HP, immunity to fear for a while. Hastes you. But decreases AC.");
553         }
554
555         {
556             int b_base = 25;
557             int sp_base = plev / 2;
558             int sp_sides = 20 + plev / 2;
559
560             if (info) {
561                 return info_duration(b_base, b_base);
562             }
563
564             if (cast) {
565                 (void)berserk(player_ptr, b_base + randint1(b_base));
566                 set_acceleration(player_ptr, randint1(sp_sides) + sp_base, false);
567             }
568         }
569         break;
570
571     case 20:
572         if (name) {
573             return _("吸血の刃", "Vampiric Branding");
574         }
575         if (desc) {
576             return _("武器に吸血の属性をつける。", "Makes current weapon Vampiric.");
577         }
578
579         {
580             if (cast) {
581                 brand_weapon(player_ptr, 4);
582             }
583         }
584         break;
585
586     case 21:
587         if (name) {
588             return _("吸血の連矢", "Vampiric Bolts");
589         }
590         if (desc) {
591             return _("3連射のボルトによりモンスター1体から生命力を吸いとる。吸いとった生命力によって体力が回復する。",
592                 "Fires 3 bolts. Each of the bolts absorbs some HP from a monster and gives them to you.");
593         }
594         {
595             int dam = 100;
596
597             if (info) {
598                 return format("%s3*%d", KWD_DAM, dam);
599             }
600
601             if (cast) {
602                 int i;
603
604                 if (!get_aim_dir(player_ptr, &dir)) {
605                     return std::nullopt;
606                 }
607
608                 chg_virtue(player_ptr, Virtue::SACRIFICE, -1);
609                 chg_virtue(player_ptr, Virtue::VITALITY, -1);
610
611                 for (i = 0; i < 3; i++) {
612                     if (hypodynamic_bolt(player_ptr, dir, dam)) {
613                         hp_player(player_ptr, dam);
614                     }
615                 }
616             }
617         }
618         break;
619
620     case 22:
621         if (name) {
622             return _("死の言魂", "Nether Wave");
623         }
624         if (desc) {
625             return _("視界内の生命のあるモンスターにダメージを与える。", "Damages all living monsters in sight.");
626         }
627
628         {
629             DICE_SID sides = plev * 3;
630
631             if (info) {
632                 return info_damage(1, sides, 0);
633             }
634
635             if (cast) {
636                 dispel_living(player_ptr, randint1(sides));
637             }
638         }
639         break;
640
641     case 23:
642         if (name) {
643             return _("暗黒の嵐", "Darkness Storm");
644         }
645         if (desc) {
646             return _("巨大な暗黒の球を放つ。", "Fires a huge ball of darkness.");
647         }
648
649         {
650             int dam = 100 + plev * 2;
651             POSITION rad = 4;
652
653             if (info) {
654                 return info_damage(0, 0, dam);
655             }
656
657             if (cast) {
658                 if (!get_aim_dir(player_ptr, &dir)) {
659                     return std::nullopt;
660                 }
661
662                 fire_ball(player_ptr, AttributeType::DARK, dir, dam, rad);
663             }
664         }
665         break;
666
667     case 24:
668         if (name) {
669             return _("死の光線", "Death Ray");
670         }
671         if (desc) {
672             return _("死の光線を放つ。", "Fires a beam of death.");
673         }
674
675         {
676             if (cast) {
677                 if (!get_aim_dir(player_ptr, &dir)) {
678                     return std::nullopt;
679                 }
680
681                 death_ray(player_ptr, dir, plev);
682             }
683         }
684         break;
685
686     case 25:
687         if (name) {
688             return _("死者召喚", "Raise the Dead");
689         }
690         if (desc) {
691             return _("1体のアンデッドを召喚する。", "Summons an undead monster.");
692         }
693         if (cast) {
694             cast_summon_undead(player_ptr, (plev * 3) / 2);
695         }
696         break;
697
698     case 26:
699         if (name) {
700             return _("死者の秘伝", "Secrets of the Dead");
701         }
702         if (desc) {
703             return _("アイテムを1つ識別する。レベルが高いとアイテムの能力を完全に知ることができる。", "Identifies or, at higher levels, *identifies* an item.");
704         }
705
706         {
707             if (cast) {
708                 if (randint1(50) > plev) {
709                     if (!ident_spell(player_ptr, false)) {
710                         return std::nullopt;
711                     }
712                 } else {
713                     if (!identify_fully(player_ptr, false)) {
714                         return std::nullopt;
715                     }
716                 }
717             }
718         }
719         break;
720
721     case 27:
722         if (name) {
723             return _("吸血鬼変化", "Polymorph Vampire");
724         }
725         if (desc) {
726             return _("一定時間、吸血鬼に変化する。変化している間は本来の種族の能力を失い、代わりに吸血鬼としての能力を得る。",
727                 "Causes you to mimic a vampire for a while. You lose the abilities of your original race and get the abilities of a vampire for that time.");
728         }
729
730         {
731             int base = 10 + plev / 2;
732
733             if (info) {
734                 return info_duration(base, base);
735             }
736
737             if (cast) {
738                 set_mimic(player_ptr, base + randint1(base), MimicKindType::VAMPIRE, false);
739             }
740         }
741         break;
742
743     case 28:
744         if (name) {
745             return _("経験値復活", "Restore Life");
746         }
747         if (desc) {
748             return _("失った経験値を回復する。", "Restores lost experience.");
749         }
750
751         {
752             if (cast) {
753                 restore_level(player_ptr);
754             }
755         }
756         break;
757
758     case 29:
759         if (name) {
760             return _("周辺抹殺", "Mass Genocide");
761         }
762         if (desc) {
763             return _("自分の周囲にいるモンスターを現在の階から消し去る。抵抗されると無効。",
764                 "Eliminates all nearby monsters, exhausting you. Powerful or unique monsters may be able to resist.");
765         }
766
767         {
768             int power = plev + 50;
769
770             if (info) {
771                 return info_power(power);
772             }
773
774             if (cast) {
775                 mass_genocide(player_ptr, power, true);
776             }
777         }
778         break;
779
780     case 30:
781         if (name) {
782             return _("地獄の劫火", "Hellfire");
783         }
784         if (desc) {
785             return _(
786                 "邪悪な力を持つ宝珠を放つ。善良なモンスターには大きなダメージを与える。", "Fires a powerful ball of evil power. Hurts good monsters greatly.");
787         }
788
789         {
790             int dam = 666;
791             POSITION rad = 3;
792
793             if (info) {
794                 return info_damage(0, 0, dam);
795             }
796
797             if (cast) {
798                 if (!get_aim_dir(player_ptr, &dir)) {
799                     return std::nullopt;
800                 }
801
802                 fire_ball(player_ptr, AttributeType::HELL_FIRE, dir, dam, rad);
803                 take_hit(player_ptr, DAMAGE_USELIFE, 20 + randint1(30), _("地獄の劫火の呪文を唱えた疲労", "the strain of casting Hellfire"));
804             }
805         }
806         break;
807
808     case 31:
809         if (name) {
810             return _("幽体化", "Wraithform");
811         }
812         if (desc) {
813             return _("一定時間、壁を通り抜けることができ受けるダメージが軽減される幽体の状態に変身する。",
814                 "Causes you to be ghost-like for a while. That reduces the damage you take and allows you to pass through walls.");
815         }
816
817         {
818             int base = plev / 2;
819
820             if (info) {
821                 return info_duration(base, base);
822             }
823
824             if (cast) {
825                 set_wraith_form(player_ptr, randint1(base) + base, false);
826             }
827         }
828         break;
829     }
830
831     return "";
832 }