OSDN Git Service

Merge pull request #1518 from Hourier/feature/Dismantle-Hex-Macro-Function
[hengbandforosx/hengbandosx.git] / src / mutation / mutation-processor.cpp
1 #include "mutation/mutation-processor.h"
2 #include "core/asking-player.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "dungeon/dungeon.h"
6 #include "floor/geometry.h"
7 #include "grid/grid.h"
8 #include "hpmp/hp-mp-processor.h"
9 #include "inventory/inventory-object.h"
10 #include "inventory/inventory-slot-types.h"
11 #include "io/input-key-requester.h"
12 #include "main/sound-of-music.h"
13 #include "monster-floor/monster-summon.h"
14 #include "monster-floor/place-monster-types.h"
15 #include "monster-race/monster-race.h"
16 #include "monster/monster-status.h"
17 #include "mutation/mutation-flag-types.h"
18 #include "mutation/mutation-investor-remover.h"
19 #include "object/lite-processor.h"
20 #include "player-info/equipment-info.h"
21 #include "player/digestion-processor.h"
22 #include "player/player-damage.h"
23 #include "player/player-status-flags.h"
24 #include "spell-kind/spells-floor.h"
25 #include "spell-kind/spells-launcher.h"
26 #include "spell-kind/spells-lite.h"
27 #include "spell-kind/spells-sight.h"
28 #include "spell-kind/spells-teleport.h"
29 #include "spell-kind/spells-world.h"
30 #include "spell-realm/spells-hex.h"
31 #include "spell-realm/spells-song.h"
32 #include "spell/spell-types.h"
33 #include "spell/summon-types.h"
34 #include "status/bad-status-setter.h"
35 #include "status/base-status.h"
36 #include "status/body-improvement.h"
37 #include "status/buff-setter.h"
38 #include "status/shape-changer.h"
39 #include "status/sight-setter.h"
40 #include "store/store-owners.h"
41 #include "store/store-util.h"
42 #include "store/store.h"
43 #include "system/floor-type-definition.h"
44 #include "system/grid-type-definition.h"
45 #include "system/monster-race-definition.h"
46 #include "system/monster-type-definition.h"
47 #include "system/object-type-definition.h"
48 #include "system/player-type-definition.h"
49 #include "target/target-checker.h"
50 #include "target/target-setter.h"
51 #include "target/target-types.h"
52 #include "term/screen-processor.h"
53 #include "view/display-messages.h"
54
55 static bool get_hack_dir(player_type *player_ptr, DIRECTION *dp)
56 {
57     *dp = 0;
58     char command;
59     DIRECTION dir = 0;
60     while (!dir) {
61         concptr p = target_okay(player_ptr)
62             ? _("方向 ('5'でターゲットへ, '*'でターゲット再選択, ESCで中断)? ", "Direction ('5' for target, '*' to re-target, Escape to cancel)? ")
63             : _("方向 ('*'でターゲット選択, ESCで中断)? ", "Direction ('*' to choose a target, Escape to cancel)? ");
64         if (!get_com(p, &command, true))
65             break;
66
67         if (use_menu && (command == '\r'))
68             command = 't';
69
70         switch (command) {
71         case 'T':
72         case 't':
73         case '.':
74         case '5':
75         case '0':
76             dir = 5;
77             break;
78         case '*':
79         case ' ':
80         case '\r':
81             if (target_set(player_ptr, TARGET_KILL))
82                 dir = 5;
83
84             break;
85         default:
86             dir = get_keymap_dir(command);
87             break;
88         }
89
90         if ((dir == 5) && !target_okay(player_ptr))
91             dir = 0;
92
93         if (!dir)
94             bell();
95     }
96
97     if (!dir)
98         return false;
99
100     command_dir = dir;
101     if (player_ptr->confused)
102         dir = ddd[randint0(8)];
103
104     if (command_dir != dir)
105         msg_print(_("あなたは混乱している。", "You are confused."));
106
107     *dp = dir;
108     return true;
109 }
110
111 /*!
112  * @brief 10ゲームターンが進行するごとに突然変異の発動判定を行う処理
113  * / Handle mutation effects once every 10 game turns
114  */
115 void process_world_aux_mutation(player_type *player_ptr)
116 {
117     if (player_ptr->muta.none() || player_ptr->phase_out || player_ptr->wild_mode)
118         return;
119
120     if (player_ptr->muta.has(MUTA::BERS_RAGE) && one_in_(3000)) {
121         disturb(player_ptr, false, true);
122         msg_print(_("ウガァァア!", "RAAAAGHH!"));
123         msg_print(_("激怒の発作に襲われた!", "You feel a fit of rage coming over you!"));
124         (void)set_shero(player_ptr, 10 + randint1(player_ptr->lev), false);
125         (void)set_afraid(player_ptr, 0);
126     }
127
128     if (player_ptr->muta.has(MUTA::COWARDICE) && (randint1(3000) == 13)) {
129         if (!has_resist_fear(player_ptr)) {
130             disturb(player_ptr, false, true);
131             msg_print(_("とても暗い... とても恐い!", "It's so dark... so scary!"));
132             set_afraid(player_ptr, player_ptr->afraid + 13 + randint1(26));
133         }
134     }
135
136     if (player_ptr->muta.has(MUTA::RTELEPORT) && (randint1(5000) == 88)) {
137         if (!has_resist_nexus(player_ptr) && player_ptr->muta.has_not(MUTA::VTELEPORT) && !player_ptr->anti_tele) {
138             disturb(player_ptr, false, true);
139             msg_print(_("あなたの位置は突然ひじょうに不確定になった...", "Your position suddenly seems very uncertain..."));
140             msg_print(nullptr);
141             teleport_player(player_ptr, 40, TELEPORT_PASSIVE);
142         }
143     }
144
145     if (player_ptr->muta.has(MUTA::ALCOHOL) && (randint1(6400) == 321)) {
146         if (!has_resist_conf(player_ptr) && !has_resist_chaos(player_ptr)) {
147             disturb(player_ptr, false, true);
148             player_ptr->redraw |= PR_EXTRA;
149             msg_print(_("いひきがもーろーとひてきたきがふる...ヒック!", "You feel a SSSCHtupor cOmINg over yOu... *HIC*!"));
150         }
151
152         if (!has_resist_conf(player_ptr)) {
153             (void)set_confused(player_ptr, player_ptr->confused + randint0(20) + 15);
154         }
155
156         if (!has_resist_chaos(player_ptr)) {
157             if (one_in_(20)) {
158                 msg_print(nullptr);
159                 if (one_in_(3))
160                     lose_all_info(player_ptr);
161                 else
162                     wiz_dark(player_ptr);
163                 (void)teleport_player_aux(player_ptr, 100, false, static_cast<teleport_flags>(TELEPORT_NONMAGICAL | TELEPORT_PASSIVE));
164                 wiz_dark(player_ptr);
165                 msg_print(_("あなたは見知らぬ場所で目が醒めた...頭が痛い。", "You wake up somewhere with a sore head..."));
166                 msg_print(_("何も覚えていない。どうやってここに来たかも分からない!", "You can't remember a thing or how you got here!"));
167             } else {
168                 if (one_in_(3)) {
169                     msg_print(_("き~れいなちょおちょらとんれいる~", "Thishcischs GooDSChtuff!"));
170                     (void)set_image(player_ptr, player_ptr->image + randint0(150) + 150);
171                 }
172             }
173         }
174     }
175
176     if (player_ptr->muta.has(MUTA::HALLU) && (randint1(6400) == 42)) {
177         if (!has_resist_chaos(player_ptr)) {
178             disturb(player_ptr, false, true);
179             player_ptr->redraw |= PR_EXTRA;
180             (void)set_image(player_ptr, player_ptr->image + randint0(50) + 20);
181         }
182     }
183
184     if (player_ptr->muta.has(MUTA::FLATULENT) && (randint1(3000) == 13)) {
185         disturb(player_ptr, false, true);
186         msg_print(_("ブゥーーッ!おっと。", "BRRAAAP! Oops."));
187         msg_print(nullptr);
188         fire_ball(player_ptr, GF_POIS, 0, player_ptr->lev, 3);
189     }
190
191     if (player_ptr->muta.has(MUTA::PROD_MANA) && !player_ptr->anti_magic && one_in_(9000)) {
192         int dire = 0;
193         disturb(player_ptr, false, true);
194         msg_print(_("魔法のエネルギーが突然あなたの中に流れ込んできた!エネルギーを解放しなければならない!",
195             "Magical energy flows through you! You must release it!"));
196
197         flush();
198         msg_print(nullptr);
199         (void)get_hack_dir(player_ptr, &dire);
200         fire_ball(player_ptr, GF_MANA, dire, player_ptr->lev * 2, 3);
201     }
202
203     if (player_ptr->muta.has(MUTA::ATT_DEMON) && !player_ptr->anti_magic && (randint1(6666) == 666)) {
204         bool pet = one_in_(6);
205         BIT_FLAGS mode = PM_ALLOW_GROUP;
206
207         if (pet)
208             mode |= PM_FORCE_PET;
209         else
210             mode |= (PM_ALLOW_UNIQUE | PM_NO_PET);
211
212         if (summon_specific(player_ptr, (pet ? -1 : 0), player_ptr->y, player_ptr->x, player_ptr->current_floor_ptr->dun_level, SUMMON_DEMON, mode)) {
213             msg_print(_("あなたはデーモンを引き寄せた!", "You have attracted a demon!"));
214             disturb(player_ptr, false, true);
215         }
216     }
217
218     if (player_ptr->muta.has(MUTA::SPEED_FLUX) && one_in_(6000)) {
219         disturb(player_ptr, false, true);
220         if (one_in_(2)) {
221             msg_print(_("精力的でなくなった気がする。", "You feel less energetic."));
222
223             if (player_ptr->fast > 0) {
224                 set_fast(player_ptr, 0, true);
225             } else {
226                 set_slow(player_ptr, randint1(30) + 10, false);
227             }
228         } else {
229             msg_print(_("精力的になった気がする。", "You feel more energetic."));
230
231             if (player_ptr->slow > 0) {
232                 set_slow(player_ptr, 0, true);
233             } else {
234                 set_fast(player_ptr, randint1(30) + 10, false);
235             }
236         }
237
238         msg_print(nullptr);
239     }
240
241     if (player_ptr->muta.has(MUTA::BANISH_ALL) && one_in_(9000)) {
242         disturb(player_ptr, false, true);
243         msg_print(_("突然ほとんど孤独になった気がする。", "You suddenly feel almost lonely."));
244
245         banish_monsters(player_ptr, 100);
246         if (!is_in_dungeon(player_ptr) && player_ptr->town_num) {
247             int n;
248             do {
249                 n = randint0(MAX_STORES);
250             } while ((n == STORE_HOME) || (n == STORE_MUSEUM));
251
252             msg_print(_("店の主人が丘に向かって走っている!", "You see one of the shopkeepers running for the hills!"));
253             store_shuffle(player_ptr, n);
254         }
255         msg_print(nullptr);
256     }
257
258     if (player_ptr->muta.has(MUTA::EAT_LIGHT) && one_in_(3000)) {
259         object_type *o_ptr;
260
261         msg_print(_("影につつまれた。", "A shadow passes over you."));
262         msg_print(nullptr);
263
264         if ((player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW) {
265             hp_player(player_ptr, 10);
266         }
267
268         o_ptr = &player_ptr->inventory_list[INVEN_LITE];
269
270         if (o_ptr->tval == TV_LITE) {
271             if (!o_ptr->is_fixed_artifact() && (o_ptr->xtra4 > 0)) {
272                 hp_player(player_ptr, o_ptr->xtra4 / 20);
273                 o_ptr->xtra4 /= 2;
274                 msg_print(_("光源からエネルギーを吸収した!", "You absorb energy from your light!"));
275                 notice_lite_change(player_ptr, o_ptr);
276             }
277         }
278
279         /*
280          * Unlite the area (radius 10) around player and
281          * do 50 points damage to every affected monster
282          */
283         unlite_area(player_ptr, 50, 10);
284     }
285
286     if (player_ptr->muta.has(MUTA::ATT_ANIMAL) && !player_ptr->anti_magic && one_in_(7000)) {
287         bool pet = one_in_(3);
288         BIT_FLAGS mode = PM_ALLOW_GROUP;
289
290         if (pet)
291             mode |= PM_FORCE_PET;
292         else
293             mode |= (PM_ALLOW_UNIQUE | PM_NO_PET);
294
295         if (summon_specific(player_ptr, (pet ? -1 : 0), player_ptr->y, player_ptr->x, player_ptr->current_floor_ptr->dun_level, SUMMON_ANIMAL, mode)) {
296             msg_print(_("動物を引き寄せた!", "You have attracted an animal!"));
297             disturb(player_ptr, false, true);
298         }
299     }
300
301     if (player_ptr->muta.has(MUTA::RAW_CHAOS) && !player_ptr->anti_magic && one_in_(8000)) {
302         disturb(player_ptr, false, true);
303         msg_print(_("周りの空間が歪んでいる気がする!", "You feel the world warping around you!"));
304         msg_print(nullptr);
305         fire_ball(player_ptr, GF_CHAOS, 0, player_ptr->lev, 8);
306     }
307
308     if (player_ptr->muta.has(MUTA::NORMALITY) && one_in_(5000)) {
309         if (!lose_mutation(player_ptr, 0))
310             msg_print(_("奇妙なくらい普通になった気がする。", "You feel oddly normal."));
311     }
312
313     if (player_ptr->muta.has(MUTA::WRAITH) && !player_ptr->anti_magic && one_in_(3000)) {
314         disturb(player_ptr, false, true);
315         msg_print(_("非物質化した!", "You feel insubstantial!"));
316         msg_print(nullptr);
317         set_wraith_form(player_ptr, randint1(player_ptr->lev / 2) + (player_ptr->lev / 2), false);
318     }
319
320     if (player_ptr->muta.has(MUTA::POLY_WOUND) && one_in_(3000))
321         do_poly_wounds(player_ptr);
322
323     if (player_ptr->muta.has(MUTA::WASTING) && one_in_(3000)) {
324         int which_stat = randint0(A_MAX);
325         int sustained = false;
326
327         switch (which_stat) {
328         case A_STR:
329             if (has_sustain_str(player_ptr))
330                 sustained = true;
331             break;
332         case A_INT:
333             if (has_sustain_int(player_ptr))
334                 sustained = true;
335             break;
336         case A_WIS:
337             if (has_sustain_wis(player_ptr))
338                 sustained = true;
339             break;
340         case A_DEX:
341             if (has_sustain_dex(player_ptr))
342                 sustained = true;
343             break;
344         case A_CON:
345             if (has_sustain_con(player_ptr))
346                 sustained = true;
347             break;
348         case A_CHR:
349             if (has_sustain_chr(player_ptr))
350                 sustained = true;
351             break;
352         default:
353             msg_print(_("不正な状態!", "Invalid stat chosen!"));
354             sustained = true;
355         }
356
357         if (!sustained) {
358             disturb(player_ptr, false, true);
359             msg_print(_("自分が衰弱していくのが分かる!", "You can feel yourself wasting away!"));
360             msg_print(nullptr);
361             (void)dec_stat(player_ptr, which_stat, randint1(6) + 6, one_in_(3));
362         }
363     }
364
365     if (player_ptr->muta.has(MUTA::ATT_DRAGON) && !player_ptr->anti_magic && one_in_(3000)) {
366         bool pet = one_in_(5);
367         BIT_FLAGS mode = PM_ALLOW_GROUP;
368         if (pet)
369             mode |= PM_FORCE_PET;
370         else
371             mode |= (PM_ALLOW_UNIQUE | PM_NO_PET);
372
373         if (summon_specific(player_ptr, (pet ? -1 : 0), player_ptr->y, player_ptr->x, player_ptr->current_floor_ptr->dun_level, SUMMON_DRAGON, mode)) {
374             msg_print(_("ドラゴンを引き寄せた!", "You have attracted a dragon!"));
375             disturb(player_ptr, false, true);
376         }
377     }
378
379     if (player_ptr->muta.has(MUTA::WEIRD_MIND) && !player_ptr->anti_magic && one_in_(3000)) {
380         if (player_ptr->tim_esp > 0) {
381             msg_print(_("精神にもやがかかった!", "Your mind feels cloudy!"));
382             set_tim_esp(player_ptr, 0, true);
383         } else {
384             msg_print(_("精神が広がった!", "Your mind expands!"));
385             set_tim_esp(player_ptr, player_ptr->lev, false);
386         }
387     }
388
389     if (player_ptr->muta.has(MUTA::NAUSEA) && !player_ptr->slow_digest && one_in_(9000)) {
390         disturb(player_ptr, false, true);
391         msg_print(_("胃が痙攣し、食事を失った!", "Your stomach roils, and you lose your lunch!"));
392         msg_print(nullptr);
393         set_food(player_ptr, PY_FOOD_WEAK);
394         if (music_singing_any(player_ptr))
395             stop_singing(player_ptr);
396
397         SpellHex spell_hex(player_ptr);
398         if (spell_hex.is_spelling_any()) {
399             (void)spell_hex.stop_all_spells();
400         }
401     }
402
403     if (player_ptr->muta.has(MUTA::WALK_SHAD) && !player_ptr->anti_magic && one_in_(12000) && !player_ptr->current_floor_ptr->inside_arena)
404         reserve_alter_reality(player_ptr, randint0(21) + 15);
405
406     if (player_ptr->muta.has(MUTA::WARNING) && one_in_(1000)) {
407         int danger_amount = 0;
408         for (MONSTER_IDX monster = 0; monster < player_ptr->current_floor_ptr->m_max; monster++) {
409             monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[monster];
410             monster_race *r_ptr = &r_info[m_ptr->r_idx];
411             if (!monster_is_valid(m_ptr))
412                 continue;
413
414             if (r_ptr->level >= player_ptr->lev) {
415                 danger_amount += r_ptr->level - player_ptr->lev + 1;
416             }
417         }
418
419         if (danger_amount > 100)
420             msg_print(_("非常に恐ろしい気がする!", "You feel utterly terrified!"));
421         else if (danger_amount > 50)
422             msg_print(_("恐ろしい気がする!", "You feel terrified!"));
423         else if (danger_amount > 20)
424             msg_print(_("非常に心配な気がする!", "You feel very worried!"));
425         else if (danger_amount > 10)
426             msg_print(_("心配な気がする!", "You feel paranoid!"));
427         else if (danger_amount > 5)
428             msg_print(_("ほとんど安全な気がする。", "You feel almost safe."));
429         else
430             msg_print(_("寂しい気がする。", "You feel lonely."));
431     }
432
433     if (player_ptr->muta.has(MUTA::INVULN) && !player_ptr->anti_magic && one_in_(5000)) {
434         disturb(player_ptr, false, true);
435         msg_print(_("無敵な気がする!", "You feel invincible!"));
436         msg_print(nullptr);
437         (void)set_invuln(player_ptr, randint1(8) + 8, false);
438     }
439
440     if (player_ptr->muta.has(MUTA::SP_TO_HP) && one_in_(2000)) {
441         MANA_POINT wounds = (MANA_POINT)(player_ptr->mhp - player_ptr->chp);
442         if (wounds > 0) {
443             HIT_POINT healing = player_ptr->csp;
444             if (healing > wounds)
445                 healing = wounds;
446
447             hp_player(player_ptr, healing);
448             player_ptr->csp -= healing;
449             player_ptr->redraw |= (PR_HP | PR_MANA);
450         }
451     }
452
453     if (player_ptr->muta.has(MUTA::HP_TO_SP) && !player_ptr->anti_magic && one_in_(4000)) {
454         HIT_POINT wounds = (HIT_POINT)(player_ptr->msp - player_ptr->csp);
455         if (wounds > 0) {
456             HIT_POINT healing = player_ptr->chp;
457             if (healing > wounds)
458                 healing = wounds;
459
460             player_ptr->csp += healing;
461             player_ptr->redraw |= (PR_HP | PR_MANA);
462             take_hit(player_ptr, DAMAGE_LOSELIFE, healing, _("頭に昇った血", "blood rushing to the head"));
463         }
464     }
465
466     if (player_ptr->muta.has(MUTA::DISARM) && one_in_(10000)) {
467         disturb(player_ptr, false, true);
468         msg_print(_("足がもつれて転んだ!", "You trip over your own feet!"));
469         take_hit(player_ptr, DAMAGE_NOESCAPE, randint1(player_ptr->wt / 6), _("転倒", "tripping"));
470         drop_weapons(player_ptr);
471     }
472 }
473
474 bool drop_weapons(player_type *player_ptr)
475 {
476     INVENTORY_IDX slot = 0;
477     object_type *o_ptr = nullptr;
478
479     if (player_ptr->wild_mode)
480         return false;
481
482     msg_print(nullptr);
483     if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND)) {
484         slot = INVEN_MAIN_HAND;
485         o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
486
487         if (has_melee_weapon(player_ptr, INVEN_SUB_HAND) && one_in_(2)) {
488             o_ptr = &player_ptr->inventory_list[INVEN_SUB_HAND];
489             slot = INVEN_SUB_HAND;
490         }
491     } else if (has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
492         o_ptr = &player_ptr->inventory_list[INVEN_SUB_HAND];
493         slot = INVEN_SUB_HAND;
494     }
495
496     if ((slot == 0) || o_ptr->is_cursed())
497         return false;
498
499     msg_print(_("武器を落としてしまった!", "You drop your weapon!"));
500     drop_from_inventory(player_ptr, slot, 1);
501     return true;
502 }