OSDN Git Service

[Fix] 対邪悪結界で打撃を撃退した際は落馬/変わり身処理を行わない
[hengbandforosx/hengbandosx.git] / src / monster / monster-status-setter.c
1 #include "monster/monster-status-setter.h"
2 #include "cmd-visual/cmd-draw.h"
3 #include "core/player-update-types.h"
4 #include "core/player-redraw-types.h"
5 #include "core/speed-table.h"
6 #include "core/stuff-handler.h"
7 #include "core/window-redrawer.h"
8 #include "dungeon/quest-completion-checker.h"
9 #include "floor/cave.h"
10 #include "monster-floor/monster-move.h"
11 #include "monster-race/monster-race.h"
12 #include "monster-race/race-flags3.h"
13 #include "monster-race/race-flags7.h"
14 #include "monster/monster-describer.h"
15 #include "monster/monster-info.h"
16 #include "monster/monster-processor.h"
17 #include "monster/monster-status.h" // todo 相互依存. 後で何とかする.
18 #include "monster/monster-util.h"
19 #include "monster/smart-learn-types.h"
20 #include "player-info/avatar.h"
21 #include "system/floor-type-definition.h"
22 #include "system/monster-type-definition.h"
23 #include "target/projection-path-calculator.h"
24 #include "view/display-messages.h"
25 #include "world/world.h"
26
27 /*!
28  * @brief モンスターをペットにする
29  * @param player_type プレーヤーへの参照ポインタ
30  * @param m_ptr モンスター情報構造体の参照ポインタ
31  * @return なし
32  */
33 void set_pet(player_type *player_ptr, monster_type *m_ptr)
34 {
35     check_quest_completion(player_ptr, m_ptr);
36     m_ptr->smart |= SM_PET;
37     if (!(r_info[m_ptr->r_idx].flags3 & (RF3_EVIL | RF3_GOOD)))
38         m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
39 }
40
41 /*!
42  * @brief モンスターを敵に回す
43  * Makes the monster hostile towards the player
44  * @param m_ptr モンスター情報構造体の参照ポインタ
45  * @return なし
46  */
47 void set_hostile(player_type *player_ptr, monster_type *m_ptr)
48 {
49     if (player_ptr->phase_out)
50         return;
51
52     m_ptr->smart &= ~SM_PET;
53     m_ptr->smart &= ~SM_FRIENDLY;
54 }
55
56 /*!
57  * @brief モンスターを怒らせる
58  * Anger the monster
59  * @param m_ptr モンスター情報構造体の参照ポインタ
60  * @return なし
61  */
62 void anger_monster(player_type *player_ptr, monster_type *m_ptr)
63 {
64     if (player_ptr->phase_out || !is_friendly(m_ptr))
65         return;
66
67     GAME_TEXT m_name[MAX_NLEN];
68     monster_desc(player_ptr, m_name, m_ptr, 0);
69     msg_format(_("%^sは怒った!", "%^s gets angry!"), m_name);
70     set_hostile(player_ptr, m_ptr);
71     chg_virtue(player_ptr, V_INDIVIDUALISM, 1);
72     chg_virtue(player_ptr, V_HONOUR, -1);
73     chg_virtue(player_ptr, V_JUSTICE, -1);
74     chg_virtue(player_ptr, V_COMPASSION, -1);
75 }
76
77 /*!
78  * @brief モンスターの時限ステータスリストを削除
79  * @param floor_ptr 現在フロアへの参照ポインタ
80  * @return m_idx モンスターの参照ID
81  * @return mproc_type 削除したいモンスターの時限ステータスID
82  * @return なし
83  */
84 static void mproc_remove(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
85 {
86     int mproc_idx = get_mproc_idx(floor_ptr, m_idx, mproc_type);
87     if (mproc_idx >= 0)
88         floor_ptr->mproc_list[mproc_type][mproc_idx] = floor_ptr->mproc_list[mproc_type][--floor_ptr->mproc_max[mproc_type]];
89 }
90
91 /*!
92  * @brief モンスターの睡眠状態値をセットする。0で起きる。 /
93  * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
94  * @param target_ptr プレーヤーへの参照ポインタ
95  * @param m_idx モンスター参照ID
96  * @param v セットする値
97  * @return 別途更新処理が必要な場合TRUEを返す
98  */
99 bool set_monster_csleep(player_type *target_ptr, MONSTER_IDX m_idx, int v)
100 {
101     floor_type *floor_ptr = target_ptr->current_floor_ptr;
102     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
103     bool notice = FALSE;
104     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
105     if (v) {
106         if (!monster_csleep_remaining(m_ptr)) {
107             mproc_add(floor_ptr, m_idx, MTIMED_CSLEEP);
108             notice = TRUE;
109         }
110     } else {
111         if (monster_csleep_remaining(m_ptr)) {
112             mproc_remove(floor_ptr, m_idx, MTIMED_CSLEEP);
113             notice = TRUE;
114         }
115     }
116
117     m_ptr->mtimed[MTIMED_CSLEEP] = (s16b)v;
118     if (!notice)
119         return FALSE;
120
121     if (m_ptr->ml) {
122         if (target_ptr->health_who == m_idx)
123             target_ptr->redraw |= PR_HEALTH;
124
125         if (target_ptr->riding == m_idx)
126             target_ptr->redraw |= PR_UHEALTH;
127     }
128
129     if (r_info[m_ptr->r_idx].flags7 & RF7_HAS_LD_MASK)
130         target_ptr->update |= PU_MON_LITE;
131
132     return TRUE;
133 }
134
135 /*!
136  * @brief モンスターの加速状態値をセット /
137  * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
138  * @param target_ptr プレーヤーへの参照ポインタ
139  * @param m_idx モンスター参照ID
140  * @param v セットする値
141  * @return 別途更新処理が必要な場合TRUEを返す
142  */
143 bool set_monster_fast(player_type *target_ptr, MONSTER_IDX m_idx, int v)
144 {
145     floor_type *floor_ptr = target_ptr->current_floor_ptr;
146     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
147     bool notice = FALSE;
148     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
149     if (v) {
150         if (!monster_fast_remaining(m_ptr)) {
151             mproc_add(floor_ptr, m_idx, MTIMED_FAST);
152             notice = TRUE;
153         }
154     } else {
155         if (monster_fast_remaining(m_ptr)) {
156             mproc_remove(floor_ptr, m_idx, MTIMED_FAST);
157             notice = TRUE;
158         }
159     }
160
161     m_ptr->mtimed[MTIMED_FAST] = (s16b)v;
162     if (!notice)
163         return FALSE;
164
165     if ((target_ptr->riding == m_idx) && !target_ptr->leaving)
166         target_ptr->update |= PU_BONUS;
167
168     return TRUE;
169 }
170
171 /*
172  * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
173  */
174 bool set_monster_slow(player_type *target_ptr, MONSTER_IDX m_idx, int v)
175 {
176     floor_type *floor_ptr = target_ptr->current_floor_ptr;
177     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
178     bool notice = FALSE;
179     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
180     if (v) {
181         if (!monster_slow_remaining(m_ptr)) {
182             mproc_add(floor_ptr, m_idx, MTIMED_SLOW);
183             notice = TRUE;
184         }
185     } else {
186         if (monster_slow_remaining(m_ptr)) {
187             mproc_remove(floor_ptr, m_idx, MTIMED_SLOW);
188             notice = TRUE;
189         }
190     }
191
192     m_ptr->mtimed[MTIMED_SLOW] = (s16b)v;
193     if (!notice)
194         return FALSE;
195
196     if ((target_ptr->riding == m_idx) && !target_ptr->leaving)
197         target_ptr->update |= PU_BONUS;
198
199     return TRUE;
200 }
201
202 /*!
203  * @brief モンスターの朦朧状態値をセット /
204  * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
205  * @param target_ptr プレーヤーへの参照ポインタ
206  * @param m_idx モンスター参照ID
207  * @param v セットする値
208  * @return 別途更新処理が必要な場合TRUEを返す
209  */
210 bool set_monster_stunned(player_type *target_ptr, MONSTER_IDX m_idx, int v)
211 {
212     floor_type *floor_ptr = target_ptr->current_floor_ptr;
213     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
214     bool notice = FALSE;
215     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
216     if (v) {
217         if (!monster_stunned_remaining(m_ptr)) {
218             mproc_add(floor_ptr, m_idx, MTIMED_STUNNED);
219             notice = TRUE;
220         }
221     } else {
222         if (monster_stunned_remaining(m_ptr)) {
223             mproc_remove(floor_ptr, m_idx, MTIMED_STUNNED);
224             notice = TRUE;
225         }
226     }
227
228     m_ptr->mtimed[MTIMED_STUNNED] = (s16b)v;
229     return notice;
230 }
231
232 /*!
233  * @brief モンスターの混乱状態値をセット /
234  * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
235  * @param target_ptr プレーヤーへの参照ポインタ
236  * @param m_idx モンスター参照ID
237  * @param v セットする値
238  * @return 別途更新処理が必要な場合TRUEを返す
239  */
240 bool set_monster_confused(player_type *target_ptr, MONSTER_IDX m_idx, int v)
241 {
242     floor_type *floor_ptr = target_ptr->current_floor_ptr;
243     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
244     bool notice = FALSE;
245     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
246     if (v) {
247         if (!monster_confused_remaining(m_ptr)) {
248             mproc_add(floor_ptr, m_idx, MTIMED_CONFUSED);
249             notice = TRUE;
250         }
251     } else {
252         if (monster_confused_remaining(m_ptr)) {
253             mproc_remove(floor_ptr, m_idx, MTIMED_CONFUSED);
254             notice = TRUE;
255         }
256     }
257
258     m_ptr->mtimed[MTIMED_CONFUSED] = (s16b)v;
259     return notice;
260 }
261
262 /*!
263  * @brief モンスターの恐慌状態値をセット /
264  * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
265  * @param target_ptr プレーヤーへの参照ポインタ
266  * @param m_idx モンスター参照ID
267  * @param v セットする値
268  * @return 別途更新処理が必要な場合TRUEを返す
269  */
270 bool set_monster_monfear(player_type *target_ptr, MONSTER_IDX m_idx, int v)
271 {
272     floor_type *floor_ptr = target_ptr->current_floor_ptr;
273     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
274     bool notice = FALSE;
275     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
276     if (v) {
277         if (!monster_fear_remaining(m_ptr)) {
278             mproc_add(floor_ptr, m_idx, MTIMED_MONFEAR);
279             notice = TRUE;
280         }
281     } else {
282         if (monster_fear_remaining(m_ptr)) {
283             mproc_remove(floor_ptr, m_idx, MTIMED_MONFEAR);
284             notice = TRUE;
285         }
286     }
287
288     m_ptr->mtimed[MTIMED_MONFEAR] = (s16b)v;
289
290     if (!notice)
291         return FALSE;
292
293     if (m_ptr->ml) {
294         if (target_ptr->health_who == m_idx)
295             target_ptr->redraw |= PR_HEALTH;
296
297         if (target_ptr->riding == m_idx)
298             target_ptr->redraw |= PR_UHEALTH;
299     }
300
301     return TRUE;
302 }
303
304 /*!
305  * @brief モンスターの無敵状態値をセット /
306  * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
307  * @param target_ptr プレーヤーへの参照ポインタ
308  * @param m_idx モンスター参照ID
309  * @param v セットする値
310  * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
311  * @return 別途更新処理が必要な場合TRUEを返す
312  */
313 bool set_monster_invulner(player_type *target_ptr, MONSTER_IDX m_idx, int v, bool energy_need)
314 {
315     floor_type *floor_ptr = target_ptr->current_floor_ptr;
316     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
317     bool notice = FALSE;
318     v = (v > 200) ? 200 : (v < 0) ? 0 : v;
319     if (v) {
320         if (!monster_invulner_remaining(m_ptr)) {
321             mproc_add(floor_ptr, m_idx, MTIMED_INVULNER);
322             notice = TRUE;
323         }
324     } else {
325         if (monster_invulner_remaining(m_ptr)) {
326             mproc_remove(floor_ptr, m_idx, MTIMED_INVULNER);
327             if (energy_need && !target_ptr->wild_mode)
328                 m_ptr->energy_need += ENERGY_NEED();
329             notice = TRUE;
330         }
331     }
332
333     m_ptr->mtimed[MTIMED_INVULNER] = (s16b)v;
334     if (!notice)
335         return FALSE;
336
337     if (m_ptr->ml) {
338         if (target_ptr->health_who == m_idx)
339             target_ptr->redraw |= PR_HEALTH;
340
341         if (target_ptr->riding == m_idx)
342             target_ptr->redraw |= PR_UHEALTH;
343     }
344
345     return TRUE;
346 }
347
348 /*!
349  * @brief モンスターの時間停止処理
350  * @param target_ptr プレーヤーへの参照ポインタ
351  * @param num 時間停止を行った敵が行動できる回数
352  * @param who 時間停止処理の主体ID
353  * @param vs_player TRUEならば時間停止開始処理を行う
354  * @return 時間停止が行われている状態ならばTRUEを返す
355  */
356 bool set_monster_timewalk(player_type *target_ptr, int num, MONSTER_IDX who, bool vs_player)
357 {
358     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[hack_m_idx];
359     if (current_world_ptr->timewalk_m_idx)
360         return FALSE;
361
362     if (vs_player) {
363         GAME_TEXT m_name[MAX_NLEN];
364         monster_desc(target_ptr, m_name, m_ptr, 0);
365
366         if (who == 1)
367             msg_format(_("「『ザ・ワールド』!時は止まった!」", "%s yells 'The World! Time has stopped!'"), m_name);
368         else if (who == 3)
369             msg_format(_("「時よ!」", "%s yells 'Time!'"), m_name);
370         else
371             msg_print("hek!");
372
373         msg_print(NULL);
374     }
375
376     current_world_ptr->timewalk_m_idx = hack_m_idx;
377     if (vs_player)
378         do_cmd_redraw(target_ptr);
379
380     while (num--) {
381         if (!monster_is_valid(m_ptr))
382             break;
383
384         process_monster(target_ptr, current_world_ptr->timewalk_m_idx);
385         reset_target(m_ptr);
386         handle_stuff(target_ptr);
387         if (vs_player)
388             term_xtra(TERM_XTRA_DELAY, 500);
389     }
390
391     target_ptr->redraw |= PR_MAP;
392     target_ptr->update |= PU_MONSTERS;
393     target_ptr->window |= PW_OVERHEAD | PW_DUNGEON;
394     current_world_ptr->timewalk_m_idx = 0;
395     if (vs_player || (player_has_los_bold(target_ptr, m_ptr->fy, m_ptr->fx) && projectable(target_ptr, target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx))) {
396         msg_print(_("「時は動きだす…」", "You feel time flowing around you once more."));
397         msg_print(NULL);
398     }
399
400     handle_stuff(target_ptr);
401     return TRUE;
402 }