OSDN Git Service

f8dd68574f68bb68be31cc858be04bcdcfec7553
[hengbandforosx/hengbandosx.git] / src / realm / realm-nature.cpp
1 #include "realm/realm-nature.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 "effect/spells-effect-util.h"
7 #include "floor/floor-object.h"
8 #include "hpmp/hp-mp-processor.h"
9 #include "monster-floor/monster-summon.h"
10 #include "monster-floor/place-monster-types.h"
11 #include "object/object-kind-hook.h"
12 #include "player-attack/player-attack.h"
13 #include "player-base/player-race.h"
14 #include "player-info/race-info.h"
15 #include "player-info/race-types.h"
16 #include "player/player-damage.h"
17 #include "player/player-status-flags.h"
18 #include "spell-kind/earthquake.h"
19 #include "spell-kind/spells-beam.h"
20 #include "spell-kind/spells-charm.h"
21 #include "spell-kind/spells-detection.h"
22 #include "spell-kind/spells-floor.h"
23 #include "spell-kind/spells-grid.h"
24 #include "spell-kind/spells-launcher.h"
25 #include "spell-kind/spells-lite.h"
26 #include "spell-kind/spells-neighbor.h"
27 #include "spell-kind/spells-perception.h"
28 #include "spell-kind/spells-sight.h"
29 #include "spell-realm/spells-nature.h"
30 #include "effect/attribute-types.h"
31 #include "spell/spells-diceroll.h"
32 #include "spell/spells-object.h"
33 #include "spell/spells-status.h"
34 #include "spell/summon-types.h"
35 #include "status/bad-status-setter.h"
36 #include "status/buff-setter.h"
37 #include "status/element-resistance.h"
38 #include "sv-definition/sv-food-types.h"
39 #include "system/object-type-definition.h"
40 #include "system/player-type-definition.h"
41 #include "target/target-getter.h"
42 #include "view/display-messages.h"
43
44 /*!
45  * @brief 自然領域魔法の各処理を行う
46  * @param player_ptr プレイヤーへの参照ポインタ
47  * @param spell 魔法ID
48  * @param mode 処理内容 (SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO / SpellProcessType::CAST)
49  * @return SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO 時には文字列ポインタを返す。SpellProcessType::CAST時はnullptr文字列を返す。
50  */
51 concptr do_nature_spell(PlayerType *player_ptr, SPELL_IDX spell, SpellProcessType mode)
52 {
53     bool name = mode == SpellProcessType::NAME;
54     bool desc = mode == SpellProcessType::DESCRIPTION;
55     bool info = mode == SpellProcessType::INFO;
56     bool cast = mode == SpellProcessType::CAST;
57
58     DIRECTION dir;
59     PLAYER_LEVEL plev = player_ptr->lev;
60
61     switch (spell) {
62     case 0:
63         if (name)
64             return _("モンスター感知", "Detect Creatures");
65         if (desc)
66             return _("近くの全ての見えるモンスターを感知する。", "Detects all monsters in your vicinity unless invisible.");
67
68         {
69             POSITION rad = DETECT_RAD_DEFAULT;
70
71             if (info)
72                 return info_radius(rad);
73
74             if (cast) {
75                 detect_monsters_normal(player_ptr, rad);
76             }
77         }
78         break;
79
80     case 1:
81         if (name)
82             return _("稲妻", "Lightning");
83         if (desc)
84             return _("電撃の短いビームを放つ。", "Fires a short beam of lightning.");
85
86         {
87             DICE_NUMBER dice = 3 + (plev - 1) / 5;
88             DICE_SID sides = 4;
89             POSITION range = plev / 6 + 2;
90
91             if (info)
92                 return format("%s%dd%d %s%d", KWD_DAM, dice, sides, KWD_RANGE, range);
93
94             if (cast) {
95                 project_length = range;
96
97                 if (!get_aim_dir(player_ptr, &dir))
98                     return nullptr;
99
100                 fire_beam(player_ptr, AttributeType::ELEC, dir, damroll(dice, sides));
101             }
102         }
103         break;
104
105     case 2:
106         if (name)
107             return _("罠と扉感知", "Detect Doors and Traps");
108         if (desc)
109             return _("近くの全ての罠と扉を感知する。", "Detects traps, doors, and stairs in your vicinity.");
110
111         {
112             POSITION rad = DETECT_RAD_DEFAULT;
113
114             if (info)
115                 return info_radius(rad);
116
117             if (cast) {
118                 detect_traps(player_ptr, rad, true);
119                 detect_doors(player_ptr, rad);
120                 detect_stairs(player_ptr, rad);
121             }
122         }
123         break;
124
125     case 3:
126         if (name)
127             return _("食糧生成", "Produce Food");
128         if (desc)
129             return _("食料を一つ作り出す。", "Produces a Ration of Food.");
130
131         {
132             if (cast) {
133                 ObjectType forge, *q_ptr = &forge;
134                 msg_print(_("食料を生成した。", "A food ration is produced."));
135
136                 /* Create the food ration */
137                 q_ptr->prep(lookup_kind(ItemKindType::FOOD, SV_FOOD_RATION));
138
139                 /* Drop the object from heaven */
140                 (void)drop_near(player_ptr, q_ptr, -1, player_ptr->y, player_ptr->x);
141             }
142         }
143         break;
144
145     case 4:
146         if (name)
147             return _("日の光", "Daylight");
148         if (desc)
149             return _("光源が照らしている範囲か部屋全体を永久に明るくする。", "Lights up nearby area and the inside of a room permanently.");
150
151         {
152             DICE_NUMBER dice = 2;
153             DICE_SID sides = plev / 2;
154             POSITION rad = (plev / 10) + 1;
155
156             if (info)
157                 return info_damage(dice, sides, 0);
158
159             if (cast) {
160                 lite_area(player_ptr, damroll(dice, sides), rad);
161
162                 PlayerRace race(player_ptr);
163                 if (race.life() == PlayerRaceLifeType::UNDEAD && race.tr_flags().has(TR_VUL_LITE) && !has_resist_lite(player_ptr)) {
164                     msg_print(_("日の光があなたの肉体を焦がした!", "The daylight scorches your flesh!"));
165                     take_hit(player_ptr, DAMAGE_NOESCAPE, damroll(2, 2), _("日の光", "daylight"));
166                 }
167             }
168         }
169         break;
170
171     case 5:
172         if (name)
173             return _("動物習し", "Animal Taming");
174         if (desc)
175             return _("動物1体を魅了する。抵抗されると無効。", "Attempts to charm an animal.");
176
177         {
178             int power = plev;
179
180             if (info)
181                 return info_power(power);
182
183             if (cast) {
184                 if (!get_aim_dir(player_ptr, &dir))
185                     return nullptr;
186
187                 charm_animal(player_ptr, dir, plev);
188             }
189         }
190         break;
191
192     case 6:
193         if (name)
194             return _("環境への耐性", "Resist Environment");
195         if (desc)
196             return _("一定時間、冷気、炎、電撃に対する耐性を得る。装備による耐性に累積する。",
197                 "Gives resistance to fire, cold and electricity for a while. These resistances can be added to those from equipment for more powerful "
198                 "resistances.");
199
200         {
201             int base = 20;
202
203             if (info)
204                 return info_duration(base, base);
205
206             if (cast) {
207                 set_oppose_cold(player_ptr, randint1(base) + base, false);
208                 set_oppose_fire(player_ptr, randint1(base) + base, false);
209                 set_oppose_elec(player_ptr, randint1(base) + base, false);
210             }
211         }
212         break;
213
214     case 7:
215         if (name)
216             return _("傷と毒治療", "Cure Wounds & Poison");
217         if (desc)
218             return _("怪我を全快させ、毒を体から完全に取り除き、体力を少し回復させる。", "Heals all cuts and poisons. Heals HP a little.");
219
220         {
221             DICE_NUMBER dice = 2;
222             DICE_SID sides = 8;
223
224             if (info)
225                 return info_heal(dice, sides, 0);
226
227             if (cast) {
228                 BadStatusSetter bss(player_ptr);
229                 hp_player(player_ptr, damroll(dice, sides));
230                 (void)bss.cut(0);
231                 (void)bss.poison(0);
232             }
233         }
234         break;
235
236     case 8:
237         if (name)
238             return _("岩石溶解", "Stone to Mud");
239         if (desc)
240             return _("壁を溶かして床にする。", "Turns one rock square to mud.");
241
242         {
243             DICE_NUMBER dice = 1;
244             DICE_SID sides = 30;
245             int base = 20;
246
247             if (info)
248                 return info_damage(dice, sides, base);
249
250             if (cast) {
251                 if (!get_aim_dir(player_ptr, &dir))
252                     return nullptr;
253
254                 wall_to_mud(player_ptr, dir, 20 + randint1(30));
255             }
256         }
257         break;
258
259     case 9:
260         if (name)
261             return _("アイス・ボルト", "Frost Bolt");
262         if (desc)
263             return _("冷気のボルトもしくはビームを放つ。", "Fires a bolt or beam of cold.");
264
265         {
266             DICE_NUMBER dice = 3 + (plev - 5) / 4;
267             DICE_SID sides = 8;
268
269             if (info)
270                 return info_damage(dice, sides, 0);
271
272             if (cast) {
273                 if (!get_aim_dir(player_ptr, &dir))
274                     return nullptr;
275                 fire_bolt_or_beam(player_ptr, beam_chance(player_ptr) - 10, AttributeType::COLD, dir, damroll(dice, sides));
276             }
277         }
278         break;
279
280     case 10:
281         if (name)
282             return _("自然の覚醒", "Nature Awareness");
283         if (desc)
284             return _(
285                 "周辺の地形を感知し、近くの罠、扉、階段、全てのモンスターを感知する。", "Maps nearby area. Detects all monsters, traps, doors and stairs.");
286
287         {
288             int rad1 = DETECT_RAD_MAP;
289             int rad2 = DETECT_RAD_DEFAULT;
290
291             if (info)
292                 return info_radius(std::max(rad1, rad2));
293
294             if (cast) {
295                 map_area(player_ptr, rad1);
296                 detect_traps(player_ptr, rad2, true);
297                 detect_doors(player_ptr, rad2);
298                 detect_stairs(player_ptr, rad2);
299                 detect_monsters_normal(player_ptr, rad2);
300             }
301         }
302         break;
303
304     case 11:
305         if (name)
306             return _("ファイア・ボルト", "Fire Bolt");
307         if (desc)
308             return _("火炎のボルトもしくはビームを放つ。", "Fires a bolt or beam of fire.");
309
310         {
311             DICE_NUMBER dice = 5 + (plev - 5) / 4;
312             DICE_SID sides = 8;
313
314             if (info)
315                 return info_damage(dice, sides, 0);
316
317             if (cast) {
318                 if (!get_aim_dir(player_ptr, &dir))
319                     return nullptr;
320                 fire_bolt_or_beam(player_ptr, beam_chance(player_ptr) - 10, AttributeType::FIRE, dir, damroll(dice, sides));
321             }
322         }
323         break;
324
325     case 12:
326         if (name)
327             return _("太陽光線", "Ray of Sunlight");
328         if (desc)
329             return _("光線を放つ。光りを嫌うモンスターに効果がある。", "Fires a beam of light which damages light-sensitive monsters.");
330
331         {
332             DICE_NUMBER dice = 6;
333             DICE_SID sides = 8;
334
335             if (info)
336                 return info_damage(dice, sides, 0);
337
338             if (cast) {
339                 if (!get_aim_dir(player_ptr, &dir))
340                     return nullptr;
341                 msg_print(_("太陽光線が現れた。", "A line of sunlight appears."));
342                 lite_line(player_ptr, dir, damroll(6, 8));
343             }
344         }
345         break;
346
347     case 13:
348         if (name)
349             return _("足かせ", "Entangle");
350         if (desc)
351             return _("視界内の全てのモンスターを減速させる。抵抗されると無効。", "Attempts to slow all monsters in sight.");
352         {
353             int power = plev;
354             if (info)
355                 return info_power(power);
356             if (cast)
357                 slow_monsters(player_ptr, plev);
358         }
359         break;
360
361     case 14:
362         if (name)
363             return _("動物召喚", "Summon Animal");
364         if (desc)
365             return _("動物を1体召喚する。", "Summons an animal.");
366
367         {
368             if (cast) {
369                 if (!(summon_specific(player_ptr, -1, player_ptr->y, player_ptr->x, plev, SUMMON_ANIMAL_RANGER, (PM_ALLOW_GROUP | PM_FORCE_PET)))) {
370                     msg_print(_("動物は現れなかった。", "No animals arrive."));
371                 }
372                 break;
373             }
374         }
375         break;
376
377     case 15:
378         if (name)
379             return _("薬草治療", "Herbal Healing");
380         if (desc)
381             return _("体力を大幅に回復させ、負傷、朦朧状態、毒から全快する。", "Heals HP greatly. Completely cures cuts, poisons and being stunned.");
382         {
383             int heal = 500;
384             if (info)
385                 return info_heal(0, 0, heal);
386             if (cast)
387                 (void)cure_critical_wounds(player_ptr, heal);
388         }
389         break;
390
391     case 16:
392         if (name)
393             return _("階段生成", "Stair Building");
394         if (desc)
395             return _("自分のいる位置に階段を作る。", "Creates a staircase which goes down or up.");
396
397         {
398             if (cast) {
399                 stair_creation(player_ptr);
400             }
401         }
402         break;
403
404     case 17:
405         if (name)
406             return _("肌石化", "Stone Skin");
407         if (desc)
408             return _("一定時間、ACを上昇させる。", "Gives a bonus to AC for a while.");
409
410         {
411             int base = 20;
412             DICE_SID sides = 30;
413
414             if (info)
415                 return info_duration(base, sides);
416
417             if (cast) {
418                 set_shield(player_ptr, randint1(sides) + base, false);
419             }
420         }
421         break;
422
423     case 18:
424         if (name)
425             return _("真・耐性", "Resistance True");
426         if (desc)
427             return _("一定時間、酸、電撃、炎、冷気、毒に対する耐性を得る。装備による耐性に累積する。",
428                 "Gives resistance to fire, cold, electricity, acid and poison for a while. These resistances can be added to those from equipment for more "
429                 "powerful resistances.");
430
431         {
432             int base = 20;
433
434             if (info)
435                 return info_duration(base, base);
436
437             if (cast) {
438                 set_oppose_acid(player_ptr, randint1(base) + base, false);
439                 set_oppose_elec(player_ptr, randint1(base) + base, false);
440                 set_oppose_fire(player_ptr, randint1(base) + base, false);
441                 set_oppose_cold(player_ptr, randint1(base) + base, false);
442                 set_oppose_pois(player_ptr, randint1(base) + base, false);
443             }
444         }
445         break;
446
447     case 19:
448         if (name)
449             return _("森林創造", "Forest Creation");
450         if (desc)
451             return _("周囲に木を作り出す。", "Creates trees in all adjacent squares.");
452
453         {
454             if (cast) {
455                 tree_creation(player_ptr, player_ptr->y, player_ptr->x);
456             }
457         }
458         break;
459
460     case 20:
461         if (name)
462             return _("動物友和", "Animal Friendship");
463         if (desc)
464             return _("視界内の全ての動物を魅了する。抵抗されると無効。", "Attempts to charm all animals in sight.");
465
466         {
467             int power = plev * 2;
468             if (info)
469                 return info_power(power);
470             if (cast)
471                 charm_animals(player_ptr, power);
472         }
473         break;
474
475     case 21:
476         if (name)
477             return _("試金石", "Stone Tell");
478         if (desc)
479             return _("アイテムの持つ能力を完全に知る。", "*Identifies* an item.");
480
481         {
482             if (cast) {
483                 if (!identify_fully(player_ptr, false))
484                     return nullptr;
485             }
486         }
487         break;
488
489     case 22:
490         if (name)
491             return _("石の壁", "Wall of Stone");
492         if (desc)
493             return _("自分の周囲に花崗岩の壁を作る。", "Creates granite walls in all adjacent squares.");
494
495         {
496             if (cast) {
497                 wall_stone(player_ptr);
498             }
499         }
500         break;
501
502     case 23:
503         if (name)
504             return _("腐食防止", "Protect from Corrosion");
505         if (desc)
506             return _("アイテムを酸で傷つかないよう加工する。", "Makes a piece of equipment acid-proof.");
507
508         {
509             if (cast) {
510                 if (!rustproof(player_ptr))
511                     return nullptr;
512             }
513         }
514         break;
515
516     case 24:
517         if (name)
518             return _("地震", "Earthquake");
519         if (desc)
520             return _(
521                 "周囲のダンジョンを揺らし、壁と床をランダムに入れ変える。", "Shakes dungeon structure, and results in random swapping of floors and walls.");
522
523         {
524             POSITION rad = 10;
525
526             if (info)
527                 return info_radius(rad);
528
529             if (cast) {
530                 earthquake(player_ptr, player_ptr->y, player_ptr->x, rad, 0);
531             }
532         }
533         break;
534
535     case 25:
536         if (name)
537             return _("カマイタチ", "Whirlwind");
538         if (desc)
539             return _("全方向に向かって攻撃する。", "Attacks all adjacent monsters.");
540         if (cast)
541             massacre(player_ptr);
542         break;
543
544     case 26:
545         if (name)
546             return _("ブリザード", "Blizzard");
547         if (desc)
548             return _("巨大な冷気の球を放つ。", "Fires a huge ball of cold.");
549
550         {
551             HIT_POINT dam = 70 + plev * 3 / 2;
552             POSITION rad = plev / 12 + 1;
553
554             if (info)
555                 return info_damage(0, 0, dam);
556
557             if (cast) {
558                 if (!get_aim_dir(player_ptr, &dir))
559                     return nullptr;
560
561                 fire_ball(player_ptr, AttributeType::COLD, dir, dam, rad);
562             }
563         }
564         break;
565
566     case 27:
567         if (name)
568             return _("稲妻嵐", "Lightning Storm");
569         if (desc)
570             return _("巨大な電撃の球を放つ。", "Fires a huge electric ball.");
571
572         {
573             HIT_POINT dam = 90 + plev * 3 / 2;
574             POSITION rad = plev / 12 + 1;
575
576             if (info)
577                 return info_damage(0, 0, dam);
578
579             if (cast) {
580                 if (!get_aim_dir(player_ptr, &dir))
581                     return nullptr;
582                 fire_ball(player_ptr, AttributeType::ELEC, dir, dam, rad);
583                 break;
584             }
585         }
586         break;
587
588     case 28:
589         if (name)
590             return _("渦潮", "Whirlpool");
591         if (desc)
592             return _("巨大な水の球を放つ。", "Fires a huge ball of water.");
593
594         {
595             HIT_POINT dam = 100 + plev * 3 / 2;
596             POSITION rad = plev / 12 + 1;
597
598             if (info)
599                 return info_damage(0, 0, dam);
600
601             if (cast) {
602                 if (!get_aim_dir(player_ptr, &dir))
603                     return nullptr;
604                 fire_ball(player_ptr, AttributeType::WATER, dir, dam, rad);
605             }
606         }
607         break;
608
609     case 29:
610         if (name)
611             return _("陽光召喚", "Call Sunlight");
612         if (desc)
613             return _("自分を中心とした光の球を発生させる。さらに、その階全体を永久に照らし、ダンジョン内すべてのアイテムを感知する。",
614                 "Generates ball of light centered on you. Maps and lights whole dungeon level. Knows all objects location.");
615
616         {
617             HIT_POINT dam = 150;
618             POSITION rad = 8;
619
620             if (info)
621                 return info_damage(0, 0, dam / 2);
622
623             if (cast) {
624                 fire_ball(player_ptr, AttributeType::LITE, 0, dam, rad);
625                 chg_virtue(player_ptr, V_KNOWLEDGE, 1);
626                 chg_virtue(player_ptr, V_ENLIGHTEN, 1);
627                 wiz_lite(player_ptr, false);
628
629                 PlayerRace race(player_ptr);
630                 if (race.life() == PlayerRaceLifeType::UNDEAD && race.tr_flags().has(TR_VUL_LITE) && !has_resist_lite(player_ptr)) {
631                     msg_print(_("日光があなたの肉体を焦がした!", "The sunlight scorches your flesh!"));
632                     take_hit(player_ptr, DAMAGE_NOESCAPE, 50, _("日光", "sunlight"));
633                 }
634             }
635         }
636         break;
637
638     case 30:
639         if (name)
640             return _("精霊の刃", "Elemental Branding");
641         if (desc)
642             return _("武器に炎か冷気の属性をつける。", "Brands current weapon with fire or frost.");
643
644         {
645             if (cast) {
646                 brand_weapon(player_ptr, randint0(2));
647             }
648         }
649         break;
650
651     case 31:
652         if (name)
653             return _("自然の脅威", "Nature's Wrath");
654         if (desc)
655             return _("近くの全てのモンスターにダメージを与え、地震を起こし、自分を中心とした分解の球を発生させる。",
656                 "Damages all monsters in sight. Makes quake. Generates disintegration ball centered on you.");
657
658         {
659             int d_dam = 4 * plev;
660             int b_dam = (100 + plev) * 2;
661             POSITION b_rad = 1 + plev / 12;
662             POSITION q_rad = 20 + plev / 2;
663
664             if (info)
665                 return format("%s%d+%d", KWD_DAM, d_dam, b_dam / 2);
666
667             if (cast) {
668                 dispel_monsters(player_ptr, d_dam);
669                 earthquake(player_ptr, player_ptr->y, player_ptr->x, q_rad, 0);
670                 project(player_ptr, 0, b_rad, player_ptr->y, player_ptr->x, b_dam, AttributeType::DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM);
671             }
672         }
673         break;
674     }
675
676     return "";
677 }