OSDN Git Service

Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband
[hengband/hengband.git] / src / status / shape-changer.c
1 #include "status/shape-changer.h"
2 #include "autopick/autopick-reader-writer.h"
3 #include "birth/birth-body-spec.h"
4 #include "birth/birth-stat.h"
5 #include "core/disturbance.h"
6 #include "core/hp-mp-processor.h"
7 #include "core/player-redraw-types.h"
8 #include "core/player-update-types.h"
9 #include "core/stuff-handler.h"
10 #include "core/window-redrawer.h"
11 #include "game-option/disturbance-options.h"
12 #include "grid/grid.h"
13 #include "mutation/mutation-investor-remover.h"
14 #include "player-info/avatar.h"
15 #include "player/player-class.h"
16 #include "player/player-damage.h"
17 #include "player/player-personality.h"
18 #include "player/player-sex.h"
19 #include "player/race-info-table.h"
20 #include "spell/spells-status.h"
21 #include "status/bad-status-setter.h"
22 #include "status/base-status.h"
23 #include "status/element-resistance.h"
24 #include "view/display-messages.h"
25 #ifdef JP
26 #else
27 #include "locale/english.h"
28 #endif
29
30 void do_poly_wounds(player_type *creature_ptr)
31 {
32     s16b wounds = creature_ptr->cut;
33     s16b hit_p = (creature_ptr->mhp - creature_ptr->chp);
34     s16b change = damroll(creature_ptr->lev, 5);
35     bool Nasty_effect = one_in_(5);
36     if (!(wounds || hit_p || Nasty_effect))
37         return;
38
39     msg_print(_("傷がより軽いものに変化した。", "Your wounds are polymorphed into less serious ones."));
40     hp_player(creature_ptr, change);
41     if (Nasty_effect) {
42         msg_print(_("新たな傷ができた!", "A new wound was created!"));
43         take_hit(creature_ptr, DAMAGE_LOSELIFE, change / 2, _("変化した傷", "a polymorphed wound"), -1);
44         set_cut(creature_ptr, change);
45     } else {
46         set_cut(creature_ptr, creature_ptr->cut - (change / 2));
47     }
48 }
49
50 /*
51  * Change player race
52  */
53 void change_race(player_type *creature_ptr, player_race_type new_race, concptr effect_msg)
54 {
55     concptr title = race_info[new_race].title;
56     int old_race = creature_ptr->prace;
57 #ifdef JP
58     msg_format("あなたは%s%sに変化した!", effect_msg, title);
59 #else
60     msg_format("You turn into %s %s%s!", (!effect_msg[0] && is_a_vowel(title[0]) ? "an" : "a"), effect_msg, title);
61 #endif
62
63     chg_virtue(creature_ptr, V_CHANCE, 2);
64     if (creature_ptr->prace < 32) {
65         creature_ptr->old_race1 |= 1L << creature_ptr->prace;
66     } else {
67         creature_ptr->old_race2 |= 1L << (creature_ptr->prace - 32);
68     }
69
70     creature_ptr->prace = new_race;
71     rp_ptr = &race_info[creature_ptr->prace];
72     creature_ptr->expfact = rp_ptr->r_exp + cp_ptr->c_exp;
73
74     bool is_special_class = creature_ptr->pclass == CLASS_MONK;
75     is_special_class |= creature_ptr->pclass == CLASS_FORCETRAINER;
76     is_special_class |= creature_ptr->pclass == CLASS_NINJA;
77     bool is_special_race = creature_ptr->prace == RACE_KLACKON;
78     is_special_race |= creature_ptr->prace == RACE_SPRITE;
79     if (is_special_class && is_special_race)
80         creature_ptr->expfact -= 15;
81
82     get_height_weight(creature_ptr);
83
84     if (creature_ptr->pclass == CLASS_SORCERER)
85         creature_ptr->hitdie = rp_ptr->r_mhp / 2 + cp_ptr->c_mhp + ap_ptr->a_mhp;
86     else
87         creature_ptr->hitdie = rp_ptr->r_mhp + cp_ptr->c_mhp + ap_ptr->a_mhp;
88
89     roll_hitdice(creature_ptr, 0L);
90     check_experience(creature_ptr);
91     creature_ptr->redraw |= (PR_BASIC);
92     creature_ptr->update |= (PU_BONUS);
93     handle_stuff(creature_ptr);
94
95     if (old_race != creature_ptr->prace)
96         autopick_load_pref(creature_ptr, FALSE);
97
98     lite_spot(creature_ptr, creature_ptr->y, creature_ptr->x);
99 }
100
101 void do_poly_self(player_type *creature_ptr)
102 {
103     int power = creature_ptr->lev;
104
105     msg_print(_("あなたは変化の訪れを感じた...", "You feel a change coming over you..."));
106     chg_virtue(creature_ptr, V_CHANCE, 1);
107
108     if ((power > randint0(20)) && one_in_(3) && (creature_ptr->prace != RACE_ANDROID)) {
109         char effect_msg[80] = "";
110         player_race_type new_race;
111
112         power -= 10;
113         if ((power > randint0(5)) && one_in_(4)) {
114             power -= 2;
115             if (creature_ptr->psex == SEX_MALE) {
116                 creature_ptr->psex = SEX_FEMALE;
117                 sp_ptr = &sex_info[creature_ptr->psex];
118                 sprintf(effect_msg, _("女性の", "female "));
119             } else {
120                 creature_ptr->psex = SEX_MALE;
121                 sp_ptr = &sex_info[creature_ptr->psex];
122                 sprintf(effect_msg, _("男性の", "male "));
123             }
124         }
125
126         if ((power > randint0(30)) && one_in_(5)) {
127             int tmp = 0;
128             power -= 15;
129             while (tmp < A_MAX) {
130                 if (one_in_(2)) {
131                     (void)dec_stat(creature_ptr, tmp, randint1(6) + 6, one_in_(3));
132                     power -= 1;
133                 }
134                 tmp++;
135             }
136
137             (void)dec_stat(creature_ptr, A_CHR, randint1(6), TRUE);
138
139             if (effect_msg[0]) {
140                 char tmp_msg[10];
141                 sprintf(tmp_msg, _("%s", "%s "), effect_msg);
142                 sprintf(effect_msg, _("奇形の%s", "deformed %s "), tmp_msg);
143             } else {
144                 sprintf(effect_msg, _("奇形の", "deformed "));
145             }
146         }
147
148         while ((power > randint0(20)) && one_in_(10)) {
149             power -= 10;
150
151             if (!lose_mutation(creature_ptr, 0))
152                 msg_print(_("奇妙なくらい普通になった気がする。", "You feel oddly normal."));
153         }
154
155         do {
156             new_race = (player_race_type)randint0(MAX_RACES);
157         } while ((new_race == creature_ptr->prace) || (new_race == RACE_ANDROID));
158
159         change_race(creature_ptr, new_race, effect_msg);
160     }
161
162     if ((power > randint0(30)) && one_in_(6)) {
163         int tmp = 0;
164         power -= 20;
165         msg_format(_("%sの構成が変化した!", "Your internal organs are rearranged!"), creature_ptr->prace == RACE_ANDROID ? "機械" : "内臓");
166
167         while (tmp < A_MAX) {
168             (void)dec_stat(creature_ptr, tmp, randint1(6) + 6, one_in_(3));
169             tmp++;
170         }
171         if (one_in_(6)) {
172             msg_print(_("現在の姿で生きていくのは困難なようだ!", "You find living difficult in your present form!"));
173             take_hit(creature_ptr, DAMAGE_LOSELIFE, damroll(randint1(10), creature_ptr->lev), _("致命的な突然変異", "a lethal mutation"), -1);
174
175             power -= 10;
176         }
177     }
178
179     if ((power > randint0(20)) && one_in_(4)) {
180         power -= 10;
181
182         get_max_stats(creature_ptr);
183         roll_hitdice(creature_ptr, 0L);
184     }
185
186     while ((power > randint0(15)) && one_in_(3)) {
187         power -= 7;
188         (void)gain_mutation(creature_ptr, 0);
189     }
190
191     if (power > randint0(5)) {
192         power -= 5;
193         do_poly_wounds(creature_ptr);
194     }
195
196     while (power > 0) {
197         status_shuffle(creature_ptr);
198         power--;
199     }
200 }
201
202 /*!
203  * @brief 変身効果の継続時間と変身先をセットする / Set "tim_mimic", and "mimic_form", notice observable changes
204  * @param v 継続時間
205  * @param p 変身内容
206  * @param do_dec 現在の継続時間より長い値のみ上書きする
207  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
208  */
209 bool set_mimic(player_type *creature_ptr, TIME_EFFECT v, MIMIC_RACE_IDX p, bool do_dec)
210 {
211     bool notice = FALSE;
212     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
213
214     if (creature_ptr->is_dead)
215         return FALSE;
216
217     if (v) {
218         if (creature_ptr->tim_mimic && (creature_ptr->mimic_form == p) && !do_dec) {
219             if (creature_ptr->tim_mimic > v)
220                 return FALSE;
221         } else if ((!creature_ptr->tim_mimic) || (creature_ptr->mimic_form != p)) {
222             msg_print(_("自分の体が変わってゆくのを感じた。", "You feel that your body changes."));
223             creature_ptr->mimic_form = p;
224             notice = TRUE;
225         }
226     }
227
228     else {
229         if (creature_ptr->tim_mimic) {
230             msg_print(_("変身が解けた。", "You are no longer transformed."));
231             if (creature_ptr->mimic_form == MIMIC_DEMON)
232                 set_oppose_fire(creature_ptr, 0, TRUE);
233             creature_ptr->mimic_form = 0;
234             notice = TRUE;
235             p = 0;
236         }
237     }
238
239     creature_ptr->tim_mimic = v;
240     if (!notice)
241         return FALSE;
242
243     if (disturb_state)
244         disturb(creature_ptr, FALSE, TRUE);
245
246     creature_ptr->redraw |= (PR_BASIC | PR_STATUS);
247     creature_ptr->update |= (PU_BONUS | PU_HP);
248
249     handle_stuff(creature_ptr);
250     return TRUE;
251 }
252
253 /*!
254  * @brief 狂戦士化の継続時間をセットする / Set "shero", notice observable changes
255  * @param v 継続時間/ 0ならば無条件にリセット
256  * @param do_dec FALSEの場合現在の継続時間より長い値のみ上書きする
257  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
258  */
259 bool set_shero(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
260 {
261     bool notice = FALSE;
262     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
263
264     if (creature_ptr->is_dead)
265         return FALSE;
266
267     if (creature_ptr->pclass == CLASS_BERSERKER)
268         v = 1;
269     if (v) {
270         if (creature_ptr->shero && !do_dec) {
271             if (creature_ptr->shero > v)
272                 return FALSE;
273         } else if (!creature_ptr->shero) {
274             msg_print(_("殺戮マシーンになった気がする!", "You feel like a killing machine!"));
275             notice = TRUE;
276         }
277     } else {
278         if (creature_ptr->shero) {
279             msg_print(_("野蛮な気持ちが消え失せた。", "You feel less berserk."));
280             notice = TRUE;
281         }
282     }
283
284     creature_ptr->shero = v;
285     creature_ptr->redraw |= (PR_STATUS);
286
287     if (!notice)
288         return FALSE;
289
290     if (disturb_state)
291         disturb(creature_ptr, FALSE, FALSE);
292     creature_ptr->update |= (PU_BONUS);
293     creature_ptr->update |= (PU_HP);
294     handle_stuff(creature_ptr);
295     return TRUE;
296 }
297
298 /*!
299  * @brief 幽体化の継続時間をセットする / Set "wraith_form", notice observable changes
300  * @param v 継続時間
301  * @param do_dec 現在の継続時間より長い値のみ上書きする
302  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
303  */
304 bool set_wraith_form(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
305 {
306     bool notice = FALSE;
307     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
308
309     if (creature_ptr->is_dead)
310         return FALSE;
311
312     if (v) {
313         if (creature_ptr->wraith_form && !do_dec) {
314             if (creature_ptr->wraith_form > v)
315                 return FALSE;
316         } else if (!creature_ptr->wraith_form) {
317             msg_print(_("物質界を離れて幽鬼のような存在になった!", "You leave the physical world and turn into a wraith-being!"));
318             notice = TRUE;
319             chg_virtue(creature_ptr, V_UNLIFE, 3);
320             chg_virtue(creature_ptr, V_HONOUR, -2);
321             chg_virtue(creature_ptr, V_SACRIFICE, -2);
322             chg_virtue(creature_ptr, V_VALOUR, -5);
323
324             creature_ptr->redraw |= (PR_MAP);
325             creature_ptr->update |= (PU_MONSTERS);
326
327             creature_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
328         }
329     } else {
330         if (creature_ptr->wraith_form) {
331             msg_print(_("不透明になった感じがする。", "You feel opaque."));
332             notice = TRUE;
333
334             creature_ptr->redraw |= (PR_MAP);
335             creature_ptr->update |= (PU_MONSTERS);
336
337             creature_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
338         }
339     }
340
341     creature_ptr->wraith_form = v;
342     creature_ptr->redraw |= (PR_STATUS);
343
344     if (!notice)
345         return FALSE;
346
347     if (disturb_state)
348         disturb(creature_ptr, FALSE, FALSE);
349     creature_ptr->update |= (PU_BONUS);
350     handle_stuff(creature_ptr);
351     return TRUE;
352 }
353
354 /*!
355  * @brief オクレ兄さんの継続時間をセットする / Set "tsuyoshi", notice observable changes
356  * @param v 継続時間
357  * @param do_dec 現在の継続時間より長い値のみ上書きする
358  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
359  */
360 bool set_tsuyoshi(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
361 {
362     bool notice = FALSE;
363     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
364
365     if (creature_ptr->is_dead)
366         return FALSE;
367
368     if (v) {
369         if (creature_ptr->tsuyoshi && !do_dec) {
370             if (creature_ptr->tsuyoshi > v)
371                 return FALSE;
372         } else if (!creature_ptr->tsuyoshi) {
373             msg_print(_("「オクレ兄さん!」", "Brother OKURE!"));
374             notice = TRUE;
375             chg_virtue(creature_ptr, V_VITALITY, 2);
376         }
377     } else {
378         if (creature_ptr->tsuyoshi) {
379             msg_print(_("肉体が急速にしぼんでいった。", "Your body has quickly shriveled."));
380
381             (void)dec_stat(creature_ptr, A_CON, 20, TRUE);
382             (void)dec_stat(creature_ptr, A_STR, 20, TRUE);
383
384             notice = TRUE;
385             chg_virtue(creature_ptr, V_VITALITY, -3);
386         }
387     }
388
389     creature_ptr->tsuyoshi = v;
390     creature_ptr->redraw |= (PR_STATUS);
391
392     if (!notice)
393         return FALSE;
394
395     if (disturb_state)
396         disturb(creature_ptr, FALSE, FALSE);
397     creature_ptr->update |= (PU_BONUS);
398     creature_ptr->update |= (PU_HP);
399     handle_stuff(creature_ptr);
400     return TRUE;
401 }