OSDN Git Service

Merge pull request #3814 from Slimebreath6078/feature/Add_Laffey_II
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-runaway.cpp
1 /*!
2  * @brief モンスターの逃走に関する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster-floor/monster-runaway.h"
8 #include "core/disturbance.h"
9 #include "dungeon/quest-completion-checker.h"
10 #include "grid/grid.h"
11 #include "monster-floor/monster-remover.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-indice-types.h"
14 #include "monster/monster-describer.h"
15 #include "monster/monster-info.h"
16 #include "monster/monster-processor-util.h"
17 #include "pet/pet-fall-off.h"
18 #include "system/angband-system.h"
19 #include "system/floor-type-definition.h"
20 #include "system/monster-entity.h"
21 #include "system/monster-race-info.h"
22 #include "system/player-type-definition.h"
23 #include "target/projection-path-calculator.h"
24 #include "view/display-messages.h"
25
26 /*!
27  * @brief monspeak.txt において、発話ではなく行動のみが描写されているモンスターであるかを調べる
28  * @param r_idx モンスター種族ID
29  * @return 会話内容が行動のみのモンスターか否か
30  */
31 static bool is_acting_monster(const MonsterRaceId r_idx)
32 {
33     auto is_acting_monster = r_idx == MonsterRaceId::GRIP;
34     is_acting_monster |= r_idx == MonsterRaceId::WOLF;
35     is_acting_monster |= r_idx == MonsterRaceId::FANG;
36     return is_acting_monster;
37 }
38
39 /*!
40  * @brief HPが1/3未満になった友好的なユニークモンスターの逃走処理を行う
41  * @param player_ptr プレイヤーへの参照ポインタ
42  * @param is_riding_mon 騎乗状態ならばTRUE
43  * @param m_ptr モンスターへの参照ポインタ
44  * @param m_name モンスター名称
45  */
46 static void escape_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, concptr m_name)
47 {
48     if (turn_flags_ptr->is_riding_mon) {
49         msg_format(_("%sはあなたの束縛から脱出した。", "%s^ succeeded to escape from your restriction!"), m_name);
50         if (process_fall_off_horse(player_ptr, -1, false)) {
51             msg_print(_("地面に落とされた。", "You have fallen from the pet you were riding."));
52         }
53     }
54
55     if (turn_flags_ptr->see_m) {
56         static constexpr auto flags = {
57             MonsterSpeakType::SPEAK_ALL,
58             MonsterSpeakType::SPEAK_BATTLE,
59             MonsterSpeakType::SPEAK_FEAR,
60         };
61
62         auto speak = m_ptr->get_monrace().speak_flags.has_any_of(flags);
63         speak &= !is_acting_monster(m_ptr->r_idx);
64         speak &= player_ptr->current_floor_ptr->has_los({ m_ptr->fy, m_ptr->fx });
65         speak &= projectable(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x);
66         if (speak) {
67             msg_format(_("%s^「ピンチだ!退却させてもらう!」", "%s^ says 'It is the pinch! I will retreat'."), m_name);
68         }
69
70         msg_format(_("%s^がテレポート・レベルの巻物を読んだ。", "%s^ reads a scroll of teleport level."), m_name);
71         msg_format(_("%s^が消え去った。", "%s^ disappears."), m_name);
72     }
73
74     if (turn_flags_ptr->is_riding_mon && process_fall_off_horse(player_ptr, -1, false)) {
75         msg_print(_("地面に落とされた。", "You have fallen from the pet you were riding."));
76     }
77 }
78
79 /*!
80  * @brief ペットや友好的なモンスターがフロアから逃げる処理を行う
81  * @param player_ptr プレイヤーへの参照ポインタ
82  * @param m_idx モンスターID
83  * @param is_riding_mon 騎乗状態ならばTRUE
84  * @param see_m モンスターが視界内にいたらTRUE
85  * @return モンスターがフロアから消えたらTRUE
86  */
87 bool runaway_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx)
88 {
89     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
90     auto *r_ptr = &m_ptr->get_monrace();
91     bool can_runaway = m_ptr->is_pet() || m_ptr->is_friendly();
92     can_runaway &= (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL));
93     can_runaway &= !AngbandSystem::get_instance().is_phase_out();
94     if (!can_runaway) {
95         return false;
96     }
97
98     static int riding_pinch = 0;
99
100     if (m_ptr->hp >= m_ptr->maxhp / 3) {
101         /* Reset the counter */
102         if (turn_flags_ptr->is_riding_mon) {
103             riding_pinch = 0;
104         }
105
106         return false;
107     }
108
109     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
110     if (turn_flags_ptr->is_riding_mon && riding_pinch < 2) {
111         msg_format(
112             _("%sは傷の痛さの余りあなたの束縛から逃れようとしている。", "%s^ seems to be in so much pain and tries to escape from your restriction."), m_name.data());
113         riding_pinch++;
114         disturb(player_ptr, true, true);
115         return false;
116     }
117
118     escape_monster(player_ptr, turn_flags_ptr, m_ptr, m_name.data());
119     QuestCompletionChecker(player_ptr, m_ptr).complete();
120     delete_monster_idx(player_ptr, m_idx);
121     return true;
122 }