OSDN Git Service

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