OSDN Git Service

80c604b88d8415e5d77910cde3e1453e48a8aa07
[hengbandforosx/hengbandosx.git] / src / status / shape-changer.cpp
1 #include "status/shape-changer.h"
2 #include "autopick/autopick-reader-writer.h"
3 #include "avatar/avatar.h"
4 #include "birth/birth-body-spec.h"
5 #include "birth/birth-stat.h"
6 #include "core/disturbance.h"
7 #include "core/player-redraw-types.h"
8 #include "core/stuff-handler.h"
9 #include "game-option/disturbance-options.h"
10 #include "grid/grid.h"
11 #include "hpmp/hp-mp-processor.h"
12 #include "locale/english.h"
13 #include "mutation/mutation-investor-remover.h"
14 #include "player-base/player-class.h"
15 #include "player-base/player-race.h"
16 #include "player-info/class-info.h"
17 #include "player/player-damage.h"
18 #include "player/player-personality.h"
19 #include "player/player-sex.h"
20 #include "player/player-status.h"
21 #include "player/race-info-table.h"
22 #include "spell/spells-status.h"
23 #include "status/bad-status-setter.h"
24 #include "status/base-status.h"
25 #include "system/player-type-definition.h"
26 #include "system/redrawing-flags-updater.h"
27 #include "timed-effect/player-cut.h"
28 #include "timed-effect/timed-effects.h"
29 #include "util/enum-converter.h"
30 #include "view/display-messages.h"
31
32 void do_poly_wounds(PlayerType *player_ptr)
33 {
34     int16_t hit_p = (player_ptr->mhp - player_ptr->chp);
35     int16_t change = damroll(player_ptr->lev, 5);
36     auto nasty_effect = one_in_(5);
37     auto player_cut = player_ptr->effects()->cut();
38     if (!player_cut->is_cut() && (hit_p == 0) && !nasty_effect) {
39         return;
40     }
41
42     msg_print(_("傷がより軽いものに変化した。", "Your wounds are polymorphed into less serious ones."));
43     hp_player(player_ptr, change);
44     BadStatusSetter bss(player_ptr);
45     if (!nasty_effect) {
46         (void)bss.mod_cut(change / 2);
47         return;
48     }
49
50     msg_print(_("新たな傷ができた!", "A new wound was created!"));
51     take_hit(player_ptr, DAMAGE_LOSELIFE, change / 2, _("変化した傷", "a polymorphed wound"));
52     (void)bss.set_cut(change);
53 }
54
55 /*
56  * Change player race
57  */
58 void change_race(PlayerType *player_ptr, PlayerRaceType new_race, concptr effect_msg)
59 {
60     concptr title = race_info[enum2i(new_race)].title;
61     PlayerRaceType old_race = player_ptr->prace;
62 #ifdef JP
63     msg_format("あなたは%s%sに変化した!", effect_msg, title);
64 #else
65     msg_format("You turn into %s %s%s!", (is_a_vowel((effect_msg[0]) ? effect_msg[0] : title[0]) ? "an" : "a"), effect_msg, title);
66 #endif
67
68     chg_virtue(player_ptr, Virtue::CHANCE, 2);
69     if (enum2i(player_ptr->prace) < 32) {
70         player_ptr->old_race1 |= 1UL << enum2i(player_ptr->prace);
71     } else {
72         player_ptr->old_race2 |= 1UL << (enum2i(player_ptr->prace) - 32);
73     }
74
75     player_ptr->prace = new_race;
76     rp_ptr = &race_info[enum2i(player_ptr->prace)];
77     player_ptr->expfact = rp_ptr->r_exp + cp_ptr->c_exp;
78
79     PlayerClass pc(player_ptr);
80     bool is_special_class = pc.equals(PlayerClassType::MONK);
81     is_special_class |= pc.equals(PlayerClassType::FORCETRAINER);
82     is_special_class |= pc.equals(PlayerClassType::NINJA);
83     PlayerRace pr(player_ptr);
84     bool is_special_race = pr.equals(PlayerRaceType::KLACKON);
85     is_special_race |= pr.equals(PlayerRaceType::SPRITE);
86     if (is_special_class && is_special_race) {
87         player_ptr->expfact -= 15;
88     }
89
90     get_height_weight(player_ptr);
91
92     if (pc.equals(PlayerClassType::SORCERER)) {
93         player_ptr->hitdie = rp_ptr->r_mhp / 2 + cp_ptr->c_mhp + ap_ptr->a_mhp;
94     } else {
95         player_ptr->hitdie = rp_ptr->r_mhp + cp_ptr->c_mhp + ap_ptr->a_mhp;
96     }
97
98     roll_hitdice(player_ptr, SPOP_NONE);
99     check_experience(player_ptr);
100     auto &rfu = RedrawingFlagsUpdater::get_instance();
101     rfu.set_flag(MainWindowRedrawingFlag::BASIC);
102     rfu.set_flag(StatusRedrawingFlag::BONUS);
103     handle_stuff(player_ptr);
104
105     if (old_race != player_ptr->prace) {
106         autopick_load_pref(player_ptr, false);
107     }
108
109     lite_spot(player_ptr, player_ptr->y, player_ptr->x);
110 }
111
112 void do_poly_self(PlayerType *player_ptr)
113 {
114     int power = player_ptr->lev;
115
116     msg_print(_("あなたは変化の訪れを感じた...", "You feel a change coming over you..."));
117     chg_virtue(player_ptr, Virtue::CHANCE, 1);
118
119     PlayerRace pr(player_ptr);
120     if ((power > randint0(20)) && one_in_(3) && !pr.equals(PlayerRaceType::ANDROID)) {
121         std::string effect_msg;
122         std::string_view sex_msg;
123         PlayerRaceType new_race;
124
125         power -= 10;
126         if ((power > randint0(5)) && one_in_(4)) {
127             power -= 2;
128             if (player_ptr->psex == SEX_MALE) {
129                 player_ptr->psex = SEX_FEMALE;
130                 sp_ptr = &sex_info[player_ptr->psex];
131                 sex_msg = _("女性の", "female");
132             } else {
133                 player_ptr->psex = SEX_MALE;
134                 sp_ptr = &sex_info[player_ptr->psex];
135                 sex_msg = _("男性の", "male");
136             }
137         }
138
139         if ((power > randint0(30)) && one_in_(5)) {
140             int tmp = 0;
141             power -= 15;
142             while (tmp < A_MAX) {
143                 if (one_in_(2)) {
144                     (void)dec_stat(player_ptr, tmp, randint1(6) + 6, one_in_(3));
145                     power -= 1;
146                 }
147                 tmp++;
148             }
149
150             (void)dec_stat(player_ptr, A_CHR, randint1(6), true);
151
152             effect_msg = _("奇形の", "deformed ");
153             if (!sex_msg.empty()) {
154                 effect_msg.append(sex_msg).append(_("", " "));
155             }
156         }
157
158         while ((power > randint0(20)) && one_in_(10)) {
159             power -= 10;
160
161             if (!lose_mutation(player_ptr, 0)) {
162                 msg_print(_("奇妙なくらい普通になった気がする。", "You feel oddly normal."));
163             }
164         }
165
166         do {
167             new_race = (PlayerRaceType)randint0(MAX_RACES);
168         } while (pr.equals(new_race) || (new_race == PlayerRaceType::ANDROID));
169
170         change_race(player_ptr, new_race, effect_msg.data());
171     }
172
173     if ((power > randint0(30)) && one_in_(6)) {
174         int tmp = 0;
175         power -= 20;
176         msg_print(_(format("%sの構成が変化した!", pr.equals(PlayerRaceType::ANDROID) ? "機械" : "内臓"), "Your internal organs are rearranged!"));
177
178         while (tmp < A_MAX) {
179             (void)dec_stat(player_ptr, tmp, randint1(6) + 6, one_in_(3));
180             tmp++;
181         }
182         if (one_in_(6)) {
183             msg_print(_("現在の姿で生きていくのは困難なようだ!", "You find living difficult in your present form!"));
184             take_hit(player_ptr, DAMAGE_LOSELIFE, damroll(randint1(10), player_ptr->lev), _("致命的な突然変異", "a lethal mutation"));
185
186             power -= 10;
187         }
188     }
189
190     if ((power > randint0(20)) && one_in_(4)) {
191         power -= 10;
192
193         get_max_stats(player_ptr);
194         roll_hitdice(player_ptr, SPOP_NONE);
195     }
196
197     while ((power > randint0(15)) && one_in_(3)) {
198         power -= 7;
199         (void)gain_mutation(player_ptr, 0);
200     }
201
202     if (power > randint0(5)) {
203         power -= 5;
204         do_poly_wounds(player_ptr);
205     }
206
207     while (power > 0) {
208         status_shuffle(player_ptr);
209         power--;
210     }
211 }