OSDN Git Service

98b00a7f8b71f5ac6c5e6d67d60099ca817a224e
[hengbandforosx/hengbandosx.git] / src / mind / mind-elementalist.cpp
1 /*!
2  * @brief 元素使いの魔法系統
3  */
4
5 #include "mind-elementalist.h"
6 #include "action/action-limited.h"
7 #include "cmd-action/cmd-spell.h"
8 #include "cmd-action/cmd-mind.h"
9 #include "cmd-io/cmd-gameoption.h"
10 #include "core/asking-player.h"
11 #include "core/hp-mp-processor.h"
12 #include "core/player-redraw-types.h"
13 #include "core/stuff-handler.h"
14 #include "core/window-redrawer.h"
15 #include "effect/effect-characteristics.h"
16 #include "effect/effect-monster-util.h"
17 #include "effect/effect-processor.h"
18 #include "effect/spells-effect-util.h"
19 #include "floor/cave.h"
20 #include "floor/floor-util.h"
21 #include "game-option/disturbance-options.h"
22 #include "game-option/input-options.h"
23 #include "game-option/text-display-options.h"
24 #include "grid/feature-flag-types.h"
25 #include "io/command-repeater.h"
26 #include "io/input-key-acceptor.h"
27 #include "io/input-key-requester.h"
28 #include "main/sound-definitions-table.h"
29 #include "main/sound-of-music.h"
30 #include "mind/mind-explanations-table.h"
31 #include "monster/monster-describer.h"
32 #include "monster-race/monster-race.h"
33 #include "monster-race/race-flags3.h"
34 #include "monster-race/race-flags7.h"
35 #include "monster-race/race-flags-resistance.h"
36 #include "mind/mind-mindcrafter.h"
37 #include "player/player-status-table.h"
38 #include "player-info/avatar.h"
39 #include "player-status/player-status-base.h"
40 #include "racial/racial-util.h"
41 #include "spell-kind/earthquake.h"
42 #include "spell-kind/spells-charm.h"
43 #include "spell-kind/spells-detection.h"
44 #include "spell-kind/spells-genocide.h"
45 #include "spell-kind/spells-launcher.h"
46 #include "spell-kind/spells-lite.h"
47 #include "spell-kind/magic-item-recharger.h"
48 #include "spell-kind/spells-beam.h"
49 #include "spell-kind/spells-sight.h"
50 #include "spell-kind/spells-teleport.h"
51 #include "spell-kind/spells-world.h"
52 #include "status/bad-status-setter.h"
53 #include "status/base-status.h"
54 #include "system/floor-type-definition.h"
55 #include "system/game-option-types.h"
56 #include "util/bit-flags-calculator.h"
57 #include "util/buffer-shaper.h"
58 #include "util/int-char-converter.h"
59 #include "target/grid-selector.h"
60 #include "target/target-getter.h"
61 #include "term/screen-processor.h"
62 #include "term/term-color-types.h"
63 #include "view/display-messages.h"
64 #include <string>
65 #include <array>
66 #include <unordered_map>
67
68 /*!
69  * @brief 元素魔法呪文のID定義
70  */
71 enum class ElementSpells {
72     BOLT_1ST = 0,
73     MON_DETECT = 1,
74     PERCEPT = 2,
75     CURE = 3,
76     BOLT_2ND = 4,
77     MAG_DETECT = 5,
78     BALL_3RD = 6,
79     BALL_1ST = 7,
80     BREATH_2ND = 8,
81     ANNIHILATE = 9,
82     BOLT_3RD = 10,
83     WAVE_1ST = 11,
84     BALL_2ND = 12,
85     BURST_1ST = 13,
86     STORM_2ND = 14,
87     BREATH_1ST = 15,
88     STORM_3ND = 16,
89     MAX
90 };
91
92 /*!
93  * @brief 元素魔法タイプ構造体
94  */
95 struct element_type {
96     std::string_view title; //!< 領域名
97     std::array<spells_type, 3> type; //!< 属性タイプリスト
98     std::array<std::string_view, 3> name; //!< 属性名リスト
99     std::unordered_map<spells_type, spells_type> extra; //!< 追加属性タイプ
100 };
101
102 /*!
103  * @brief 元素魔法難易度構造体
104  */
105 struct element_power {
106     int elem; //!< 使用属性番号
107     mind_type info; //!< 難易度構造体
108 };
109
110 using element_type_list = const std::unordered_map<ElementRealm, element_type>;
111 using element_power_list = const std::unordered_map<ElementSpells, element_power>;
112 using element_tip_list = const std::unordered_map<ElementSpells, std::string_view>;
113 using element_text_list = const std::unordered_map<ElementRealm, std::string_view>;
114
115 // clang-format off
116 /*!
117  * @brief 元素魔法タイプ定義
118  */
119 static element_type_list element_types = {
120     {
121         ElementRealm::FIRE, {
122             _("炎", "Fire"),
123             { GF_FIRE, GF_HELL_FIRE, GF_PLASMA },
124             { _("火炎", "Fire"), _("業火", "Hell Fire"), _("プラズマ", "Plasma") },
125             { },
126         }
127     },
128     {
129         ElementRealm::ICE, {
130             _("氷", "Ice"),
131             { GF_COLD, GF_INERTIAL, GF_TIME },
132             { _("冷気", "Ice"), _("遅鈍", "Inertia"), _("時間逆転", "Time Stream") },
133             { { GF_COLD, GF_ICE} },
134         }
135     },
136     {
137         ElementRealm::SKY, {
138             _("空", "Sky"),
139             { GF_ELEC, GF_LITE, GF_MANA },
140             { _("電撃", "Lightning"), _("光", "Light"), _("魔力", "Mana") },
141             { },
142         }
143     },
144     {
145         ElementRealm::SEA, {
146             _("海", "Sea"),
147             { GF_ACID, GF_WATER, GF_DISINTEGRATE },
148             { _("酸", "Acid"), _("水", "Water"), _("分解", "Disintegration") },
149             { },
150         }
151     },
152     {
153         ElementRealm::DARKNESS, {
154             _("闇", "Darkness"),
155             { GF_DARK, GF_NETHER, GF_VOID },
156             { _("暗黒", "Darkness"), _("地獄", "Nether"), _("虚無", "void") },
157             { { GF_DARK, GF_ABYSS } },
158         }
159     },
160     {
161         ElementRealm::CHAOS, {
162             _("混沌", "Chaos"),
163             { GF_CONFUSION, GF_CHAOS, GF_NEXUS },
164             { _("混乱", "Confusion"), _("カオス", "Chaos"), _("因果混乱", "Nexus") },
165             { },
166         }
167     },
168     {
169         ElementRealm::EARTH, {
170             _("地", "Earth"),
171             { GF_SHARDS, GF_FORCE, GF_METEOR },
172             { _("破片", "Shards"), _("フォース", "Force"), _("隕石", "Meteor") },
173             { },
174         }
175     },
176     {
177         ElementRealm::DEATH, {
178             _("瘴気", "Death"),
179             { GF_POIS, GF_HYPODYNAMIA, GF_DISENCHANT },
180             { _("毒", "Poison"), _("吸血", "Drain Life"), _("劣化", "Disenchantment") },
181             { },
182         }
183     },
184 };
185
186 /*!
187  * @brief 元素魔法呪文定義
188  */
189 static element_power_list element_powers = {
190     { ElementSpells::BOLT_1ST,   { 0, {  1,  1,  15, _("%sの矢", "%s Bolt") }}},
191     { ElementSpells::MON_DETECT, { 0, {  2,  2,  20, _("モンスター感知", "Detect Monsters") }}},
192     { ElementSpells::PERCEPT,    { 0, {  5,  5,  50, _("擬似鑑定", "Psychometry") }}},
193     { ElementSpells::CURE,       { 0, {  6,  5,  35, _("傷の治癒", "Cure Wounds") }}},
194     { ElementSpells::BOLT_2ND,   { 1, {  8,  6,  35, _("%sの矢", "%s Bolt") }}},
195     { ElementSpells::MAG_DETECT, { 0, { 10,  8,  60, _("魔法感知", "Detect Magical Objs") }}},
196     { ElementSpells::BALL_3RD,   { 2, { 15, 10,  55, _("%s放射", "%s Spout") }}},
197     { ElementSpells::BALL_1ST,   { 0, { 18, 13,  65, _("%sの球", "%s Ball") }}},
198     { ElementSpells::BREATH_2ND, { 1, { 21, 20,  70, _("%sのブレス", "Breath of %s") }}},
199     { ElementSpells::ANNIHILATE, { 0, { 24, 20,  75, _("モンスター消滅", "Annihilation") }}},
200     { ElementSpells::BOLT_3RD,   { 2, { 25, 15,  60, _("%sの矢", "%s Bolt") }}},
201     { ElementSpells::WAVE_1ST,   { 0, { 28, 30,  75, _("元素の波動", "Elemental Wave") }}},
202     { ElementSpells::BALL_2ND,   { 1, { 28, 22,  75, _("%sの球", "%s Ball") }}},
203     { ElementSpells::BURST_1ST,  { 0, { 33, 35,  75, _("精気乱射", "%s Blast") }}},
204     { ElementSpells::STORM_2ND,  { 1, { 35, 30,  75, _("%sの嵐", "%s Storm") }}},
205     { ElementSpells::BREATH_1ST, { 0, { 42, 48,  75, _("%sのブレス", "Breath of %s") }}},
206     { ElementSpells::STORM_3ND,  { 2, { 45, 60,  80, _("%sの嵐", "%s Storm") }}},
207 };
208
209 /*!
210  * @brief 元素魔法呪文説明文定義
211  */
212 static element_tip_list element_tips = {
213     { ElementSpells::BOLT_1ST,
214     _("弱い%sの矢を放つ。", "Fire a weak bolt of %s.") },
215     { ElementSpells::MON_DETECT,
216     _("近くの全てのモンスターを感知する。", "Detects monsters.") },
217     { ElementSpells::PERCEPT,
218     _("アイテムの雰囲気を知る。", "Gives feeling of an item.") },
219     { ElementSpells::CURE,
220     _("怪我と体力を少し回復させる。", "Heals HP and wounds a bit.") },
221     { ElementSpells::BOLT_2ND,
222     _("%sの矢を放つ。", "Fire a bolt of %s.") },
223     { ElementSpells::MAG_DETECT,
224     _("近くの魔法のアイテムを感知する。", "Detects magic devices.") },
225     { ElementSpells::BALL_3RD,
226     _("高威力で射程が短い%sの球を放つ。", "Fire a strong, short-range, ball of %s.") },
227     { ElementSpells::BALL_1ST,
228     _("%sの球を放つ。",  "Fire a ball of %s.") },
229     { ElementSpells::BREATH_2ND,
230     _("%sのブレスを吐く。", "Fire a breath of %s.") },
231     { ElementSpells::ANNIHILATE,
232     _("%s耐性のないモンスターを1体抹殺する。", "Erase a monster unless it resists %s.") },
233     { ElementSpells::BOLT_3RD,
234     _("%sの矢を放つ。", "Fire a bolt of %s.") },
235     { ElementSpells::WAVE_1ST,
236     _("視界内の全ての敵に%sによるダメージを与える。", "Inflict %s damage on all monsters in sight.") },
237     { ElementSpells::BALL_2ND,
238     _("%sの球を放つ。",  "Fire a ball of %s.") },
239     { ElementSpells::BURST_1ST,
240     _("ランダムな方向に%sの矢を放つ。", "Fire some bolts of %s in random direction.") },
241     { ElementSpells::STORM_2ND,
242     _("%sの巨大な球を放つ。", "Fire a large ball of %s.") },
243     { ElementSpells::BREATH_1ST,
244     _("%sのブレスを吐く。", "Fire a breath of %s.") },
245     { ElementSpells::STORM_3ND,
246     _("%sの巨大な球を放つ。", "Fire a large ball of %s.") },
247 };
248
249 /*!
250  * @brief 元素魔法選択時説明文定義
251  */
252 static element_text_list element_texts = {
253     { ElementRealm::FIRE,
254     _("炎系統は巨大なエネルギーで灼熱を生み出し、全ての敵を燃やし尽くそうとします。",
255         "Great energy of Fire system will be able to burn out all of your enemies.")},
256     { ElementRealm::ICE,
257     _("氷系統の魔法はその冷たさで敵の動きを奪い尽くし、魂すらも止めてしまうでしょう。",
258         "Ice system will freeze your enemies, even their souls.")},
259     { ElementRealm::SKY,
260     _("空系統は大いなる天空のエネルギーを駆使して敵の全てを撃滅できます。",
261         "Sky system can terminate all of your enemies powerfully with the energy of the great sky.")},
262     { ElementRealm::SEA,
263     _("海系統はその敵の全てを溶かし、大いなる海へと返してしまいます。",
264         "Sea system melts all of your enemies and returns them to the great ocean.")},
265     { ElementRealm::DARKNESS,
266     _("闇系統は恐るべき力を常闇から引き出し、敵を地獄へと叩き落とすでしょう。",
267         "Dark system draws terrifying power from the darkness and knocks your enemies into hell.")},
268     { ElementRealm::CHAOS,
269     _("混沌系統は敵の意識も条理も捻じ曲げ、その存在をあの世に送ってしまいます。",
270         "Chaos system twists and wraps your enemies, even their souls, and scatters them as dust in the wind.")},
271     { ElementRealm::EARTH,
272     _("地系統は偉大なる大地の力を呼び出して、数多の敵のことごとくを粉砕しようとします。",
273         "Earth system smashes all of your enemies massively using its huge powers.")},
274     { ElementRealm::DEATH,
275     _("瘴気系統は全ての生ける者にとって途轍もない毒です。",
276         "Death system is a tremendous poison for all living enemies.")},
277 };
278
279 // clang-format on
280
281 /*!
282  * @brief 元素魔法の領域名を返す
283  * @param realm_idx 領域番号
284  * @return 領域名
285  */
286 concptr get_element_title(int realm_idx)
287 {
288     auto realm = static_cast<ElementRealm>(realm_idx);
289     return element_types.at(realm).title.data();
290 }
291
292 /*!
293  * @brief 元素魔法領域の属性リストを返す
294  * @param realm_idx 領域番号
295  * @return 領域で使用できる属性リスト
296  */
297 static std::array<spells_type, 3> get_element_types(int realm_idx)
298 {
299     auto realm = static_cast<ElementRealm>(realm_idx);
300     return element_types.at(realm).type;
301 }
302
303 /*!
304  * @brief 元素魔法領域のn番目の属性を返す
305  * @param realm_idx 領域番号
306  * @param n 属性の何番目か
307  * @return 属性タイプ
308  */
309 spells_type get_element_type(int realm_idx, int n)
310 {
311     return get_element_types(realm_idx)[n];
312 }
313
314 /*!
315  * @brief 元素魔法領域のn番目の呪文用の属性を返す
316  * @param realm_idx 領域番号
317  * @param n 属性の何番目か
318  * @return 属性タイプ
319  */
320 static spells_type get_element_spells_type(player_type *caster_ptr, int n) {
321     auto realm = element_types.at(static_cast<ElementRealm>(caster_ptr->realm1));
322     auto t = realm.type.at(n);
323     if (realm.extra.find(t) != realm.extra.end()) {
324         if (randint0(100) < caster_ptr->lev * 2)
325             return realm.extra.at(t);
326     }
327     return t;
328 }
329
330 /*!
331  * @brief 元素魔法領域の属性名リストを返す
332  * @param realm_idx 領域番号
333  * @return 領域で使用できる属性の名称リスト
334  */
335 static std::array<std::string_view, 3> get_element_names(int realm_idx)
336 {
337     auto realm = static_cast<ElementRealm>(realm_idx);
338     return element_types.at(realm).name;
339 }
340
341 /*!
342  * @brief 元素魔法領域のn番目の属性名を返す
343  * @param realm_idx 領域番号
344  * @param n 属性の何番目か
345  * @return 属性名
346  */
347 concptr get_element_name(int realm_idx, int n)
348 {
349     return get_element_names(realm_idx)[n].data();
350 }
351
352 /*!
353  * @brief 元素魔法の説明文を取得
354  * @param caster_ptr プレイヤー情報への参照ポインタ
355  * @param spell_idx 呪文番号
356  * @return 説明文
357  */
358 static concptr get_element_tip(player_type *caster_ptr, int spell_idx)
359 {
360     auto realm = static_cast<ElementRealm>(caster_ptr->realm1);
361     auto spell = static_cast<ElementSpells>(spell_idx);
362     auto elem = element_powers.at(spell).elem;
363     return format(element_tips.at(spell).data(), element_types.at(realm).name[elem].data());
364 }
365
366 /*!
367  * @brief 元素魔法の説明文を取得
368  * @param caster_ptr プレイヤー情報への参照ポインタ
369  * @param spell_idx 呪文番号
370  * @return 説明文
371  */
372 static int get_elemental_elem(player_type *caster_ptr, int spell_idx)
373 {
374     (void)caster_ptr;
375     auto spell = static_cast<ElementSpells>(spell_idx);
376     return element_powers.at(spell).elem;
377 }
378
379 /*!
380  * @brief 元素魔法呪文の難易度データを取得
381  * @param caster_ptr プレイヤー情報への参照ポインタ
382  * @param spell_idx 呪文番号
383  * @return 説明文
384  */
385 static mind_type get_elemental_info(player_type *caster_ptr, int spell_idx)
386 {
387     (void)caster_ptr;
388     auto spell = static_cast<ElementSpells>(spell_idx);
389     return element_powers.at(spell).info;
390 }
391
392 /*!
393  * @brief 元素魔法呪文の効果表示文字列を取得
394  * @param caster_ptr プレイヤー情報への参照ポインタ
395  * @param spell_idx 呪文番号
396  * @param p バッファ
397  * @return なし(pを更新)
398  */
399 void get_element_effect_info(player_type *caster_ptr, int spell_idx, char *p)
400 {
401     PLAYER_LEVEL plev = caster_ptr->lev;
402     auto spell = static_cast<ElementSpells>(spell_idx);
403     int dam = 0;
404
405     switch (spell) {
406     case ElementSpells::BOLT_1ST:
407         sprintf(p, " %s%dd%d", KWD_DAM, 3 + ((plev - 1) / 5), 4);
408         break;
409     case ElementSpells::CURE:
410         sprintf(p, " %s%dd%d", KWD_HEAL, 2, 8);
411         break;
412     case ElementSpells::BOLT_2ND:
413         sprintf(p, " %s%dd%d", KWD_DAM, 8 + ((plev - 5) / 4), 8);
414         break;
415     case ElementSpells::BALL_3RD:
416         sprintf(p, " %s%d", KWD_DAM, (50 + plev * 2));
417         break;
418     case ElementSpells::BALL_1ST:
419         sprintf(p, " %s%d", KWD_DAM, 55 + plev);
420         break;
421     case ElementSpells::BREATH_2ND:
422         dam = p_ptr->chp / 2;
423         sprintf(p, " %s%d", KWD_DAM, (dam > 150) ? 150 : dam);
424         break;
425     case ElementSpells::ANNIHILATE:
426         sprintf(p, " %s%d", _("効力:", "pow "), 50 + plev);
427         break;
428     case ElementSpells::BOLT_3RD:
429         sprintf(p, " %s%dd%d", KWD_DAM, 12 + ((plev - 5) / 4), 8);
430         break;
431     case ElementSpells::WAVE_1ST:
432         sprintf(p, " %s50+d%d", KWD_DAM, plev * 3);
433         break;
434     case ElementSpells::BALL_2ND:
435         sprintf(p, " %s%d", KWD_DAM, 75 + plev * 3 / 2);
436         break;
437     case ElementSpells::BURST_1ST:
438         sprintf(p, " %s%dd%d", KWD_DAM, 6 + plev / 8, 7);
439         break;
440     case ElementSpells::STORM_2ND:
441         sprintf(p, " %s%d", KWD_DAM, 115 + plev * 5 / 2);
442         break;
443     case ElementSpells::BREATH_1ST:
444         sprintf(p, " %s%d", KWD_DAM, p_ptr->chp * 2 / 3);
445         break;
446     case ElementSpells::STORM_3ND:
447         sprintf(p, " %s%d", KWD_DAM, 300 + plev * 5);
448         break;
449     default:
450         p[0] = '\0';
451         break;
452     }
453 }
454
455 /*!
456  * @brief 元素魔法呪文を実行する
457  * @param caster_ptr プレイヤー情報への参照ポインタ
458  * @param spell_idx 呪文番号
459  * @return 実行したらTRUE、キャンセルならFALSE
460  */
461 static bool cast_element_spell(player_type *caster_ptr, SPELL_IDX spell_idx)
462 {
463     auto spell = static_cast<ElementSpells>(spell_idx);
464     auto power = element_powers.at(spell);
465     spells_type typ;
466     DIRECTION dir;
467     PLAYER_LEVEL plev = caster_ptr->lev;
468     HIT_POINT dam;
469     POSITION y, x;
470     int num;
471
472     switch (spell) {
473     case ElementSpells::BOLT_1ST:
474         if (!get_aim_dir(caster_ptr, &dir))
475             return FALSE;
476         dam = damroll(3 + ((plev - 1) / 5), 4);
477         typ = get_element_spells_type(caster_ptr, power.elem);
478         (void)fire_bolt(caster_ptr, typ, dir, dam);
479         break;
480     case ElementSpells::MON_DETECT:
481         (void)detect_monsters_normal(caster_ptr, DETECT_RAD_DEFAULT);
482         (void)detect_monsters_invis(caster_ptr, DETECT_RAD_DEFAULT);
483         break;
484     case ElementSpells::PERCEPT:
485         return psychometry(caster_ptr);
486     case ElementSpells::CURE:
487         (void)hp_player(caster_ptr, damroll(2, 8));
488         (void)set_cut(caster_ptr, caster_ptr->cut - 10);
489         break;
490     case ElementSpells::BOLT_2ND:
491         if (!get_aim_dir(caster_ptr, &dir))
492             return FALSE;
493         dam = damroll(8 + ((plev - 5) / 4), 8);
494         typ = get_element_spells_type(caster_ptr, power.elem);
495         if (fire_bolt_or_beam(caster_ptr, plev, typ, dir, dam)) {
496             if (typ == GF_HYPODYNAMIA) {
497                 (void)hp_player(caster_ptr, dam / 2);
498             }
499         }
500         break;
501     case ElementSpells::MAG_DETECT:
502         (void)detect_objects_magic(caster_ptr, DETECT_RAD_DEFAULT);
503         break;
504     case ElementSpells::BALL_3RD:
505         project_length = 4;
506         if (!get_aim_dir(caster_ptr, &dir))
507             return FALSE;
508         typ = get_element_spells_type(caster_ptr, power.elem);
509         dam = 50 + plev * 2;
510         (void)fire_ball(caster_ptr, typ, dir, dam, 1);
511         project_length = 0;
512         break;
513     case ElementSpells::BALL_1ST:
514         if (!get_aim_dir(caster_ptr, &dir))
515             return FALSE;
516         dam = 55 + plev;
517         typ = get_element_spells_type(caster_ptr, power.elem);
518         (void)fire_ball(caster_ptr, typ, dir, dam, 2);
519         break;
520     case ElementSpells::BREATH_2ND:
521         if (!get_aim_dir(caster_ptr, &dir))
522             return FALSE;
523         dam = MIN(150, caster_ptr->chp / 2);
524         typ = get_element_spells_type(caster_ptr, power.elem);
525         if (fire_breath(caster_ptr, typ, dir, dam, 3)) {
526             if (typ == GF_HYPODYNAMIA) {
527                 (void)hp_player(caster_ptr, dam / 2);
528             }
529         }
530         break;
531     case ElementSpells::ANNIHILATE:
532         if (!get_aim_dir(caster_ptr, &dir))
533             return FALSE;
534         fire_ball_hide(caster_ptr, GF_E_GENOCIDE, dir, plev + 50, 0);
535         break;
536     case ElementSpells::BOLT_3RD:
537         if (!get_aim_dir(caster_ptr, &dir))
538             return FALSE;
539         dam = damroll(12 + ((plev - 5) / 4), 8);
540         typ = get_element_spells_type(caster_ptr, power.elem);
541         fire_bolt_or_beam(caster_ptr, plev, typ, dir, dam);
542         break;
543     case ElementSpells::WAVE_1ST:
544         dam = 50 + randint1(plev * 3);
545         typ = get_element_spells_type(caster_ptr, power.elem);
546         project_all_los(caster_ptr, typ, dam);
547         break;
548     case ElementSpells::BALL_2ND:
549         if (!get_aim_dir(caster_ptr, &dir))
550             return FALSE;
551         dam = 75 + plev * 3 / 2;
552         typ = get_element_spells_type(caster_ptr, power.elem);
553         if (fire_ball(caster_ptr, typ, dir, dam, 3)) {
554             if (typ == GF_HYPODYNAMIA) {
555                 (void)hp_player(caster_ptr, dam / 2);
556             }
557         }
558         break;
559     case ElementSpells::BURST_1ST:
560         y = caster_ptr->y;
561         x = caster_ptr->x;
562         num = damroll(4, 3);
563         typ = get_element_spells_type(caster_ptr, power.elem);
564         for (int k = 0; k < num; k++) {
565             int attempts = 1000;
566             while (attempts--) {
567                 scatter(caster_ptr, &y, &x, caster_ptr->y, caster_ptr->x, 4, PROJECT_NONE);
568                 if (!cave_has_flag_bold(caster_ptr->current_floor_ptr, y, x, FF_PROJECT))
569                     continue;
570                 if (!player_bold(caster_ptr, y, x))
571                     break;
572             }
573             project(caster_ptr, 0, 0, y, x, damroll(6 + plev / 8, 7), typ, (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL), -1);
574         }
575         break;
576     case ElementSpells::STORM_2ND:
577         if (!get_aim_dir(caster_ptr, &dir))
578             return FALSE;
579         dam = 115 + plev * 5 / 2;
580         typ = get_element_spells_type(caster_ptr, power.elem);
581         if (fire_ball(caster_ptr, typ, dir, dam, 4)) {
582             if (typ == GF_HYPODYNAMIA) {
583                 (void)hp_player(caster_ptr, dam / 2);
584             }
585         }
586         break;
587     case ElementSpells::BREATH_1ST:
588         if (!get_aim_dir(caster_ptr, &dir))
589             return FALSE;
590         dam = caster_ptr->chp * 2 / 3;
591         typ = get_element_spells_type(caster_ptr, power.elem);
592         (void)fire_breath(caster_ptr, typ, dir, dam, 3);
593         break;
594     case ElementSpells::STORM_3ND:
595         if (!get_aim_dir(caster_ptr, &dir))
596             return FALSE;
597         dam = 300 + plev * 5;
598         typ = get_element_spells_type(caster_ptr, power.elem);
599         (void)fire_ball(caster_ptr, typ, dir, dam, 5);
600         break;
601     default:
602         return FALSE;
603     }
604
605     return TRUE;
606 }
607
608 /*!
609  * @brief 元素魔法呪文の失敗率を計算
610  * @param caster_ptr プレイヤー情報への参照ポインタ
611  * @param spell_idx 呪文番号
612  * @return 失敗率
613  */
614 static PERCENTAGE decide_element_chance(player_type *caster_ptr, mind_type spell)
615 {
616     PERCENTAGE chance = spell.fail;
617
618     chance -= 3 * (caster_ptr->lev - spell.min_lev);
619     chance += caster_ptr->to_m_chance;
620     chance -= 3 * (adj_mag_stat[caster_ptr->stat_index[A_WIS]] - 1);
621     
622     PERCENTAGE minfail = adj_mag_fail[caster_ptr->stat_index[A_WIS]];
623     if (chance < minfail)
624         chance = minfail;
625
626     if (caster_ptr->stun > 50)
627         chance += 25;
628     else if (caster_ptr->stun)
629         chance += 15;
630
631     if (heavy_armor(caster_ptr))
632         chance += 5;
633
634     if (caster_ptr->icky_wield[0])
635         chance += 5;
636
637     if (caster_ptr->icky_wield[1])
638         chance += 5;
639
640     if (chance > 95)
641         chance = 95;
642
643     return chance;
644 }
645
646 /*!
647  * @brief 元素魔法呪文の消費MPを計算
648  * @param caster_ptr プレイヤー情報への参照ポインタ
649  * @param spell_idx 呪文番号
650  * @return 消費MP
651  */
652 static MANA_POINT decide_element_mana_cost(player_type *caster_ptr, mind_type spell)
653 {
654     (void)caster_ptr;
655     return spell.mana_cost;
656 }
657
658 /*!
659  * @brief 元素魔法呪文を選択して取得
660  * @param caster_ptr プレイヤー情報への参照ポインタ
661  * @param sn 呪文番号
662  * @param only_browse 閲覧モードかどうか
663  * @return 選んだらTRUE、選ばなかったらFALSE
664  */
665 bool get_element_power(player_type *caster_ptr, SPELL_IDX *sn, bool only_browse)
666 {
667     SPELL_IDX i;
668     int num = 0;
669     TERM_LEN y = 1;
670     TERM_LEN x = 10;
671     PLAYER_LEVEL plev = caster_ptr->lev;
672     int ask = TRUE;
673     char choice;
674     char out_val[160];
675     char comment[80];
676     COMMAND_CODE code;
677     bool flag, redraw;
678     int menu_line = (use_menu ? 1 : 0);
679
680     *sn = -1;
681     if (repeat_pull(&code)) {
682         *sn = (SPELL_IDX)code;
683         if (get_elemental_info(caster_ptr, *sn).min_lev <= plev)
684             return TRUE;
685     }
686
687     concptr p = _("元素魔法", "magic");
688     flag = FALSE;
689     redraw = FALSE;
690
691     for (i = 0; i < static_cast<SPELL_IDX>(ElementSpells::MAX); i++) {
692         if (get_elemental_info(caster_ptr, i).min_lev <= plev)
693             num++;
694     }
695
696     if (only_browse)
697         (void)strnfmt(out_val, 78, 
698             _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
699             p, I2A(0), I2A(num - 1), p);
700     else
701         (void)strnfmt(out_val, 78, 
702             _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
703             p, I2A(0), I2A(num - 1), p);
704
705     if (use_menu && !only_browse)
706         screen_save();
707
708     int elem;
709     mind_type spell;
710     choice = (always_show_list || use_menu) ? ESCAPE : 1;
711     while (!flag) {
712         if (choice == ESCAPE)
713             choice = ' ';
714         else if (!get_com(out_val, &choice, TRUE))
715             break;
716
717         if (use_menu && choice != ' ') {
718             switch (choice) {
719             case '0':
720                 if (!only_browse)
721                     screen_load();
722                 return FALSE;
723             case '8':
724             case 'k':
725             case 'K':
726                 menu_line += (num - 1);
727                 break;
728             case '2':
729             case 'j':
730             case 'J':
731                 menu_line++;
732                 break;
733             case 'x':
734             case 'X':
735             case '\r':
736             case '\n':
737                 i = menu_line - 1;
738                 ask = FALSE;
739                 break;
740             }
741
742             if (menu_line > num)
743                 menu_line -= num;
744         }
745
746         int spell_max = static_cast<int>(ElementSpells::MAX);
747         if ((choice == ' ') || (choice == '*') || (choice == '?') || (use_menu && ask)) {
748             if (!redraw || use_menu) {
749                 char desc[80];
750                 char name[80];
751                 redraw = TRUE;
752                 if (!only_browse && !use_menu)
753                     screen_save();
754
755                 prt("", y, x);
756                 put_str(_("名前", "Name"), y, x + 5);
757                 put_str(_("Lv   MP   失率 効果", "Lv   MP   Fail Info"), y, x + 35);
758                 for (i = 0; i < spell_max; i++) {
759                     elem = get_elemental_elem(caster_ptr, i);
760                     spell = get_elemental_info(caster_ptr, i);
761
762                     if (spell.min_lev > plev)
763                         break;
764
765                     PERCENTAGE chance = decide_element_chance(caster_ptr, spell);
766                     int mana_cost = decide_element_mana_cost(caster_ptr, spell);
767                     get_element_effect_info(caster_ptr, i, comment);
768
769                     if (use_menu) {
770                         if (i == (menu_line - 1))
771                             strcpy(desc, _("  》 ", "  >  "));
772                         else
773                             strcpy(desc, "     ");
774                     } else
775                         sprintf(desc, "  %c) ", I2A(i));
776
777                     concptr s = get_element_name(caster_ptr->realm1, elem);
778                     sprintf(name, spell.name, s);
779                     strcat(desc,
780                         format("%-30s%2d %4d %3d%%%s", name, spell.min_lev, mana_cost, chance, comment));
781                     prt(desc, y + i + 1, x);
782                 }
783
784                 prt("", y + i + 1, x);
785             } else if (!only_browse) {
786                 redraw = FALSE;
787                 screen_load();
788             }
789
790             continue;
791         }
792
793         if (!use_menu) {
794             ask = isupper(choice);
795             if (ask)
796                 choice = (char)tolower(choice);
797
798             i = (islower(choice) ? A2I(choice) : -1);
799         }
800
801         if ((i < 0) || (i >= num)) {
802             bell();
803             continue;
804         }
805
806         spell = get_elemental_info(caster_ptr, i);
807         if (ask) {
808             char tmp_val[160];
809             (void)strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), spell.name);
810             if (!get_check(tmp_val))
811                 continue;
812         }
813
814         flag = TRUE;
815     }
816
817     if (redraw && !only_browse)
818         screen_load();
819
820     set_bits(caster_ptr->window_flags, PW_SPELL);
821     handle_stuff(caster_ptr);
822     if (!flag)
823         return FALSE;
824
825     *sn = i;
826     repeat_push((COMMAND_CODE)i);
827     return TRUE;
828 }
829
830 /*!
831  * @brief 元素魔法呪文をMPがなくても挑戦するか確認する
832  * @param caster_ptr プレイヤー情報への参照ポインタ
833  * @param mana_cost 消費MP
834  * @return 詠唱するならTRUE、しないならFALSE
835  */
836 static bool check_element_mp_sufficiency(player_type *caster_ptr, int mana_cost)
837 {
838     if (mana_cost <= caster_ptr->csp)
839         return TRUE;
840
841     msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
842     if (!over_exert)
843         return FALSE;
844
845     return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
846 }
847
848 /*!
849  * @brief 元素魔法呪文の詠唱を試み、成功なら詠唱し、失敗ならファンブルする
850  * @param caster_ptr プレイヤー情報への参照ポインタ
851  * @param spell_idx 呪文番号
852  * @param chance 失敗率
853  * @return 詠唱して実行したらTRUE、されなかったらFALSE
854  */
855 static bool try_cast_element_spell(player_type *caster_ptr, SPELL_IDX spell_idx, PERCENTAGE chance)
856 {
857     if (randint0(100) >= chance) {
858         sound(SOUND_ZAP);
859         return cast_element_spell(caster_ptr, spell_idx);
860     }
861
862     if (flush_failure)
863         flush();
864
865     msg_format(_("魔力の集中に失敗した!", "You failed to concentrate hard enough for Mana!"));
866     sound(SOUND_FAIL);
867
868     if (randint1(100) < chance / 2) {
869         int plev = caster_ptr->lev;
870         msg_print(_("元素の力が制御できない氾流となって解放された!",
871             "Elemental power unleashes its power in an uncontrollable storm!"));
872         project(caster_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + plev / 10, caster_ptr->y, caster_ptr->x, plev * 2,
873             get_element_types(caster_ptr->realm1)[0],
874             PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM, -1);
875         caster_ptr->csp = MAX(0, caster_ptr->csp - caster_ptr->msp * 10 / (20 + randint1(10)));
876
877         take_turn(caster_ptr, 100);
878         set_bits(caster_ptr->redraw, PR_MANA);
879         set_bits(caster_ptr->window_flags, PW_PLAYER | PW_SPELL);
880
881         return FALSE;
882     }
883
884     return TRUE;
885 }
886
887 /*!
888  * @brief 元素魔法コマンドのメインルーチン
889  * @param caster_ptr プレイヤー情報への参照ポインタ
890  * @return なし
891  */
892 void do_cmd_element(player_type *caster_ptr)
893 {
894     SPELL_IDX i;
895     if (cmd_limit_confused(caster_ptr) || !get_element_power(caster_ptr, &i, FALSE))
896         return;
897
898     mind_type spell = get_elemental_info(caster_ptr, i);
899     PERCENTAGE chance = decide_element_chance(caster_ptr, spell);
900     int mana_cost = decide_element_mana_cost(caster_ptr, spell);
901
902     if (!check_element_mp_sufficiency(caster_ptr, mana_cost))
903         return;
904
905     if (!try_cast_element_spell(caster_ptr, i, chance))
906         return;
907
908     if (mana_cost <= caster_ptr->csp) {
909         caster_ptr->csp -= mana_cost;
910     } else {
911         int oops = mana_cost;
912         caster_ptr->csp = 0;
913         caster_ptr->csp_frac = 0;
914         msg_print(_("精神を集中しすぎて気を失ってしまった!", "You faint from the effort!"));
915         (void)set_paralyzed(caster_ptr, caster_ptr->paralyzed + randint1(5 * oops + 1));
916         chg_virtue(caster_ptr, V_KNOWLEDGE, -10);
917         if (randint0(100) < 50) {
918             bool perm = (randint0(100) < 25);
919             msg_print(_("体を悪くしてしまった!", "You have damaged your health!"));
920             (void)dec_stat(caster_ptr, A_CON, 15 + randint1(10), perm);
921         }
922     }
923
924     take_turn(caster_ptr, 100);
925     set_bits(caster_ptr->redraw, PR_MANA);
926     set_bits(caster_ptr->window_flags, PW_PLAYER | PW_SPELL);
927 }
928
929 /*!
930  * @brief 現在プレイヤーが使用可能な元素魔法の一覧表示
931  * @param caster_ptr プレイヤー情報への参照ポインタ
932  * @return なし
933  */
934 void do_cmd_element_browse(player_type *caster_ptr)
935 {
936     SPELL_IDX n = 0;
937     char temp[62 * 5];
938
939     screen_save();
940     while (TRUE) {
941         if (!get_element_power(caster_ptr, &n, TRUE)) {
942             screen_load();
943             return;
944         }
945
946         term_erase(12, 21, 255);
947         term_erase(12, 20, 255);
948         term_erase(12, 19, 255);
949         term_erase(12, 18, 255);
950         term_erase(12, 17, 255);
951         term_erase(12, 16, 255);
952         shape_buffer(get_element_tip(caster_ptr, n), 62, temp, sizeof(temp));
953         for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
954             prt(&temp[j], line, 15);
955             line++;
956         }
957
958         prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
959         (void)inkey();
960     }
961 }
962
963 /*!
964  * @brief 元素魔法の単体抹殺が有効か確認する
965  * @param r_ptr モンスター種族への参照ポインタ
966  * @param type 魔法攻撃属性
967  * @return 効果があるならTRUE、なければFALSE
968  */
969 bool is_elemental_genocide_effective(monster_race *r_ptr, spells_type type)
970 {
971     switch (type) {
972     case GF_FIRE:
973         if (any_bits(r_ptr->flagsr, RFR_IM_FIRE))
974             return FALSE;
975         break;
976     case GF_COLD:
977         if (any_bits(r_ptr->flagsr, RFR_IM_COLD))
978             return FALSE;
979         break;
980     case GF_ELEC:
981         if (any_bits(r_ptr->flagsr, RFR_IM_ELEC))
982             return FALSE;
983         break;
984     case GF_ACID:
985         if (any_bits(r_ptr->flagsr, RFR_IM_ACID))
986             return FALSE;
987         break;
988     case GF_DARK:
989         if (any_bits(r_ptr->flagsr, RFR_RES_DARK) || any_bits(r_ptr->r_flags3, RF3_HURT_LITE))
990             return FALSE;
991         break;
992     case GF_CONFUSION:
993         if (any_bits(r_ptr->flags3, RF3_NO_CONF))
994             return FALSE;
995         break;
996     case GF_SHARDS:
997         if (any_bits(r_ptr->flagsr, RFR_RES_SHAR))
998             return FALSE;
999         break;
1000     case GF_POIS:
1001         if (any_bits(r_ptr->flagsr, RFR_IM_POIS))
1002             return FALSE;
1003         break;
1004     default:
1005         return FALSE;
1006     }
1007
1008     return TRUE;
1009 }
1010
1011 /*!
1012  * @brief 元素魔法の単体抹殺の効果を発動する 
1013  * @param caster_ptr プレイヤー情報への参照ポインタ
1014  * @param em_ptr 魔法効果情報への参照ポインタ
1015  * @return 効果処理を続けるかどうか
1016  */
1017 process_result effect_monster_elemental_genocide(player_type *caster_ptr, effect_monster_type *em_ptr)
1018 {
1019     auto type = get_element_type(caster_ptr->realm1, 0);
1020     auto name = get_element_name(caster_ptr->realm1, 0);
1021     bool b = is_elemental_genocide_effective(em_ptr->r_ptr, type);
1022
1023     if (em_ptr->seen_msg)
1024         msg_format(_("%sが%sを包み込んだ。", "The %s surrounds %s."), name, em_ptr->m_name);
1025
1026     if (em_ptr->seen)
1027         em_ptr->obvious = TRUE;
1028
1029     if (!b) {
1030         if (em_ptr->seen_msg)
1031             msg_format(_("%sには効果がなかった。", "%^s is unaffected."), em_ptr->m_name);
1032         em_ptr->dam = 0;
1033         return PROCESS_TRUE;
1034     }
1035
1036     if (genocide_aux(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam, !em_ptr->who, (em_ptr->r_ptr->level + 1) / 2, _("モンスター消滅", "Genocide One"))) {
1037         if (em_ptr->seen_msg)
1038             msg_format(_("%sは消滅した!", "%^s disappeared!"), em_ptr->m_name);
1039         em_ptr->dam = 0;
1040         chg_virtue(caster_ptr, V_VITALITY, -1);
1041         return PROCESS_TRUE;
1042     }
1043
1044     em_ptr->skipped = TRUE;
1045     return PROCESS_CONTINUE;
1046 }
1047
1048 /*!
1049  * @brief 元素領域とレベルの条件に見合うかチェックする
1050  * @param caster_ptr プレイヤー情報への参照ポインタ
1051  * @param realm 領域
1052  * @param lev プレイヤーレベル
1053  * @return 見合うならTRUE、そうでなければFALSE
1054  * @detail
1055  * レベルに応じて取得する耐性などの判定に使用する
1056  */
1057 bool has_element_resist(player_type *creature_ptr, ElementRealm realm, PLAYER_LEVEL lev)
1058 {
1059     if (creature_ptr->pclass != CLASS_ELEMENTALIST)
1060         return FALSE;
1061
1062     auto prealm = static_cast<ElementRealm>(creature_ptr->realm1);
1063     return (prealm == realm && creature_ptr->lev >= lev);
1064 }
1065
1066 /*!
1067  * @brief 領域選択時のカーソル表示(シンボル+領域名)
1068  * @param i 位置
1069  * @param n 最後尾の位置
1070  * @param color 表示色
1071  * @return なし
1072  */
1073 static void display_realm_cursor(int i, int n, term_color_type color)
1074 {
1075     char cur[80];
1076     char sym;
1077     concptr name;
1078     if (i == n) {
1079         sym = '*';
1080         name = _("ランダム", "Random");
1081     } else {
1082         sym = I2A(i);
1083         name = element_types.at(static_cast<ElementRealm>(i + 1)).title.data();
1084     }
1085     sprintf(cur, "%c) %s", sym, name);
1086
1087     c_put_str(color, cur, 12 + (i / 5), 2 + 15 * (i % 5));
1088 }
1089
1090 /*!
1091  * @brief 領域選択時の移動キー処理
1092  * @param cs 現在位置
1093  * @param n 最後尾の位置
1094  * @param c 入力キー
1095  * @return 新しい位置
1096  */
1097 static int interpret_realm_select_key(int cs, int n, char c)
1098 {
1099     if (c == 'Q')
1100         quit(NULL);
1101
1102     if (c == '8')
1103         if (cs >= 5)
1104             return cs - 5;
1105
1106     if (c == '4')
1107         if (cs > 0)
1108             return cs - 1;
1109
1110     if (c == '6')
1111         if (cs < n)
1112             return cs + 1;
1113
1114     if (c == '2')
1115         if (cs + 5 <= n)
1116             return cs + 5;
1117
1118     return cs;
1119 }
1120
1121 /*!
1122  * @brief 領域選択ループ処理
1123  * @param creature_ptr プレイヤー情報への参照ポインタ
1124  * @param n 最後尾の位置
1125  * @return 領域番号
1126  */
1127 static int get_element_realm(player_type *creature_ptr, int is, int n)
1128 {
1129     int cs = MAX(0, is);
1130     int os = cs;
1131     int k;
1132
1133     char buf[80];
1134     sprintf(buf, _("領域を選んで下さい(%c-%c) ('='初期オプション設定): ", "Choose a realm (%c-%c) ('=' for options): "), I2A(0), I2A(n - 1));
1135
1136     while (TRUE) {
1137         display_realm_cursor(os, n, TERM_WHITE);
1138         display_realm_cursor(cs, n, TERM_YELLOW);
1139         put_str(buf, 10, 10);
1140         os = cs;
1141
1142         char c = inkey();
1143         cs = interpret_realm_select_key(cs, n, c);
1144
1145         if (c == 'S')
1146             return 255;
1147
1148         if (c == ' ' || c == '\r' || c == '\n') {
1149             if (cs == n) {
1150                 display_realm_cursor(cs, n, TERM_WHITE);
1151                 cs = randint0(n - 1);
1152             }
1153             break;
1154         }
1155
1156         if (c == '*') {
1157             display_realm_cursor(cs, n, TERM_WHITE);
1158             cs = randint0(n - 1);
1159             break;
1160         }
1161
1162         k = islower(c) ? A2I(c) : -1;
1163         if (k >= 0 && k < n) {
1164             display_realm_cursor(cs, n, TERM_WHITE);
1165             cs = k;
1166             break;
1167         }
1168
1169         k = isupper(c) ? (26 + c - 'A') : -1;
1170         if (k >= 26 && k < n) {
1171             display_realm_cursor(cs, n, TERM_WHITE);
1172             cs = k;
1173             break;
1174         }
1175
1176         if (c == '=') {
1177             screen_save();
1178             do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
1179             screen_load();
1180         } else if (c != '2' && c != '4' && c != '6' && c != '8')
1181             bell();
1182     }
1183
1184     display_realm_cursor(cs, n, TERM_YELLOW);
1185     return (cs + 1);
1186 }
1187
1188 /*!
1189  * @brief 領域選択
1190  * @param creature_ptr プレイヤー情報への参照ポインタ
1191  * @return 領域番号
1192  */
1193 byte select_element_realm(player_type *creature_ptr)
1194 {
1195     clear_from(10);
1196
1197     int realm_max = static_cast<int>(ElementRealm::MAX);
1198     int realm_idx = 1;
1199     int row = 16;
1200     while (1) {
1201         put_str(
1202             _("注意:元素系統の選択によりあなたが習得する呪文のタイプが決まります。", "Note: The system of element will determine which spells you can learn."),
1203             23, 5);
1204
1205         for (int i = 0; i < realm_max; i++) {
1206             display_realm_cursor(i, realm_max - 1, TERM_WHITE);
1207         }
1208
1209         realm_idx = get_element_realm(creature_ptr, realm_idx - 1, realm_max - 1);
1210         if (realm_idx == 255)
1211             break;
1212
1213         auto realm = static_cast<ElementRealm>(realm_idx);
1214         char temp[80 * 5];
1215         shape_buffer(element_texts.at(realm).data(), 74, temp, sizeof(temp));
1216         concptr t = temp;
1217         for (int i = 0; i < 5; i++) {
1218             if (t[0] == 0)
1219                 break;
1220             prt(t, row + i, 3);
1221             t += strlen(t) + 1;
1222         }
1223
1224         if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
1225             break;
1226
1227         clear_from(row);
1228     }
1229
1230     clear_from(10);
1231     return (byte)realm_idx;
1232 }
1233
1234 /*!
1235  * @brief クラスパワー情報を追加
1236  * @param creature_ptr プレイヤー情報への参照ポインタ
1237  * @param rc_ptr レイシャルパワー情報への参照ポインタ
1238  * @return なし
1239  */
1240 void switch_element_racial(player_type *creature_ptr, rc_type *rc_ptr)
1241 {
1242     auto plev = creature_ptr->lev;
1243     auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
1244     switch (realm) {
1245     case ElementRealm::FIRE:
1246         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("ライト・エリア", "Light area"));
1247         rc_ptr->power_desc[rc_ptr->num].min_level = 3;
1248         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1249         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1250         rc_ptr->power_desc[rc_ptr->num].fail = 10;
1251         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1252         break;
1253     case ElementRealm::ICE:
1254         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("周辺フリーズ", "Sleep monsters"));
1255         rc_ptr->power_desc[rc_ptr->num].min_level = 10;
1256         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1257         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1258         rc_ptr->power_desc[rc_ptr->num].fail = 25;
1259         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1260         break;
1261     case ElementRealm::SKY:
1262         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("魔力充填", "Recharging"));
1263         rc_ptr->power_desc[rc_ptr->num].min_level = 20;
1264         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1265         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1266         rc_ptr->power_desc[rc_ptr->num].fail = 25;
1267         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1268         break;
1269     case ElementRealm::SEA:
1270         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("岩石溶解", "Stone to mud"));
1271         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1272         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1273         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1274         rc_ptr->power_desc[rc_ptr->num].fail = 10;
1275         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1276         break;
1277     case ElementRealm::DARKNESS:
1278         sprintf(rc_ptr->power_desc[rc_ptr->num].racial_name, _("闇の扉(半径%d)", "Door to darkness(rad %d)"), 15 + plev / 2);
1279         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1280         rc_ptr->power_desc[rc_ptr->num].cost = 5 + plev / 7;
1281         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1282         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1283         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1284         break;
1285     case ElementRealm::CHAOS:
1286         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("現実変容", "Alter reality"));
1287         rc_ptr->power_desc[rc_ptr->num].min_level = 35;
1288         rc_ptr->power_desc[rc_ptr->num].cost = 30;
1289         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1290         rc_ptr->power_desc[rc_ptr->num].fail = 40;
1291         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1292         break;
1293     case ElementRealm::EARTH:
1294         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("地震", "Earthquake"));
1295         rc_ptr->power_desc[rc_ptr->num].min_level = 25;
1296         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1297         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1298         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1299         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1300         break;
1301     case ElementRealm::DEATH:
1302         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("増殖阻止", "Sterilization"));
1303         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1304         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1305         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1306         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1307         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1308         break;
1309     default:
1310         break;
1311     }
1312 }
1313
1314 /*!
1315  * @todo 宣言だけ。後日適切な場所に移動
1316  */
1317 static bool door_to_darkness(player_type *caster_ptr, POSITION dist);
1318
1319 /*!
1320  * @brief クラスパワーを実行
1321  * @param creature_ptr プレイヤー情報への参照ポインタ
1322  * @return 実行したらTRUE、しなかったらFALSE
1323  */
1324 bool switch_element_execution(player_type *creature_ptr)
1325 {
1326     auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
1327     PLAYER_LEVEL plev = creature_ptr->lev;
1328     DIRECTION dir;
1329
1330     switch (realm) {
1331     case ElementRealm::FIRE:
1332         (void)lite_area(creature_ptr, damroll(2, plev / 2), plev / 10);
1333         break;
1334     case ElementRealm::ICE:
1335         (void)project(creature_ptr, 0, 5, creature_ptr->y, creature_ptr->x, 1, GF_COLD, PROJECT_ITEM, -1);
1336         (void)project_all_los(creature_ptr, GF_OLD_SLEEP, 20 + plev * 3 / 2);
1337         break;
1338     case ElementRealm::SKY:
1339         (void)recharge(creature_ptr, 120);
1340         break;
1341     case ElementRealm::SEA:
1342         if (!get_aim_dir(creature_ptr, &dir))
1343             return FALSE;
1344         (void)wall_to_mud(creature_ptr, dir, plev * 3 / 2);
1345         break;
1346     case ElementRealm::DARKNESS:
1347         return door_to_darkness(creature_ptr, 15 + plev / 2);
1348         break;
1349     case ElementRealm::CHAOS:
1350         reserve_alter_reality(creature_ptr, randint0(21) + 15);
1351         break;
1352     case ElementRealm::EARTH:
1353         (void)earthquake(creature_ptr, creature_ptr->y, creature_ptr->x, 10, 0);
1354         break;
1355     case ElementRealm::DEATH:
1356         if (creature_ptr->current_floor_ptr->num_repro <= MAX_REPRO)
1357             creature_ptr->current_floor_ptr->num_repro += MAX_REPRO;
1358         break;
1359     default:
1360         return FALSE;
1361     }
1362
1363     return TRUE;
1364 }
1365
1366 /*!
1367  * @brief 指定したマスが暗いかどうか
1368  * @param f_ptr 階の情報への参照ポインタ
1369  * @param y 指定のy座標
1370  * @param x 指定のx座標
1371  * @return 暗いならTRUE、そうでないならFALSE
1372  */
1373 static bool is_target_grid_dark(floor_type* f_ptr, POSITION y, POSITION x)
1374 {
1375     if (any_bits(f_ptr->grid_array[y][x].info, CAVE_MNLT))
1376         return FALSE;
1377
1378     bool is_dark = FALSE;
1379     bool is_lite = any_bits(f_ptr->grid_array[y][x].info, CAVE_GLOW | CAVE_LITE);
1380
1381     for (int dx = x - 2; dx <= x + 2; dx++)
1382         for (int dy = y - 2; dy <= y + 2; dy++) {
1383             if (dx == x && dy == y)
1384                 continue;
1385             if (!in_bounds(f_ptr, dy, dx))
1386                 continue;
1387
1388             MONSTER_IDX m_idx = f_ptr->grid_array[dy][dx].m_idx;
1389             if (!m_idx)
1390                 continue;
1391
1392             POSITION d = distance(dy, dx, y, x);
1393             monster_race *r_ptr = &r_info[f_ptr->m_list[m_idx].r_idx];
1394             if (d <= 1 && any_bits(r_ptr->flags7, RF7_HAS_LITE_1 | RF7_SELF_LITE_1))
1395                 return FALSE;
1396             if (d <= 2 && any_bits(r_ptr->flags7, RF7_HAS_LITE_2 | RF7_SELF_LITE_2))
1397                 return FALSE;
1398             if (d <= 1 && any_bits(r_ptr->flags7, RF7_HAS_DARK_1 | RF7_SELF_DARK_1))
1399                 is_dark = TRUE;
1400             if (d <= 2 && any_bits(r_ptr->flags7, RF7_HAS_DARK_2 | RF7_SELF_DARK_2))
1401                 is_dark = TRUE;
1402         }
1403
1404     return !is_lite || is_dark;
1405 }
1406
1407 /*!
1408  * @breif 暗いところ限定での次元の扉
1409  * @param caster_ptr プレイヤー情報への参照ポインタ
1410  */
1411 static bool door_to_darkness(player_type* caster_ptr, POSITION dist)
1412 {
1413     POSITION y = caster_ptr->y;
1414     POSITION x = caster_ptr->x;
1415     floor_type *f_ptr;
1416
1417     for (int i = 0; i < 3; i++) {
1418         if (!tgt_pt(caster_ptr, &x, &y))
1419             return FALSE;
1420
1421         f_ptr = caster_ptr->current_floor_ptr;
1422
1423         if (distance(y, x, caster_ptr->y, caster_ptr->x) > dist) {
1424             msg_print(_("遠すぎる!", "There is too far!"));
1425             continue;
1426         }
1427
1428         if (!is_cave_empty_bold(caster_ptr, y, x) || f_ptr->grid_array[y][x].info & CAVE_ICKY) {
1429             msg_print(_("そこには移動できない。", "Can not teleport to there."));
1430             continue;
1431         }
1432
1433         break;
1434     }
1435
1436     bool flag = cave_player_teleportable_bold(caster_ptr, y, x, TELEPORT_SPONTANEOUS)  && is_target_grid_dark(f_ptr, y, x);
1437     if (flag) {
1438         teleport_player_to(caster_ptr, y, x, TELEPORT_SPONTANEOUS);
1439     } else {
1440         msg_print(_("闇の扉は開かなかった!", "Door to darkness does not open!"));
1441     }
1442     return TRUE;
1443 }