OSDN Git Service

[Refactor] enum spells-typeをenum class AttributeTypeに置換
[hengbandforosx/hengbandosx.git] / src / spell-kind / spells-random.cpp
1 /*!
2  * @brief ダイス目により様々な効果を及ぼす魔法の処理
3  * @date 2020/06/05
4  * @author Hourier
5  */
6
7 #include "spell-kind/spells-random.h"
8 #include "avatar/avatar.h"
9 #include "effect/effect-characteristics.h"
10 #include "effect/effect-processor.h"
11 #include "hpmp/hp-mp-processor.h"
12 #include "monster-floor/monster-summon.h"
13 #include "monster-floor/place-monster-types.h"
14 #include "mutation/mutation-investor-remover.h"
15 #include "player/player-damage.h"
16 #include "spell-kind/earthquake.h"
17 #include "spell-kind/spells-equipment.h"
18 #include "spell-kind/spells-floor.h"
19 #include "spell-kind/spells-genocide.h"
20 #include "spell-kind/spells-launcher.h"
21 #include "spell-kind/spells-lite.h"
22 #include "spell-kind/spells-neighbor.h"
23 #include "spell-kind/spells-sight.h"
24 #include "spell-kind/spells-specific-bolt.h"
25 #include "spell-kind/spells-teleport.h"
26 #include "effect/attribute-types.h"
27 #include "spell/spells-diceroll.h"
28 #include "spell/spells-status.h"
29 #include "spell/spells-summon.h"
30 #include "spell/summon-types.h"
31 #include "status/bad-status-setter.h"
32 #include "status/base-status.h"
33 #include "status/experience.h"
34 #include "system/floor-type-definition.h"
35 #include "system/player-type-definition.h"
36 #include "target/target-getter.h"
37 #include "view/display-messages.h"
38
39 /*!
40  * @brief 混沌招来処理
41  * @return 作用が実際にあった場合TRUEを返す
42  */
43 void call_chaos(player_type *player_ptr)
44 {
45     AttributeType hurt_types[31] = { AttributeType::ELEC, AttributeType::POIS, AttributeType::ACID, AttributeType::COLD, AttributeType::FIRE, 
46         AttributeType::MISSILE, AttributeType::ARROW, AttributeType::PLASMA, AttributeType::HOLY_FIRE, AttributeType::WATER, AttributeType::LITE, 
47         AttributeType::DARK, AttributeType::FORCE, AttributeType::INERTIAL, AttributeType::MANA, AttributeType::METEOR, AttributeType::ICE,
48         AttributeType::CHAOS, AttributeType::NETHER, AttributeType::DISENCHANT, AttributeType::SHARDS, AttributeType::SOUND, AttributeType::NEXUS,
49         AttributeType::CONFUSION, AttributeType::TIME, AttributeType::GRAVITY, AttributeType::ROCKET, AttributeType::NUKE, AttributeType::HELL_FIRE,
50         AttributeType::DISINTEGRATE, AttributeType::PSY_SPEAR };
51
52     AttributeType chaos_type = hurt_types[randint0(31)];
53     bool line_chaos = false;
54     if (one_in_(4))
55         line_chaos = true;
56
57     int dir;
58     if (one_in_(6)) {
59         for (int dummy = 1; dummy < 10; dummy++) {
60             if (dummy - 5) {
61                 if (line_chaos)
62                     fire_beam(player_ptr, chaos_type, dummy, 150);
63                 else
64                     fire_ball(player_ptr, chaos_type, dummy, 150, 2);
65             }
66         }
67
68         return;
69     }
70
71     if (one_in_(3)) {
72         fire_ball(player_ptr, chaos_type, 0, 500, 8);
73         return;
74     }
75
76     if (!get_aim_dir(player_ptr, &dir))
77         return;
78     if (line_chaos)
79         fire_beam(player_ptr, chaos_type, dir, 250);
80     else
81         fire_ball(player_ptr, chaos_type, dir, 250, 3 + (player_ptr->lev / 35));
82 }
83
84 /*!
85  * @brief TY_CURSE処理発動 / Activate the evil Topi Ylinen curse
86  * @param player_ptr プレイヤーへの参照ポインタ
87  * @param stop_ty 再帰処理停止フラグ
88  * @param count 発動回数
89  * @return 作用が実際にあった場合TRUEを返す
90  * @details
91  * <pre>
92  * rr9: Stop the nasty things when a Cyberdemon is summoned
93  * or the player gets paralyzed.
94  * </pre>
95  */
96 bool activate_ty_curse(player_type *player_ptr, bool stop_ty, int *count)
97 {
98     BIT_FLAGS flg = (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP);
99     bool is_first_curse = true;
100     floor_type *floor_ptr = player_ptr->current_floor_ptr;
101     while (is_first_curse || (one_in_(3) && !stop_ty)) {
102         is_first_curse = false;
103         switch (randint1(34)) {
104         case 28:
105         case 29:
106             if (!(*count)) {
107                 msg_print(_("地面が揺れた...", "The ground trembles..."));
108                 earthquake(player_ptr, player_ptr->y, player_ptr->x, 5 + randint0(10), 0);
109                 if (!one_in_(6))
110                     break;
111             }
112             /* Fall through */
113         case 30:
114         case 31:
115             if (!(*count)) {
116                 HIT_POINT dam = damroll(10, 10);
117                 msg_print(_("純粋な魔力の次元への扉が開いた!", "A portal opens to a plane of raw mana!"));
118                 project(player_ptr, 0, 8, player_ptr->y, player_ptr->x, dam, AttributeType::MANA, flg);
119                 take_hit(player_ptr, DAMAGE_NOESCAPE, dam, _("純粋な魔力の解放", "released pure mana"));
120                 if (!one_in_(6))
121                     break;
122             }
123             /* Fall through */
124         case 32:
125         case 33:
126             if (!(*count)) {
127                 msg_print(_("周囲の空間が歪んだ!", "Space warps about you!"));
128                 teleport_player(player_ptr, damroll(10, 10), TELEPORT_PASSIVE);
129                 if (randint0(13))
130                     (*count) += activate_hi_summon(player_ptr, player_ptr->y, player_ptr->x, false);
131                 if (!one_in_(6))
132                     break;
133             }
134             /* Fall through */
135         case 34:
136             msg_print(_("エネルギーのうねりを感じた!", "You feel a surge of energy!"));
137             wall_breaker(player_ptr);
138             if (!randint0(7)) {
139                 project(player_ptr, 0, 7, player_ptr->y, player_ptr->x, 50, AttributeType::KILL_WALL, flg);
140                 take_hit(player_ptr, DAMAGE_NOESCAPE, 50, _("エネルギーのうねり", "surge of energy"));
141             }
142
143             if (!one_in_(6))
144                 break;
145             /* Fall through */
146         case 1:
147         case 2:
148         case 3:
149         case 16:
150         case 17:
151             aggravate_monsters(player_ptr, 0);
152             if (!one_in_(6))
153                 break;
154             /* Fall through */
155         case 4:
156         case 5:
157         case 6:
158             (*count) += activate_hi_summon(player_ptr, player_ptr->y, player_ptr->x, false);
159             if (!one_in_(6))
160                 break;
161             /* Fall through */
162         case 7:
163         case 8:
164         case 9:
165         case 18:
166             (*count) += summon_specific(
167                 player_ptr, 0, player_ptr->y, player_ptr->x, floor_ptr->dun_level, SUMMON_NONE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
168             if (!one_in_(6))
169                 break;
170             /* Fall through */
171         case 10:
172         case 11:
173         case 12:
174             msg_print(_("経験値が体から吸い取られた気がする!", "You feel your experience draining away..."));
175             lose_exp(player_ptr, player_ptr->exp / 16);
176             if (!one_in_(6))
177                 break;
178             /* Fall through */
179         case 13:
180         case 14:
181         case 15:
182         case 19:
183         case 20: {
184             auto is_statue = stop_ty;
185             is_statue |= player_ptr->free_act && (randint1(125) < player_ptr->skill_sav);
186             is_statue |= player_ptr->pclass == PlayerClassType::BERSERKER;
187             if (!is_statue) {
188                 msg_print(_("彫像になった気分だ!", "You feel like a statue!"));
189                 TIME_EFFECT turns = player_ptr->free_act ? randint1(3) : randint1(13);
190                 (void)BadStatusSetter(player_ptr).mod_paralysis(turns);
191                 stop_ty = true;
192             }
193
194             if (!one_in_(6)) {
195                 break;
196             }
197         }
198             /* Fall through */
199         case 21:
200         case 22:
201         case 23:
202             (void)do_dec_stat(player_ptr, randint0(6));
203             if (!one_in_(6))
204                 break;
205             /* Fall through */
206         case 24:
207             msg_print(_("ほえ?私は誰?ここで何してる?", "Huh? Who am I? What am I doing here?"));
208             lose_all_info(player_ptr);
209             if (!one_in_(6))
210                 break;
211             /* Fall through */
212         case 25:
213             if ((floor_ptr->dun_level > 65) && !stop_ty) {
214                 (*count) += summon_cyber(player_ptr, -1, player_ptr->y, player_ptr->x);
215                 stop_ty = true;
216                 break;
217             }
218
219             if (!one_in_(6))
220                 break;
221             /* Fall through */
222         default:
223             for (int i = 0; i < A_MAX; i++) {
224                 do {
225                     (void)do_dec_stat(player_ptr, i);
226                 } while(one_in_(2));
227             }
228         }
229     }
230
231     return stop_ty;
232 }
233
234 /*!
235  * @brief 運命の輪、並びにカオス的な効果の発動
236  * @param player_ptr プレイヤーへの参照ポインタ
237  * @param spell ランダムな効果を選択するための基準ID
238  */
239 void wild_magic(player_type *player_ptr, int spell)
240 {
241     int type = SUMMON_MOLD + randint0(6);
242     if (type < SUMMON_MOLD)
243         type = SUMMON_MOLD;
244     else if (type > SUMMON_MIMIC)
245         type = SUMMON_MIMIC;
246
247     floor_type *floor_ptr = player_ptr->current_floor_ptr;
248     switch (randint1(spell) + randint1(8) + 1) {
249     case 1:
250     case 2:
251     case 3:
252         teleport_player(player_ptr, 10, TELEPORT_PASSIVE);
253         break;
254     case 4:
255     case 5:
256     case 6:
257         teleport_player(player_ptr, 100, TELEPORT_PASSIVE);
258         break;
259     case 7:
260     case 8:
261         teleport_player(player_ptr, 200, TELEPORT_PASSIVE);
262         break;
263     case 9:
264     case 10:
265     case 11:
266         unlite_area(player_ptr, 10, 3);
267         break;
268     case 12:
269     case 13:
270     case 14:
271         lite_area(player_ptr, damroll(2, 3), 2);
272         break;
273     case 15:
274         destroy_doors_touch(player_ptr);
275         break;
276     case 16:
277     case 17:
278         wall_breaker(player_ptr);
279         break;
280     case 18:
281         sleep_monsters_touch(player_ptr);
282         break;
283     case 19:
284     case 20:
285         trap_creation(player_ptr, player_ptr->y, player_ptr->x);
286         break;
287     case 21:
288     case 22:
289         door_creation(player_ptr, player_ptr->y, player_ptr->x);
290         break;
291     case 23:
292     case 24:
293     case 25:
294         aggravate_monsters(player_ptr, 0);
295         break;
296     case 26:
297         earthquake(player_ptr, player_ptr->y, player_ptr->x, 5, 0);
298         break;
299     case 27:
300     case 28:
301         (void)gain_mutation(player_ptr, 0);
302         break;
303     case 29:
304     case 30:
305         apply_disenchant(player_ptr, 1);
306         break;
307     case 31:
308         lose_all_info(player_ptr);
309         break;
310     case 32:
311         fire_ball(player_ptr, AttributeType::CHAOS, 0, spell + 5, 1 + (spell / 10));
312         break;
313     case 33:
314         wall_stone(player_ptr);
315         break;
316     case 34:
317     case 35:
318         for (int counter = 0; counter < 8; counter++) {
319             (void)summon_specific(
320                 player_ptr, 0, player_ptr->y, player_ptr->x, (floor_ptr->dun_level * 3) / 2, i2enum<summon_type>(type), (PM_ALLOW_GROUP | PM_NO_PET));
321         }
322
323         break;
324     case 36:
325     case 37:
326         activate_hi_summon(player_ptr, player_ptr->y, player_ptr->x, false);
327         break;
328     case 38:
329         (void)summon_cyber(player_ptr, -1, player_ptr->y, player_ptr->x);
330         break;
331     default: {
332         int count = 0;
333         (void)activate_ty_curse(player_ptr, false, &count);
334         break;
335     }
336     }
337 }
338
339 /*!
340  * @brief 「ワンダー」のランダムな効果を決定して処理する。
341  * @param player_ptr プレイヤーへの参照ポインタ
342  * @param dir 方向ID
343  * @details
344  * This spell should become more useful (more controlled) as the\n
345  * player gains experience levels.  Thus, add 1/5 of the player's\n
346  * level to the die roll.  This eliminates the worst effects later on,\n
347  * while keeping the results quite random.  It also allows some potent\n
348  * effects only at high level.
349  */
350 void cast_wonder(player_type *player_ptr, DIRECTION dir)
351 {
352     PLAYER_LEVEL plev = player_ptr->lev;
353     int die = randint1(100) + plev / 5;
354     int vir = virtue_number(player_ptr, V_CHANCE);
355     if (vir) {
356         if (player_ptr->virtues[vir - 1] > 0) {
357             while (randint1(400) < player_ptr->virtues[vir - 1])
358                 die++;
359         } else {
360             while (randint1(400) < (0 - player_ptr->virtues[vir - 1]))
361                 die--;
362         }
363     }
364
365     if (die < 26) {
366         chg_virtue(player_ptr, V_CHANCE, 1);
367     }
368
369     if (die > 100) {
370         msg_print(_("あなたは力がみなぎるのを感じた!", "You feel a surge of power!"));
371     }
372
373     if (die < 8) {
374         clone_monster(player_ptr, dir);
375         return;
376     }
377
378     if (die < 14) {
379         speed_monster(player_ptr, dir, plev);
380         return;
381     }
382
383     if (die < 26) {
384         heal_monster(player_ptr, dir, damroll(4, 6));
385         return;
386     }
387
388     if (die < 31) {
389         poly_monster(player_ptr, dir, plev);
390         return;
391     }
392
393     if (die < 36) {
394         fire_bolt_or_beam(player_ptr, beam_chance(player_ptr) - 10, AttributeType::MISSILE, dir, damroll(3 + ((plev - 1) / 5), 4));
395         return;
396     }
397
398     if (die < 41) {
399         confuse_monster(player_ptr, dir, plev);
400         return;
401     }
402
403     if (die < 46) {
404         fire_ball(player_ptr, AttributeType::POIS, dir, 20 + (plev / 2), 3);
405         return;
406     }
407
408     if (die < 51) {
409         (void)lite_line(player_ptr, dir, damroll(6, 8));
410         return;
411     }
412
413     if (die < 56) {
414         fire_bolt_or_beam(player_ptr, beam_chance(player_ptr) - 10, AttributeType::ELEC, dir, damroll(3 + ((plev - 5) / 4), 8));
415         return;
416     }
417
418     if (die < 61) {
419         fire_bolt_or_beam(player_ptr, beam_chance(player_ptr) - 10, AttributeType::COLD, dir, damroll(5 + ((plev - 5) / 4), 8));
420         return;
421     }
422
423     if (die < 66) {
424         fire_bolt_or_beam(player_ptr, beam_chance(player_ptr), AttributeType::ACID, dir, damroll(6 + ((plev - 5) / 4), 8));
425         return;
426     }
427
428     if (die < 71) {
429         fire_bolt_or_beam(player_ptr, beam_chance(player_ptr), AttributeType::FIRE, dir, damroll(8 + ((plev - 5) / 4), 8));
430         return;
431     }
432
433     if (die < 76) {
434         hypodynamic_bolt(player_ptr, dir, 75);
435         return;
436     }
437
438     if (die < 81) {
439         fire_ball(player_ptr, AttributeType::ELEC, dir, 30 + plev / 2, 2);
440         return;
441     }
442
443     if (die < 86) {
444         fire_ball(player_ptr, AttributeType::ACID, dir, 40 + plev, 2);
445         return;
446     }
447
448     if (die < 91) {
449         fire_ball(player_ptr, AttributeType::ICE, dir, 70 + plev, 3);
450         return;
451     }
452
453     if (die < 96) {
454         fire_ball(player_ptr, AttributeType::FIRE, dir, 80 + plev, 3);
455         return;
456     }
457
458     if (die < 101) {
459         hypodynamic_bolt(player_ptr, dir, 100 + plev);
460         return;
461     }
462
463     if (die < 104) {
464         earthquake(player_ptr, player_ptr->y, player_ptr->x, 12, 0);
465         return;
466     }
467
468     if (die < 106) {
469         (void)destroy_area(player_ptr, player_ptr->y, player_ptr->x, 13 + randint0(5), false);
470         return;
471     }
472
473     if (die < 108) {
474         symbol_genocide(player_ptr, plev + 50, true);
475         return;
476     }
477
478     if (die < 110) {
479         dispel_monsters(player_ptr, 120);
480         return;
481     }
482
483     dispel_monsters(player_ptr, 150);
484     slow_monsters(player_ptr, plev);
485     sleep_monsters(player_ptr, plev);
486     hp_player(player_ptr, 300);
487 }