OSDN Git Service

[Refactor] #2628 Renamed object-type-definition.cpp/h to item-entity.cpp/h
[hengbandforosx/hengbandosx.git] / src / monster / monster-compaction.cpp
1 #include "monster/monster-compaction.h"
2 #include "core/stuff-handler.h"
3 #include "game-option/play-record-options.h"
4 #include "io/write-diary.h"
5 #include "monster-floor/monster-remover.h"
6 #include "monster-race/monster-race.h"
7 #include "monster-race/race-flags1.h"
8 #include "monster/monster-describer.h"
9 #include "monster/monster-description-types.h"
10 #include "monster/monster-info.h"
11 #include "monster/monster-status.h"
12 #include "system/floor-type-definition.h"
13 #include "system/grid-type-definition.h"
14 #include "system/item-entity.h"
15 #include "system/monster-race-definition.h"
16 #include "system/monster-type-definition.h"
17 #include "system/player-type-definition.h"
18 #include "target/target-checker.h"
19 #include "view/display-messages.h"
20
21 /*!
22  * @brief モンスター情報を配列内移動する / Move an object from index i1 to index i2 in the object list
23  * @param player_ptr プレイヤーへの参照ポインタ
24  * @param i1 配列移動元添字
25  * @param i2 配列移動先添字
26  */
27 static void compact_monsters_aux(PlayerType *player_ptr, MONSTER_IDX i1, MONSTER_IDX i2)
28 {
29     if (i1 == i2) {
30         return;
31     }
32
33     auto *floor_ptr = player_ptr->current_floor_ptr;
34     MonsterEntity *m_ptr;
35     m_ptr = &floor_ptr->m_list[i1];
36
37     POSITION y = m_ptr->fy;
38     POSITION x = m_ptr->fx;
39     grid_type *g_ptr;
40     g_ptr = &floor_ptr->grid_array[y][x];
41     g_ptr->m_idx = i2;
42
43     for (const auto this_o_idx : m_ptr->hold_o_idx_list) {
44         ItemEntity *o_ptr;
45         o_ptr = &floor_ptr->o_list[this_o_idx];
46         o_ptr->held_m_idx = i2;
47     }
48
49     if (target_who == i1) {
50         target_who = i2;
51     }
52
53     if (player_ptr->pet_t_m_idx == i1) {
54         player_ptr->pet_t_m_idx = i2;
55     }
56     if (player_ptr->riding_t_m_idx == i1) {
57         player_ptr->riding_t_m_idx = i2;
58     }
59
60     if (player_ptr->riding == i1) {
61         player_ptr->riding = i2;
62     }
63
64     if (player_ptr->health_who == i1) {
65         health_track(player_ptr, i2);
66     }
67
68     if (m_ptr->is_pet()) {
69         for (int i = 1; i < floor_ptr->m_max; i++) {
70             MonsterEntity *m2_ptr = &floor_ptr->m_list[i];
71
72             if (m2_ptr->parent_m_idx == i1) {
73                 m2_ptr->parent_m_idx = i2;
74             }
75         }
76     }
77
78     floor_ptr->m_list[i2] = floor_ptr->m_list[i1];
79     floor_ptr->m_list[i1] = {};
80
81     for (int i = 0; i < MAX_MTIMED; i++) {
82         int mproc_idx = get_mproc_idx(floor_ptr, i1, i);
83         if (mproc_idx >= 0) {
84             floor_ptr->mproc_list[i][mproc_idx] = i2;
85         }
86     }
87 }
88
89 /*!
90  * @brief モンスター情報配列を圧縮する / Compact and Reorder the monster list
91  * @param player_ptr プレイヤーへの参照ポインタ
92  * @param size 圧縮後のモンスター件数目標
93  * @details
94  * This function can be very dangerous, use with caution!
95  *
96  * When actually "compacting" monsters, we base the saving throw
97  * on a combination of monster level, distance from player, and
98  * current "desperation".
99  *
100  * After "compacting" (if needed), we "reorder" the monsters into a more
101  * compact order, and we reset the allocation info, and the "live" array.
102  */
103 void compact_monsters(PlayerType *player_ptr, int size)
104 {
105     if (size) {
106         msg_print(_("モンスター情報を圧縮しています...", "Compacting monsters..."));
107     }
108
109     /* Compact at least 'size' objects */
110     auto *floor_ptr = player_ptr->current_floor_ptr;
111     for (int num = 0, cnt = 1; num < size; cnt++) {
112         int cur_lev = 5 * cnt;
113         int cur_dis = 5 * (20 - cnt);
114         for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
115             auto *m_ptr = &floor_ptr->m_list[i];
116             auto *r_ptr = &monraces_info[m_ptr->r_idx];
117             if (!m_ptr->is_valid()) {
118                 continue;
119             }
120             if (r_ptr->level > cur_lev) {
121                 continue;
122             }
123             if (i == player_ptr->riding) {
124                 continue;
125             }
126             if ((cur_dis > 0) && (m_ptr->cdis < cur_dis)) {
127                 continue;
128             }
129
130             int chance = 90;
131             if ((r_ptr->flags1 & (RF1_QUESTOR)) && (cnt < 1000)) {
132                 chance = 100;
133             }
134
135             if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
136                 chance = 100;
137             }
138
139             if (randint0(100) < chance) {
140                 continue;
141             }
142
143             if (record_named_pet && m_ptr->is_pet() && m_ptr->nickname) {
144                 GAME_TEXT m_name[MAX_NLEN];
145                 monster_desc(player_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
146                 exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_COMPACT, m_name);
147             }
148
149             delete_monster_idx(player_ptr, i);
150             num++;
151         }
152     }
153
154     /* Excise dead monsters (backwards!) */
155     for (MONSTER_IDX i = floor_ptr->m_max - 1; i >= 1; i--) {
156         auto *m_ptr = &floor_ptr->m_list[i];
157         if (MonsterRace(m_ptr->r_idx).is_valid()) {
158             continue;
159         }
160         compact_monsters_aux(player_ptr, floor_ptr->m_max - 1, i);
161         floor_ptr->m_max--;
162     }
163 }