2 * @brief モンスターの移動に関する処理
7 #include "monster/monster-move.h"
8 #include "monster/monster-attack.h"
9 #include "monster/monster-object.h"
10 #include "monster/monster-update.h"
11 #include "cmd/cmd-pet.h"
14 #include "monster/monster-status.h"
15 #include "player/player-move.h"
16 #include "spell/spells-type.h"
17 #include "spell/process-effect.h"
18 #include "effect/effect-characteristics.h"
20 static bool check_hp_for_feat_destruction(feature_type *f_ptr, monster_type *m_ptr)
22 return !have_flag(f_ptr->flags, FF_GLASS) ||
23 (r_info[m_ptr->r_idx].flags2 & RF2_STUPID) ||
24 (m_ptr->hp >= MAX(m_ptr->maxhp / 3, 200));
29 * @brief モンスターによる壁の透過・破壊を行う
30 * @param target_ptr プレーヤーへの参照ポインタ
31 * @param m_ptr モンスターへの参照ポインタ
34 * @param can_cross モンスターが地形を踏破できるならばTRUE
35 * @return 透過も破壊もしなかった場合はFALSE、それ以外はTRUE
37 static bool process_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx, bool can_cross)
39 monster_race *r_ptr = &r_info[m_ptr->r_idx];
41 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
43 f_ptr = &f_info[g_ptr->feat];
44 if (player_bold(target_ptr, ny, nx))
46 turn_flags_ptr->do_move = TRUE;
52 turn_flags_ptr->do_move = TRUE;
56 if (((r_ptr->flags2 & RF2_KILL_WALL) != 0) &&
57 (can_cross ? !have_flag(f_ptr->flags, FF_LOS) : !turn_flags_ptr->is_riding_mon) &&
58 have_flag(f_ptr->flags, FF_HURT_DISI) && !have_flag(f_ptr->flags, FF_PERMANENT) &&
59 check_hp_for_feat_destruction(f_ptr, m_ptr))
61 turn_flags_ptr->do_move = TRUE;
62 if (!can_cross) turn_flags_ptr->must_alter_to_move = TRUE;
64 turn_flags_ptr->did_kill_wall = TRUE;
68 if (!can_cross) return FALSE;
70 turn_flags_ptr->do_move = TRUE;
71 if (((r_ptr->flags2 & RF2_PASS_WALL) != 0) && (!turn_flags_ptr->is_riding_mon || target_ptr->pass_wall) &&
72 have_flag(f_ptr->flags, FF_CAN_PASS))
74 turn_flags_ptr->did_pass_wall = TRUE;
82 * @brief モンスターが普通のドアを開ける処理
83 * @param target_ptr プレーヤーへの参照ポインタ
84 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
85 * @param m_ptr モンスターへの参照ポインタ
88 * @return ここではドアを開けず、ガラスのドアを開ける可能性があるならTRUE
90 static bool bash_normal_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
92 monster_race *r_ptr = &r_info[m_ptr->r_idx];
94 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
96 f_ptr = &f_info[g_ptr->feat];
97 turn_flags_ptr->do_move = FALSE;
98 if (((r_ptr->flags2 & RF2_OPEN_DOOR) == 0) || !have_flag(f_ptr->flags, FF_OPEN) ||
99 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
102 if (f_ptr->power == 0)
104 turn_flags_ptr->did_open_door = TRUE;
105 turn_flags_ptr->do_turn = TRUE;
109 if (randint0(m_ptr->hp / 10) > f_ptr->power)
111 cave_alter_feat(target_ptr, ny, nx, FF_DISARM);
112 turn_flags_ptr->do_turn = TRUE;
121 * @brief モンスターがガラスのドアを開ける処理
122 * @param target_ptr プレーヤーへの参照ポインタ
123 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
124 * @param m_ptr モンスターへの参照ポインタ
125 * @param g_ptr グリッドへの参照ポインタ
126 * @param f_ptr 地形への参照ポインタ
129 static void bash_glass_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, feature_type *f_ptr, bool may_bash)
131 monster_race *r_ptr = &r_info[m_ptr->r_idx];
132 if (!may_bash || ((r_ptr->flags2 & RF2_BASH_DOOR) == 0) || !have_flag(f_ptr->flags, FF_BASH) ||
133 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
136 if (!check_hp_for_feat_destruction(f_ptr, m_ptr) || (randint0(m_ptr->hp / 10) <= f_ptr->power))
139 if (have_flag(f_ptr->flags, FF_GLASS))
140 msg_print(_("ガラスが砕ける音がした!", "You hear glass breaking!"));
142 msg_print(_("ドアを叩き開ける音がした!", "You hear a door burst open!"));
144 if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
146 turn_flags_ptr->did_bash_door = TRUE;
147 turn_flags_ptr->do_move = TRUE;
148 turn_flags_ptr->must_alter_to_move = TRUE;
153 * @brief モンスターによるドアの開放・破壊を行う
154 * @param target_ptr プレーヤーへの参照ポインタ
155 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
156 * @param m_ptr モンスターへの参照ポインタ
157 * @param ny モンスターのY座標
158 * @param nx モンスターのX座標
159 * @return モンスターが死亡した場合のみFALSE
161 static bool process_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
163 monster_race *r_ptr = &r_info[m_ptr->r_idx];
165 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
166 if (!is_closed_door(target_ptr, g_ptr->feat)) return TRUE;
169 f_ptr = &f_info[g_ptr->feat];
170 bool may_bash = bash_normal_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx);
171 bash_glass_door(target_ptr, turn_flags_ptr, m_ptr, f_ptr, may_bash);
173 if (!turn_flags_ptr->did_open_door && !turn_flags_ptr->did_bash_door) return TRUE;
175 if (turn_flags_ptr->did_bash_door &&
176 ((randint0(100) < 50) || (feat_state(target_ptr, g_ptr->feat, FF_OPEN) == g_ptr->feat) || have_flag(f_ptr->flags, FF_GLASS)))
178 cave_alter_feat(target_ptr, ny, nx, FF_BASH);
179 if (!monster_is_valid(m_ptr))
181 target_ptr->update |= (PU_FLOW);
182 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
183 if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_BASH_DOOR);
190 cave_alter_feat(target_ptr, ny, nx, FF_OPEN);
193 f_ptr = &f_info[g_ptr->feat];
194 turn_flags_ptr->do_view = TRUE;
200 * @brief 守りのルーンによるモンスターの移動制限を処理する
201 * @param target_ptr プレーヤーへの参照ポインタ
202 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
203 * @param m_ptr モンスターへの参照ポインタ
204 * @param ny モンスターのY座標
205 * @param nx モンスターのX座標
208 static bool process_protection_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
211 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
212 monster_race *r_ptr = &r_info[m_ptr->r_idx];
213 if (!turn_flags_ptr->do_move || !is_glyph_grid(g_ptr) ||
214 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
217 turn_flags_ptr->do_move = FALSE;
218 if (is_pet(m_ptr) || (randint1(BREAK_GLYPH) >= r_ptr->level))
221 if (g_ptr->info & CAVE_MARK)
223 msg_print(_("守りのルーンが壊れた!", "The rune of protection is broken!"));
226 g_ptr->info &= ~(CAVE_MARK);
227 g_ptr->info &= ~(CAVE_OBJECT);
229 turn_flags_ptr->do_move = TRUE;
230 note_spot(target_ptr, ny, nx);
237 * @param target_ptr プレーヤーへの参照ポインタ
238 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
239 * @param m_ptr モンスターへの参照ポインタ
240 * @param ny モンスターのY座標
241 * @param nx モンスターのX座標
242 * @return モンスターが死亡した場合のみFALSE
244 static bool process_explosive_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
247 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
248 monster_race *r_ptr = &r_info[m_ptr->r_idx];
249 if (!turn_flags_ptr->do_move || !is_explosive_rune_grid(g_ptr) ||
250 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
253 turn_flags_ptr->do_move = FALSE;
254 if (is_pet(m_ptr)) return TRUE;
256 if (randint1(BREAK_MINOR_GLYPH) > r_ptr->level)
258 if (g_ptr->info & CAVE_MARK)
260 msg_print(_("ルーンが爆発した!", "The rune explodes!"));
261 BIT_FLAGS project_flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
262 project(target_ptr, 0, 2, ny, nx, 2 * (target_ptr->lev + damroll(7, 7)), GF_MANA, project_flags, -1);
267 msg_print(_("爆発のルーンは解除された。", "An explosive rune was disarmed."));
270 g_ptr->info &= ~(CAVE_MARK);
271 g_ptr->info &= ~(CAVE_OBJECT);
274 note_spot(target_ptr, ny, nx);
275 lite_spot(target_ptr, ny, nx);
277 if (!monster_is_valid(m_ptr)) return FALSE;
279 turn_flags_ptr->do_move = TRUE;
285 * @brief モンスターが壁を掘った後続処理を実行する
286 * @param target_ptr プレーヤーへの参照ポインタ
287 * @turn_flags_ptr ターン経過処理フラグへの参照ポインタ
288 * @param m_ptr モンスターへの参照ポインタ
289 * @param ny モンスターのY座標
290 * @param nx モンスターのX座標
291 * @return モンスターが死亡した場合のみFALSE
293 static bool process_post_dig_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
295 monster_race *r_ptr = &r_info[m_ptr->r_idx];
297 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
299 f_ptr = &f_info[g_ptr->feat];
300 if (!turn_flags_ptr->did_kill_wall || !turn_flags_ptr->do_move) return TRUE;
302 if (one_in_(GRINDNOISE))
304 if (have_flag(f_ptr->flags, FF_GLASS))
305 msg_print(_("何かの砕ける音が聞こえる。", "There is a crashing sound."));
307 msg_print(_("ギシギシいう音が聞こえる。", "There is a grinding sound."));
310 cave_alter_feat(target_ptr, ny, nx, FF_HURT_DISI);
312 if (!monster_is_valid(m_ptr))
314 target_ptr->update |= (PU_FLOW);
315 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
316 if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_KILL_WALL);
321 f_ptr = &f_info[g_ptr->feat];
322 turn_flags_ptr->do_view = TRUE;
323 turn_flags_ptr->do_turn = TRUE;
329 * todo 少し長いが、これといってブロックとしてまとまった部分もないので暫定でこのままとする
330 * @brief モンスターの移動に関するメインルーチン
331 * @param target_ptr プレーヤーへの参照ポインタ
332 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
333 * @param m_idx モンスターID
334 * @param mm モンスターの移動方向
335 * @param oy 移動前の、モンスターのY座標
336 * @param ox 移動前の、モンスターのX座標
337 * @param count 移動回数 (のはず todo)
338 * @return 移動が阻害される何か (ドア等)があったらFALSE
340 bool process_monster_movement(player_type *target_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, POSITION oy, POSITION ox, int *count)
342 for (int i = 0; mm[i]; i++)
345 if (d == 5) d = ddd[randint0(8)];
347 POSITION ny = oy + ddy[d];
348 POSITION nx = ox + ddx[d];
349 if (!in_bounds2(target_ptr->current_floor_ptr, ny, nx)) continue;
352 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
353 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
354 monster_race *r_ptr = &r_info[m_ptr->r_idx];
355 bool can_cross = monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0);
357 if (!process_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx, can_cross))
359 if (!process_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
363 if (!process_protection_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
365 if (!process_explosive_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
369 exe_monster_attack_to_player(target_ptr, turn_flags_ptr, m_idx, ny, nx);
370 if (process_monster_attack_to_monster(target_ptr, turn_flags_ptr, m_idx, g_ptr, can_cross)) return FALSE;
372 if (turn_flags_ptr->is_riding_mon)
374 if (!target_ptr->riding_ryoute && !MON_MONFEAR(&target_ptr->current_floor_ptr->m_list[target_ptr->riding])) turn_flags_ptr->do_move = FALSE;
377 if (!process_post_dig_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx)) return FALSE;
379 if (turn_flags_ptr->must_alter_to_move && (r_ptr->flags7 & RF7_AQUATIC))
381 if (!monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0))
382 turn_flags_ptr->do_move = FALSE;
385 if (turn_flags_ptr->do_move && !can_cross && !turn_flags_ptr->did_kill_wall && !turn_flags_ptr->did_bash_door)
386 turn_flags_ptr->do_move = FALSE;
388 if (turn_flags_ptr->do_move && (r_ptr->flags1 & RF1_NEVER_MOVE))
390 if (is_original_ap_and_seen(target_ptr, m_ptr))
391 r_ptr->r_flags1 |= (RF1_NEVER_MOVE);
393 turn_flags_ptr->do_move = FALSE;
396 if (!turn_flags_ptr->do_move)
398 if (turn_flags_ptr->do_turn) break;
403 turn_flags_ptr->do_turn = TRUE;
405 f_ptr = &f_info[g_ptr->feat];
406 if (have_flag(f_ptr->flags, FF_TREE))
408 if (!(r_ptr->flags7 & RF7_CAN_FLY) && !(r_ptr->flags8 & RF8_WILD_WOOD))
410 m_ptr->energy_need += ENERGY_NEED();
414 if (!update_riding_monster(target_ptr, turn_flags_ptr, m_idx, oy, ox, ny, nx)) break;
416 monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
419 (disturb_near && (m_ptr->mflag & MFLAG_VIEW) && projectable(target_ptr, target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx)) ||
420 (disturb_high && ap_r_ptr->r_tkills && ap_r_ptr->level >= target_ptr->lev)))
422 if (is_hostile(m_ptr))
423 disturb(target_ptr, FALSE, TRUE);
426 bool is_takable_or_killable = g_ptr->o_idx > 0;
427 is_takable_or_killable &= (r_ptr->flags2 & (RF2_TAKE_ITEM | RF2_KILL_ITEM)) != 0;
429 bool is_pickup_items = (target_ptr->pet_extra_flags & PF_PICKUP_ITEMS) != 0;
430 is_pickup_items &= (r_ptr->flags2 & RF2_TAKE_ITEM) != 0;
432 is_takable_or_killable &= !is_pet(m_ptr) || is_pickup_items;
433 if (!is_takable_or_killable)
435 if (turn_flags_ptr->do_turn) break;
440 update_object_by_monster_movement(target_ptr, turn_flags_ptr, m_idx, ny, nx);
441 if (turn_flags_ptr->do_turn) break;
451 * @brief モンスターを喋らせたり足音を立てたりする
452 * @param target_ptr プレーヤーへの参照ポインタ
453 * @param m_idx モンスターID
454 * @param oy モンスターが元々いたY座標
455 * @param ox モンスターが元々いたX座標
456 * @param aware モンスターがプレーヤーに気付いているならばTRUE、超隠密状態ならばFALSE
459 void process_speak_sound(player_type *target_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, bool aware)
461 if (target_ptr->phase_out) return;
463 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
464 monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
465 if (m_ptr->ap_r_idx == MON_CYBER &&
466 one_in_(CYBERNOISE) &&
467 !m_ptr->ml && (m_ptr->cdis <= MAX_SIGHT))
469 if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
470 msg_print(_("重厚な足音が聞こえた。", "You hear heavy steps."));
473 if (((ap_r_ptr->flags2 & RF2_CAN_SPEAK) == 0) || !aware ||
474 !one_in_(SPEAK_CHANCE) ||
475 !player_has_los_bold(target_ptr, oy, ox) ||
476 !projectable(target_ptr, oy, ox, target_ptr->y, target_ptr->x))
479 GAME_TEXT m_name[MAX_NLEN];
480 char monmessage[1024];
484 monster_desc(target_ptr, m_name, m_ptr, 0);
486 strcpy(m_name, _("それ", "It"));
488 if (MON_MONFEAR(m_ptr))
489 filename = _("monfear_j.txt", "monfear.txt");
490 else if (is_pet(m_ptr))
491 filename = _("monpet_j.txt", "monpet.txt");
492 else if (is_friendly(m_ptr))
493 filename = _("monfrien_j.txt", "monfrien.txt");
495 filename = _("monspeak_j.txt", "monspeak.txt");
497 if (get_rnd_line(filename, m_ptr->ap_r_idx, monmessage) == 0)
499 msg_format(_("%^s%s", "%^s %s"), m_name, monmessage);