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-race.h"
13 #include "monster-race/race-flags3.h"
14 #include "monster-race/race-flags7.h"
15 #include "monster-race/race-indice-types.h"
16 #include "monster/monster-describer.h"
17 #include "monster/monster-info.h"
18 #include "monster/monster-processor.h"
19 #include "monster/monster-status.h" //!< @todo 相互依存. 後で何とかする.
20 #include "monster/monster-util.h"
21 #include "monster/smart-learn-types.h"
22 #include "system/floor-type-definition.h"
23 #include "system/monster-race-definition.h"
24 #include "system/monster-type-definition.h"
25 #include "system/player-type-definition.h"
26 #include "target/projection-path-calculator.h"
27 #include "view/display-messages.h"
28 #include "world/world.h"
32 * @param PlayerType プレイヤーへの参照ポインタ
33 * @param m_ptr モンスター情報構造体の参照ポインタ
35 void set_pet(PlayerType *player_ptr, monster_type *m_ptr)
37 QuestCompletionChecker(player_ptr, m_ptr).complete();
38 m_ptr->mflag2.set(MonsterConstantFlagType::PET);
39 if (!(r_info[m_ptr->r_idx].flags3 & (RF3_EVIL | RF3_GOOD)))
40 m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
45 * Makes the monster hostile towards the player
46 * @param m_ptr モンスター情報構造体の参照ポインタ
48 void set_hostile(PlayerType *player_ptr, monster_type *m_ptr)
50 if (player_ptr->phase_out)
53 m_ptr->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
59 * @param m_ptr モンスター情報構造体の参照ポインタ
61 void anger_monster(PlayerType *player_ptr, monster_type *m_ptr)
63 if (player_ptr->phase_out || !is_friendly(m_ptr))
66 GAME_TEXT m_name[MAX_NLEN];
67 monster_desc(player_ptr, m_name, m_ptr, 0);
68 msg_format(_("%^sは怒った!", "%^s gets angry!"), m_name);
69 set_hostile(player_ptr, m_ptr);
70 chg_virtue(player_ptr, V_INDIVIDUALISM, 1);
71 chg_virtue(player_ptr, V_HONOUR, -1);
72 chg_virtue(player_ptr, V_JUSTICE, -1);
73 chg_virtue(player_ptr, V_COMPASSION, -1);
77 * @brief モンスターの時限ステータスリストを削除
78 * @param floor_ptr 現在フロアへの参照ポインタ
79 * @return m_idx モンスターの参照ID
80 * @return mproc_type 削除したいモンスターの時限ステータスID
82 static void mproc_remove(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
84 int mproc_idx = get_mproc_idx(floor_ptr, m_idx, mproc_type);
86 floor_ptr->mproc_list[mproc_type][mproc_idx] = floor_ptr->mproc_list[mproc_type][--floor_ptr->mproc_max[mproc_type]];
90 * @brief モンスターの睡眠状態値をセットする。0で起きる。 /
91 * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
92 * @param player_ptr プレイヤーへの参照ポインタ
93 * @param m_idx モンスター参照ID
95 * @return 別途更新処理が必要な場合TRUEを返す
97 bool set_monster_csleep(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
99 auto *floor_ptr = player_ptr->current_floor_ptr;
100 auto *m_ptr = &floor_ptr->m_list[m_idx];
102 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
104 if (!monster_csleep_remaining(m_ptr)) {
105 mproc_add(floor_ptr, m_idx, MTIMED_CSLEEP);
109 if (monster_csleep_remaining(m_ptr)) {
110 mproc_remove(floor_ptr, m_idx, MTIMED_CSLEEP);
115 m_ptr->mtimed[MTIMED_CSLEEP] = (int16_t)v;
120 if (player_ptr->health_who == m_idx)
121 player_ptr->redraw |= PR_HEALTH;
123 if (player_ptr->riding == m_idx)
124 player_ptr->redraw |= PR_UHEALTH;
127 if (r_info[m_ptr->r_idx].flags7 & RF7_HAS_LD_MASK)
128 player_ptr->update |= PU_MON_LITE;
134 * @brief モンスターの加速状態値をセット /
135 * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
136 * @param player_ptr プレイヤーへの参照ポインタ
137 * @param m_idx モンスター参照ID
139 * @return 別途更新処理が必要な場合TRUEを返す
141 bool set_monster_fast(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
143 auto *floor_ptr = player_ptr->current_floor_ptr;
144 auto *m_ptr = &floor_ptr->m_list[m_idx];
146 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
148 if (!monster_fast_remaining(m_ptr)) {
149 mproc_add(floor_ptr, m_idx, MTIMED_FAST);
153 if (monster_fast_remaining(m_ptr)) {
154 mproc_remove(floor_ptr, m_idx, MTIMED_FAST);
159 m_ptr->mtimed[MTIMED_FAST] = (int16_t)v;
163 if ((player_ptr->riding == m_idx) && !player_ptr->leaving)
164 player_ptr->update |= PU_BONUS;
170 * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
172 bool set_monster_slow(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
174 auto *floor_ptr = player_ptr->current_floor_ptr;
175 auto *m_ptr = &floor_ptr->m_list[m_idx];
177 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
179 if (!monster_slow_remaining(m_ptr)) {
180 mproc_add(floor_ptr, m_idx, MTIMED_SLOW);
184 if (monster_slow_remaining(m_ptr)) {
185 mproc_remove(floor_ptr, m_idx, MTIMED_SLOW);
190 m_ptr->mtimed[MTIMED_SLOW] = (int16_t)v;
194 if ((player_ptr->riding == m_idx) && !player_ptr->leaving)
195 player_ptr->update |= PU_BONUS;
201 * @brief モンスターの朦朧状態値をセット /
202 * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
203 * @param player_ptr プレイヤーへの参照ポインタ
204 * @param m_idx モンスター参照ID
206 * @return 別途更新処理が必要な場合TRUEを返す
208 bool set_monster_stunned(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
210 auto *floor_ptr = player_ptr->current_floor_ptr;
211 auto *m_ptr = &floor_ptr->m_list[m_idx];
213 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
215 if (!monster_stunned_remaining(m_ptr)) {
216 mproc_add(floor_ptr, m_idx, MTIMED_STUNNED);
220 if (monster_stunned_remaining(m_ptr)) {
221 mproc_remove(floor_ptr, m_idx, MTIMED_STUNNED);
226 m_ptr->mtimed[MTIMED_STUNNED] = (int16_t)v;
231 * @brief モンスターの混乱状態値をセット /
232 * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
233 * @param player_ptr プレイヤーへの参照ポインタ
234 * @param m_idx モンスター参照ID
236 * @return 別途更新処理が必要な場合TRUEを返す
238 bool set_monster_confused(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
240 auto *floor_ptr = player_ptr->current_floor_ptr;
241 auto *m_ptr = &floor_ptr->m_list[m_idx];
243 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
245 if (!monster_confused_remaining(m_ptr)) {
246 mproc_add(floor_ptr, m_idx, MTIMED_CONFUSED);
250 if (monster_confused_remaining(m_ptr)) {
251 mproc_remove(floor_ptr, m_idx, MTIMED_CONFUSED);
256 m_ptr->mtimed[MTIMED_CONFUSED] = (int16_t)v;
261 * @brief モンスターの恐慌状態値をセット /
262 * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
263 * @param player_ptr プレイヤーへの参照ポインタ
264 * @param m_idx モンスター参照ID
266 * @return 別途更新処理が必要な場合TRUEを返す
268 bool set_monster_monfear(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
270 auto *floor_ptr = player_ptr->current_floor_ptr;
271 auto *m_ptr = &floor_ptr->m_list[m_idx];
273 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
275 if (!monster_fear_remaining(m_ptr)) {
276 mproc_add(floor_ptr, m_idx, MTIMED_MONFEAR);
280 if (monster_fear_remaining(m_ptr)) {
281 mproc_remove(floor_ptr, m_idx, MTIMED_MONFEAR);
286 m_ptr->mtimed[MTIMED_MONFEAR] = (int16_t)v;
292 if (player_ptr->health_who == m_idx)
293 player_ptr->redraw |= PR_HEALTH;
295 if (player_ptr->riding == m_idx)
296 player_ptr->redraw |= PR_UHEALTH;
303 * @brief モンスターの無敵状態値をセット /
304 * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
305 * @param player_ptr プレイヤーへの参照ポインタ
306 * @param m_idx モンスター参照ID
308 * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
309 * @return 別途更新処理が必要な場合TRUEを返す
311 bool set_monster_invulner(PlayerType *player_ptr, MONSTER_IDX m_idx, int v, bool energy_need)
313 auto *floor_ptr = player_ptr->current_floor_ptr;
314 auto *m_ptr = &floor_ptr->m_list[m_idx];
316 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
318 if (!monster_invulner_remaining(m_ptr)) {
319 mproc_add(floor_ptr, m_idx, MTIMED_INVULNER);
323 if (monster_invulner_remaining(m_ptr)) {
324 mproc_remove(floor_ptr, m_idx, MTIMED_INVULNER);
325 if (energy_need && !player_ptr->wild_mode)
326 m_ptr->energy_need += ENERGY_NEED();
331 m_ptr->mtimed[MTIMED_INVULNER] = (int16_t)v;
336 if (player_ptr->health_who == m_idx)
337 player_ptr->redraw |= PR_HEALTH;
339 if (player_ptr->riding == m_idx)
340 player_ptr->redraw |= PR_UHEALTH;
347 * @brief モンスターの時間停止処理
348 * @param player_ptr プレイヤーへの参照ポインタ
349 * @param num 時間停止を行った敵が行動できる回数
350 * @param who 時間停止を行う敵の種族番号
351 * @param vs_player TRUEならば時間停止開始処理を行う
352 * @return 時間停止が行われている状態ならばTRUEを返す
354 bool set_monster_timewalk(PlayerType *player_ptr, int num, MONRACE_IDX who, bool vs_player)
356 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[hack_m_idx];
357 if (w_ptr->timewalk_m_idx)
361 GAME_TEXT m_name[MAX_NLEN];
362 monster_desc(player_ptr, m_name, m_ptr, 0);
367 mes = _("「『ザ・ワールド』! 時は止まった!」", "%s yells 'The World! Time has stopped!'");
370 mes = _("「時よ!」", "%s yells 'Time!'");
373 mes = _("『キング・クリムゾン』!", "%s yells 'King Crison!'");
380 msg_format(mes, m_name);
384 w_ptr->timewalk_m_idx = hack_m_idx;
386 do_cmd_redraw(player_ptr);
389 if (!monster_is_valid(m_ptr))
392 process_monster(player_ptr, w_ptr->timewalk_m_idx);
394 handle_stuff(player_ptr);
396 term_xtra(TERM_XTRA_DELAY, 500);
399 player_ptr->redraw |= PR_MAP;
400 player_ptr->update |= PU_MONSTERS;
401 player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
402 w_ptr->timewalk_m_idx = 0;
403 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))) {
407 mes = _("これが我が『キング・クリムゾン』の能力! 『時間を消し去って』飛び越えさせた…!!",
408 "This is the ability of my 'King Crimson'! 'Erase the time' and let it jump over... !!");
411 mes = _("「時は動きだす…」", "You feel time flowing around you once more.");
419 handle_stuff(player_ptr);