OSDN Git Service

4af2c387864dbd4666f4c61516ba039fe3092eef
[hengbandforosx/hengbandosx.git] / src / mind / mind-force-trainer.cpp
1 #include "mind/mind-force-trainer.h"
2 #include "core/disturbance.h"
3 #include "core/player-redraw-types.h"
4 #include "core/player-update-types.h"
5 #include "core/stuff-handler.h"
6 #include "effect/spells-effect-util.h"
7 #include "floor/cave.h"
8 #include "floor/geometry.h"
9 #include "game-option/disturbance-options.h"
10 #include "grid/grid.h"
11 #include "mind/mind-magic-resistance.h"
12 #include "mind/mind-numbers.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-race/race-flags7.h"
17 #include "monster/monster-describer.h"
18 #include "monster/monster-status.h"
19 #include "monster/monster-update.h"
20 #include "pet/pet-util.h"
21 #include "player-info/avatar.h"
22 #include "player-info/equipment-info.h"
23 #include "player/player-damage.h"
24 #include "spell-kind/spells-launcher.h"
25 #include "spell-kind/spells-lite.h"
26 #include "spell/spell-types.h"
27 #include "spell/summon-types.h"
28 #include "status/temporary-resistance.h"
29 #include "system/floor-type-definition.h"
30 #include "system/monster-race-definition.h"
31 #include "system/monster-type-definition.h"
32 #include "system/player-type-definition.h"
33 #include "target/projection-path-calculator.h"
34 #include "target/target-checker.h"
35 #include "target/target-getter.h"
36 #include "target/target-setter.h"
37 #include "target/target-types.h"
38 #include "view/display-messages.h"
39
40 /*!
41  * @brief 練気術師が「練気」で溜めた気の量を返す
42  * @param caster_ptr プレーヤーの参照ポインタ
43  * @return 現在溜まっている気の量
44  */
45 MAGIC_NUM1 get_current_ki(player_type *caster_ptr)
46 {
47     return caster_ptr->magic_num1[0];
48 }
49
50 /*!
51  * @brief 練気術師において、気を溜める
52  * @param caster_ptr プレーヤーの参照ポインタ
53  * @param is_reset TRUEなら気の量をkiにセットし、FALSEなら加減算を行う
54  * @param ki 気の量
55  * @return なし
56  */
57 void set_current_ki(player_type *caster_ptr, bool is_reset, MAGIC_NUM1 ki)
58 {
59     if (is_reset) {
60         caster_ptr->magic_num1[0] = ki;
61         return;
62     }
63
64     caster_ptr->magic_num1[0] += ki;
65 }
66
67 bool clear_mind(player_type *creature_ptr)
68 {
69     if (total_friends) {
70         msg_print(_("今はペットを操ることに集中していないと。", "Your pets demand all of your attention."));
71         return FALSE;
72     }
73
74     msg_print(_("少し頭がハッキリした。", "You feel your head clear a little."));
75
76     creature_ptr->csp += (3 + creature_ptr->lev / 20);
77     if (creature_ptr->csp >= creature_ptr->msp) {
78         creature_ptr->csp = creature_ptr->msp;
79         creature_ptr->csp_frac = 0;
80     }
81
82     creature_ptr->redraw |= (PR_MANA);
83     return TRUE;
84 }
85
86 /*!
87  * @brief 光速移動の継続時間をセットする / Set "lightspeed", notice observable changes
88  * @param v 継続時間
89  * @param do_dec 現在の継続時間より長い値のみ上書きする
90  * @return なし
91  */
92 void set_lightspeed(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
93 {
94     bool notice = FALSE;
95     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
96
97     if (creature_ptr->is_dead)
98         return;
99
100     if (creature_ptr->wild_mode)
101         v = 0;
102
103     if (v) {
104         if (creature_ptr->lightspeed && !do_dec) {
105             if (creature_ptr->lightspeed > v)
106                 return;
107         } else if (!creature_ptr->lightspeed) {
108             msg_print(_("非常に素早く動けるようになった!", "You feel yourself moving extremely fast!"));
109             notice = TRUE;
110             chg_virtue(creature_ptr, V_PATIENCE, -1);
111             chg_virtue(creature_ptr, V_DILIGENCE, 1);
112         }
113     } else {
114         if (creature_ptr->lightspeed) {
115             msg_print(_("動きの素早さがなくなったようだ。", "You feel yourself slow down."));
116             notice = TRUE;
117         }
118     }
119
120     creature_ptr->lightspeed = v;
121
122     if (!notice)
123         return;
124
125     if (disturb_state)
126         disturb(creature_ptr, FALSE, FALSE);
127     creature_ptr->update |= (PU_BONUS);
128     handle_stuff(creature_ptr);
129 }
130
131 /*!
132  * @brief 一時的闘気のオーラの継続時間をセットする / Set "tim_sh_touki", notice observable changes
133  * @param v 継続時間
134  * @param do_dec 現在の継続時間より長い値のみ上書きする
135  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
136  */
137 bool set_tim_sh_force(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
138 {
139     bool notice = FALSE;
140     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
141
142     if (creature_ptr->is_dead)
143         return FALSE;
144
145     if (v) {
146         if (creature_ptr->tim_sh_touki && !do_dec) {
147             if (creature_ptr->tim_sh_touki > v)
148                 return FALSE;
149         } else if (!creature_ptr->tim_sh_touki) {
150             msg_print(_("体が闘気のオーラで覆われた。", "You are enveloped by an aura of the Force!"));
151             notice = TRUE;
152         }
153     } else {
154         if (creature_ptr->tim_sh_touki) {
155             msg_print(_("闘気が消えた。", "The aura of the Force disappeared."));
156             notice = TRUE;
157         }
158     }
159
160     creature_ptr->tim_sh_touki = v;
161     creature_ptr->redraw |= (PR_STATUS);
162
163     if (!notice)
164         return FALSE;
165
166     if (disturb_state)
167         disturb(creature_ptr, FALSE, FALSE);
168     handle_stuff(creature_ptr);
169     return TRUE;
170 }
171
172 /*!
173  * @brief 衝波
174  * @param caster_ptr プレーヤーへの参照ポインタ
175  * @return 命中したらTRUE
176  */
177 bool shock_power(player_type *caster_ptr)
178 {
179     int boost = get_current_ki(caster_ptr);
180     if (heavy_armor(caster_ptr))
181         boost /= 2;
182
183     project_length = 1;
184     DIRECTION dir;
185     if (!get_aim_dir(caster_ptr, &dir))
186         return FALSE;
187
188     POSITION y = caster_ptr->y + ddy[dir];
189     POSITION x = caster_ptr->x + ddx[dir];
190     PLAYER_LEVEL plev = caster_ptr->lev;
191     HIT_POINT dam = damroll(8 + ((plev - 5) / 4) + boost / 12, 8);
192     fire_beam(caster_ptr, GF_MISSILE, dir, dam);
193     if (!caster_ptr->current_floor_ptr->grid_array[y][x].m_idx)
194         return TRUE;
195
196     POSITION ty = y, tx = x;
197     POSITION oy = y, ox = x;
198     MONSTER_IDX m_idx = caster_ptr->current_floor_ptr->grid_array[y][x].m_idx;
199     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
200     monster_race *r_ptr = &r_info[m_ptr->r_idx];
201     GAME_TEXT m_name[MAX_NLEN];
202     monster_desc(caster_ptr, m_name, m_ptr, 0);
203
204     if (randint1(r_ptr->level * 3 / 2) > randint0(dam / 2) + dam / 2) {
205         msg_format(_("%sは飛ばされなかった。", "%^s was not blown away."), m_name);
206         return TRUE;
207     }
208
209     for (int i = 0; i < 5; i++) {
210         y += ddy[dir];
211         x += ddx[dir];
212         if (is_cave_empty_bold(caster_ptr, y, x)) {
213             ty = y;
214             tx = x;
215         } else {
216             break;
217         }
218     }
219
220     bool is_shock_successful = ty != oy;
221     is_shock_successful |= tx != ox;
222     if (is_shock_successful)
223         return TRUE;
224
225     msg_format(_("%sを吹き飛ばした!", "You blow %s away!"), m_name);
226     caster_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = 0;
227     caster_ptr->current_floor_ptr->grid_array[ty][tx].m_idx = m_idx;
228     m_ptr->fy = ty;
229     m_ptr->fx = tx;
230
231     update_monster(caster_ptr, m_idx, TRUE);
232     lite_spot(caster_ptr, oy, ox);
233     lite_spot(caster_ptr, ty, tx);
234
235     if (r_ptr->flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
236         caster_ptr->update |= (PU_MON_LITE);
237
238     return TRUE;
239 }
240
241 /*!
242  * @brief 練気術の発動 /
243  * do_cmd_cast calls this function if the player's class is 'ForceTrainer'.
244  * @param spell 発動する特殊技能のID
245  * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
246  */
247 bool cast_force_spell(player_type *caster_ptr, mind_force_trainer_type spell)
248 {
249     DIRECTION dir;
250     PLAYER_LEVEL plev = caster_ptr->lev;
251     int boost = get_current_ki(caster_ptr);
252     if (heavy_armor(caster_ptr))
253         boost /= 2;
254
255     switch (spell) {
256     case SMALL_FORCE_BALL:
257         if (!get_aim_dir(caster_ptr, &dir))
258             return FALSE;
259
260         fire_ball(caster_ptr, GF_MISSILE, dir, damroll(3 + ((plev - 1) / 5) + boost / 12, 4), 0);
261         break;
262     case FLASH_LIGHT:
263         (void)lite_area(caster_ptr, damroll(2, (plev / 2)), (plev / 10) + 1);
264         break;
265     case FLYING_TECHNIQUE:
266         set_tim_levitation(caster_ptr, randint1(30) + 30 + boost / 5, FALSE);
267         break;
268     case KAMEHAMEHA:
269         project_length = plev / 8 + 3;
270         if (!get_aim_dir(caster_ptr, &dir))
271             return FALSE;
272
273         fire_beam(caster_ptr, GF_MISSILE, dir, damroll(5 + ((plev - 1) / 5) + boost / 10, 5));
274         break;
275     case MAGIC_RESISTANCE:
276         set_resist_magic(caster_ptr, randint1(20) + 20 + boost / 5, FALSE);
277         break;
278     case IMPROVE_FORCE:
279         msg_print(_("気を練った。", "You improved the Force."));
280         set_current_ki(caster_ptr, FALSE, 70 + plev);
281         caster_ptr->update |= (PU_BONUS);
282         if (randint1(get_current_ki(caster_ptr)) > (plev * 4 + 120)) {
283             msg_print(_("気が暴走した!", "The Force exploded!"));
284             fire_ball(caster_ptr, GF_MANA, 0, get_current_ki(caster_ptr) / 2, 10);
285             take_hit(caster_ptr, DAMAGE_LOSELIFE, caster_ptr->magic_num1[0] / 2, _("気の暴走", "Explosion of the Force"));
286         } else
287             return TRUE;
288
289         break;
290     case AURA_OF_FORCE:
291         set_tim_sh_force(caster_ptr, randint1(plev / 2) + 15 + boost / 7, FALSE);
292         break;
293     case SHOCK_POWER:
294         return shock_power(caster_ptr);
295         break;
296     case LARGE_FORCE_BALL:
297         if (!get_aim_dir(caster_ptr, &dir))
298             return FALSE;
299
300         fire_ball(caster_ptr, GF_MISSILE, dir, damroll(10, 6) + plev * 3 / 2 + boost * 3 / 5, (plev < 30) ? 2 : 3);
301         break;
302     case DISPEL_MAGIC: {
303         if (!target_set(caster_ptr, TARGET_KILL))
304             return FALSE;
305
306         MONSTER_IDX m_idx = caster_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
307         if ((m_idx == 0) || !player_has_los_bold(caster_ptr, target_row, target_col)
308             || !projectable(caster_ptr, caster_ptr->y, caster_ptr->x, target_row, target_col))
309             break;
310
311         dispel_monster_status(caster_ptr, m_idx);
312         break;
313     }
314     case SUMMON_GHOST: {
315         bool success = FALSE;
316         for (int i = 0; i < 1 + boost / 100; i++)
317             if (summon_specific(caster_ptr, -1, caster_ptr->y, caster_ptr->x, plev, SUMMON_PHANTOM, PM_FORCE_PET))
318                 success = TRUE;
319
320         if (success)
321             msg_print(_("御用でございますが、御主人様?", "'Your wish, master?'"));
322         else
323             msg_print(_("何も現れなかった。", "Nothing happens."));
324
325         break;
326     }
327     case EXPLODING_FLAME:
328         fire_ball(caster_ptr, GF_FIRE, 0, 200 + (2 * plev) + boost * 2, 10);
329         break;
330     case SUPER_KAMEHAMEHA:
331         if (!get_aim_dir(caster_ptr, &dir))
332             return FALSE;
333
334         fire_beam(caster_ptr, GF_MANA, dir, damroll(10 + (plev / 2) + boost * 3 / 10, 15));
335         break;
336     case LIGHT_SPEED:
337         set_lightspeed(caster_ptr, randint1(16) + 16 + boost / 20, FALSE);
338         break;
339     default:
340         msg_print(_("なに?", "Zap?"));
341     }
342
343     set_current_ki(caster_ptr, TRUE, 0);
344     caster_ptr->update |= PU_BONUS;
345     return TRUE;
346 }