OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / cmd-building / cmd-inn.cpp
1 #include "cmd-building/cmd-inn.h"
2 #include "cmd-item/cmd-magiceat.h"
3 #include "core/turn-compensator.h"
4 #include "game-option/birth-options.h"
5 #include "io/write-diary.h"
6 #include "market/bounty.h"
7 #include "market/building-actions-table.h"
8 #include "player-base/player-class.h"
9 #include "player-base/player-race.h"
10 #include "player-info/magic-eater-data-type.h"
11 #include "player-info/race-info.h"
12 #include "player-info/race-types.h"
13 #include "player/digestion-processor.h"
14 #include "player/eldritch-horror.h"
15 #include "status/bad-status-setter.h"
16 #include "store/rumor.h"
17 #include "system/player-type-definition.h"
18 #include "timed-effect/player-cut.h"
19 #include "timed-effect/player-poison.h"
20 #include "timed-effect/player-stun.h"
21 #include "timed-effect/timed-effects.h"
22 #include "view/display-messages.h"
23 #include "world/world.h"
24
25 /*!
26  * @brief 宿屋で食事を摂る
27  * @param player_ptr プレイヤーへの参照ポインタ
28  * @return 満腹ならFALSE、そうでないならTRUE
29  */
30 static bool buy_food(PlayerType *player_ptr)
31 {
32     if (player_ptr->food >= PY_FOOD_FULL) {
33         msg_print(_("今は満腹だ。", "You are full now."));
34         return false;
35     }
36
37     msg_print(_("バーテンはいくらかの食べ物とビールをくれた。", "The barkeep gives you some gruel and a beer."));
38     (void)set_food(player_ptr, PY_FOOD_MAX - 1);
39     return true;
40 }
41
42 /*!
43  * @brief 健康体しか宿屋に泊めない処理
44  * @param player_ptr プレイヤーへの参照ポインタ
45  * @return 毒でも切り傷でもないならTRUE、そうでないならFALSE
46  */
47 static bool is_healthy_stay(PlayerType *player_ptr)
48 {
49     const auto effects = player_ptr->effects();
50     if (!effects->poison()->is_poisoned() && !effects->cut()->is_cut()) {
51         return true;
52     }
53
54     msg_print(_("あなたに必要なのは部屋ではなく、治療者です。", "You need a healer, not a room."));
55     msg_print(nullptr);
56     msg_print(_("すみません、でもうちで誰かに死なれちゃ困りますんで。", "Sorry, but I don't want anyone dying in here."));
57     return false;
58 }
59
60 static bool is_player_undead(PlayerType *player_ptr)
61 {
62     return PlayerRace(player_ptr, true).life() == PlayerRaceLifeType::UNDEAD;
63 }
64
65 /*!
66  * @brief 宿屋に泊まったことを日記に残す
67  * @param player_ptr プレイヤーへの参照ポインタ
68  * @param prev_hour 宿屋に入った直後のゲーム内時刻
69  */
70 static void write_diary_stay_inn(PlayerType *player_ptr, int prev_hour)
71 {
72     if ((prev_hour >= 6) && (prev_hour < 18)) {
73         const auto stay_message = _(is_player_undead(player_ptr) ? "宿屋に泊まった。" : "日が暮れるまで宿屋で過ごした。", "stayed during the day at the inn.");
74         exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, stay_message);
75         return;
76     }
77
78     const auto stay_message = _(is_player_undead(player_ptr) ? "夜が明けるまで宿屋で過ごした。" : "宿屋に泊まった。", "stayed overnight at the inn.");
79     exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, stay_message);
80 }
81
82 /*!
83  * @brief 宿泊によってゲーム内ターンを経過させる
84  * @param なし
85  */
86 static void pass_game_turn_by_stay(void)
87 {
88     int32_t oldturn = w_ptr->game_turn;
89     w_ptr->game_turn = (w_ptr->game_turn / (TURNS_PER_TICK * TOWN_DAWN / 2) + 1) * (TURNS_PER_TICK * TOWN_DAWN / 2);
90     if (w_ptr->dungeon_turn >= w_ptr->dungeon_turn_limit) {
91         return;
92     }
93
94     constexpr auto stay_magnificant = 10;
95     w_ptr->dungeon_turn += std::min<int>((w_ptr->game_turn - oldturn), TURNS_PER_TICK * 250) * stay_magnificant;
96     if (w_ptr->dungeon_turn > w_ptr->dungeon_turn_limit) {
97         w_ptr->dungeon_turn = w_ptr->dungeon_turn_limit;
98     }
99 }
100
101 /*!
102  * @brief 悪夢モードなら悪夢を見せる
103  * @param player_ptr プレイヤーへの参照ポインタ
104  * @return 悪夢モードならばTRUE
105  */
106 static bool has_a_nightmare(PlayerType *player_ptr)
107 {
108     if (!ironman_nightmare) {
109         return false;
110     }
111
112     msg_print(_("眠りに就くと恐ろしい光景が心をよぎった。", "Horrible visions flit through your mind as you sleep."));
113
114     while (true) {
115         sanity_blast(player_ptr, nullptr, false);
116         if (!one_in_(3)) {
117             break;
118         }
119     }
120
121     msg_print(_("あなたは絶叫して目を覚ました。", "You awake screaming."));
122     exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("悪夢にうなされてよく眠れなかった。", "had a nightmare."));
123     return true;
124 }
125
126 /*!
127  * @brief 体調を元に戻す
128  * @param player_ptr プレイヤーへの参照ポインタ
129  */
130 static void back_to_health(PlayerType *player_ptr)
131 {
132     BadStatusSetter bss(player_ptr);
133     (void)bss.set_blindness(0);
134     (void)bss.set_confusion(0);
135     player_ptr->effects()->stun()->reset();
136     player_ptr->chp = player_ptr->mhp;
137     player_ptr->csp = player_ptr->msp;
138 }
139
140 /*!
141  * @brief 魔道具術師の取り込んだ魔法をすべて完全に回復した状態にする
142  * @param player_ptr プレイヤーへの参照ポインタ
143  */
144 static void charge_magic_eating_energy(PlayerType *player_ptr)
145 {
146     auto magic_eater_data = PlayerClass(player_ptr).get_specific_data<magic_eater_data_type>();
147     if (!magic_eater_data) {
148         return;
149     }
150
151     for (auto tval : { ItemKindType::STAFF, ItemKindType::WAND }) {
152         for (auto &item : magic_eater_data->get_item_group(tval)) {
153             item.charge = item.count * EATER_CHARGE;
154         }
155     }
156     for (auto &item : magic_eater_data->get_item_group(ItemKindType::ROD)) {
157         item.charge = 0;
158     }
159 }
160
161 /*!
162  * @brief リフレッシュ結果を画面に表示する
163  * @param player_ptr プレイヤーへの参照ポインタ
164  * @param prev_hour 宿屋に入った直後のゲーム内時刻
165  */
166 static void display_stay_result(PlayerType *player_ptr, int prev_hour)
167 {
168     if ((prev_hour >= 6) && (prev_hour < 18)) {
169 #if JP
170         msg_format("あなたはリフレッシュして目覚め、%sを迎えた。", is_player_undead(player_ptr) ? "夜" : "夕方");
171 #else
172         msg_format("You awake refreshed for the %s.", is_player_undead(player_ptr) ? "evening" : "twilight");
173 #endif
174         const auto awake_message = _(is_player_undead(player_ptr) ? "すがすがしい夜を迎えた。" : "夕方を迎えた。", "awoke refreshed.");
175         exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, awake_message);
176         return;
177     }
178
179     msg_print(_("あなたはリフレッシュして目覚め、新たな日を迎えた。", "You awake refreshed for the new day."));
180     const auto awake_message = _(is_player_undead(player_ptr) ? "すがすがしい朝を迎えた。" : "朝を迎えた。", "awoke refreshed.");
181     exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, awake_message);
182 }
183
184 /*!
185  * @brief 宿屋への宿泊実行処理
186  * @param player_ptr プレイヤーへの参照ポインタ
187  * @return 泊まれたらTRUE
188  */
189 static bool stay_inn(PlayerType *player_ptr)
190 {
191     if (!is_healthy_stay(player_ptr)) {
192         return false;
193     }
194
195     int prev_day, prev_hour, prev_min;
196     extract_day_hour_min(player_ptr, &prev_day, &prev_hour, &prev_min);
197     write_diary_stay_inn(player_ptr, prev_hour);
198
199     pass_game_turn_by_stay();
200     prevent_turn_overflow(player_ptr);
201
202     if ((prev_hour >= 18) && (prev_hour <= 23)) {
203         determine_daily_bounty(player_ptr, false); /* Update daily bounty */
204         exe_write_diary(player_ptr, DiaryKind::DIALY, 0);
205     }
206
207     player_ptr->chp = player_ptr->mhp;
208     if (has_a_nightmare(player_ptr)) {
209         return true;
210     }
211
212     back_to_health(player_ptr);
213     charge_magic_eating_energy(player_ptr);
214
215     display_stay_result(player_ptr, prev_hour);
216     return true;
217 }
218
219 /*!
220  * @brief 宿屋を利用する
221  * @param player_ptr プレイヤーへの参照ポインタ
222  * @param cmd 宿屋の利用施設ID
223  * @return 施設の利用が実際に行われたらTRUE
224  * @details inn commands
225  * Note that resting for the night was a perfect way to avoid player
226  * ghosts in the town *if* you could only make it to the inn in time (-:
227  * Now that the ghosts are temporarily disabled in 2.8.X, this function
228  * will not be that useful.  I will keep it in the hopes the player
229  * ghost code does become a reality again. Does help to avoid filthy urchins.
230  * Resting at night is also a quick way to restock stores -KMW-
231  * @todo 悪夢を見る前後に全回復しているが、何か意図がある?
232  */
233 bool inn_comm(PlayerType *player_ptr, int cmd)
234 {
235     switch (cmd) {
236     case BACT_FOOD:
237         return buy_food(player_ptr);
238     case BACT_REST:
239         return stay_inn(player_ptr);
240     case BACT_RUMORS:
241         display_rumor(player_ptr, true);
242         return true;
243     default:
244         //!< @todo リファクタリング前のコードもTRUEだった、FALSEにすべきでは.
245         return true;
246     }
247 }