OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[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         if (ask) {
807             char name[80];
808             char tmp_val[160];
809             elem = get_elemental_elem(caster_ptr, i);
810             spell = get_elemental_info(caster_ptr, i);
811             (void)sprintf(name, spell.name, get_element_name(caster_ptr->realm1, elem));
812             (void)strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), name);
813             if (!get_check(tmp_val))
814                 continue;
815         }
816
817         flag = TRUE;
818     }
819
820     if (redraw && !only_browse)
821         screen_load();
822
823     set_bits(caster_ptr->window_flags, PW_SPELL);
824     handle_stuff(caster_ptr);
825     if (!flag)
826         return FALSE;
827
828     *sn = i;
829     repeat_push((COMMAND_CODE)i);
830     return TRUE;
831 }
832
833 /*!
834  * @brief 元素魔法呪文をMPがなくても挑戦するか確認する
835  * @param caster_ptr プレイヤー情報への参照ポインタ
836  * @param mana_cost 消費MP
837  * @return 詠唱するならTRUE、しないならFALSE
838  */
839 static bool check_element_mp_sufficiency(player_type *caster_ptr, int mana_cost)
840 {
841     if (mana_cost <= caster_ptr->csp)
842         return TRUE;
843
844     msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
845     if (!over_exert)
846         return FALSE;
847
848     return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
849 }
850
851 /*!
852  * @brief 元素魔法呪文の詠唱を試み、成功なら詠唱し、失敗ならファンブルする
853  * @param caster_ptr プレイヤー情報への参照ポインタ
854  * @param spell_idx 呪文番号
855  * @param chance 失敗率
856  * @return 詠唱して実行したらTRUE、されなかったらFALSE
857  */
858 static bool try_cast_element_spell(player_type *caster_ptr, SPELL_IDX spell_idx, PERCENTAGE chance)
859 {
860     if (randint0(100) >= chance) {
861         sound(SOUND_ZAP);
862         return cast_element_spell(caster_ptr, spell_idx);
863     }
864
865     if (flush_failure)
866         flush();
867
868     msg_format(_("魔力の集中に失敗した!", "You failed to concentrate hard enough for Mana!"));
869     sound(SOUND_FAIL);
870
871     if (randint1(100) < chance / 2) {
872         int plev = caster_ptr->lev;
873         msg_print(_("元素の力が制御できない氾流となって解放された!",
874             "Elemental power unleashes its power in an uncontrollable storm!"));
875         project(caster_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + plev / 10, caster_ptr->y, caster_ptr->x, plev * 2,
876             get_element_types(caster_ptr->realm1)[0],
877             PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM, -1);
878         caster_ptr->csp = MAX(0, caster_ptr->csp - caster_ptr->msp * 10 / (20 + randint1(10)));
879
880         take_turn(caster_ptr, 100);
881         set_bits(caster_ptr->redraw, PR_MANA);
882         set_bits(caster_ptr->window_flags, PW_PLAYER | PW_SPELL);
883
884         return FALSE;
885     }
886
887     return TRUE;
888 }
889
890 /*!
891  * @brief 元素魔法コマンドのメインルーチン
892  * @param caster_ptr プレイヤー情報への参照ポインタ
893  * @return なし
894  */
895 void do_cmd_element(player_type *caster_ptr)
896 {
897     SPELL_IDX i;
898     if (cmd_limit_confused(caster_ptr) || !get_element_power(caster_ptr, &i, FALSE))
899         return;
900
901     mind_type spell = get_elemental_info(caster_ptr, i);
902     PERCENTAGE chance = decide_element_chance(caster_ptr, spell);
903     int mana_cost = decide_element_mana_cost(caster_ptr, spell);
904
905     if (!check_element_mp_sufficiency(caster_ptr, mana_cost))
906         return;
907
908     if (!try_cast_element_spell(caster_ptr, i, chance))
909         return;
910
911     if (mana_cost <= caster_ptr->csp) {
912         caster_ptr->csp -= mana_cost;
913     } else {
914         int oops = mana_cost;
915         caster_ptr->csp = 0;
916         caster_ptr->csp_frac = 0;
917         msg_print(_("精神を集中しすぎて気を失ってしまった!", "You faint from the effort!"));
918         (void)set_paralyzed(caster_ptr, caster_ptr->paralyzed + randint1(5 * oops + 1));
919         chg_virtue(caster_ptr, V_KNOWLEDGE, -10);
920         if (randint0(100) < 50) {
921             bool perm = (randint0(100) < 25);
922             msg_print(_("体を悪くしてしまった!", "You have damaged your health!"));
923             (void)dec_stat(caster_ptr, A_CON, 15 + randint1(10), perm);
924         }
925     }
926
927     take_turn(caster_ptr, 100);
928     set_bits(caster_ptr->redraw, PR_MANA);
929     set_bits(caster_ptr->window_flags, PW_PLAYER | PW_SPELL);
930 }
931
932 /*!
933  * @brief 現在プレイヤーが使用可能な元素魔法の一覧表示
934  * @param caster_ptr プレイヤー情報への参照ポインタ
935  * @return なし
936  */
937 void do_cmd_element_browse(player_type *caster_ptr)
938 {
939     SPELL_IDX n = 0;
940     char temp[62 * 5];
941
942     screen_save();
943     while (TRUE) {
944         if (!get_element_power(caster_ptr, &n, TRUE)) {
945             screen_load();
946             return;
947         }
948
949         term_erase(12, 21, 255);
950         term_erase(12, 20, 255);
951         term_erase(12, 19, 255);
952         term_erase(12, 18, 255);
953         term_erase(12, 17, 255);
954         term_erase(12, 16, 255);
955         shape_buffer(get_element_tip(caster_ptr, n), 62, temp, sizeof(temp));
956         for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
957             prt(&temp[j], line, 15);
958             line++;
959         }
960
961         prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
962         (void)inkey();
963     }
964 }
965
966 /*!
967  * @brief 元素魔法の単体抹殺が有効か確認する
968  * @param r_ptr モンスター種族への参照ポインタ
969  * @param type 魔法攻撃属性
970  * @return 効果があるならTRUE、なければFALSE
971  */
972 bool is_elemental_genocide_effective(monster_race *r_ptr, spells_type type)
973 {
974     switch (type) {
975     case GF_FIRE:
976         if (any_bits(r_ptr->flagsr, RFR_IM_FIRE))
977             return FALSE;
978         break;
979     case GF_COLD:
980         if (any_bits(r_ptr->flagsr, RFR_IM_COLD))
981             return FALSE;
982         break;
983     case GF_ELEC:
984         if (any_bits(r_ptr->flagsr, RFR_IM_ELEC))
985             return FALSE;
986         break;
987     case GF_ACID:
988         if (any_bits(r_ptr->flagsr, RFR_IM_ACID))
989             return FALSE;
990         break;
991     case GF_DARK:
992         if (any_bits(r_ptr->flagsr, RFR_RES_DARK) || any_bits(r_ptr->r_flags3, RF3_HURT_LITE))
993             return FALSE;
994         break;
995     case GF_CONFUSION:
996         if (any_bits(r_ptr->flags3, RF3_NO_CONF))
997             return FALSE;
998         break;
999     case GF_SHARDS:
1000         if (any_bits(r_ptr->flagsr, RFR_RES_SHAR))
1001             return FALSE;
1002         break;
1003     case GF_POIS:
1004         if (any_bits(r_ptr->flagsr, RFR_IM_POIS))
1005             return FALSE;
1006         break;
1007     default:
1008         return FALSE;
1009     }
1010
1011     return TRUE;
1012 }
1013
1014 /*!
1015  * @brief 元素魔法の単体抹殺の効果を発動する 
1016  * @param caster_ptr プレイヤー情報への参照ポインタ
1017  * @param em_ptr 魔法効果情報への参照ポインタ
1018  * @return 効果処理を続けるかどうか
1019  */
1020 process_result effect_monster_elemental_genocide(player_type *caster_ptr, effect_monster_type *em_ptr)
1021 {
1022     auto type = get_element_type(caster_ptr->realm1, 0);
1023     auto name = get_element_name(caster_ptr->realm1, 0);
1024     bool b = is_elemental_genocide_effective(em_ptr->r_ptr, type);
1025
1026     if (em_ptr->seen_msg)
1027         msg_format(_("%sが%sを包み込んだ。", "The %s surrounds %s."), name, em_ptr->m_name);
1028
1029     if (em_ptr->seen)
1030         em_ptr->obvious = TRUE;
1031
1032     if (!b) {
1033         if (em_ptr->seen_msg)
1034             msg_format(_("%sには効果がなかった。", "%^s is unaffected."), em_ptr->m_name);
1035         em_ptr->dam = 0;
1036         return PROCESS_TRUE;
1037     }
1038
1039     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"))) {
1040         if (em_ptr->seen_msg)
1041             msg_format(_("%sは消滅した!", "%^s disappeared!"), em_ptr->m_name);
1042         em_ptr->dam = 0;
1043         chg_virtue(caster_ptr, V_VITALITY, -1);
1044         return PROCESS_TRUE;
1045     }
1046
1047     em_ptr->skipped = TRUE;
1048     return PROCESS_CONTINUE;
1049 }
1050
1051 /*!
1052  * @brief 元素領域とレベルの条件に見合うかチェックする
1053  * @param caster_ptr プレイヤー情報への参照ポインタ
1054  * @param realm 領域
1055  * @param lev プレイヤーレベル
1056  * @return 見合うならTRUE、そうでなければFALSE
1057  * @detail
1058  * レベルに応じて取得する耐性などの判定に使用する
1059  */
1060 bool has_element_resist(player_type *creature_ptr, ElementRealm realm, PLAYER_LEVEL lev)
1061 {
1062     if (creature_ptr->pclass != CLASS_ELEMENTALIST)
1063         return FALSE;
1064
1065     auto prealm = static_cast<ElementRealm>(creature_ptr->realm1);
1066     return (prealm == realm && creature_ptr->lev >= lev);
1067 }
1068
1069 /*!
1070  * @brief 領域選択時のカーソル表示(シンボル+領域名)
1071  * @param i 位置
1072  * @param n 最後尾の位置
1073  * @param color 表示色
1074  * @return なし
1075  */
1076 static void display_realm_cursor(int i, int n, term_color_type color)
1077 {
1078     char cur[80];
1079     char sym;
1080     concptr name;
1081     if (i == n) {
1082         sym = '*';
1083         name = _("ランダム", "Random");
1084     } else {
1085         sym = I2A(i);
1086         name = element_types.at(static_cast<ElementRealm>(i + 1)).title.data();
1087     }
1088     sprintf(cur, "%c) %s", sym, name);
1089
1090     c_put_str(color, cur, 12 + (i / 5), 2 + 15 * (i % 5));
1091 }
1092
1093 /*!
1094  * @brief 領域選択時の移動キー処理
1095  * @param cs 現在位置
1096  * @param n 最後尾の位置
1097  * @param c 入力キー
1098  * @return 新しい位置
1099  */
1100 static int interpret_realm_select_key(int cs, int n, char c)
1101 {
1102     if (c == 'Q')
1103         quit(NULL);
1104
1105     if (c == '8')
1106         if (cs >= 5)
1107             return cs - 5;
1108
1109     if (c == '4')
1110         if (cs > 0)
1111             return cs - 1;
1112
1113     if (c == '6')
1114         if (cs < n)
1115             return cs + 1;
1116
1117     if (c == '2')
1118         if (cs + 5 <= n)
1119             return cs + 5;
1120
1121     return cs;
1122 }
1123
1124 /*!
1125  * @brief 領域選択ループ処理
1126  * @param creature_ptr プレイヤー情報への参照ポインタ
1127  * @param n 最後尾の位置
1128  * @return 領域番号
1129  */
1130 static int get_element_realm(player_type *creature_ptr, int is, int n)
1131 {
1132     int cs = MAX(0, is);
1133     int os = cs;
1134     int k;
1135
1136     char buf[80];
1137     sprintf(buf, _("領域を選んで下さい(%c-%c) ('='初期オプション設定): ", "Choose a realm (%c-%c) ('=' for options): "), I2A(0), I2A(n - 1));
1138
1139     while (TRUE) {
1140         display_realm_cursor(os, n, TERM_WHITE);
1141         display_realm_cursor(cs, n, TERM_YELLOW);
1142         put_str(buf, 10, 10);
1143         os = cs;
1144
1145         char c = inkey();
1146         cs = interpret_realm_select_key(cs, n, c);
1147
1148         if (c == 'S')
1149             return 255;
1150
1151         if (c == ' ' || c == '\r' || c == '\n') {
1152             if (cs == n) {
1153                 display_realm_cursor(cs, n, TERM_WHITE);
1154                 cs = randint0(n - 1);
1155             }
1156             break;
1157         }
1158
1159         if (c == '*') {
1160             display_realm_cursor(cs, n, TERM_WHITE);
1161             cs = randint0(n - 1);
1162             break;
1163         }
1164
1165         k = islower(c) ? A2I(c) : -1;
1166         if (k >= 0 && k < n) {
1167             display_realm_cursor(cs, n, TERM_WHITE);
1168             cs = k;
1169             break;
1170         }
1171
1172         k = isupper(c) ? (26 + c - 'A') : -1;
1173         if (k >= 26 && k < n) {
1174             display_realm_cursor(cs, n, TERM_WHITE);
1175             cs = k;
1176             break;
1177         }
1178
1179         if (c == '=') {
1180             screen_save();
1181             do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
1182             screen_load();
1183         } else if (c != '2' && c != '4' && c != '6' && c != '8')
1184             bell();
1185     }
1186
1187     display_realm_cursor(cs, n, TERM_YELLOW);
1188     return (cs + 1);
1189 }
1190
1191 /*!
1192  * @brief 領域選択
1193  * @param creature_ptr プレイヤー情報への参照ポインタ
1194  * @return 領域番号
1195  */
1196 byte select_element_realm(player_type *creature_ptr)
1197 {
1198     clear_from(10);
1199
1200     int realm_max = static_cast<int>(ElementRealm::MAX);
1201     int realm_idx = 1;
1202     int row = 16;
1203     while (1) {
1204         put_str(
1205             _("注意:元素系統の選択によりあなたが習得する呪文のタイプが決まります。", "Note: The system of element will determine which spells you can learn."),
1206             23, 5);
1207
1208         for (int i = 0; i < realm_max; i++) {
1209             display_realm_cursor(i, realm_max - 1, TERM_WHITE);
1210         }
1211
1212         realm_idx = get_element_realm(creature_ptr, realm_idx - 1, realm_max - 1);
1213         if (realm_idx == 255)
1214             break;
1215
1216         auto realm = static_cast<ElementRealm>(realm_idx);
1217         char temp[80 * 5];
1218         shape_buffer(element_texts.at(realm).data(), 74, temp, sizeof(temp));
1219         concptr t = temp;
1220         for (int i = 0; i < 5; i++) {
1221             if (t[0] == 0)
1222                 break;
1223             prt(t, row + i, 3);
1224             t += strlen(t) + 1;
1225         }
1226
1227         if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
1228             break;
1229
1230         clear_from(row);
1231     }
1232
1233     clear_from(10);
1234     return (byte)realm_idx;
1235 }
1236
1237 /*!
1238  * @brief クラスパワー情報を追加
1239  * @param creature_ptr プレイヤー情報への参照ポインタ
1240  * @param rc_ptr レイシャルパワー情報への参照ポインタ
1241  * @return なし
1242  */
1243 void switch_element_racial(player_type *creature_ptr, rc_type *rc_ptr)
1244 {
1245     auto plev = creature_ptr->lev;
1246     auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
1247     switch (realm) {
1248     case ElementRealm::FIRE:
1249         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("ライト・エリア", "Light area"));
1250         rc_ptr->power_desc[rc_ptr->num].min_level = 3;
1251         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1252         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1253         rc_ptr->power_desc[rc_ptr->num].fail = 10;
1254         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1255         break;
1256     case ElementRealm::ICE:
1257         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("周辺フリーズ", "Sleep monsters"));
1258         rc_ptr->power_desc[rc_ptr->num].min_level = 10;
1259         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1260         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1261         rc_ptr->power_desc[rc_ptr->num].fail = 25;
1262         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1263         break;
1264     case ElementRealm::SKY:
1265         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("魔力充填", "Recharging"));
1266         rc_ptr->power_desc[rc_ptr->num].min_level = 20;
1267         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1268         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1269         rc_ptr->power_desc[rc_ptr->num].fail = 25;
1270         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1271         break;
1272     case ElementRealm::SEA:
1273         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("岩石溶解", "Stone to mud"));
1274         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1275         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1276         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1277         rc_ptr->power_desc[rc_ptr->num].fail = 10;
1278         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1279         break;
1280     case ElementRealm::DARKNESS:
1281         sprintf(rc_ptr->power_desc[rc_ptr->num].racial_name, _("闇の扉(半径%d)", "Door to darkness(rad %d)"), 15 + plev / 2);
1282         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1283         rc_ptr->power_desc[rc_ptr->num].cost = 5 + plev / 7;
1284         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1285         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1286         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1287         break;
1288     case ElementRealm::CHAOS:
1289         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("現実変容", "Alter reality"));
1290         rc_ptr->power_desc[rc_ptr->num].min_level = 35;
1291         rc_ptr->power_desc[rc_ptr->num].cost = 30;
1292         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1293         rc_ptr->power_desc[rc_ptr->num].fail = 40;
1294         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1295         break;
1296     case ElementRealm::EARTH:
1297         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("地震", "Earthquake"));
1298         rc_ptr->power_desc[rc_ptr->num].min_level = 25;
1299         rc_ptr->power_desc[rc_ptr->num].cost = 15;
1300         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1301         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1302         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1303         break;
1304     case ElementRealm::DEATH:
1305         strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("増殖阻止", "Sterilization"));
1306         rc_ptr->power_desc[rc_ptr->num].min_level = 5;
1307         rc_ptr->power_desc[rc_ptr->num].cost = 5;
1308         rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
1309         rc_ptr->power_desc[rc_ptr->num].fail = 20;
1310         rc_ptr->power_desc[rc_ptr->num++].number = -4;
1311         break;
1312     default:
1313         break;
1314     }
1315 }
1316
1317 /*!
1318  * @todo 宣言だけ。後日適切な場所に移動
1319  */
1320 static bool door_to_darkness(player_type *caster_ptr, POSITION dist);
1321
1322 /*!
1323  * @brief クラスパワーを実行
1324  * @param creature_ptr プレイヤー情報への参照ポインタ
1325  * @return 実行したらTRUE、しなかったらFALSE
1326  */
1327 bool switch_element_execution(player_type *creature_ptr)
1328 {
1329     auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
1330     PLAYER_LEVEL plev = creature_ptr->lev;
1331     DIRECTION dir;
1332
1333     switch (realm) {
1334     case ElementRealm::FIRE:
1335         (void)lite_area(creature_ptr, damroll(2, plev / 2), plev / 10);
1336         break;
1337     case ElementRealm::ICE:
1338         (void)project(creature_ptr, 0, 5, creature_ptr->y, creature_ptr->x, 1, GF_COLD, PROJECT_ITEM, -1);
1339         (void)project_all_los(creature_ptr, GF_OLD_SLEEP, 20 + plev * 3 / 2);
1340         break;
1341     case ElementRealm::SKY:
1342         (void)recharge(creature_ptr, 120);
1343         break;
1344     case ElementRealm::SEA:
1345         if (!get_aim_dir(creature_ptr, &dir))
1346             return FALSE;
1347         (void)wall_to_mud(creature_ptr, dir, plev * 3 / 2);
1348         break;
1349     case ElementRealm::DARKNESS:
1350         return door_to_darkness(creature_ptr, 15 + plev / 2);
1351         break;
1352     case ElementRealm::CHAOS:
1353         reserve_alter_reality(creature_ptr, randint0(21) + 15);
1354         break;
1355     case ElementRealm::EARTH:
1356         (void)earthquake(creature_ptr, creature_ptr->y, creature_ptr->x, 10, 0);
1357         break;
1358     case ElementRealm::DEATH:
1359         if (creature_ptr->current_floor_ptr->num_repro <= MAX_REPRO)
1360             creature_ptr->current_floor_ptr->num_repro += MAX_REPRO;
1361         break;
1362     default:
1363         return FALSE;
1364     }
1365
1366     return TRUE;
1367 }
1368
1369 /*!
1370  * @brief 指定したマスが暗いかどうか
1371  * @param f_ptr 階の情報への参照ポインタ
1372  * @param y 指定のy座標
1373  * @param x 指定のx座標
1374  * @return 暗いならTRUE、そうでないならFALSE
1375  */
1376 static bool is_target_grid_dark(floor_type* f_ptr, POSITION y, POSITION x)
1377 {
1378     if (any_bits(f_ptr->grid_array[y][x].info, CAVE_MNLT))
1379         return FALSE;
1380
1381     bool is_dark = FALSE;
1382     bool is_lite = any_bits(f_ptr->grid_array[y][x].info, CAVE_GLOW | CAVE_LITE);
1383
1384     for (int dx = x - 2; dx <= x + 2; dx++)
1385         for (int dy = y - 2; dy <= y + 2; dy++) {
1386             if (dx == x && dy == y)
1387                 continue;
1388             if (!in_bounds(f_ptr, dy, dx))
1389                 continue;
1390
1391             MONSTER_IDX m_idx = f_ptr->grid_array[dy][dx].m_idx;
1392             if (!m_idx)
1393                 continue;
1394
1395             POSITION d = distance(dy, dx, y, x);
1396             monster_race *r_ptr = &r_info[f_ptr->m_list[m_idx].r_idx];
1397             if (d <= 1 && any_bits(r_ptr->flags7, RF7_HAS_LITE_1 | RF7_SELF_LITE_1))
1398                 return FALSE;
1399             if (d <= 2 && any_bits(r_ptr->flags7, RF7_HAS_LITE_2 | RF7_SELF_LITE_2))
1400                 return FALSE;
1401             if (d <= 1 && any_bits(r_ptr->flags7, RF7_HAS_DARK_1 | RF7_SELF_DARK_1))
1402                 is_dark = TRUE;
1403             if (d <= 2 && any_bits(r_ptr->flags7, RF7_HAS_DARK_2 | RF7_SELF_DARK_2))
1404                 is_dark = TRUE;
1405         }
1406
1407     return !is_lite || is_dark;
1408 }
1409
1410 /*!
1411  * @breif 暗いところ限定での次元の扉
1412  * @param caster_ptr プレイヤー情報への参照ポインタ
1413  */
1414 static bool door_to_darkness(player_type* caster_ptr, POSITION dist)
1415 {
1416     POSITION y = caster_ptr->y;
1417     POSITION x = caster_ptr->x;
1418     floor_type *f_ptr;
1419
1420     for (int i = 0; i < 3; i++) {
1421         if (!tgt_pt(caster_ptr, &x, &y))
1422             return FALSE;
1423
1424         f_ptr = caster_ptr->current_floor_ptr;
1425
1426         if (distance(y, x, caster_ptr->y, caster_ptr->x) > dist) {
1427             msg_print(_("遠すぎる!", "There is too far!"));
1428             continue;
1429         }
1430
1431         if (!is_cave_empty_bold(caster_ptr, y, x) || f_ptr->grid_array[y][x].info & CAVE_ICKY) {
1432             msg_print(_("そこには移動できない。", "Can not teleport to there."));
1433             continue;
1434         }
1435
1436         break;
1437     }
1438
1439     bool flag = cave_player_teleportable_bold(caster_ptr, y, x, TELEPORT_SPONTANEOUS)  && is_target_grid_dark(f_ptr, y, x);
1440     if (flag) {
1441         teleport_player_to(caster_ptr, y, x, TELEPORT_SPONTANEOUS);
1442     } else {
1443         msg_print(_("闇の扉は開かなかった!", "Door to darkness does not open!"));
1444     }
1445     return TRUE;
1446 }