OSDN Git Service

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