OSDN Git Service

18f978a6d0e23be80c45ce30d234a08740919177
[hengband/hengband.git] / src / spells-status.c
1 #include "angband.h"
2 #include "core.h"
3 #include "util.h"
4
5 #include "avatar.h"
6 #include "floor.h"
7 #include "object-flavor.h"
8 #include "player-status.h"
9 #include "spells-status.h"
10 #include "spells.h"
11 #include "monster.h"
12 #include "cmd-spell.h"
13 #include "player-effects.h"
14 #include "objectkind.h"
15 #include "targeting.h"
16 #include "realm-song.h"
17
18 /*!
19  * @brief モンスター回復処理
20  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
21  * @param dam 威力
22  * @return 作用が実際にあった場合TRUEを返す
23  */
24 bool heal_monster(DIRECTION dir, HIT_POINT dam)
25 {
26         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
27         return (project_hook(GF_OLD_HEAL, dir, dam, flg));
28 }
29
30 /*!
31  * @brief モンスター加速処理
32  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
33  * @param power 効力
34  * @return 作用が実際にあった場合TRUEを返す
35  */
36 bool speed_monster(DIRECTION dir, int power)
37 {
38         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
39         return (project_hook(GF_OLD_SPEED, dir, power, flg));
40 }
41
42 /*!
43  * @brief モンスター減速処理
44  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
45  * @param power 効力
46  * @return 作用が実際にあった場合TRUEを返す
47  */
48 bool slow_monster(DIRECTION dir, int power)
49 {
50         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
51         return (project_hook(GF_OLD_SLOW, dir, power, flg));
52 }
53
54 /*!
55  * @brief モンスター催眠処理
56  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
57  * @param power 効力
58  * @return 作用が実際にあった場合TRUEを返す
59  */
60 bool sleep_monster(DIRECTION dir, int power)
61 {
62         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
63         return (project_hook(GF_OLD_SLEEP, dir, power, flg));
64 }
65
66 /*!
67  * @brief モンスター拘束(STASIS)処理
68  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
69  * @return 作用が実際にあった場合TRUEを返す
70  * @details 威力はプレイヤーレベル*2に固定
71  */
72 bool stasis_monster(DIRECTION dir)
73 {
74         return (fire_ball_hide(GF_STASIS, dir, p_ptr->lev * 2, 0));
75 }
76
77 /*!
78  * @brief 邪悪なモンスター拘束(STASIS)処理
79  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
80  * @return 作用が実際にあった場合TRUEを返す
81  * @details 威力はプレイヤーレベル*2に固定
82  */
83 bool stasis_evil(DIRECTION dir)
84 {
85         return (fire_ball_hide(GF_STASIS_EVIL, dir, p_ptr->lev * 2, 0));
86 }
87
88 /*!
89  * @brief モンスター混乱処理
90  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
91  * @param plev プレイヤーレベル(=効力)
92  * @return 作用が実際にあった場合TRUEを返す
93  */
94 bool confuse_monster(DIRECTION dir, PLAYER_LEVEL plev)
95 {
96         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
97         return (project_hook(GF_OLD_CONF, dir, plev, flg));
98 }
99
100 /*!
101  * @brief モンスター朦朧処理
102  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
103  * @param plev プレイヤーレベル(=効力)
104  * @return 作用が実際にあった場合TRUEを返す
105  */
106 bool stun_monster(DIRECTION dir, PLAYER_LEVEL plev)
107 {
108         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
109         return (project_hook(GF_STUN, dir, plev, flg));
110 }
111
112 /*!
113  * @brief チェンジモンスター処理
114  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
115  * @param power 効力
116  * @return 作用が実際にあった場合TRUEを返す
117  */
118 bool poly_monster(DIRECTION dir, int power)
119 {
120         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
121         bool tester = (project_hook(GF_OLD_POLY, dir, power, flg));
122         if (tester)
123                 chg_virtue(V_CHANCE, 1);
124         return(tester);
125 }
126
127 /*!
128  * @brief クローンモンスター処理
129  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
130  * @return 作用が実際にあった場合TRUEを返す
131  */
132 bool clone_monster(DIRECTION dir)
133 {
134         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
135         return (project_hook(GF_OLD_CLONE, dir, 0, flg));
136 }
137
138 /*!
139  * @brief モンスター恐慌処理
140  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
141  * @param plev プレイヤーレベル(=効力)
142  * @return 作用が実際にあった場合TRUEを返す
143  */
144 bool fear_monster(DIRECTION dir, PLAYER_LEVEL plev)
145 {
146         BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE;
147         return (project_hook(GF_TURN_ALL, dir, plev, flg));
148 }
149
150 /*!
151 * @brief 歌の停止を処理する / Stop singing if the player is a Bard
152 * @return なし
153 */
154 void stop_singing(player_type *creature_ptr)
155 {
156         if (creature_ptr->pclass != CLASS_BARD) return;
157
158         /* Are there interupted song? */
159         if (INTERUPTING_SONG_EFFECT(creature_ptr))
160         {
161                 /* Forget interupted song */
162                 INTERUPTING_SONG_EFFECT(creature_ptr) = MUSIC_NONE;
163                 return;
164         }
165
166         /* The player is singing? */
167         if (!SINGING_SONG_EFFECT(creature_ptr)) return;
168
169         /* Hack -- if called from set_action(), avoid recursive loop */
170         if (creature_ptr->action == ACTION_SING) set_action(ACTION_NONE);
171
172         /* Message text of each song or etc. */
173         do_spell(REALM_MUSIC, SINGING_SONG_ID(creature_ptr), SPELL_STOP);
174
175         SINGING_SONG_EFFECT(creature_ptr) = MUSIC_NONE;
176         SINGING_SONG_ID(creature_ptr) = 0;
177         creature_ptr->update |= (PU_BONUS);
178         creature_ptr->redraw |= (PR_STATUS);
179 }
180
181 bool time_walk(player_type *creature_ptr)
182 {
183         if (creature_ptr->timewalk)
184         {
185                 msg_print(_("既に時は止まっている。", "Time is already stopped."));
186                 return (FALSE);
187         }
188         creature_ptr->timewalk = TRUE;
189         msg_print(_("「時よ!」", "You yell 'Time!'"));
190 //      msg_print(_("「『ザ・ワールド』!時は止まった!」", "You yell 'The World! Time has stopped!'"));
191         msg_print(NULL);
192
193         /* Hack */
194         creature_ptr->energy_need -= 1000 + (100 + p_ptr->csp - 50)*TURNS_PER_TICK / 10;
195         creature_ptr->redraw |= (PR_MAP);
196         creature_ptr->update |= (PU_MONSTERS);
197         creature_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
198         handle_stuff();
199         return TRUE;
200 }
201
202 /*!
203  * @brief プレイヤーのヒットダイスを振る / Role Hitpoints
204  * @param options スペル共通オプション
205  * @return なし
206  */
207 void roll_hitdice(player_type *creature_ptr, SPOP_FLAGS options)
208 {
209         PERCENTAGE percent;
210
211         /* Minimum hitpoints at highest level */
212         HIT_POINT min_value = creature_ptr->hitdie + ((PY_MAX_LEVEL + 2) * (creature_ptr->hitdie + 1)) * 3 / 8;
213
214         /* Maximum hitpoints at highest level */
215         HIT_POINT max_value = creature_ptr->hitdie + ((PY_MAX_LEVEL + 2) * (creature_ptr->hitdie + 1)) * 5 / 8;
216
217         int i;
218
219         /* Rerate */
220         while (1)
221         {
222                 /* Pre-calculate level 1 hitdice */
223                 creature_ptr->player_hp[0] = (HIT_POINT)creature_ptr->hitdie;
224
225                 for (i = 1; i < 4; i++)
226                 {
227                         creature_ptr->player_hp[0] += randint1(creature_ptr->hitdie);
228                 }
229
230                 /* Roll the hitpoint values */
231                 for (i = 1; i < PY_MAX_LEVEL; i++)
232                 {
233                         creature_ptr->player_hp[i] = creature_ptr->player_hp[i - 1] + randint1(creature_ptr->hitdie);
234                 }
235
236                 /* Require "valid" hitpoints at highest level */
237                 if ((creature_ptr->player_hp[PY_MAX_LEVEL - 1] >= min_value) &&
238                         (creature_ptr->player_hp[PY_MAX_LEVEL - 1] <= max_value)) break;
239         }
240
241         percent = (int)(((long)creature_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) /
242                 (2 * creature_ptr->hitdie + ((PY_MAX_LEVEL - 1 + 3) * (creature_ptr->hitdie + 1))));
243
244         /* Update and redraw hitpoints */
245         creature_ptr->update |= (PU_HP);
246         creature_ptr->redraw |= (PR_HP);
247         creature_ptr->window |= (PW_PLAYER);
248
249         if (!(options & SPOP_NO_UPDATE)) handle_stuff();
250
251         if (options & SPOP_DISPLAY_MES)
252         {
253                 if (options & SPOP_DEBUG)
254                 {
255                         msg_format(_("現在の体力ランクは %d/100 です。", "Your life rate is %d/100 now."), percent);
256                         creature_ptr->knowledge |= KNOW_HPRATE;
257                 }
258                 else
259                 {
260                         msg_print(_("体力ランクが変わった。", "Life rate is changed."));
261                         creature_ptr->knowledge &= ~(KNOW_HPRATE);
262                 }
263         }
264 }
265
266 bool_hack life_stream(bool_hack message, bool_hack virtue_change)
267 {
268         if (virtue_change)
269         {
270                 chg_virtue(V_VITALITY, 1);
271                 chg_virtue(V_UNLIFE, -5);
272         }
273         if (message)
274         {
275                 msg_print(_("体中に生命力が満ちあふれてきた!", "You feel life flow through your body!"));
276         }
277         restore_level();
278         (void)set_poisoned(0);
279         (void)set_blind(0);
280         (void)set_confused(0);
281         (void)set_image(0);
282         (void)set_stun(0);
283         (void)set_cut(0);
284         (void)restore_all_status();
285         (void)set_shero(0, TRUE);
286         handle_stuff();
287         hp_player(5000);
288
289         return TRUE;
290 }
291
292 bool_hack heroism(int base)
293 {
294         bool_hack ident = FALSE;
295         if (set_afraid(0)) ident = TRUE;
296         if (set_hero(p_ptr->hero + randint1(base) + base, FALSE)) ident = TRUE;
297         if (hp_player(10)) ident = TRUE;
298         return ident;
299 }
300
301 bool_hack berserk(int base)
302 {
303         bool_hack ident = FALSE;
304         if (set_afraid(0)) ident = TRUE;
305         if (set_shero(p_ptr->shero + randint1(base) + base, FALSE)) ident = TRUE;
306         if (hp_player(30)) ident = TRUE;
307         return ident;
308 }
309
310 bool_hack cure_light_wounds(DICE_NUMBER dice, DICE_SID sides)
311 {
312         bool_hack ident = FALSE;
313         if (hp_player(damroll(dice, sides))) ident = TRUE;
314         if (set_blind(0)) ident = TRUE;
315         if (set_cut(p_ptr->cut - 10)) ident = TRUE;
316         if (set_shero(0, TRUE)) ident = TRUE;
317         return ident;
318 }
319
320 bool_hack cure_serious_wounds(DICE_NUMBER dice, DICE_SID sides)
321 {
322         bool_hack ident = FALSE;
323         if (hp_player(damroll(dice, sides))) ident = TRUE;
324         if (set_blind(0)) ident = TRUE;
325         if (set_confused(0)) ident = TRUE;
326         if (set_cut((p_ptr->cut / 2) - 50)) ident = TRUE;
327         if (set_shero(0, TRUE)) ident = TRUE;
328         return ident;
329 }
330
331 bool_hack cure_critical_wounds(HIT_POINT pow)
332 {
333         bool_hack ident = FALSE;
334         if (hp_player(pow)) ident = TRUE;
335         if (set_blind(0)) ident = TRUE;
336         if (set_confused(0)) ident = TRUE;
337         if (set_poisoned(0)) ident = TRUE;
338         if (set_stun(0)) ident = TRUE;
339         if (set_cut(0)) ident = TRUE;
340         if (set_shero(0, TRUE)) ident = TRUE;
341         return ident;
342 }
343
344 bool_hack true_healing(HIT_POINT pow)
345 {
346         bool_hack ident = FALSE;
347         if (hp_player(pow)) ident = TRUE;
348         if (set_blind(0)) ident = TRUE;
349         if (set_confused(0)) ident = TRUE;
350         if (set_poisoned(0)) ident = TRUE;
351         if (set_stun(0)) ident = TRUE;
352         if (set_cut(0)) ident = TRUE;
353         if (set_image(0)) ident = TRUE;
354         return ident;
355 }
356
357 bool_hack restore_mana(bool_hack magic_eater)
358 {
359         bool_hack ident = FALSE;
360
361         if (p_ptr->pclass == CLASS_MAGIC_EATER && magic_eater)
362         {
363                 int i;
364                 for (i = 0; i < EATER_EXT * 2; i++)
365                 {
366                         p_ptr->magic_num1[i] += (p_ptr->magic_num2[i] < 10) ? EATER_CHARGE * 3 : p_ptr->magic_num2[i] * EATER_CHARGE / 3;
367                         if (p_ptr->magic_num1[i] > p_ptr->magic_num2[i] * EATER_CHARGE) p_ptr->magic_num1[i] = p_ptr->magic_num2[i] * EATER_CHARGE;
368                 }
369                 for (; i < EATER_EXT * 3; i++)
370                 {
371                         KIND_OBJECT_IDX k_idx = lookup_kind(TV_ROD, i - EATER_EXT * 2);
372                         p_ptr->magic_num1[i] -= ((p_ptr->magic_num2[i] < 10) ? EATER_ROD_CHARGE * 3 : p_ptr->magic_num2[i] * EATER_ROD_CHARGE / 3)*k_info[k_idx].pval;
373                         if (p_ptr->magic_num1[i] < 0) p_ptr->magic_num1[i] = 0;
374                 }
375                 msg_print(_("頭がハッキリとした。", "You feel your head clear."));
376                 p_ptr->window |= (PW_PLAYER);
377                 ident = TRUE;
378         }
379         else if (p_ptr->csp < p_ptr->msp)
380         {
381                 p_ptr->csp = p_ptr->msp;
382                 p_ptr->csp_frac = 0;
383                 msg_print(_("頭がハッキリとした。", "You feel your head clear."));
384                 p_ptr->redraw |= (PR_MANA);
385                 p_ptr->window |= (PW_PLAYER);
386                 p_ptr->window |= (PW_SPELL);
387                 ident = TRUE;
388         }
389
390         return ident;
391 }
392
393 bool restore_all_status(void)
394 {
395         bool ident = FALSE;
396         if (do_res_stat(A_STR)) ident = TRUE;
397         if (do_res_stat(A_INT)) ident = TRUE;
398         if (do_res_stat(A_WIS)) ident = TRUE;
399         if (do_res_stat(A_DEX)) ident = TRUE;
400         if (do_res_stat(A_CON)) ident = TRUE;
401         if (do_res_stat(A_CHR)) ident = TRUE;
402         return ident;
403 }
404
405 bool fishing(player_type *creature_ptr)
406 {
407         DIRECTION dir;
408         POSITION x, y;
409
410         if (!get_direction(&dir, FALSE, FALSE)) return FALSE;
411         y = creature_ptr->y + ddy[dir];
412         x = creature_ptr->x + ddx[dir];
413         creature_ptr->fishing_dir = dir;
414         if (!cave_have_flag_bold(y, x, FF_WATER))
415         {
416                 msg_print(_("そこは水辺ではない。", "There is no fishing place."));
417                 return FALSE;
418         }
419         else if (current_floor_ptr->grid_array[y][x].m_idx)
420         {
421                 GAME_TEXT m_name[MAX_NLEN];
422                 monster_desc(m_name, &current_floor_ptr->m_list[current_floor_ptr->grid_array[y][x].m_idx], 0);
423                 msg_format(_("%sが邪魔だ!", "%^s is stand in your way."), m_name);
424                 free_turn(creature_ptr);
425                 return FALSE;
426         }
427         set_action(ACTION_FISH);
428         creature_ptr->redraw |= (PR_STATE);
429         return TRUE;
430 }
431
432
433 bool cosmic_cast_off(player_type *creature_ptr, object_type *o_ptr)
434 {
435         INVENTORY_IDX inv;
436         int t;
437         OBJECT_IDX o_idx;
438         GAME_TEXT o_name[MAX_NLEN];
439         object_type forge;
440
441         /* Cast off activated item */
442         for (inv = INVEN_RARM; inv <= INVEN_FEET; inv++)
443         {
444                 if (o_ptr == &p_ptr->inventory_list[inv]) break;
445         }
446         if (inv > INVEN_FEET) return FALSE;
447
448         object_copy(&forge, o_ptr);
449         inven_item_increase(inv, (0 - o_ptr->number));
450         inven_item_optimize(inv);
451         o_idx = drop_near(&forge, 0, creature_ptr->y, creature_ptr->x);
452         o_ptr = &current_floor_ptr->o_list[o_idx];
453
454         object_desc(o_name, o_ptr, OD_NAME_ONLY);
455         msg_format(_("%sを脱ぎ捨てた。", "You cast off %s."), o_name);
456
457         /* Get effects */
458         msg_print(_("「燃え上がれ俺の小宇宙!」", "You say, 'Burn up my cosmo!"));
459         t = 20 + randint1(20);
460         (void)set_blind(creature_ptr->blind + t);
461         (void)set_afraid(0);
462         (void)set_tim_esp(creature_ptr->tim_esp + t, FALSE);
463         (void)set_tim_regen(creature_ptr->tim_regen + t, FALSE);
464         (void)set_hero(creature_ptr->hero + t, FALSE);
465         (void)set_blessed(creature_ptr->blessed + t, FALSE);
466         (void)set_fast(creature_ptr->fast + t, FALSE);
467         (void)set_shero(creature_ptr->shero + t, FALSE);
468         if (creature_ptr->pclass == CLASS_FORCETRAINER)
469         {
470                 P_PTR_KI = creature_ptr->lev * 5 + 190;
471                 msg_print(_("気が爆発寸前になった。", "Your force are immediatly before explosion."));
472         }
473
474         return TRUE;
475 }
476
477
478 /*!
479  * @brief プレイヤーの因果混乱処理 / Apply Nexus
480  * @param m_ptr 因果混乱をプレイヤーに与えたモンスターの情報参照ポインタ
481  * @return なし
482  */
483 void apply_nexus(monster_type *m_ptr)
484 {
485         switch (randint1(7))
486         {
487         case 1: case 2: case 3:
488         {
489                 teleport_player(200, TELEPORT_PASSIVE);
490                 break;
491         }
492
493         case 4: case 5:
494         {
495                 teleport_player_to(m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
496                 break;
497         }
498
499         case 6:
500         {
501                 if (randint0(100) < p_ptr->skill_sav)
502                 {
503                         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
504                         break;
505                 }
506                 teleport_level(0);
507                 break;
508         }
509
510         case 7:
511         {
512                 if (randint0(100) < p_ptr->skill_sav)
513                 {
514                         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
515                         break;
516                 }
517
518                 msg_print(_("体がねじれ始めた...", "Your body starts to scramble..."));
519                 status_shuffle();
520                 break;
521         }
522         }
523 }
524
525 /*!
526  * @brief プレイヤーのステータスシャッフル処理
527  * @return なし
528  */
529 void status_shuffle(void)
530 {
531         BASE_STATUS max1, cur1, max2, cur2;
532         int ii, jj, i;
533
534         /* Pick a pair of stats */
535         ii = randint0(A_MAX);
536         for (jj = ii; jj == ii; jj = randint0(A_MAX)) /* loop */;
537
538         max1 = p_ptr->stat_max[ii];
539         cur1 = p_ptr->stat_cur[ii];
540         max2 = p_ptr->stat_max[jj];
541         cur2 = p_ptr->stat_cur[jj];
542
543         p_ptr->stat_max[ii] = max2;
544         p_ptr->stat_cur[ii] = cur2;
545         p_ptr->stat_max[jj] = max1;
546         p_ptr->stat_cur[jj] = cur1;
547
548         for (i = 0; i < A_MAX; i++)
549         {
550                 if (p_ptr->stat_max[i] > p_ptr->stat_max_max[i]) p_ptr->stat_max[i] = p_ptr->stat_max_max[i];
551                 if (p_ptr->stat_cur[i] > p_ptr->stat_max_max[i]) p_ptr->stat_cur[i] = p_ptr->stat_max_max[i];
552         }
553
554         p_ptr->update |= (PU_BONUS);
555 }