OSDN Git Service

[Refactor] #2523 PlayerType::blind をPlayerBlindnessの呼び出しに差し替えた
[hengbandforosx/hengbandosx.git] / src / core / player-processor.cpp
1 #include "core/player-processor.h"
2 #include "action/run-execution.h"
3 #include "action/travel-execution.h"
4 #include "core/disturbance.h"
5 #include "core/player-redraw-types.h"
6 #include "core/player-update-types.h"
7 #include "core/special-internal-keys.h"
8 #include "core/speed-table.h"
9 #include "core/stuff-handler.h"
10 #include "core/window-redrawer.h"
11 #include "dungeon/dungeon.h"
12 #include "floor/floor-save-util.h"
13 #include "floor/floor-util.h"
14 #include "floor/geometry.h"
15 #include "floor/wild.h"
16 #include "game-option/cheat-options.h"
17 #include "game-option/disturbance-options.h"
18 #include "game-option/map-screen-options.h"
19 #include "grid/grid.h"
20 #include "inventory/pack-overflow.h"
21 #include "io/cursor.h"
22 #include "io/input-key-acceptor.h"
23 #include "io/input-key-processor.h"
24 #include "io/input-key-requester.h"
25 #include "mind/mind-force-trainer.h"
26 #include "mind/mind-sniper.h"
27 #include "monster-floor/monster-generator.h"
28 #include "monster-floor/place-monster-types.h"
29 #include "monster-race/monster-race-hook.h"
30 #include "monster-race/monster-race.h"
31 #include "monster-race/race-flags1.h"
32 #include "monster/monster-describer.h"
33 #include "monster/monster-flag-types.h"
34 #include "monster/monster-list.h"
35 #include "monster/monster-status-setter.h"
36 #include "monster/monster-status.h"
37 #include "monster/monster-update.h"
38 #include "monster/monster-util.h"
39 #include "mutation/mutation-investor-remover.h"
40 #include "player-base/player-class.h"
41 #include "player-info/bluemage-data-type.h"
42 #include "player-info/mane-data-type.h"
43 #include "player-info/samurai-data-type.h"
44 #include "player-info/sniper-data-type.h"
45 #include "player-status/player-energy.h"
46 #include "player/attack-defense-types.h"
47 #include "player/eldritch-horror.h"
48 #include "player/player-skill.h"
49 #include "player/special-defense-types.h"
50 #include "spell-kind/spells-random.h"
51 #include "spell-realm/spells-hex.h"
52 #include "spell-realm/spells-song.h"
53 #include "status/action-setter.h"
54 #include "system/floor-type-definition.h"
55 #include "system/grid-type-definition.h"
56 #include "system/monster-race-definition.h"
57 #include "system/player-type-definition.h"
58 #include "term/screen-processor.h"
59 #include "timed-effect/player-blindness.h"
60 #include "timed-effect/player-confusion.h"
61 #include "timed-effect/player-cut.h"
62 #include "timed-effect/player-hallucination.h"
63 #include "timed-effect/player-paralysis.h"
64 #include "timed-effect/player-stun.h"
65 #include "timed-effect/timed-effects.h"
66 #include "util/bit-flags-calculator.h"
67 #include "view/display-messages.h"
68 #include "window/display-sub-windows.h"
69 #include "world/world-turn-processor.h"
70
71 bool load = true;
72 bool can_save = false;
73
74 static void process_fishing(PlayerType *player_ptr)
75 {
76     term_xtra(TERM_XTRA_DELAY, 10);
77     if (one_in_(1000)) {
78         MonsterRaceId r_idx;
79         bool success = false;
80         get_mon_num_prep(player_ptr, monster_is_fishing_target, nullptr);
81         r_idx = get_mon_num(player_ptr, 0,
82             is_in_dungeon(player_ptr) ? player_ptr->current_floor_ptr->dun_level
83                                       : wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level,
84             0);
85         msg_print(nullptr);
86         if (MonsterRace(r_idx).is_valid() && one_in_(2)) {
87             POSITION y, x;
88             y = player_ptr->y + ddy[player_ptr->fishing_dir];
89             x = player_ptr->x + ddx[player_ptr->fishing_dir];
90             if (place_monster_aux(player_ptr, 0, y, x, r_idx, PM_NO_KAGE)) {
91                 GAME_TEXT m_name[MAX_NLEN];
92                 monster_desc(player_ptr, m_name, &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[y][x].m_idx], 0);
93                 msg_format(_("%sが釣れた!", "You have a good catch!"), m_name);
94                 success = true;
95             }
96         }
97
98         if (!success) {
99             msg_print(_("餌だけ食われてしまった!くっそ~!", "Damn!  The fish stole your bait!"));
100         }
101
102         disturb(player_ptr, false, true);
103     }
104 }
105
106 bool continuous_action_running(PlayerType *player_ptr)
107 {
108     return player_ptr->running || travel.run || command_rep || (player_ptr->action == ACTION_REST) || (player_ptr->action == ACTION_FISH);
109 }
110
111 /*!
112  * @brief プレイヤーの行動処理 / Process the player
113  * @note
114  * Notice the annoying code to handle "pack overflow", which\n
115  * must come first just in case somebody manages to corrupt\n
116  * the savefiles by clever use of menu commands or something.\n
117  */
118 void process_player(PlayerType *player_ptr)
119 {
120     if (player_ptr->hack_mutation) {
121         msg_print(_("何か変わった気がする!", "You feel different!"));
122         (void)gain_mutation(player_ptr, 0);
123         player_ptr->hack_mutation = false;
124     }
125
126     if (player_ptr->invoking_midnight_curse) {
127         int count = 0;
128         activate_ty_curse(player_ptr, false, &count);
129         player_ptr->invoking_midnight_curse = false;
130     }
131
132     if (player_ptr->phase_out) {
133         for (MONSTER_IDX m_idx = 1; m_idx < player_ptr->current_floor_ptr->m_max; m_idx++) {
134             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
135             if (!monster_is_valid(m_ptr)) {
136                 continue;
137             }
138
139             m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
140             update_monster(player_ptr, m_idx, false);
141         }
142
143         WorldTurnProcessor(player_ptr).print_time();
144     } else if (!(load && player_ptr->energy_need <= 0)) {
145         player_ptr->energy_need -= speed_to_energy(player_ptr->pspeed);
146     }
147
148     if (player_ptr->energy_need > 0) {
149         return;
150     }
151     if (!command_rep) {
152         WorldTurnProcessor(player_ptr).print_time();
153     }
154
155     if (fresh_once && (continuous_action_running(player_ptr) || !command_rep)) {
156         stop_term_fresh();
157     }
158
159     if (player_ptr->resting < 0) {
160         if (player_ptr->resting == COMMAND_ARG_REST_FULL_HEALING) {
161             if ((player_ptr->chp == player_ptr->mhp) && (player_ptr->csp >= player_ptr->msp)) {
162                 set_action(player_ptr, ACTION_NONE);
163             }
164         } else if (player_ptr->resting == COMMAND_ARG_REST_UNTIL_DONE) {
165             if (player_ptr->is_fully_healthy()) {
166                 set_action(player_ptr, ACTION_NONE);
167             }
168         }
169     }
170
171     if (player_ptr->action == ACTION_FISH) {
172         process_fishing(player_ptr);
173     }
174
175     if (check_abort) {
176         if (continuous_action_running(player_ptr)) {
177             inkey_scan = true;
178             if (inkey()) {
179                 flush();
180                 disturb(player_ptr, false, true);
181                 msg_print(_("中断しました。", "Canceled."));
182             }
183         }
184     }
185
186     const auto effects = player_ptr->effects();
187     if (player_ptr->riding && !effects->confusion()->is_confused() && !effects->blindness()->is_blind()) {
188         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
189         auto *r_ptr = &r_info[m_ptr->r_idx];
190         if (monster_csleep_remaining(m_ptr)) {
191             GAME_TEXT m_name[MAX_NLEN];
192             (void)set_monster_csleep(player_ptr, player_ptr->riding, 0);
193             monster_desc(player_ptr, m_name, m_ptr, 0);
194             msg_format(_("%^sを起こした。", "You have woken %s up."), m_name);
195         }
196
197         if (monster_stunned_remaining(m_ptr)) {
198             if (set_monster_stunned(player_ptr, player_ptr->riding,
199                     (randint0(r_ptr->level) < player_ptr->skill_exp[PlayerSkillKindType::RIDING]) ? 0 : (monster_stunned_remaining(m_ptr) - 1))) {
200                 GAME_TEXT m_name[MAX_NLEN];
201                 monster_desc(player_ptr, m_name, m_ptr, 0);
202                 msg_format(_("%^sを朦朧状態から立ち直らせた。", "%^s is no longer stunned."), m_name);
203             }
204         }
205
206         if (monster_confused_remaining(m_ptr)) {
207             if (set_monster_confused(player_ptr, player_ptr->riding,
208                     (randint0(r_ptr->level) < player_ptr->skill_exp[PlayerSkillKindType::RIDING]) ? 0 : (monster_confused_remaining(m_ptr) - 1))) {
209                 GAME_TEXT m_name[MAX_NLEN];
210                 monster_desc(player_ptr, m_name, m_ptr, 0);
211                 msg_format(_("%^sを混乱状態から立ち直らせた。", "%^s is no longer confused."), m_name);
212             }
213         }
214
215         if (monster_fear_remaining(m_ptr)) {
216             if (set_monster_monfear(player_ptr, player_ptr->riding,
217                     (randint0(r_ptr->level) < player_ptr->skill_exp[PlayerSkillKindType::RIDING]) ? 0 : (monster_fear_remaining(m_ptr) - 1))) {
218                 GAME_TEXT m_name[MAX_NLEN];
219                 monster_desc(player_ptr, m_name, m_ptr, 0);
220                 msg_format(_("%^sを恐怖から立ち直らせた。", "%^s is no longer fearful."), m_name);
221             }
222         }
223
224         handle_stuff(player_ptr);
225     }
226
227     load = false;
228     if (player_ptr->lightspeed) {
229         set_lightspeed(player_ptr, player_ptr->lightspeed - 1, true);
230     }
231
232     if (PlayerClass(player_ptr).equals(PlayerClassType::FORCETRAINER) && get_current_ki(player_ptr)) {
233         if (get_current_ki(player_ptr) < 40) {
234             set_current_ki(player_ptr, true, 0);
235         } else {
236             set_current_ki(player_ptr, false, -40);
237         }
238         player_ptr->update |= (PU_BONUS);
239     }
240
241     if (player_ptr->action == ACTION_LEARN) {
242         int32_t cost = 0L;
243         uint32_t cost_frac = (player_ptr->msp + 30L) * 256L;
244         s64b_lshift(&cost, &cost_frac, 16);
245         if (s64b_cmp(player_ptr->csp, player_ptr->csp_frac, cost, cost_frac) < 0) {
246             player_ptr->csp = 0;
247             player_ptr->csp_frac = 0;
248             set_action(player_ptr, ACTION_NONE);
249         } else {
250             s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), cost, cost_frac);
251         }
252
253         player_ptr->redraw |= PR_MANA;
254     }
255
256     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) {
257         if (player_ptr->csp < 3) {
258             set_action(player_ptr, ACTION_NONE);
259         } else {
260             player_ptr->csp -= 2;
261             player_ptr->redraw |= (PR_MANA);
262         }
263     }
264
265     /*** Handle actual user input ***/
266     while (player_ptr->energy_need <= 0) {
267         player_ptr->window_flags |= PW_PLAYER;
268         player_ptr->sutemi = false;
269         player_ptr->counter = false;
270         player_ptr->now_damaged = false;
271
272         update_monsters(player_ptr, false);
273         handle_stuff(player_ptr);
274         move_cursor_relative(player_ptr->y, player_ptr->x);
275         if (fresh_before) {
276             term_fresh_force();
277         }
278
279         pack_overflow(player_ptr);
280         if (!command_new) {
281             command_see = false;
282         }
283
284         PlayerEnergy energy(player_ptr);
285         energy.reset_player_turn();
286         auto is_knocked_out = effects->stun()->is_knocked_out();
287         auto is_paralyzed = effects->paralysis()->is_paralyzed();
288         if (player_ptr->phase_out) {
289             move_cursor_relative(player_ptr->y, player_ptr->x);
290             command_cmd = SPECIAL_KEY_BUILDING;
291             process_command(player_ptr);
292         } else if ((is_paralyzed || is_knocked_out) && !cheat_immortal) {
293             energy.set_player_turn_energy(100);
294         } else if (player_ptr->action == ACTION_REST) {
295             if (player_ptr->resting > 0) {
296                 player_ptr->resting--;
297                 if (!player_ptr->resting) {
298                     set_action(player_ptr, ACTION_NONE);
299                 }
300                 player_ptr->redraw |= (PR_STATE);
301             }
302
303             energy.set_player_turn_energy(100);
304         } else if (player_ptr->action == ACTION_FISH) {
305             energy.set_player_turn_energy(100);
306         } else if (player_ptr->running) {
307             run_step(player_ptr, 0);
308         } else if (travel.run) {
309             travel_step(player_ptr);
310         } else if (command_rep) {
311             command_rep--;
312             player_ptr->redraw |= (PR_STATE);
313             handle_stuff(player_ptr);
314             msg_flag = false;
315             prt("", 0, 0);
316             process_command(player_ptr);
317         } else {
318             move_cursor_relative(player_ptr->y, player_ptr->x);
319
320             player_ptr->window_flags |= PW_MONSTER_LIST;
321             window_stuff(player_ptr);
322
323             can_save = true;
324             InputKeyRequestor(player_ptr, false).request_command();
325             can_save = false;
326             process_command(player_ptr);
327         }
328
329         pack_overflow(player_ptr);
330         if (player_ptr->energy_use) {
331             if (player_ptr->timewalk || player_ptr->energy_use > 400) {
332                 player_ptr->energy_need += player_ptr->energy_use * TURNS_PER_TICK / 10;
333             } else {
334                 player_ptr->energy_need += (int16_t)((int32_t)player_ptr->energy_use * ENERGY_NEED() / 100L);
335             }
336
337             if (effects->hallucination()->is_hallucinated()) {
338                 player_ptr->redraw |= (PR_MAP);
339             }
340
341             for (MONSTER_IDX m_idx = 1; m_idx < player_ptr->current_floor_ptr->m_max; m_idx++) {
342                 monster_type *m_ptr;
343                 monster_race *r_ptr;
344                 m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
345                 if (!monster_is_valid(m_ptr)) {
346                     continue;
347                 }
348
349                 r_ptr = &r_info[m_ptr->ap_r_idx];
350
351                 // モンスターのシンボル/カラーの更新
352                 if (m_ptr->ml && r_ptr->visual_flags.has_any_of({ MonsterVisualType::MULTI_COLOR, MonsterVisualType::SHAPECHANGER })) {
353                     lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
354                 }
355
356                 // 出現して即魔法を使わないようにするフラグを落とす処理
357                 if (m_ptr->mflag.has(MonsterTemporaryFlagType::PREVENT_MAGIC)) {
358                     m_ptr->mflag.reset(MonsterTemporaryFlagType::PREVENT_MAGIC);
359                 }
360
361                 if (m_ptr->mflag.has(MonsterTemporaryFlagType::SANITY_BLAST)) {
362                     m_ptr->mflag.reset(MonsterTemporaryFlagType::SANITY_BLAST);
363                     sanity_blast(player_ptr, m_ptr, false);
364                 }
365
366                 // 感知中のモンスターのフラグを落とす処理
367                 // 感知したターンはMFLAG2_SHOWを落とし、次のターンに感知中フラグのMFLAG2_MARKを落とす
368                 if (m_ptr->mflag2.has(MonsterConstantFlagType::MARK)) {
369                     if (m_ptr->mflag2.has(MonsterConstantFlagType::SHOW)) {
370                         m_ptr->mflag2.reset(MonsterConstantFlagType::SHOW);
371                     } else {
372                         m_ptr->mflag2.reset(MonsterConstantFlagType::MARK);
373                         m_ptr->ml = false;
374                         update_monster(player_ptr, m_idx, false);
375                         if (player_ptr->health_who == m_idx) {
376                             player_ptr->redraw |= (PR_HEALTH);
377                         }
378                         if (player_ptr->riding == m_idx) {
379                             player_ptr->redraw |= (PR_UHEALTH);
380                         }
381
382                         lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
383                     }
384                 }
385             }
386
387             if (PlayerClass(player_ptr).equals(PlayerClassType::IMITATOR)) {
388                 auto mane_data = PlayerClass(player_ptr).get_specific_data<mane_data_type>();
389                 if (static_cast<int>(mane_data->mane_list.size()) > (player_ptr->lev > 44 ? 3 : player_ptr->lev > 29 ? 2
390                                                                                                                      : 1)) {
391                     mane_data->mane_list.pop_front();
392                 }
393
394                 mane_data->new_mane = false;
395                 player_ptr->redraw |= (PR_IMITATION);
396             }
397
398             if (player_ptr->action == ACTION_LEARN) {
399                 auto mane_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
400                 mane_data->new_magic_learned = false;
401                 player_ptr->redraw |= (PR_STATE);
402             }
403
404             if (player_ptr->timewalk && (player_ptr->energy_need > -1000)) {
405                 player_ptr->redraw |= (PR_MAP);
406                 player_ptr->update |= (PU_MONSTERS);
407                 player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
408
409                 msg_print(_("「時は動きだす…」", "You feel time flowing around you once more."));
410                 msg_print(nullptr);
411                 player_ptr->timewalk = false;
412                 player_ptr->energy_need = ENERGY_NEED();
413
414                 handle_stuff(player_ptr);
415             }
416         }
417
418         if (!player_ptr->playing || player_ptr->is_dead) {
419             player_ptr->timewalk = false;
420             break;
421         }
422
423         auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
424         if (player_ptr->energy_use && sniper_data && sniper_data->reset_concent) {
425             reset_concentration(player_ptr, true);
426         }
427
428         if (player_ptr->leaving) {
429             break;
430         }
431     }
432
433     update_smell(player_ptr->current_floor_ptr, player_ptr);
434 }
435
436 /*!
437  * @brief プレイヤーの行動エネルギーが充填される(=プレイヤーのターンが回る)毎に行われる処理  / process the effects per 100 energy at player speed.
438  */
439 void process_upkeep_with_speed(PlayerType *player_ptr)
440 {
441     if (!load && player_ptr->enchant_energy_need > 0 && !player_ptr->leaving) {
442         player_ptr->enchant_energy_need -= speed_to_energy(player_ptr->pspeed);
443     }
444
445     if (player_ptr->enchant_energy_need > 0) {
446         return;
447     }
448
449     while (player_ptr->enchant_energy_need <= 0) {
450         if (!load) {
451             check_music(player_ptr);
452         }
453
454         SpellHex spell_hex(player_ptr);
455         if (!load) {
456             spell_hex.decrease_mana();
457         }
458
459         if (!load) {
460             spell_hex.continue_revenge();
461         }
462
463         player_ptr->enchant_energy_need += ENERGY_NEED();
464     }
465 }