OSDN Git Service

[Implement] ウサウサストライカー召喚処理を追加
[hengbandforosx/hengbandosx.git] / src / system / monster-entity.cpp
1 #include "system/monster-entity.h"
2 #include "game-option/birth-options.h"
3 #include "monster-race/monster-race.h"
4 #include "monster-race/race-indice-types.h"
5 #include "monster-race/race-kind-flags.h"
6 #include "monster/monster-status.h"
7 #include "system/angband-system.h"
8 #include "system/monster-race-info.h"
9 #include "term/term-color-types.h"
10 #include "util/bit-flags-calculator.h"
11 #include "util/string-processor.h"
12 #include <algorithm>
13
14 /*!
15  * @brief モンスターの属性に基づいた敵対関係の有無を返す
16  * @param sub_align1 モンスター1のサブフラグ
17  * @param sub_align2 モンスター2のサブフラグ
18  * @return 敵対関係にあるか否か
19  */
20 bool MonsterEntity::check_sub_alignments(const byte sub_align1, const byte sub_align2)
21 {
22     if (sub_align1 == sub_align2) {
23         return false;
24     }
25
26     auto this_evil = any_bits(sub_align1, SUB_ALIGN_EVIL);
27     this_evil &= any_bits(sub_align2, SUB_ALIGN_GOOD);
28     if (this_evil) {
29         return true;
30     }
31
32     auto this_good = any_bits(sub_align1, SUB_ALIGN_GOOD);
33     this_good &= any_bits(sub_align2, SUB_ALIGN_EVIL);
34     return this_good;
35 }
36
37 bool MonsterEntity::is_friendly() const
38 {
39     return this->mflag2.has(MonsterConstantFlagType::FRIENDLY);
40 }
41
42 bool MonsterEntity::is_pet() const
43 {
44     return this->mflag2.has(MonsterConstantFlagType::PET);
45 }
46
47 bool MonsterEntity::is_hostile() const
48 {
49     return !this->is_friendly() && !this->is_pet();
50 }
51
52 /*!
53  * @brief モンスターの属性の基づいた敵対関係の有無を返す
54  * @param other 比較対象モンスターへの参照
55  * @return 敵対関係にあるか否か
56  */
57 bool MonsterEntity::is_hostile_to_melee(const MonsterEntity &other) const
58 {
59     if (AngbandSystem::get_instance().is_phase_out()) {
60         return !this->is_pet() && !other.is_pet();
61     }
62
63     const auto &monrace1 = monraces_info[this->r_idx];
64     const auto &monrace2 = monraces_info[other.r_idx];
65     const auto is_m1_wild = monrace1.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
66     const auto is_m2_wild = monrace2.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
67     if (is_m1_wild && is_m2_wild) {
68         if (!this->is_pet() && !other.is_pet()) {
69             return false;
70         }
71     }
72
73     if (this->is_hostile_align(other.sub_align)) {
74         if (this->mflag2.has_not(MonsterConstantFlagType::CHAMELEON) || other.mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
75             return true;
76         }
77     }
78
79     return this->is_hostile() != other.is_hostile();
80 }
81
82 /*!
83  * @brief モンスターの属性の基づいた敵対関係の有無を返す
84  * @param other 比較対象のサブフラグ
85  * @return 敵対関係にあるか否か
86  */
87 bool MonsterEntity::is_hostile_align(const byte other_sub_align) const
88 {
89     return MonsterEntity::check_sub_alignments(this->sub_align, other_sub_align);
90 }
91
92 bool MonsterEntity::is_named() const
93 {
94     return !this->nickname.empty();
95 }
96
97 bool MonsterEntity::is_named_pet() const
98 {
99     return this->is_pet() && this->is_named();
100 }
101
102 bool MonsterEntity::is_original_ap() const
103 {
104     return this->ap_r_idx == this->r_idx;
105 }
106
107 /*!
108  * @brief モンスターがアイテム類に擬態しているかどうかを返す
109  * @param m_ptr モンスターの参照ポインタ
110  * @return モンスターがアイテム類に擬態しているならTRUE、そうでなければFALSE
111  * @details
112  * ユニークミミックは常時擬態状態
113  * 一般モンスターもビハインダーだけ特別扱い
114  * その他増やしたい時はis_special_mimic に「|=」で追加すること
115  *
116  */
117 bool MonsterEntity::is_mimicry() const
118 {
119     auto is_special_mimic = this->ap_r_idx == MonsterRaceId::BEHINDER;
120     if (is_special_mimic) {
121         return true;
122     }
123
124     const auto &r_ref = this->get_appearance_monrace();
125     const auto mimic_symbols = "/|\\()[]=$,.!?&`#%<>+~";
126     if (angband_strchr(mimic_symbols, r_ref.d_char) == nullptr) {
127         return false;
128     }
129
130     if (r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
131         return true;
132     }
133
134     return r_ref.behavior_flags.has(MonsterBehaviorType::NEVER_MOVE) || this->is_asleep();
135 }
136
137 bool MonsterEntity::is_valid() const
138 {
139     return MonsterRace(this->r_idx).is_valid();
140 }
141
142 MonsterRaceId MonsterEntity::get_real_monrace_id() const
143 {
144     const auto &monrace = this->get_monrace();
145     if (this->mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
146         return this->r_idx;
147     }
148
149     return monrace.kind_flags.has(MonsterKindType::UNIQUE) ? MonsterRaceId::CHAMELEON_K : MonsterRaceId::CHAMELEON;
150 }
151
152 /*!
153  * @brief モンスターの真の種族定義を返す (CHAMAELEONフラグ専用)
154  * @return 真のモンスター種族参照
155  */
156 MonsterRaceInfo &MonsterEntity::get_real_monrace() const
157 {
158     return monraces_info[this->get_real_monrace_id()];
159 }
160
161 MonsterRaceInfo &MonsterEntity::get_appearance_monrace() const
162 {
163     return monraces_info[this->ap_r_idx];
164 }
165
166 MonsterRaceInfo &MonsterEntity::get_monrace() const
167 {
168     return monraces_info[this->r_idx];
169 }
170
171 short MonsterEntity::get_remaining_sleep() const
172 {
173     return this->mtimed[MTIMED_CSLEEP];
174 }
175
176 bool MonsterEntity::is_dead() const
177 {
178     return this->hp < 0;
179 }
180
181 bool MonsterEntity::is_asleep() const
182 {
183     return this->get_remaining_sleep() > 0;
184 }
185
186 short MonsterEntity::get_remaining_acceleration() const
187 {
188     return this->mtimed[MTIMED_FAST];
189 }
190
191 bool MonsterEntity::is_accelerated() const
192 {
193     return this->get_remaining_acceleration() > 0;
194 }
195
196 short MonsterEntity::get_remaining_deceleration() const
197 {
198     return this->mtimed[MTIMED_SLOW];
199 }
200
201 bool MonsterEntity::is_decelerated() const
202 {
203     return this->get_remaining_deceleration() > 0;
204 }
205
206 short MonsterEntity::get_remaining_stun() const
207 {
208     return this->mtimed[MTIMED_STUNNED];
209 }
210
211 bool MonsterEntity::is_stunned() const
212 {
213     return this->get_remaining_stun() > 0;
214 }
215
216 short MonsterEntity::get_remaining_confusion() const
217 {
218     return this->mtimed[MTIMED_CONFUSED];
219 }
220
221 bool MonsterEntity::is_confused() const
222 {
223     return this->get_remaining_confusion() > 0;
224 }
225
226 short MonsterEntity::get_remaining_fear() const
227 {
228     return this->mtimed[MTIMED_MONFEAR];
229 }
230
231 bool MonsterEntity::is_fearful() const
232 {
233     return this->get_remaining_fear() > 0;
234 }
235
236 short MonsterEntity::get_remaining_invulnerability() const
237 {
238     return this->mtimed[MTIMED_INVULNER];
239 }
240
241 bool MonsterEntity::is_invulnerable() const
242 {
243     return this->get_remaining_invulnerability() > 0;
244 }
245
246 /*
247  * @brief 悪夢モード、一時加速、一時減速に基づくモンスターの現在速度を返す
248  */
249 byte MonsterEntity::get_temporary_speed() const
250 {
251     auto speed = this->mspeed;
252     if (ironman_nightmare) {
253         speed += 5;
254     }
255
256     if (this->is_accelerated()) {
257         speed += 10;
258     }
259
260     if (this->is_decelerated()) {
261         speed -= 10;
262     }
263
264     return speed;
265 }
266
267 /*!
268  * @brief モンスターが生命体かどうかを返す
269  * @param is_apperance たぬき、カメレオン、各種誤認ならtrue
270  * @return 生命体ならばtrue
271  * @todo kind_flags をMonsterEntityへコピーする (将来的なモンスター仕様の拡張)
272  */
273 bool MonsterEntity::has_living_flag(bool is_apperance) const
274 {
275     const auto &monrace = is_apperance ? this->get_appearance_monrace() : this->get_monrace();
276     return monrace.has_living_flag();
277 }
278
279 bool MonsterEntity::is_explodable() const
280 {
281     const auto &monrace = this->get_monrace();
282     return monrace.is_explodable();
283 }
284
285 std::string MonsterEntity::get_died_message() const
286 {
287     const auto &monrace = this->get_monrace();
288     return monrace.get_died_message();
289 }
290
291 /*!
292  * @brief モンスターの状態(無敵、起きているか、HPの割合)に応じてHPバーの色と長さを算出する
293  * @return HPバーの色と長さ(1-10)のペア
294  */
295 std::pair<TERM_COLOR, int> MonsterEntity::get_hp_bar_data() const
296 {
297     const auto percent = (this->maxhp > 0) ? (100 * this->hp / this->maxhp) : 0;
298     const auto len = std::clamp(percent / 10 + 1, 1, 10);
299
300     if (this->is_invulnerable()) {
301         return { TERM_WHITE, len };
302     }
303     if (this->is_asleep()) {
304         return { TERM_BLUE, len };
305     }
306     if (percent >= 100) {
307         return { TERM_L_GREEN, len };
308     }
309     if (percent >= 60) {
310         return { TERM_YELLOW, len };
311     }
312     if (percent >= 25) {
313         return { TERM_ORANGE, len };
314     }
315     if (percent >= 10) {
316         return { TERM_L_RED, len };
317     }
318     return { TERM_RED, len };
319 }
320
321 /*!
322  * @brief モンスターを敵に回す
323  */
324 void MonsterEntity::set_hostile()
325 {
326     if (AngbandSystem::get_instance().is_phase_out()) {
327         return;
328     }
329
330     this->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
331 }
332
333 std::string MonsterEntity::get_pronoun_of_summoned_kin() const
334 {
335     return this->get_monrace().get_pronoun_of_summoned_kin();
336 }