OSDN Git Service

[Release] 3.0.0Alpha48
[hengbandforosx/hengbandosx.git] / src / cmd-action / cmd-mind.cpp
1 /*!
2  * @brief 各職業の特殊技能実装 / Special magics
3  * @date 2014/01/15
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  * This software may be copied and distributed for educational, research,\n
7  * and not for profit purposes provided that this copyright and statement\n
8  * are included in all such copies.  Other copyrights may also apply.\n
9  * 2005 henkma \n
10  * 2014 Deskull rearranged comment for Doxygen.\n
11  */
12
13 #include "cmd-action/cmd-mind.h"
14 #include "action/action-limited.h"
15 #include "core/asking-player.h"
16 #include "core/player-redraw-types.h"
17 #include "core/window-redrawer.h"
18 #include "effect/effect-characteristics.h"
19 #include "effect/effect-processor.h"
20 #include "game-option/disturbance-options.h"
21 #include "game-option/input-options.h"
22 #include "grid/grid.h"
23 #include "inventory/inventory-slot-types.h"
24 #include "io/input-key-acceptor.h"
25 #include "main/sound-definitions-table.h"
26 #include "main/sound-of-music.h"
27 #include "mind/mind-berserker.h"
28 #include "mind/mind-explanations-table.h"
29 #include "mind/mind-force-trainer.h"
30 #include "mind/mind-mindcrafter.h"
31 #include "mind/mind-mirror-master.h"
32 #include "mind/mind-ninja.h"
33 #include "mind/mind-numbers.h"
34 #include "mind/mind-power-getter.h"
35 #include "mind/mind-types.h"
36 #include "player-info/class-info.h"
37 #include "player-info/equipment-info.h"
38 #include "player-status/player-energy.h"
39 #include "player/player-damage.h"
40 #include "player/player-status-table.h"
41 #include "player/player-status.h"
42 #include "spell-kind/spells-teleport.h"
43 #include "effect/attribute-types.h"
44 #include "status/bad-status-setter.h"
45 #include "status/base-status.h"
46 #include "system/floor-type-definition.h"
47 #include "system/grid-type-definition.h"
48 #include "system/player-type-definition.h"
49 #include "term/screen-processor.h"
50 #include "timed-effect/player-stun.h"
51 #include "timed-effect/timed-effects.h"
52 #include "util/buffer-shaper.h"
53 #include "util/enum-converter.h"
54 #include "view/display-messages.h"
55
56 /*!
57  * @brief 職業別特殊技能の処理用構造体
58  */
59 typedef struct cm_type {
60     MindKindType use_mind; //!< 使った職業技能構造体
61     concptr mind_explanation; //!< 特殊技能の説明
62     SPELL_IDX n; //!< 職業種別毎ID
63     int b; //!< 失敗時チャート用乱数
64     PERCENTAGE chance; //!< 失敗率
65     PERCENTAGE minfail; //!< 最低失敗率
66     PLAYER_LEVEL plev; //!< 取得レベル
67     int old_csp; //!< 行使前のMP
68     mind_type spell; //!< 職業技能の基本設定構造体
69     bool cast; //!< 行使の成否
70     int mana_cost; //!< 最終算出消費MP
71     bool on_mirror; //!< 鏡の上に乗っているどうかの判定
72 } cm_type;
73
74 /*!
75  * @brief 職業技能処理構造体の初期化
76  */
77 static cm_type *initialize_cm_type(PlayerType *player_ptr, cm_type *cm_ptr)
78 {
79     cm_ptr->n = 0;
80     cm_ptr->b = 0;
81     cm_ptr->minfail = 0;
82     cm_ptr->plev = player_ptr->lev;
83     cm_ptr->old_csp = player_ptr->csp;
84     cm_ptr->on_mirror = false;
85     return cm_ptr;
86 }
87
88 /*!
89  * @brief 職業別の行使可能な技能種別を構造体に付加する
90  */
91 static void switch_mind_kind(PlayerType *player_ptr, cm_type *cm_ptr)
92 {
93     switch (player_ptr->pclass) {
94     case PlayerClassType::MINDCRAFTER:
95         cm_ptr->use_mind = MindKindType::MINDCRAFTER;
96         cm_ptr->mind_explanation = _("精神", "skill");
97         break;
98     case PlayerClassType::FORCETRAINER:
99         cm_ptr->use_mind = MindKindType::KI;
100         cm_ptr->mind_explanation = _("気", "skill");
101         break;
102     case PlayerClassType::BERSERKER:
103         cm_ptr->use_mind = MindKindType::BERSERKER;
104         cm_ptr->mind_explanation = _("怒り", "skill");
105         break;
106     case PlayerClassType::MIRROR_MASTER:
107         cm_ptr->use_mind = MindKindType::MIRROR_MASTER;
108         cm_ptr->mind_explanation = _("鏡魔法", "skill");
109         break;
110     case PlayerClassType::NINJA:
111         cm_ptr->use_mind = MindKindType::NINJUTSU;
112         cm_ptr->mind_explanation = _("精神", "skill");
113         break;
114     default:
115         cm_ptr->use_mind = (MindKindType)0;
116         cm_ptr->mind_explanation = _("超能力", "skill");
117         break;
118     }
119 }
120
121 static void decide_mind_ki_chance(PlayerType *player_ptr, cm_type *cm_ptr)
122 {
123     if (cm_ptr->use_mind != MindKindType::KI)
124         return;
125
126     if (heavy_armor(player_ptr))
127         cm_ptr->chance += 20;
128
129     if (player_ptr->is_icky_wield[0])
130         cm_ptr->chance += 20;
131     else if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND))
132         cm_ptr->chance += 10;
133
134     if (player_ptr->is_icky_wield[1])
135         cm_ptr->chance += 20;
136     else if (has_melee_weapon(player_ptr, INVEN_SUB_HAND))
137         cm_ptr->chance += 10;
138
139     if (cm_ptr->n == 5)
140         for (int j = 0; j < get_current_ki(player_ptr) / 50; j++)
141             cm_ptr->mana_cost += (j + 1) * 3 / 2;
142 }
143
144 static bool check_mind_hp_mp_sufficiency(PlayerType *player_ptr, cm_type *cm_ptr)
145 {
146     if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
147         if (cm_ptr->mana_cost > player_ptr->chp) {
148             msg_print(_("HPが足りません。", "You do not have enough hp to use this power."));
149             return false;
150         }
151
152         return true;
153     }
154
155     if (cm_ptr->mana_cost <= player_ptr->csp)
156         return true;
157
158     msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
159     if (!over_exert)
160         return false;
161
162     return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
163 }
164
165 static void decide_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
166 {
167     if (cm_ptr->chance == 0)
168         return;
169
170     cm_ptr->chance -= 3 * (cm_ptr->plev - cm_ptr->spell.min_lev);
171     cm_ptr->chance += player_ptr->to_m_chance;
172     cm_ptr->chance -= 3 * (adj_mag_stat[player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
173     if ((cm_ptr->mana_cost > player_ptr->csp) && (cm_ptr->use_mind != MindKindType::BERSERKER) && (cm_ptr->use_mind != MindKindType::NINJUTSU))
174         cm_ptr->chance += 5 * (cm_ptr->mana_cost - player_ptr->csp);
175
176     cm_ptr->minfail = adj_mag_fail[player_ptr->stat_index[mp_ptr->spell_stat]];
177     if (cm_ptr->chance < cm_ptr->minfail)
178         cm_ptr->chance = cm_ptr->minfail;
179
180     auto player_stun = player_ptr->effects()->stun();
181     cm_ptr->chance += player_stun->get_magic_chance_penalty();
182
183     if (cm_ptr->use_mind != MindKindType::KI)
184         return;
185
186     if (heavy_armor(player_ptr))
187         cm_ptr->chance += 5;
188
189     if (player_ptr->is_icky_wield[0])
190         cm_ptr->chance += 5;
191
192     if (player_ptr->is_icky_wield[1])
193         cm_ptr->chance += 5;
194 }
195
196 static void check_mind_mindcrafter(PlayerType *player_ptr, cm_type *cm_ptr)
197 {
198     if (cm_ptr->use_mind != MindKindType::MINDCRAFTER)
199         return;
200
201     if (cm_ptr->b < 5) {
202         msg_print(_("なんてこった!頭の中が真っ白になった!", "Oh, no! Your mind has gone blank!"));
203         lose_all_info(player_ptr);
204         return;
205     }
206
207     BadStatusSetter bss(player_ptr);
208     if (cm_ptr->b < 15) {
209         msg_print(_("奇妙な光景が目の前で踊っている...", "Weird visions seem to dance before your eyes..."));
210         (void)bss.mod_hallucination(5 + randint1(10));
211         return;
212     }
213
214     if (cm_ptr->b < 45) {
215         msg_print(_("あなたの頭は混乱した!", "Your brain is addled!"));
216         (void)bss.mod_confusion(randint1(8));
217         return;
218     }
219
220     if (cm_ptr->b < 90) {
221         (void)bss.mod_stun(randint1(8));
222         return;
223     }
224
225     msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
226     project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
227         PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
228     player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
229 }
230
231 static void check_mind_mirror_master(PlayerType *player_ptr, cm_type *cm_ptr)
232 {
233     if (cm_ptr->use_mind != MindKindType::MIRROR_MASTER)
234         return;
235
236     if (cm_ptr->b < 51)
237         return;
238
239     if (cm_ptr->b < 81) {
240         msg_print(_("鏡の世界の干渉を受けた!", "Weird visions seem to dance before your eyes..."));
241         teleport_player(player_ptr, 10, TELEPORT_PASSIVE);
242         return;
243     }
244
245     if (cm_ptr->b < 96) {
246         msg_print(_("まわりのものがキラキラ輝いている!", "Your brain is addled!"));
247         (void)BadStatusSetter(player_ptr).mod_hallucination(5 + randint1(10));
248         return;
249     }
250
251     msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
252     project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
253         PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
254     player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
255 }
256
257 static void check_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
258 {
259     if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU))
260         return;
261
262     if ((cm_ptr->use_mind == MindKindType::KI) && (cm_ptr->n != 5) && get_current_ki(player_ptr)) {
263         msg_print(_("気が散ってしまった...", "Your improved Force has gone away..."));
264         set_current_ki(player_ptr, true, 0);
265     }
266
267     if (randint1(100) >= (cm_ptr->chance / 2))
268         return;
269
270     cm_ptr->b = randint1(100);
271     check_mind_mindcrafter(player_ptr, cm_ptr);
272     check_mind_mirror_master(player_ptr, cm_ptr);
273 }
274
275 static bool switch_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
276 {
277     switch (cm_ptr->use_mind) {
278     case MindKindType::MINDCRAFTER:
279         cm_ptr->cast = cast_mindcrafter_spell(player_ptr, i2enum<mind_mindcrafter_type>(cm_ptr->n));
280         return true;
281     case MindKindType::KI:
282         cm_ptr->cast = cast_force_spell(player_ptr, i2enum<mind_force_trainer_type>(cm_ptr->n));
283         return true;
284     case MindKindType::BERSERKER:
285         cm_ptr->cast = cast_berserk_spell(player_ptr, i2enum<mind_berserker_type>(cm_ptr->n));
286         return true;
287     case MindKindType::MIRROR_MASTER:
288         if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].is_mirror())
289             cm_ptr->on_mirror = true;
290
291         cm_ptr->cast = cast_mirror_spell(player_ptr, i2enum<mind_mirror_master_type>(cm_ptr->n));
292         return true;
293     case MindKindType::NINJUTSU:
294         cm_ptr->cast = cast_ninja_spell(player_ptr, i2enum<mind_ninja_type>(cm_ptr->n));
295         return true;
296     default:
297         msg_format(_("謎の能力:%d, %d", "Mystery power:%d, %d"), cm_ptr->use_mind, cm_ptr->n);
298         return false;
299     }
300 }
301
302 static void mind_turn_passing(PlayerType *player_ptr, cm_type *cm_ptr)
303 {
304     PlayerEnergy energy(player_ptr);
305     if (cm_ptr->on_mirror && (player_ptr->pclass == PlayerClassType::MIRROR_MASTER)) {
306         if (cm_ptr->n == 3 || cm_ptr->n == 5 || cm_ptr->n == 7 || cm_ptr->n == 16) {
307             energy.set_player_turn_energy(50);
308             return;
309         }
310     }
311
312     energy.set_player_turn_energy(100);
313 }
314
315 static bool judge_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
316 {
317     if (randint0(100) >= cm_ptr->chance) {
318         sound(SOUND_ZAP);
319         return switch_mind_class(player_ptr, cm_ptr) && cm_ptr->cast;
320     }
321
322     if (flush_failure)
323         flush();
324
325     msg_format(_("%sの集中に失敗した!", "You failed to concentrate hard enough for %s!"), cm_ptr->mind_explanation);
326     sound(SOUND_FAIL);
327     check_mind_class(player_ptr, cm_ptr);
328     return true;
329 }
330
331 static void mind_reflection(PlayerType *player_ptr, cm_type *cm_ptr)
332 {
333     int oops = cm_ptr->mana_cost - cm_ptr->old_csp;
334     if ((player_ptr->csp - cm_ptr->mana_cost) < 0)
335         player_ptr->csp_frac = 0;
336
337     player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->mana_cost);
338     msg_format(_("%sを集中しすぎて気を失ってしまった!", "You faint from the effort!"), cm_ptr->mind_explanation);
339     (void)BadStatusSetter(player_ptr).mod_paralysis(randint1(5 * oops + 1));
340     if (randint0(100) >= 50)
341         return;
342
343     bool perm = randint0(100) < 25;
344     msg_print(_("自分の精神を攻撃してしまった!", "You have damaged your mind!"));
345     (void)dec_stat(player_ptr, A_WIS, 15 + randint1(10), perm);
346 }
347
348 static void process_hard_concentration(PlayerType *player_ptr, cm_type *cm_ptr)
349 {
350     if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
351         take_hit(player_ptr, DAMAGE_USELIFE, cm_ptr->mana_cost, _("過度の集中", "concentrating too hard"));
352         player_ptr->redraw |= PR_HP;
353         return;
354     }
355
356     if (cm_ptr->mana_cost > cm_ptr->old_csp) {
357         mind_reflection(player_ptr, cm_ptr);
358         return;
359     }
360
361     player_ptr->csp -= cm_ptr->mana_cost;
362     if (player_ptr->csp < 0)
363         player_ptr->csp = 0;
364
365     if ((cm_ptr->use_mind == MindKindType::MINDCRAFTER) && (cm_ptr->n == 13)) {
366         player_ptr->csp = 0;
367         player_ptr->csp_frac = 0;
368     }
369 }
370
371 /*!
372  * @brief 特殊技能コマンドのメインルーチン /
373  */
374 void do_cmd_mind(PlayerType *player_ptr)
375 {
376     cm_type tmp_cm;
377     cm_type *cm_ptr = initialize_cm_type(player_ptr, &tmp_cm);
378     if (cmd_limit_confused(player_ptr) || !MindPowerGetter(player_ptr).get_mind_power(&cm_ptr->n, false))
379         return;
380
381     switch_mind_kind(player_ptr, cm_ptr);
382     cm_ptr->spell = mind_powers[enum2i(cm_ptr->use_mind)].info[cm_ptr->n];
383     cm_ptr->chance = cm_ptr->spell.fail;
384     cm_ptr->mana_cost = cm_ptr->spell.mana_cost;
385     decide_mind_ki_chance(player_ptr, cm_ptr);
386     if (!check_mind_hp_mp_sufficiency(player_ptr, cm_ptr))
387         return;
388
389     decide_mind_chance(player_ptr, cm_ptr);
390     if (cm_ptr->chance > 95)
391         cm_ptr->chance = 95;
392
393     if (!judge_mind_chance(player_ptr, cm_ptr))
394         return;
395
396     mind_turn_passing(player_ptr, cm_ptr);
397     process_hard_concentration(player_ptr, cm_ptr);
398     player_ptr->redraw |= PR_MANA;
399     player_ptr->window_flags |= PW_PLAYER;
400     player_ptr->window_flags |= PW_SPELL;
401 }
402
403 static MindKindType decide_use_mind_browse(PlayerType *player_ptr)
404 {
405     switch (player_ptr->pclass) {
406     case PlayerClassType::MINDCRAFTER:
407         return MindKindType::MINDCRAFTER;
408     case PlayerClassType::FORCETRAINER:
409         return MindKindType::KI;
410     case PlayerClassType::BERSERKER:
411         return MindKindType::BERSERKER;
412     case PlayerClassType::NINJA:
413         return MindKindType::NINJUTSU;
414     case PlayerClassType::MIRROR_MASTER:
415         return MindKindType::MIRROR_MASTER;
416     default:
417         return (MindKindType)0; // 実質PlayerClassType::MINDCRAFTERと同じ.
418     }
419 }
420
421 /*!
422  * @brief 現在プレイヤーが使用可能な特殊技能の一覧表示 /
423  */
424 void do_cmd_mind_browse(PlayerType *player_ptr)
425 {
426     SPELL_IDX n = 0;
427     char temp[62 * 5];
428     MindKindType use_mind = decide_use_mind_browse(player_ptr);
429     screen_save();
430     while (true) {
431         if (!MindPowerGetter(player_ptr).get_mind_power(&n, true)) {
432             screen_load();
433             return;
434         }
435
436         term_erase(12, 21, 255);
437         term_erase(12, 20, 255);
438         term_erase(12, 19, 255);
439         term_erase(12, 18, 255);
440         term_erase(12, 17, 255);
441         term_erase(12, 16, 255);
442         shape_buffer(mind_tips[(int)use_mind][n], 62, temp, sizeof(temp));
443         for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
444             prt(&temp[j], line, 15);
445             line++;
446         }
447
448         switch (use_mind) {
449         case MindKindType::MIRROR_MASTER:
450         case MindKindType::NINJUTSU:
451             prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
452             (void)inkey();
453             break;
454         default:
455             break;
456         }
457     }
458 }