1 #include "monster/monster-status-setter.h"
2 #include "avatar/avatar.h"
3 #include "cmd-visual/cmd-draw.h"
4 #include "core/player-redraw-types.h"
5 #include "core/player-update-types.h"
6 #include "core/speed-table.h"
7 #include "core/stuff-handler.h"
8 #include "core/window-redrawer.h"
9 #include "dungeon/quest-completion-checker.h"
10 #include "floor/cave.h"
11 #include "monster-floor/monster-move.h"
12 #include "monster-race/monster-kind-mask.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-brightness-mask.h"
15 #include "monster-race/race-flags3.h"
16 #include "monster-race/race-flags7.h"
17 #include "monster-race/race-indice-types.h"
18 #include "monster/monster-describer.h"
19 #include "monster/monster-info.h"
20 #include "monster/monster-processor.h"
21 #include "monster/monster-status.h" //!< @todo 相互依存. 後で何とかする.
22 #include "monster/monster-util.h"
23 #include "monster/smart-learn-types.h"
24 #include "system/floor-type-definition.h"
25 #include "system/monster-entity.h"
26 #include "system/monster-race-info.h"
27 #include "system/player-type-definition.h"
28 #include "target/projection-path-calculator.h"
29 #include "view/display-messages.h"
30 #include "world/world.h"
34 * @param PlayerType プレイヤーへの参照ポインタ
35 * @param m_ptr モンスター情報構造体の参照ポインタ
37 void set_pet(PlayerType *player_ptr, MonsterEntity *m_ptr)
39 QuestCompletionChecker(player_ptr, m_ptr).complete();
40 m_ptr->mflag2.set(MonsterConstantFlagType::PET);
41 if (monraces_info[m_ptr->r_idx].kind_flags.has_none_of(alignment_mask)) {
42 m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
48 * Makes the monster hostile towards the player
49 * @param m_ptr モンスター情報構造体の参照ポインタ
51 void set_hostile(PlayerType *player_ptr, MonsterEntity *m_ptr)
53 if (player_ptr->phase_out) {
57 m_ptr->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
63 * @param m_ptr モンスター情報構造体の参照ポインタ
65 void anger_monster(PlayerType *player_ptr, MonsterEntity *m_ptr)
67 if (player_ptr->phase_out || !m_ptr->is_friendly()) {
71 const auto m_name = monster_desc(player_ptr, m_ptr, 0);
72 msg_format(_("%^sは怒った!", "%^s gets angry!"), m_name.data());
73 set_hostile(player_ptr, m_ptr);
74 chg_virtue(player_ptr, V_INDIVIDUALISM, 1);
75 chg_virtue(player_ptr, V_HONOUR, -1);
76 chg_virtue(player_ptr, V_JUSTICE, -1);
77 chg_virtue(player_ptr, V_COMPASSION, -1);
81 * @brief モンスターの時限ステータスリストを削除
82 * @param floor_ptr 現在フロアへの参照ポインタ
83 * @return m_idx モンスターの参照ID
84 * @return mproc_type 削除したいモンスターの時限ステータスID
86 static void mproc_remove(FloorType *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
88 int mproc_idx = get_mproc_idx(floor_ptr, m_idx, mproc_type);
90 floor_ptr->mproc_list[mproc_type][mproc_idx] = floor_ptr->mproc_list[mproc_type][--floor_ptr->mproc_max[mproc_type]];
95 * @brief モンスターの睡眠状態値をセットする。0で起きる。 /
96 * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
97 * @param player_ptr プレイヤーへの参照ポインタ
98 * @param m_idx モンスター参照ID
100 * @return 別途更新処理が必要な場合TRUEを返す
102 bool set_monster_csleep(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
104 auto *floor_ptr = player_ptr->current_floor_ptr;
105 auto *m_ptr = &floor_ptr->m_list[m_idx];
107 v = (v > 10000) ? 10000 : (v < 0) ? 0
110 if (!m_ptr->is_asleep()) {
111 mproc_add(floor_ptr, m_idx, MTIMED_CSLEEP);
115 if (m_ptr->is_asleep()) {
116 mproc_remove(floor_ptr, m_idx, MTIMED_CSLEEP);
121 m_ptr->mtimed[MTIMED_CSLEEP] = (int16_t)v;
127 if (player_ptr->health_who == m_idx) {
128 player_ptr->redraw |= PR_HEALTH;
131 if (player_ptr->riding == m_idx) {
132 player_ptr->redraw |= PR_UHEALTH;
136 if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(has_ld_mask)) {
137 player_ptr->update |= PU_MON_LITE;
144 * @brief モンスターの加速状態値をセット /
145 * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
146 * @param player_ptr プレイヤーへの参照ポインタ
147 * @param m_idx モンスター参照ID
149 * @return 別途更新処理が必要な場合TRUEを返す
151 bool set_monster_fast(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
153 auto *floor_ptr = player_ptr->current_floor_ptr;
154 auto *m_ptr = &floor_ptr->m_list[m_idx];
156 v = (v > 200) ? 200 : (v < 0) ? 0
159 if (!m_ptr->is_accelerated()) {
160 mproc_add(floor_ptr, m_idx, MTIMED_FAST);
164 if (m_ptr->is_accelerated()) {
165 mproc_remove(floor_ptr, m_idx, MTIMED_FAST);
170 m_ptr->mtimed[MTIMED_FAST] = (int16_t)v;
175 if ((player_ptr->riding == m_idx) && !player_ptr->leaving) {
176 player_ptr->update |= PU_BONUS;
183 * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
185 bool set_monster_slow(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
187 auto *floor_ptr = player_ptr->current_floor_ptr;
188 auto *m_ptr = &floor_ptr->m_list[m_idx];
190 v = (v > 200) ? 200 : (v < 0) ? 0
193 if (!m_ptr->is_decelerated()) {
194 mproc_add(floor_ptr, m_idx, MTIMED_SLOW);
198 if (m_ptr->is_decelerated()) {
199 mproc_remove(floor_ptr, m_idx, MTIMED_SLOW);
204 m_ptr->mtimed[MTIMED_SLOW] = (int16_t)v;
209 if ((player_ptr->riding == m_idx) && !player_ptr->leaving) {
210 player_ptr->update |= PU_BONUS;
217 * @brief モンスターの朦朧状態値をセット /
218 * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
219 * @param player_ptr プレイヤーへの参照ポインタ
220 * @param m_idx モンスター参照ID
222 * @return 別途更新処理が必要な場合TRUEを返す
224 bool set_monster_stunned(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
226 auto *floor_ptr = player_ptr->current_floor_ptr;
227 auto *m_ptr = &floor_ptr->m_list[m_idx];
229 v = (v > 200) ? 200 : (v < 0) ? 0
232 if (!m_ptr->is_stunned()) {
233 mproc_add(floor_ptr, m_idx, MTIMED_STUNNED);
237 if (m_ptr->is_stunned()) {
238 mproc_remove(floor_ptr, m_idx, MTIMED_STUNNED);
243 m_ptr->mtimed[MTIMED_STUNNED] = (int16_t)v;
248 * @brief モンスターの混乱状態値をセット /
249 * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
250 * @param player_ptr プレイヤーへの参照ポインタ
251 * @param m_idx モンスター参照ID
253 * @return 別途更新処理が必要な場合TRUEを返す
255 bool set_monster_confused(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
257 auto *floor_ptr = player_ptr->current_floor_ptr;
258 auto *m_ptr = &floor_ptr->m_list[m_idx];
260 v = (v > 200) ? 200 : (v < 0) ? 0
263 if (!m_ptr->is_confused()) {
264 mproc_add(floor_ptr, m_idx, MTIMED_CONFUSED);
268 if (m_ptr->is_confused()) {
269 mproc_remove(floor_ptr, m_idx, MTIMED_CONFUSED);
274 m_ptr->mtimed[MTIMED_CONFUSED] = (int16_t)v;
279 * @brief モンスターの恐慌状態値をセット /
280 * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
281 * @param player_ptr プレイヤーへの参照ポインタ
282 * @param m_idx モンスター参照ID
284 * @return 別途更新処理が必要な場合TRUEを返す
286 bool set_monster_monfear(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
288 auto *floor_ptr = player_ptr->current_floor_ptr;
289 auto *m_ptr = &floor_ptr->m_list[m_idx];
291 v = (v > 200) ? 200 : (v < 0) ? 0
294 if (!m_ptr->is_fearful()) {
295 mproc_add(floor_ptr, m_idx, MTIMED_MONFEAR);
299 if (m_ptr->is_fearful()) {
300 mproc_remove(floor_ptr, m_idx, MTIMED_MONFEAR);
305 m_ptr->mtimed[MTIMED_MONFEAR] = (int16_t)v;
312 if (player_ptr->health_who == m_idx) {
313 player_ptr->redraw |= PR_HEALTH;
316 if (player_ptr->riding == m_idx) {
317 player_ptr->redraw |= PR_UHEALTH;
325 * @brief モンスターの無敵状態値をセット /
326 * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
327 * @param player_ptr プレイヤーへの参照ポインタ
328 * @param m_idx モンスター参照ID
330 * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
331 * @return 別途更新処理が必要な場合TRUEを返す
333 bool set_monster_invulner(PlayerType *player_ptr, MONSTER_IDX m_idx, int v, bool energy_need)
335 auto *floor_ptr = player_ptr->current_floor_ptr;
336 auto *m_ptr = &floor_ptr->m_list[m_idx];
338 v = (v > 200) ? 200 : (v < 0) ? 0
341 if (!m_ptr->is_invulnerable()) {
342 mproc_add(floor_ptr, m_idx, MTIMED_INVULNER);
346 if (m_ptr->is_invulnerable()) {
347 mproc_remove(floor_ptr, m_idx, MTIMED_INVULNER);
348 if (energy_need && !player_ptr->wild_mode) {
349 m_ptr->energy_need += ENERGY_NEED();
355 m_ptr->mtimed[MTIMED_INVULNER] = (int16_t)v;
361 if (player_ptr->health_who == m_idx) {
362 player_ptr->redraw |= PR_HEALTH;
365 if (player_ptr->riding == m_idx) {
366 player_ptr->redraw |= PR_UHEALTH;
374 * @brief モンスターの時間停止処理
375 * @param player_ptr プレイヤーへの参照ポインタ
376 * @param num 時間停止を行った敵が行動できる回数
377 * @param who 時間停止を行う敵の種族番号
378 * @param vs_player TRUEならば時間停止開始処理を行う
379 * @return 時間停止が行われている状態ならばTRUEを返す
381 bool set_monster_timewalk(PlayerType *player_ptr, int num, MonsterRaceId who, bool vs_player)
383 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[hack_m_idx];
384 if (w_ptr->timewalk_m_idx) {
389 const auto m_name = monster_desc(player_ptr, m_ptr, 0);
393 case MonsterRaceId::DIO:
394 mes = _("「『ザ・ワールド』! 時は止まった!」", "%s yells 'The World! Time has stopped!'");
396 case MonsterRaceId::WONG:
397 mes = _("「時よ!」", "%s yells 'Time!'");
399 case MonsterRaceId::DIAVOLO:
400 mes = _("『キング・クリムゾン』!", "%s yells 'King Crison!'");
407 msg_format(mes, m_name.data());
411 w_ptr->timewalk_m_idx = hack_m_idx;
413 do_cmd_redraw(player_ptr);
417 if (!m_ptr->is_valid()) {
421 process_monster(player_ptr, w_ptr->timewalk_m_idx);
423 handle_stuff(player_ptr);
425 term_xtra(TERM_XTRA_DELAY, 500);
429 player_ptr->redraw |= PR_MAP;
430 player_ptr->update |= PU_MONSTERS;
431 player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
432 w_ptr->timewalk_m_idx = 0;
433 if (vs_player || (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx) && projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx))) {
436 case MonsterRaceId::DIAVOLO:
437 mes = _("これが我が『キング・クリムゾン』の能力! 『時間を消し去って』飛び越えさせた…!!",
438 "This is the ability of my 'King Crimson'! 'Erase the time' and let it jump over... !!");
441 mes = _("「時は動きだす…」", "You feel time flowing around you once more.");
449 handle_stuff(player_ptr);