8 #include "spell-class/spells-mirror-master.h"
9 #include "core/stuff-handler.h"
10 #include "dungeon/dungeon-flag-types.h"
11 #include "effect/attribute-types.h"
12 #include "effect/effect-characteristics.h"
13 #include "effect/effect-feature.h"
14 #include "effect/effect-item.h"
15 #include "effect/effect-monster.h"
16 #include "effect/effect-processor.h"
17 #include "effect/spells-effect-util.h"
18 #include "floor/cave.h"
19 #include "floor/geometry.h"
20 #include "game-option/map-screen-options.h"
21 #include "game-option/special-options.h"
22 #include "grid/feature.h"
23 #include "grid/grid.h"
24 #include "io/cursor.h"
25 #include "io/screen-util.h"
26 #include "monster/monster-update.h"
27 #include "pet/pet-util.h"
28 #include "spell-kind/spells-teleport.h"
29 #include "system/dungeon-info.h"
30 #include "system/floor-type-definition.h"
31 #include "system/grid-type-definition.h"
32 #include "system/monster-entity.h"
33 #include "system/player-type-definition.h"
34 #include "system/redrawing-flags-updater.h"
35 #include "system/terrain-type-definition.h"
36 #include "target/grid-selector.h"
37 #include "target/projection-path-calculator.h"
38 #include "target/target-checker.h"
39 #include "timed-effect/player-blindness.h"
40 #include "timed-effect/player-hallucination.h"
41 #include "timed-effect/timed-effects.h"
42 #include "util/bit-flags-calculator.h"
43 #include "view/display-messages.h"
47 SpellsMirrorMaster::SpellsMirrorMaster(PlayerType *player_ptr)
48 : player_ptr(player_ptr)
52 void SpellsMirrorMaster::remove_mirror(int y, int x)
54 auto &floor = *this->player_ptr->current_floor_ptr;
55 auto *g_ptr = &floor.grid_array[y][x];
56 reset_bits(g_ptr->info, CAVE_OBJECT);
58 if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
59 reset_bits(g_ptr->info, CAVE_GLOW);
60 if (!view_torch_grids) {
61 reset_bits(g_ptr->info, CAVE_MARK);
65 update_monster(this->player_ptr, g_ptr->m_idx, false);
68 update_local_illumination(this->player_ptr, y, x);
71 note_spot(this->player_ptr, y, x);
72 lite_spot(this->player_ptr, y, x);
76 * @brief 全鏡の消去 / Remove all mirrors in this floor
77 * @param player_ptr プレイヤーへの参照ポインタ
78 * @param explode 爆発処理を伴うならばTRUE
80 void SpellsMirrorMaster::remove_all_mirrors(bool explode)
82 const auto *floor_ptr = this->player_ptr->current_floor_ptr;
83 for (auto x = 0; x < floor_ptr->width; x++) {
84 for (auto y = 0; y < floor_ptr->height; y++) {
85 if (!floor_ptr->grid_array[y][x].is_mirror()) {
89 this->remove_mirror(y, x);
94 constexpr BIT_FLAGS projection = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
95 project(this->player_ptr, 0, 2, y, x, this->player_ptr->lev / 2 + 5, AttributeType::SHARDS, projection);
101 * @brief 鏡抜け処理のメインルーチン /
102 * Mirror Master's Dimension Door
103 * @param player_ptr プレイヤーへの参照ポインタ
104 * @return ターンを消費した場合TRUEを返す
106 bool SpellsMirrorMaster::mirror_tunnel()
110 if (!tgt_pt(this->player_ptr, &x, &y)) {
114 if (exe_dimension_door(this->player_ptr, x, y)) {
118 msg_print(_("鏡の世界をうまく通れなかった!", "You could not enter the mirror!"));
124 * @return 実際に設置が行われた場合TRUEを返す
126 bool SpellsMirrorMaster::place_mirror()
128 auto y = this->player_ptr->y;
129 auto x = this->player_ptr->x;
130 auto *floor_ptr = this->player_ptr->current_floor_ptr;
131 if (!cave_clean_bold(floor_ptr, y, x)) {
132 msg_print(_("床上のアイテムが呪文を跳ね返した。", "The object resists the spell."));
136 /* Create a mirror */
137 auto *g_ptr = &floor_ptr->grid_array[y][x];
138 set_bits(g_ptr->info, CAVE_OBJECT);
139 g_ptr->mimic = feat_mirror;
141 /* Turn on the light */
142 set_bits(g_ptr->info, CAVE_GLOW);
144 note_spot(this->player_ptr, y, x);
145 lite_spot(this->player_ptr, y, x);
146 update_local_illumination(this->player_ptr, y, x);
152 * @param player_ptr プレイヤーへの参照ポインタ
153 * @return ペットを操っている場合を除きTRUE
155 bool SpellsMirrorMaster::mirror_concentration()
158 msg_print(_("今はペットを操ることに集中していないと。", "Your pets demand all of your attention."));
162 if (!this->player_ptr->current_floor_ptr->grid_array[this->player_ptr->y][this->player_ptr->x].is_mirror()) {
163 msg_print(_("鏡の上でないと集中できない!", "There's no mirror here!"));
167 msg_print(_("少し頭がハッキリした。", "You feel your head clear a little."));
168 this->player_ptr->csp += (5 + this->player_ptr->lev * this->player_ptr->lev / 100);
169 if (this->player_ptr->csp >= this->player_ptr->msp) {
170 this->player_ptr->csp = this->player_ptr->msp;
171 this->player_ptr->csp_frac = 0;
174 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
179 * @brief 鏡魔法「鏡の封印」の効果処理
181 * @return 効果があったらTRUEを返す
183 void SpellsMirrorMaster::seal_of_mirror(const int dam)
185 const auto *floor_ptr = this->player_ptr->current_floor_ptr;
186 for (auto x = 0; x < floor_ptr->width; x++) {
187 for (auto y = 0; y < floor_ptr->height; y++) {
188 const auto &g_ref = floor_ptr->grid_array[y][x];
189 if (!g_ref.is_mirror()) {
193 constexpr BIT_FLAGS flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP;
194 if (!affect_monster(this->player_ptr, 0, 0, y, x, dam, AttributeType::GENOCIDE, flags, true)) {
198 if (g_ref.m_idx == 0) {
199 this->remove_mirror(y, x);
205 void SpellsMirrorMaster::seeker_ray(int dir, int dam)
207 POSITION tx = this->player_ptr->x + ddx[dir];
208 POSITION ty = this->player_ptr->y + ddy[dir];
209 if ((dir == 5) && target_okay(this->player_ptr)) {
214 project_seeker_ray(tx, ty, dam);
217 void SpellsMirrorMaster::super_ray(int dir, int dam)
219 POSITION tx = this->player_ptr->x + ddx[dir];
220 POSITION ty = this->player_ptr->y + ddy[dir];
221 if ((dir == 5) && target_okay(this->player_ptr)) {
226 project_super_ray(tx, ty, dam);
230 * @brief 配置した鏡リストの次を取得する /
231 * Get another mirror. for SEEKER
232 * @param next_y 次の鏡のy座標を返す参照ポインタ
233 * @param next_x 次の鏡のx座標を返す参照ポインタ
234 * @param cury 現在の鏡のy座標
235 * @param curx 現在の鏡のx座標
237 void SpellsMirrorMaster::next_mirror(int *next_y, int *next_x, int cury, int curx)
239 POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
240 int mirror_num = 0; /* 鏡の数 */
242 auto *floor_ptr = this->player_ptr->current_floor_ptr;
244 for (POSITION x = 0; x < floor_ptr->width; x++) {
245 for (POSITION y = 0; y < floor_ptr->height; y++) {
246 if (floor_ptr->grid_array[y][x].is_mirror()) {
247 mirror_y[mirror_num] = y;
248 mirror_x[mirror_num] = x;
255 int num = randint0(mirror_num);
256 *next_y = mirror_y[num];
257 *next_x = mirror_x[num];
262 *next_y = cury + randint0(5) - 2;
263 *next_x = curx + randint0(5) - 2;
264 } while ((*next_y == cury) && (*next_x == curx));
267 void SpellsMirrorMaster::project_seeker_ray(int target_x, int target_y, int dam)
273 constexpr auto typ = AttributeType::SEEKER;
274 BIT_FLAGS flag = PROJECT_BEAM | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM | PROJECT_THRU | PROJECT_MIRROR;
277 monster_target_y = this->player_ptr->y;
278 monster_target_x = this->player_ptr->x;
279 auto *floor_ptr = this->player_ptr->current_floor_ptr;
283 x1 = this->player_ptr->x;
284 y1 = this->player_ptr->y;
289 if ((x1 == x2) && (y1 == y2)) {
290 reset_bits(flag, PROJECT_THRU);
293 /* Calculate the projection path */
294 handle_stuff(this->player_ptr);
302 projection_path path_g(this->player_ptr, (project_length ? project_length : get_max_range(this->player_ptr)), y1, x1, y2, x2, flag);
304 if (path_g.path_num() == 0) {
308 for (auto path_g_ite = path_g.begin(); path_g_ite != path_g.end(); path_g_ite++) {
309 const auto [oy, ox] = *(path_g_ite == path_g.begin() ? path_g.begin() : path_g_ite - 1);
310 const auto [ny, nx] = *path_g_ite;
312 if (delay_factor > 0 && !this->player_ptr->effects()->blindness()->is_blind()) {
313 if (panel_contains(ny, nx) && player_has_los_bold(this->player_ptr, ny, nx)) {
314 print_bolt_pict(this->player_ptr, oy, ox, ny, nx, typ);
315 move_cursor_relative(ny, nx);
317 term_xtra(TERM_XTRA_DELAY, delay_factor);
318 lite_spot(this->player_ptr, ny, nx);
321 print_bolt_pict(this->player_ptr, ny, nx, ny, nx, typ);
325 term_xtra(TERM_XTRA_DELAY, delay_factor);
329 if (affect_item(this->player_ptr, 0, 0, ny, nx, dam, typ)) {
334 for (const auto &[py, px] : path_g) {
335 if (affect_monster(this->player_ptr, 0, 0, py, px, dam, typ, flag, true)) {
338 auto *g_ptr = &floor_ptr->grid_array[project_m_y][project_m_x];
339 auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
340 if (project_m_n == 1 && g_ptr->m_idx > 0 && m_ptr->ml) {
341 if (!this->player_ptr->effects()->hallucination()->is_hallucinated()) {
342 monster_race_track(this->player_ptr, m_ptr->ap_r_idx);
344 health_track(this->player_ptr, g_ptr->m_idx);
347 (void)affect_feature(this->player_ptr, 0, 0, py, px, dam, typ);
350 const auto [y, x] = path_g.back();
352 if (!floor_ptr->grid_array[y][x].is_mirror()) {
356 monster_target_y = y;
357 monster_target_x = x;
358 this->remove_mirror(y, x);
359 this->next_mirror(&y2, &x2, y, x);
365 static void draw_super_ray_pict(PlayerType *player_ptr, const std::map<int, std::vector<projection_path::const_iterator>> &pos_list_map,
366 const std::vector<projection_path> &second_path_g_list, const std::pair<int, int> ¢er)
368 if (delay_factor <= 0) {
372 constexpr auto typ = AttributeType::SUPER_RAY;
374 // 8方向のスーパーレイの軌道上の最後の到達点の座標のリスト
375 std::vector<std::pair<int, int>> last_pos_list;
376 std::transform(second_path_g_list.begin(), second_path_g_list.end(), std::back_inserter(last_pos_list),
377 [](const auto &path_g) { return path_g.back(); });
379 // スーパーレイの描画を行った座標のリスト。スーパーレイの全ての描画完了後に描画を消去するのに使用する。
380 std::vector<std::pair<int, int>> drawn_pos_list;
382 for (const auto &[n, pos_list] : pos_list_map) {
383 // スーパーレイの最終到達点の座標の描画を行った座標のリスト。最終到達点の描画を '*' で上書きするのに使用する。
384 std::vector<std::pair<int, int>> drawn_last_pos_list;
386 for (const auto &it : pos_list) {
387 const auto [y, x] = (n == 1) ? center : *std::next(it, -1);
388 const auto [ny, nx] = *it;
390 if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
391 print_bolt_pict(player_ptr, y, x, y, x, typ);
392 drawn_pos_list.emplace_back(y, x);
394 if (panel_contains(ny, nx) && player_has_los_bold(player_ptr, ny, nx)) {
395 print_bolt_pict(player_ptr, y, x, ny, nx, typ);
396 if (std::find(last_pos_list.begin(), last_pos_list.end(), *it) != last_pos_list.end()) {
397 drawn_last_pos_list.emplace_back(ny, nx);
402 term_xtra(TERM_XTRA_DELAY, delay_factor);
404 for (const auto &[y, x] : drawn_last_pos_list) {
405 if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
406 print_bolt_pict(player_ptr, y, x, y, x, typ);
407 drawn_pos_list.emplace_back(y, x);
413 term_xtra(TERM_XTRA_DELAY, delay_factor);
415 for (const auto &[y, x] : drawn_pos_list) {
416 lite_spot(player_ptr, y, x);
420 static bool activate_super_ray_effect(PlayerType *player_ptr, int y, int x, int dam, BIT_FLAGS flag)
422 constexpr auto typ = AttributeType::SUPER_RAY;
425 (void)affect_feature(player_ptr, 0, 0, y, x, dam, typ);
427 if (affect_item(player_ptr, 0, 0, y, x, dam, typ)) {
431 (void)affect_monster(player_ptr, 0, 0, y, x, dam, typ, flag, true);
433 const auto *floor_ptr = player_ptr->current_floor_ptr;
434 const auto *g_ptr = &floor_ptr->grid_array[project_m_y][project_m_x];
435 const auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
436 if (project_m_n == 1 && g_ptr->m_idx > 0 && m_ptr->ml) {
437 if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
438 monster_race_track(player_ptr, m_ptr->ap_r_idx);
440 health_track(player_ptr, g_ptr->m_idx);
446 void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
452 constexpr auto typ = AttributeType::SUPER_RAY;
453 BIT_FLAGS flag = PROJECT_BEAM | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM | PROJECT_THRU | PROJECT_MIRROR;
456 monster_target_y = this->player_ptr->y;
457 monster_target_x = this->player_ptr->x;
458 auto *floor_ptr = this->player_ptr->current_floor_ptr;
462 x1 = this->player_ptr->x;
463 y1 = this->player_ptr->y;
468 if ((x1 == x2) && (y1 == y2)) {
469 flag &= ~(PROJECT_THRU);
472 /* Calculate the projection path */
473 projection_path path_g(this->player_ptr, (project_length ? project_length : get_max_range(this->player_ptr)), y1, x1, y2, x2, flag);
474 std::vector<projection_path> second_path_g_list;
475 handle_stuff(this->player_ptr);
477 if (path_g.path_num() == 0) {
487 std::vector<std::pair<int, int>> drawn_pos_list;
488 for (const auto &[ny, nx] : path_g) {
489 if (delay_factor > 0) {
490 if (panel_contains(ny, nx) && player_has_los_bold(this->player_ptr, ny, nx)) {
491 print_bolt_pict(this->player_ptr, oy, ox, ny, nx, typ);
492 move_cursor_relative(ny, nx);
494 term_xtra(TERM_XTRA_DELAY, delay_factor);
495 lite_spot(this->player_ptr, ny, nx);
498 print_bolt_pict(this->player_ptr, ny, nx, ny, nx, typ);
500 drawn_pos_list.emplace_back(ny, nx);
503 term_xtra(TERM_XTRA_DELAY, delay_factor);
507 if (!cave_has_flag_bold(floor_ptr, ny, nx, TerrainCharacteristics::PROJECT)) {
514 for (const auto &[y, x] : drawn_pos_list) {
515 lite_spot(player_ptr, y, x);
519 const auto [y, x] = path_g.back();
520 if (floor_ptr->grid_array[y][x].is_mirror()) {
521 this->remove_mirror(y, x);
522 auto project_flag = flag;
523 reset_bits(project_flag, PROJECT_MIRROR);
525 const auto length = project_length ? project_length : get_max_range(this->player_ptr);
527 const auto dy = ddy[i];
528 const auto dx = ddx[i];
529 second_path_g_list.emplace_back(this->player_ptr, length, y, x, y + dy, x + dx, project_flag);
534 for (const auto &[py, px] : path_g) {
535 res.notice |= activate_super_ray_effect(this->player_ptr, py, px, dam, flag);
538 // 起点の鏡からの距離 → 8方向へのスーパーレイの軌道上のその距離にある座標のイテレータのリストの map
539 std::map<int, std::vector<projection_path::const_iterator>> pos_list_map;
540 for (const auto &second_path_g : second_path_g_list) {
541 for (auto it = second_path_g.begin(); it != second_path_g.end(); ++it) {
542 const auto [o_y, o_x] = path_g.back();
543 const auto [y, x] = *it;
544 auto d = distance(o_y, o_x, y, x);
545 pos_list_map[d].push_back(it);
549 draw_super_ray_pict(this->player_ptr, pos_list_map, second_path_g_list, path_g.back());
551 for (auto &&[n, pos_list] : pos_list_map) {
552 rand_shuffle(pos_list.begin(), pos_list.end());
554 for (const auto &it : pos_list) {
555 const auto [y, x] = *it;
556 res.notice |= activate_super_ray_effect(player_ptr, y, x, dam, flag);