OSDN Git Service

21388f81a03c3a1dc4fd616e0ef9487fcf6722b8
[hengbandforosx/hengbandosx.git] / src / pet / pet-fall-off.cpp
1 /*!
2  * @brief 落馬処理
3  * @date 2020/05/31
4  * @author Hourier
5  */
6
7 #include "pet/pet-fall-off.h"
8 #include "core/player-redraw-types.h"
9 #include "core/player-update-types.h"
10 #include "core/stuff-handler.h"
11 #include "core/window-redrawer.h"
12 #include "floor/cave.h"
13 #include "floor/geometry.h"
14 #include "grid/grid.h"
15 #include "monster-attack/monster-attack-player.h"
16 #include "monster-race/monster-race.h"
17 #include "monster/monster-describer.h"
18 #include "pet/pet-util.h"
19 #include "player-base/player-class.h"
20 #include "player/player-damage.h"
21 #include "player/player-move.h"
22 #include "player/player-skill.h"
23 #include "system/floor-type-definition.h"
24 #include "system/grid-type-definition.h"
25 #include "system/monster-race-info.h"
26 #include "system/monster-type-definition.h"
27 #include "system/player-type-definition.h"
28 #include "system/terrain-type-definition.h"
29 #include "target/target-checker.h"
30 #include "view/display-messages.h"
31
32 /*!
33  * @brief モンスターから直接攻撃を受けた時に落馬するかどうかを判定し、判定アウトならば落馬させる
34  * @param player_ptr プレイヤーへの参照ポインタ
35  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
36  */
37 void check_fall_off_horse(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
38 {
39     if ((player_ptr->riding == 0) || (monap_ptr->damage == 0)) {
40         return;
41     }
42
43     char m_steed_name[MAX_NLEN];
44     monster_desc(player_ptr, m_steed_name, &player_ptr->current_floor_ptr->m_list[player_ptr->riding], 0);
45     if (process_fall_off_horse(player_ptr, (monap_ptr->damage > 200) ? 200 : monap_ptr->damage, false)) {
46         msg_format(_("%^sから落ちてしまった!", "You have fallen from %s."), m_steed_name);
47     }
48 }
49
50 /*!
51  * @brief 落馬する可能性を計算する
52  * @param player_ptr プレイヤーへの参照ポインタ
53  * @param dam 落馬判定を発した際に受けたダメージ量
54  * @param force TRUEならば強制的に落馬する
55  * @param 乗馬中のモンスターのレベル
56  * @return FALSEなら落馬しないことで確定、TRUEなら処理続行
57  * @details レベルの低い乗馬からは落馬しにくい
58  */
59 static bool calc_fall_off_possibility(PlayerType *player_ptr, const int dam, const bool force, MonsterRaceInfo *r_ptr)
60 {
61     if (force) {
62         return true;
63     }
64
65     auto cur = player_ptr->skill_exp[PlayerSkillKindType::RIDING];
66
67     int fall_off_level = r_ptr->level;
68     if (player_ptr->riding_ryoute) {
69         fall_off_level += 20;
70     }
71
72     PlayerSkill(player_ptr).gain_riding_skill_exp_on_fall_off_check(dam);
73
74     if (randint0(dam / 2 + fall_off_level * 2) >= cur / 30 + 10) {
75         return true;
76     }
77
78     if ((PlayerClass(player_ptr).is_tamer() && !player_ptr->riding_ryoute) || !one_in_(player_ptr->lev * (player_ptr->riding_ryoute ? 2 : 3) + 30)) {
79         return false;
80     }
81
82     return true;
83 }
84
85 /*!
86  * @brief プレイヤーの落馬判定処理
87  * @param dam 落馬判定を発した際に受けたダメージ量
88  * @param force TRUEならば強制的に落馬する
89  * @return 実際に落馬したらTRUEを返す
90  */
91 bool process_fall_off_horse(PlayerType *player_ptr, int dam, bool force)
92 {
93     POSITION sy = 0;
94     POSITION sx = 0;
95     int sn = 0;
96     GAME_TEXT m_name[MAX_NLEN];
97     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
98     auto *r_ptr = &monraces_info[m_ptr->r_idx];
99
100     if (!player_ptr->riding || player_ptr->wild_mode) {
101         return false;
102     }
103
104     if (dam >= 0 || force) {
105         if (!calc_fall_off_possibility(player_ptr, dam, force, r_ptr)) {
106             return false;
107         }
108
109         /* Check around the player */
110         for (DIRECTION i = 0; i < 8; i++) {
111             POSITION y = player_ptr->y + ddy_ddd[i];
112             POSITION x = player_ptr->x + ddx_ddd[i];
113
114             grid_type *g_ptr;
115             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
116
117             if (g_ptr->m_idx) {
118                 continue;
119             }
120
121             /* Skip non-empty grids */
122             if (!g_ptr->cave_has_flag(TerrainCharacteristics::MOVE) && !g_ptr->cave_has_flag(TerrainCharacteristics::CAN_FLY)) {
123                 if (!can_player_ride_pet(player_ptr, g_ptr, false)) {
124                     continue;
125                 }
126             }
127
128             if (g_ptr->cave_has_flag(TerrainCharacteristics::PATTERN)) {
129                 continue;
130             }
131
132             /* Count "safe" grids */
133             sn++;
134
135             /* Randomize choice */
136             if (randint0(sn) > 0) {
137                 continue;
138             }
139
140             /* Save the safe location */
141             sy = y;
142             sx = x;
143         }
144
145         if (!sn) {
146             monster_desc(player_ptr, m_name, m_ptr, 0);
147             msg_format(_("%sから振り落とされそうになって、壁にぶつかった。", "You have nearly fallen from %s but bumped into a wall."), m_name);
148             take_hit(player_ptr, DAMAGE_NOESCAPE, r_ptr->level + 3, _("壁への衝突", "bumping into a wall"));
149             return false;
150         }
151
152         POSITION old_y = player_ptr->y;
153         POSITION old_x = player_ptr->x;
154         player_ptr->y = sy;
155         player_ptr->x = sx;
156         lite_spot(player_ptr, old_y, old_x);
157         lite_spot(player_ptr, player_ptr->y, player_ptr->x);
158         verify_panel(player_ptr);
159     }
160
161     player_ptr->riding = 0;
162     player_ptr->pet_extra_flags &= ~(PF_TWO_HANDS);
163     player_ptr->riding_ryoute = player_ptr->old_riding_ryoute = false;
164
165     player_ptr->update |= (PU_BONUS | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
166     handle_stuff(player_ptr);
167
168     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
169     player_ptr->redraw |= (PR_EXTRA);
170
171     /* Update health track of mount */
172     player_ptr->redraw |= (PR_UHEALTH);
173
174     bool fall_dam = false;
175     if (player_ptr->levitation && !force) {
176         monster_desc(player_ptr, m_name, m_ptr, 0);
177         msg_format(_("%sから落ちたが、空中でうまく体勢を立て直して着地した。", "You are thrown from %s but make a good landing."), m_name);
178     } else {
179         take_hit(player_ptr, DAMAGE_NOESCAPE, r_ptr->level + 3, _("落馬", "Falling from riding"));
180         fall_dam = true;
181     }
182
183     if (sy && !player_ptr->is_dead) {
184         (void)move_player_effect(player_ptr, player_ptr->y, player_ptr->x, MPE_DONT_PICKUP | MPE_DONT_SWAP_MON);
185     }
186
187     return fall_dam;
188 }