OSDN Git Service

67a76401f25bbab9eef399f7b5300547875a0897
[hengbandforosx/hengbandosx.git] / src / status / buff-setter.cpp
1 #include "status/buff-setter.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "core/player-update-types.h"
6 #include "core/speed-table.h"
7 #include "core/stuff-handler.h"
8 #include "core/window-redrawer.h"
9 #include "game-option/disturbance-options.h"
10 #include "monster/monster-status-setter.h"
11 #include "player-info/class-info.h"
12 #include "player-info/race-info.h"
13 #include "player/attack-defense-types.h"
14 #include "player/player-status.h"
15 #include "realm/realm-song-numbers.h"
16 #include "spell-realm/spells-song.h"
17 #include "status/base-status.h"
18 #include "status/buff-setter.h"
19 #include "status/element-resistance.h"
20 #include "system/player-type-definition.h"
21 #include "timed-effect/player-cut.h"
22 #include "timed-effect/player-stun.h"
23 #include "timed-effect/timed-effects.h"
24 #include "view/display-messages.h"
25
26 /*!
27  * @brief プレイヤーの全ての時限効果をリセットする。 / reset timed flags
28  */
29 void reset_tim_flags(player_type *player_ptr)
30 {
31     auto effects = player_ptr->effects();
32     player_ptr->fast = 0; /* Timed -- Fast */
33     player_ptr->lightspeed = 0;
34     player_ptr->slow = 0; /* Timed -- Slow */
35     player_ptr->blind = 0; /* Timed -- Blindness */
36     player_ptr->paralyzed = 0; /* Timed -- Paralysis */
37     player_ptr->confused = 0; /* Timed -- Confusion */
38     player_ptr->afraid = 0; /* Timed -- Fear */
39     player_ptr->hallucinated = 0; /* Timed -- Hallucination */
40     player_ptr->poisoned = 0; /* Timed -- Poisoned */
41     effects->cut()->reset();
42     effects->stun()->reset();
43
44     player_ptr->protevil = 0; /* Timed -- Protection */
45     player_ptr->invuln = 0; /* Timed -- Invulnerable */
46     player_ptr->ult_res = 0;
47     player_ptr->hero = 0; /* Timed -- Heroism */
48     player_ptr->shero = 0; /* Timed -- Super Heroism */
49     player_ptr->shield = 0; /* Timed -- Shield Spell */
50     player_ptr->blessed = 0; /* Timed -- Blessed */
51     player_ptr->tim_invis = 0; /* Timed -- Invisibility */
52     player_ptr->tim_infra = 0; /* Timed -- Infra Vision */
53     player_ptr->tim_regen = 0; /* Timed -- Regeneration */
54     player_ptr->tim_stealth = 0; /* Timed -- Stealth */
55     player_ptr->tim_esp = 0;
56     player_ptr->wraith_form = 0; /* Timed -- Wraith Form */
57     player_ptr->tim_levitation = 0;
58     player_ptr->tim_sh_touki = 0;
59     player_ptr->tim_sh_fire = 0;
60     player_ptr->tim_sh_holy = 0;
61     player_ptr->tim_eyeeye = 0;
62     player_ptr->magicdef = 0;
63     player_ptr->resist_magic = 0;
64     player_ptr->tsuyoshi = 0;
65     player_ptr->tim_pass_wall = 0;
66     player_ptr->tim_res_nether = 0;
67     player_ptr->tim_res_time = 0;
68     player_ptr->tim_mimic = 0;
69     player_ptr->mimic_form = 0;
70     player_ptr->tim_reflect = 0;
71     player_ptr->multishadow = 0;
72     player_ptr->dustrobe = 0;
73     player_ptr->action = ACTION_NONE;
74
75     player_ptr->oppose_acid = 0; /* Timed -- oppose acid */
76     player_ptr->oppose_elec = 0; /* Timed -- oppose lightning */
77     player_ptr->oppose_fire = 0; /* Timed -- oppose heat */
78     player_ptr->oppose_cold = 0; /* Timed -- oppose cold */
79     player_ptr->oppose_pois = 0; /* Timed -- oppose poison */
80
81     player_ptr->word_recall = 0;
82     player_ptr->alter_reality = 0;
83     player_ptr->sutemi = false;
84     player_ptr->counter = false;
85     player_ptr->ele_attack = 0;
86     player_ptr->ele_immune = 0;
87     player_ptr->special_attack = 0L;
88     player_ptr->special_defense = 0L;
89
90     while (player_ptr->energy_need < 0)
91         player_ptr->energy_need += ENERGY_NEED();
92
93     player_ptr->timewalk = false;
94
95     if (player_ptr->riding) {
96         (void)set_monster_fast(player_ptr, player_ptr->riding, 0);
97         (void)set_monster_slow(player_ptr, player_ptr->riding, 0);
98         (void)set_monster_invulner(player_ptr, player_ptr->riding, 0, false);
99     }
100
101     if (player_ptr->pclass == CLASS_BARD) {
102         set_singing_song_effect(player_ptr, MUSIC_NONE);
103         set_singing_song_id(player_ptr, 0);
104     }
105 }
106
107 /*!
108  * @brief 加速の継続時間をセットする / Set "fast", notice observable changes
109  * @param v 継続時間
110  * @param do_dec 現在の継続時間より長い値のみ上書きする
111  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
112  */
113 bool set_fast(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
114 {
115     bool notice = false;
116     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
117
118     if (player_ptr->is_dead)
119         return false;
120
121     if (v) {
122         if (player_ptr->fast && !do_dec) {
123             if (player_ptr->fast > v)
124                 return false;
125         } else if (!is_fast(player_ptr) && !player_ptr->lightspeed) {
126             msg_print(_("素早く動けるようになった!", "You feel yourself moving much faster!"));
127             notice = true;
128             chg_virtue(player_ptr, V_PATIENCE, -1);
129             chg_virtue(player_ptr, V_DILIGENCE, 1);
130         }
131     } else {
132         if (player_ptr->fast && !player_ptr->lightspeed && !music_singing(player_ptr, MUSIC_SPEED) && !music_singing(player_ptr, MUSIC_SHERO)) {
133             msg_print(_("動きの素早さがなくなったようだ。", "You feel yourself slow down."));
134             notice = true;
135         }
136     }
137
138     player_ptr->fast = v;
139     if (!notice)
140         return false;
141
142     if (disturb_state)
143         disturb(player_ptr, false, false);
144     player_ptr->update |= (PU_BONUS);
145     handle_stuff(player_ptr);
146     return true;
147 }
148
149 /*!
150  * @brief 肌石化の継続時間をセットする / Set "shield", notice observable changes
151  * @param v 継続時間
152  * @param do_dec 現在の継続時間より長い値のみ上書きする
153  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
154  */
155 bool set_shield(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
156 {
157     bool notice = false;
158     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
159
160     if (player_ptr->is_dead)
161         return false;
162
163     if (v) {
164         if (player_ptr->shield && !do_dec) {
165             if (player_ptr->shield > v)
166                 return false;
167         } else if (!player_ptr->shield) {
168             msg_print(_("肌が石になった。", "Your skin turns to stone."));
169             notice = true;
170         }
171     } else {
172         if (player_ptr->shield) {
173             msg_print(_("肌が元に戻った。", "Your skin returns to normal."));
174             notice = true;
175         }
176     }
177
178     player_ptr->shield = v;
179     player_ptr->redraw |= (PR_STATUS);
180
181     if (!notice)
182         return false;
183
184     if (disturb_state)
185         disturb(player_ptr, false, false);
186     player_ptr->update |= (PU_BONUS);
187     handle_stuff(player_ptr);
188     return true;
189 }
190
191 /*!
192  * @brief 魔法の鎧の継続時間をセットする / Set "magicdef", notice observable changes
193  * @param v 継続時間
194  * @param do_dec 現在の継続時間より長い値のみ上書きする
195  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
196  */
197 bool set_magicdef(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
198 {
199     bool notice = false;
200     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
201
202     if (player_ptr->is_dead)
203         return false;
204
205     if (v) {
206         if (player_ptr->magicdef && !do_dec) {
207             if (player_ptr->magicdef > v)
208                 return false;
209         } else if (!player_ptr->magicdef) {
210             msg_print(_("魔法の防御力が増したような気がする。", "You feel more resistant to magic."));
211             notice = true;
212         }
213     } else {
214         if (player_ptr->magicdef) {
215             msg_print(_("魔法の防御力が元に戻った。", "You feel less resistant to magic."));
216             notice = true;
217         }
218     }
219
220     player_ptr->magicdef = v;
221     player_ptr->redraw |= (PR_STATUS);
222
223     if (!notice)
224         return false;
225
226     if (disturb_state)
227         disturb(player_ptr, false, false);
228     player_ptr->update |= (PU_BONUS);
229     handle_stuff(player_ptr);
230     return true;
231 }
232
233 /*!
234  * @brief 祝福の継続時間をセットする / Set "blessed", notice observable changes
235  * @param v 継続時間
236  * @param do_dec 現在の継続時間より長い値のみ上書きする
237  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
238  */
239 bool set_blessed(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
240 {
241     bool notice = false;
242     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
243
244     if (player_ptr->is_dead)
245         return false;
246
247     if (v) {
248         if (player_ptr->blessed && !do_dec) {
249             if (player_ptr->blessed > v)
250                 return false;
251         } else if (!is_blessed(player_ptr)) {
252             msg_print(_("高潔な気分になった!", "You feel righteous!"));
253             notice = true;
254         }
255     } else {
256         if (player_ptr->blessed && !music_singing(player_ptr, MUSIC_BLESS)) {
257             msg_print(_("高潔な気分が消え失せた。", "The prayer has expired."));
258             notice = true;
259         }
260     }
261
262     player_ptr->blessed = v;
263     player_ptr->redraw |= (PR_STATUS);
264
265     if (!notice)
266         return false;
267
268     if (disturb_state)
269         disturb(player_ptr, false, false);
270     player_ptr->update |= (PU_BONUS);
271     handle_stuff(player_ptr);
272     return true;
273 }
274
275 /*!
276  * @brief 士気高揚の継続時間をセットする / Set "hero", notice observable changes
277  * @param v 継続時間
278  * @param do_dec 現在の継続時間より長い値のみ上書きする
279  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
280  */
281 bool set_hero(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
282 {
283     bool notice = false;
284     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
285
286     if (player_ptr->is_dead)
287         return false;
288
289     if (v) {
290         if (player_ptr->hero && !do_dec) {
291             if (player_ptr->hero > v)
292                 return false;
293         } else if (!is_hero(player_ptr)) {
294             msg_print(_("ヒーローになった気がする!", "You feel like a hero!"));
295             notice = true;
296         }
297     } else {
298         if (player_ptr->hero && !music_singing(player_ptr, MUSIC_HERO) && !music_singing(player_ptr, MUSIC_SHERO)) {
299             msg_print(_("ヒーローの気分が消え失せた。", "The heroism wears off."));
300             notice = true;
301         }
302     }
303
304     player_ptr->hero = v;
305     player_ptr->redraw |= (PR_STATUS);
306
307     if (!notice)
308         return false;
309
310     if (disturb_state)
311         disturb(player_ptr, false, false);
312     player_ptr->update |= (PU_BONUS);
313     player_ptr->update |= (PU_HP);
314     handle_stuff(player_ptr);
315     return true;
316 }
317
318 /*!
319  * @brief 変身効果の継続時間と変身先をセットする / Set "tim_mimic", and "mimic_form", notice observable changes
320  * @param v 継続時間
321  * @param mimic_race_idx 変身内容
322  * @param do_dec 現在の継続時間より長い値のみ上書きする
323  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
324  */
325 bool set_mimic(player_type *player_ptr, TIME_EFFECT v, int16_t mimic_race_idx, bool do_dec)
326 {
327     bool notice = false;
328     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
329
330     if (player_ptr->is_dead)
331         return false;
332
333     if (v) {
334         if (player_ptr->tim_mimic && (player_ptr->mimic_form == mimic_race_idx) && !do_dec) {
335             if (player_ptr->tim_mimic > v)
336                 return false;
337         } else if ((!player_ptr->tim_mimic) || (player_ptr->mimic_form != mimic_race_idx)) {
338             msg_print(_("自分の体が変わってゆくのを感じた。", "You feel that your body changes."));
339             player_ptr->mimic_form = mimic_race_idx;
340             notice = true;
341         }
342     }
343
344     else {
345         if (player_ptr->tim_mimic) {
346             msg_print(_("変身が解けた。", "You are no longer transformed."));
347             if (player_ptr->mimic_form == MIMIC_DEMON)
348                 set_oppose_fire(player_ptr, 0, true);
349             player_ptr->mimic_form = 0;
350             notice = true;
351             mimic_race_idx = 0;
352         }
353     }
354
355     player_ptr->tim_mimic = v;
356     if (!notice)
357         return false;
358
359     if (disturb_state)
360         disturb(player_ptr, false, true);
361
362     player_ptr->redraw |= (PR_BASIC | PR_STATUS);
363     player_ptr->update |= (PU_BONUS | PU_HP);
364
365     handle_stuff(player_ptr);
366     return true;
367 }
368
369 /*!
370  * @brief 狂戦士化の継続時間をセットする / Set "shero", notice observable changes
371  * @param v 継続時間/ 0ならば無条件にリセット
372  * @param do_dec FALSEの場合現在の継続時間より長い値のみ上書きする
373  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
374  */
375 bool set_shero(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
376 {
377     bool notice = false;
378     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
379
380     if (player_ptr->is_dead)
381         return false;
382
383     if (player_ptr->pclass == CLASS_BERSERKER) {
384         v = 1;
385         return false;
386     }
387
388     if (v) {
389         if (player_ptr->shero && !do_dec) {
390             if (player_ptr->shero > v)
391                 return false;
392         } else if (!player_ptr->shero) {
393             msg_print(_("殺戮マシーンになった気がする!", "You feel like a killing machine!"));
394             notice = true;
395         }
396     } else {
397         if (player_ptr->shero) {
398             msg_print(_("野蛮な気持ちが消え失せた。", "You feel less berserk."));
399             notice = true;
400         }
401     }
402
403     player_ptr->shero = v;
404     player_ptr->redraw |= (PR_STATUS);
405
406     if (!notice)
407         return false;
408
409     if (disturb_state)
410         disturb(player_ptr, false, false);
411     player_ptr->update |= (PU_BONUS);
412     player_ptr->update |= (PU_HP);
413     handle_stuff(player_ptr);
414     return true;
415 }
416
417 /*!
418  * @brief 幽体化の継続時間をセットする / Set "wraith_form", notice observable changes
419  * @param v 継続時間
420  * @param do_dec 現在の継続時間より長い値のみ上書きする
421  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
422  */
423 bool set_wraith_form(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
424 {
425     bool notice = false;
426     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
427
428     if (player_ptr->is_dead)
429         return false;
430
431     if (v) {
432         if (player_ptr->wraith_form && !do_dec) {
433             if (player_ptr->wraith_form > v)
434                 return false;
435         } else if (!player_ptr->wraith_form) {
436             msg_print(_("物質界を離れて幽鬼のような存在になった!", "You leave the physical world and turn into a wraith-being!"));
437             notice = true;
438             chg_virtue(player_ptr, V_UNLIFE, 3);
439             chg_virtue(player_ptr, V_HONOUR, -2);
440             chg_virtue(player_ptr, V_SACRIFICE, -2);
441             chg_virtue(player_ptr, V_VALOUR, -5);
442
443             player_ptr->redraw |= (PR_MAP);
444             player_ptr->update |= (PU_MONSTERS);
445
446             player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
447         }
448     } else {
449         if (player_ptr->wraith_form) {
450             msg_print(_("不透明になった感じがする。", "You feel opaque."));
451             notice = true;
452
453             player_ptr->redraw |= (PR_MAP);
454             player_ptr->update |= (PU_MONSTERS);
455
456             player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
457         }
458     }
459
460     player_ptr->wraith_form = v;
461     player_ptr->redraw |= (PR_STATUS);
462
463     if (!notice)
464         return false;
465
466     if (disturb_state)
467         disturb(player_ptr, false, false);
468     player_ptr->update |= (PU_BONUS);
469     handle_stuff(player_ptr);
470     return true;
471 }
472
473 /*!
474  * @brief オクレ兄さんの継続時間をセットする / Set "tsuyoshi", notice observable changes
475  * @param v 継続時間
476  * @param do_dec 現在の継続時間より長い値のみ上書きする
477  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
478  */
479 bool set_tsuyoshi(player_type *player_ptr, TIME_EFFECT v, bool do_dec)
480 {
481     bool notice = false;
482     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
483
484     if (player_ptr->is_dead)
485         return false;
486
487     if (v) {
488         if (player_ptr->tsuyoshi && !do_dec) {
489             if (player_ptr->tsuyoshi > v)
490                 return false;
491         } else if (!player_ptr->tsuyoshi) {
492             msg_print(_("「オクレ兄さん!」", "Brother OKURE!"));
493             notice = true;
494             chg_virtue(player_ptr, V_VITALITY, 2);
495         }
496     } else {
497         if (player_ptr->tsuyoshi) {
498             msg_print(_("肉体が急速にしぼんでいった。", "Your body has quickly shriveled."));
499
500             (void)dec_stat(player_ptr, A_CON, 20, true);
501             (void)dec_stat(player_ptr, A_STR, 20, true);
502
503             notice = true;
504             chg_virtue(player_ptr, V_VITALITY, -3);
505         }
506     }
507
508     player_ptr->tsuyoshi = v;
509     player_ptr->redraw |= (PR_STATUS);
510
511     if (!notice)
512         return false;
513
514     if (disturb_state)
515         disturb(player_ptr, false, false);
516     player_ptr->update |= (PU_BONUS);
517     player_ptr->update |= (PU_HP);
518     handle_stuff(player_ptr);
519     return true;
520 }