OSDN Git Service

48abdf7d1d06f2634db1a1621fc5aff19c7eb8bb
[hengbandforosx/hengbandosx.git] / src / monster / monster-status-setter.cpp
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"
29
30 /*!
31  * @brief モンスターをペットにする
32  * @param PlayerType プレイヤーへの参照ポインタ
33  * @param m_ptr モンスター情報構造体の参照ポインタ
34  */
35 void set_pet(PlayerType *player_ptr, monster_type *m_ptr)
36 {
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;
41 }
42
43 /*!
44  * @brief モンスターを敵に回す
45  * Makes the monster hostile towards the player
46  * @param m_ptr モンスター情報構造体の参照ポインタ
47  */
48 void set_hostile(PlayerType *player_ptr, monster_type *m_ptr)
49 {
50     if (player_ptr->phase_out)
51         return;
52
53     m_ptr->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
54 }
55
56 /*!
57  * @brief モンスターを怒らせる
58  * Anger the monster
59  * @param m_ptr モンスター情報構造体の参照ポインタ
60  */
61 void anger_monster(PlayerType *player_ptr, monster_type *m_ptr)
62 {
63     if (player_ptr->phase_out || !is_friendly(m_ptr))
64         return;
65
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);
74 }
75
76 /*!
77  * @brief モンスターの時限ステータスリストを削除
78  * @param floor_ptr 現在フロアへの参照ポインタ
79  * @return m_idx モンスターの参照ID
80  * @return mproc_type 削除したいモンスターの時限ステータスID
81  */
82 static void mproc_remove(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
83 {
84     int mproc_idx = get_mproc_idx(floor_ptr, m_idx, mproc_type);
85     if (mproc_idx >= 0)
86         floor_ptr->mproc_list[mproc_type][mproc_idx] = floor_ptr->mproc_list[mproc_type][--floor_ptr->mproc_max[mproc_type]];
87 }
88
89 /*!
90  * @brief モンスターの睡眠状態値をセットする。0で起きる。 /
91  * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
92  * @param player_ptr プレイヤーへの参照ポインタ
93  * @param m_idx モンスター参照ID
94  * @param v セットする値
95  * @return 別途更新処理が必要な場合TRUEを返す
96  */
97 bool set_monster_csleep(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
98 {
99     auto *floor_ptr = player_ptr->current_floor_ptr;
100     auto *m_ptr = &floor_ptr->m_list[m_idx];
101     bool notice = false;
102     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
103     if (v) {
104         if (!monster_csleep_remaining(m_ptr)) {
105             mproc_add(floor_ptr, m_idx, MTIMED_CSLEEP);
106             notice = true;
107         }
108     } else {
109         if (monster_csleep_remaining(m_ptr)) {
110             mproc_remove(floor_ptr, m_idx, MTIMED_CSLEEP);
111             notice = true;
112         }
113     }
114
115     m_ptr->mtimed[MTIMED_CSLEEP] = (int16_t)v;
116     if (!notice)
117         return false;
118
119     if (m_ptr->ml) {
120         if (player_ptr->health_who == m_idx)
121             player_ptr->redraw |= PR_HEALTH;
122
123         if (player_ptr->riding == m_idx)
124             player_ptr->redraw |= PR_UHEALTH;
125     }
126
127     if (r_info[m_ptr->r_idx].flags7 & RF7_HAS_LD_MASK)
128         player_ptr->update |= PU_MON_LITE;
129
130     return true;
131 }
132
133 /*!
134  * @brief モンスターの加速状態値をセット /
135  * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
136  * @param player_ptr プレイヤーへの参照ポインタ
137  * @param m_idx モンスター参照ID
138  * @param v セットする値
139  * @return 別途更新処理が必要な場合TRUEを返す
140  */
141 bool set_monster_fast(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
142 {
143     auto *floor_ptr = player_ptr->current_floor_ptr;
144     auto *m_ptr = &floor_ptr->m_list[m_idx];
145     bool notice = false;
146     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
147     if (v) {
148         if (!monster_fast_remaining(m_ptr)) {
149             mproc_add(floor_ptr, m_idx, MTIMED_FAST);
150             notice = true;
151         }
152     } else {
153         if (monster_fast_remaining(m_ptr)) {
154             mproc_remove(floor_ptr, m_idx, MTIMED_FAST);
155             notice = true;
156         }
157     }
158
159     m_ptr->mtimed[MTIMED_FAST] = (int16_t)v;
160     if (!notice)
161         return false;
162
163     if ((player_ptr->riding == m_idx) && !player_ptr->leaving)
164         player_ptr->update |= PU_BONUS;
165
166     return true;
167 }
168
169 /*
170  * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
171  */
172 bool set_monster_slow(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
173 {
174     auto *floor_ptr = player_ptr->current_floor_ptr;
175     auto *m_ptr = &floor_ptr->m_list[m_idx];
176     bool notice = false;
177     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
178     if (v) {
179         if (!monster_slow_remaining(m_ptr)) {
180             mproc_add(floor_ptr, m_idx, MTIMED_SLOW);
181             notice = true;
182         }
183     } else {
184         if (monster_slow_remaining(m_ptr)) {
185             mproc_remove(floor_ptr, m_idx, MTIMED_SLOW);
186             notice = true;
187         }
188     }
189
190     m_ptr->mtimed[MTIMED_SLOW] = (int16_t)v;
191     if (!notice)
192         return false;
193
194     if ((player_ptr->riding == m_idx) && !player_ptr->leaving)
195         player_ptr->update |= PU_BONUS;
196
197     return true;
198 }
199
200 /*!
201  * @brief モンスターの朦朧状態値をセット /
202  * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
203  * @param player_ptr プレイヤーへの参照ポインタ
204  * @param m_idx モンスター参照ID
205  * @param v セットする値
206  * @return 別途更新処理が必要な場合TRUEを返す
207  */
208 bool set_monster_stunned(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
209 {
210     auto *floor_ptr = player_ptr->current_floor_ptr;
211     auto *m_ptr = &floor_ptr->m_list[m_idx];
212     bool notice = false;
213     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
214     if (v) {
215         if (!monster_stunned_remaining(m_ptr)) {
216             mproc_add(floor_ptr, m_idx, MTIMED_STUNNED);
217             notice = true;
218         }
219     } else {
220         if (monster_stunned_remaining(m_ptr)) {
221             mproc_remove(floor_ptr, m_idx, MTIMED_STUNNED);
222             notice = true;
223         }
224     }
225
226     m_ptr->mtimed[MTIMED_STUNNED] = (int16_t)v;
227     return notice;
228 }
229
230 /*!
231  * @brief モンスターの混乱状態値をセット /
232  * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
233  * @param player_ptr プレイヤーへの参照ポインタ
234  * @param m_idx モンスター参照ID
235  * @param v セットする値
236  * @return 別途更新処理が必要な場合TRUEを返す
237  */
238 bool set_monster_confused(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
239 {
240     auto *floor_ptr = player_ptr->current_floor_ptr;
241     auto *m_ptr = &floor_ptr->m_list[m_idx];
242     bool notice = false;
243     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
244     if (v) {
245         if (!monster_confused_remaining(m_ptr)) {
246             mproc_add(floor_ptr, m_idx, MTIMED_CONFUSED);
247             notice = true;
248         }
249     } else {
250         if (monster_confused_remaining(m_ptr)) {
251             mproc_remove(floor_ptr, m_idx, MTIMED_CONFUSED);
252             notice = true;
253         }
254     }
255
256     m_ptr->mtimed[MTIMED_CONFUSED] = (int16_t)v;
257     return notice;
258 }
259
260 /*!
261  * @brief モンスターの恐慌状態値をセット /
262  * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
263  * @param player_ptr プレイヤーへの参照ポインタ
264  * @param m_idx モンスター参照ID
265  * @param v セットする値
266  * @return 別途更新処理が必要な場合TRUEを返す
267  */
268 bool set_monster_monfear(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
269 {
270     auto *floor_ptr = player_ptr->current_floor_ptr;
271     auto *m_ptr = &floor_ptr->m_list[m_idx];
272     bool notice = false;
273     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
274     if (v) {
275         if (!monster_fear_remaining(m_ptr)) {
276             mproc_add(floor_ptr, m_idx, MTIMED_MONFEAR);
277             notice = true;
278         }
279     } else {
280         if (monster_fear_remaining(m_ptr)) {
281             mproc_remove(floor_ptr, m_idx, MTIMED_MONFEAR);
282             notice = true;
283         }
284     }
285
286     m_ptr->mtimed[MTIMED_MONFEAR] = (int16_t)v;
287
288     if (!notice)
289         return false;
290
291     if (m_ptr->ml) {
292         if (player_ptr->health_who == m_idx)
293             player_ptr->redraw |= PR_HEALTH;
294
295         if (player_ptr->riding == m_idx)
296             player_ptr->redraw |= PR_UHEALTH;
297     }
298
299     return true;
300 }
301
302 /*!
303  * @brief モンスターの無敵状態値をセット /
304  * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
305  * @param player_ptr プレイヤーへの参照ポインタ
306  * @param m_idx モンスター参照ID
307  * @param v セットする値
308  * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
309  * @return 別途更新処理が必要な場合TRUEを返す
310  */
311 bool set_monster_invulner(PlayerType *player_ptr, MONSTER_IDX m_idx, int v, bool energy_need)
312 {
313     auto *floor_ptr = player_ptr->current_floor_ptr;
314     auto *m_ptr = &floor_ptr->m_list[m_idx];
315     bool notice = false;
316     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
317     if (v) {
318         if (!monster_invulner_remaining(m_ptr)) {
319             mproc_add(floor_ptr, m_idx, MTIMED_INVULNER);
320             notice = true;
321         }
322     } else {
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();
327             notice = true;
328         }
329     }
330
331     m_ptr->mtimed[MTIMED_INVULNER] = (int16_t)v;
332     if (!notice)
333         return false;
334
335     if (m_ptr->ml) {
336         if (player_ptr->health_who == m_idx)
337             player_ptr->redraw |= PR_HEALTH;
338
339         if (player_ptr->riding == m_idx)
340             player_ptr->redraw |= PR_UHEALTH;
341     }
342
343     return true;
344 }
345
346 /*!
347  * @brief モンスターの時間停止処理
348  * @param player_ptr プレイヤーへの参照ポインタ
349  * @param num 時間停止を行った敵が行動できる回数
350  * @param who 時間停止を行う敵の種族番号
351  * @param vs_player TRUEならば時間停止開始処理を行う
352  * @return 時間停止が行われている状態ならばTRUEを返す
353  */
354 bool set_monster_timewalk(PlayerType *player_ptr, int num, MONRACE_IDX who, bool vs_player)
355 {
356     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[hack_m_idx];
357     if (w_ptr->timewalk_m_idx)
358         return false;
359
360     if (vs_player) {
361         GAME_TEXT m_name[MAX_NLEN];
362         monster_desc(player_ptr, m_name, m_ptr, 0);
363
364         concptr mes;
365         switch (who) {
366         case MON_DIO:
367             mes = _("「『ザ・ワールド』! 時は止まった!」", "%s yells 'The World! Time has stopped!'");
368             break;
369         case MON_WONG:
370             mes = _("「時よ!」", "%s yells 'Time!'");
371             break;
372         case MON_DIAVOLO:
373             mes = _("『キング・クリムゾン』!", "%s yells 'King Crison!'");
374             break;
375         default:
376             mes = "hek!";
377             break;
378         }
379
380         msg_format(mes, m_name);
381         msg_print(nullptr);
382     }
383
384     w_ptr->timewalk_m_idx = hack_m_idx;
385     if (vs_player)
386         do_cmd_redraw(player_ptr);
387
388     while (num--) {
389         if (!monster_is_valid(m_ptr))
390             break;
391
392         process_monster(player_ptr, w_ptr->timewalk_m_idx);
393         reset_target(m_ptr);
394         handle_stuff(player_ptr);
395         if (vs_player)
396             term_xtra(TERM_XTRA_DELAY, 500);
397     }
398
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))) {
404         concptr mes;
405         switch (who) {
406         case MON_DIAVOLO:
407             mes = _("これが我が『キング・クリムゾン』の能力! 『時間を消し去って』飛び越えさせた…!!",
408                 "This is the ability of my 'King Crimson'! 'Erase the time' and let it jump over... !!");
409             break;
410         default:
411             mes = _("「時は動きだす…」", "You feel time flowing around you once more.");
412             break;
413         }
414
415         msg_print(mes);
416         msg_print(nullptr);
417     }
418
419     handle_stuff(player_ptr);
420     return true;
421 }