OSDN Git Service

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