OSDN Git Service

Merge pull request #2809 from Hourier/Change-Type-Entity
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-object.cpp
1 /*!
2  * @brief モンスターが移動した結果、床のアイテムに重なった時の処理と、モンスターがアイテムを落とす処理
3  * @date 2020/03/07
4  * @author Hourier
5  */
6
7 #include "monster-floor/monster-object.h"
8 #include "flavor/flavor-describer.h"
9 #include "floor/cave.h"
10 #include "floor/floor-object.h"
11 #include "floor/geometry.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-flags-resistance.h"
14 #include "monster-race/race-flags2.h"
15 #include "monster-race/race-flags3.h"
16 #include "monster-race/race-resistance-mask.h"
17 #include "monster/monster-describer.h"
18 #include "monster/monster-description-types.h"
19 #include "monster/monster-info.h"
20 #include "monster/monster-processor-util.h"
21 #include "monster/smart-learn-types.h"
22 #include "object-enchant/tr-types.h"
23 #include "object/object-flags.h"
24 #include "object/object-mark-types.h"
25 #include "system/floor-type-definition.h"
26 #include "system/grid-type-definition.h"
27 #include "system/item-entity.h"
28 #include "system/monster-entity.h"
29 #include "system/monster-race-info.h"
30 #include "system/player-type-definition.h"
31 #include "util/bit-flags-calculator.h"
32 #include "view/display-messages.h"
33
34 /*!
35  * @brief オブジェクトのフラグを更新する
36  */
37 static void update_object_flags(const TrFlags &flgs, EnumClassFlagGroup<MonsterKindType> &flg_monster_kind, EnumClassFlagGroup<MonsterResistanceType> &flgr)
38 {
39     if (flgs.has(TR_SLAY_DRAGON)) {
40         flg_monster_kind.set(MonsterKindType::DRAGON);
41     }
42     if (flgs.has(TR_KILL_DRAGON)) {
43         flg_monster_kind.set(MonsterKindType::DRAGON);
44     }
45     if (flgs.has(TR_SLAY_TROLL)) {
46         flg_monster_kind.set(MonsterKindType::TROLL);
47     }
48     if (flgs.has(TR_KILL_TROLL)) {
49         flg_monster_kind.set(MonsterKindType::TROLL);
50     }
51     if (flgs.has(TR_SLAY_GIANT)) {
52         flg_monster_kind.set(MonsterKindType::GIANT);
53     }
54     if (flgs.has(TR_KILL_GIANT)) {
55         flg_monster_kind.set(MonsterKindType::GIANT);
56     }
57     if (flgs.has(TR_SLAY_ORC)) {
58         flg_monster_kind.set(MonsterKindType::ORC);
59     }
60     if (flgs.has(TR_KILL_ORC)) {
61         flg_monster_kind.set(MonsterKindType::ORC);
62     }
63     if (flgs.has(TR_SLAY_DEMON)) {
64         flg_monster_kind.set(MonsterKindType::DEMON);
65     }
66     if (flgs.has(TR_KILL_DEMON)) {
67         flg_monster_kind.set(MonsterKindType::DEMON);
68     }
69     if (flgs.has(TR_SLAY_UNDEAD)) {
70         flg_monster_kind.set(MonsterKindType::UNDEAD);
71     }
72     if (flgs.has(TR_KILL_UNDEAD)) {
73         flg_monster_kind.set(MonsterKindType::UNDEAD);
74     }
75     if (flgs.has(TR_SLAY_ANIMAL)) {
76         flg_monster_kind.set(MonsterKindType::ANIMAL);
77     }
78     if (flgs.has(TR_KILL_ANIMAL)) {
79         flg_monster_kind.set(MonsterKindType::ANIMAL);
80     }
81     if (flgs.has(TR_SLAY_EVIL)) {
82         flg_monster_kind.set(MonsterKindType::EVIL);
83     }
84     if (flgs.has(TR_KILL_EVIL)) {
85         flg_monster_kind.set(MonsterKindType::EVIL);
86     }
87     if (flgs.has(TR_SLAY_GOOD)) {
88         flg_monster_kind.set(MonsterKindType::GOOD);
89     }
90     if (flgs.has(TR_KILL_GOOD)) {
91         flg_monster_kind.set(MonsterKindType::GOOD);
92     }
93     if (flgs.has(TR_SLAY_HUMAN)) {
94         flg_monster_kind.set(MonsterKindType::HUMAN);
95     }
96     if (flgs.has(TR_KILL_HUMAN)) {
97         flg_monster_kind.set(MonsterKindType::HUMAN);
98     }
99     if (flgs.has(TR_BRAND_ACID)) {
100         flgr.set(MonsterResistanceType::IMMUNE_ACID);
101     }
102     if (flgs.has(TR_BRAND_ELEC)) {
103         flgr.set(MonsterResistanceType::IMMUNE_ELEC);
104     }
105     if (flgs.has(TR_BRAND_FIRE)) {
106         flgr.set(MonsterResistanceType::IMMUNE_FIRE);
107     }
108     if (flgs.has(TR_BRAND_COLD)) {
109         flgr.set(MonsterResistanceType::IMMUNE_COLD);
110     }
111     if (flgs.has(TR_BRAND_POIS)) {
112         flgr.set(MonsterResistanceType::IMMUNE_POISON);
113     }
114 }
115
116 /*!
117  * @brief モンスターがアイテムを拾うか壊す処理
118  * @param player_ptr プレイヤーへの参照ポインタ
119  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
120  * @param m_idx モンスターID
121  * @param o_ptr オブジェクトへの参照ポインタ
122  * @param is_unpickable_object モンスターが拾えないアイテム (アーティファクト等)であればTRUE
123  * @param ny 移動後の、モンスターのY座標
124  * @param nx 移動後の、モンスターのX座標
125  * @param m_name モンスター名
126  * @param o_name アイテム名
127  * @param this_o_idx モンスターが乗ったオブジェクトID
128  */
129 static void monster_pickup_object(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MONSTER_IDX m_idx, ItemEntity *o_ptr, const bool is_unpickable_object,
130     const POSITION ny, const POSITION nx, const GAME_TEXT *m_name, const GAME_TEXT *o_name, const OBJECT_IDX this_o_idx)
131 {
132     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
133     auto *r_ptr = &monraces_info[m_ptr->r_idx];
134     if (is_unpickable_object) {
135         if (turn_flags_ptr->do_take && r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
136             turn_flags_ptr->did_take_item = true;
137             if (m_ptr->ml && player_can_see_bold(player_ptr, ny, nx)) {
138                 msg_format(_("%^sは%sを拾おうとしたが、だめだった。", "%^s tries to pick up %s, but fails."), m_name, o_name);
139             }
140         }
141
142         return;
143     }
144
145     if (turn_flags_ptr->do_take) {
146         turn_flags_ptr->did_take_item = true;
147         if (player_can_see_bold(player_ptr, ny, nx)) {
148             msg_format(_("%^sが%sを拾った。", "%^s picks up %s."), m_name, o_name);
149         }
150
151         excise_object_idx(player_ptr->current_floor_ptr, this_o_idx);
152         o_ptr->marked &= OM_TOUCHED;
153         o_ptr->iy = o_ptr->ix = 0;
154         o_ptr->held_m_idx = m_idx;
155         m_ptr->hold_o_idx_list.add(player_ptr->current_floor_ptr, this_o_idx);
156         return;
157     }
158
159     if (m_ptr->is_pet()) {
160         return;
161     }
162
163     turn_flags_ptr->did_kill_item = true;
164     if (player_has_los_bold(player_ptr, ny, nx)) {
165         msg_format(_("%^sが%sを破壊した。", "%^s destroys %s."), m_name, o_name);
166     }
167
168     delete_object_idx(player_ptr, this_o_idx);
169 }
170
171 /*!
172  * @brief モンスターの移動に伴うオブジェクト処理 (アイテム破壊等)
173  * @param player_ptr プレイヤーへの参照ポインタ
174  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
175  * @param m_idx モンスターID
176  * @param ny 移動後の、モンスターのY座標
177  * @param nx 移動後の、モンスターのX座標
178  */
179 void update_object_by_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx)
180 {
181     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
182     auto *r_ptr = &monraces_info[m_ptr->r_idx];
183     grid_type *g_ptr;
184     g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
185
186     turn_flags_ptr->do_take = r_ptr->behavior_flags.has(MonsterBehaviorType::TAKE_ITEM);
187     for (auto it = g_ptr->o_idx_list.begin(); it != g_ptr->o_idx_list.end();) {
188         EnumClassFlagGroup<MonsterKindType> flg_monster_kind;
189         EnumClassFlagGroup<MonsterResistanceType> flgr;
190         GAME_TEXT m_name[MAX_NLEN], o_name[MAX_NLEN];
191         OBJECT_IDX this_o_idx = *it++;
192         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
193
194         if (turn_flags_ptr->do_take) {
195             /* Skip gold, corpse and statue */
196             if (o_ptr->tval == ItemKindType::GOLD || (o_ptr->tval == ItemKindType::CORPSE) || (o_ptr->tval == ItemKindType::STATUE)) {
197                 continue;
198             }
199         }
200
201         auto flgs = object_flags(o_ptr);
202         describe_flavor(player_ptr, o_name, o_ptr, 0);
203         monster_desc(player_ptr, m_name, m_ptr, MD_INDEF_HIDDEN);
204         update_object_flags(flgs, flg_monster_kind, flgr);
205
206         auto is_unpickable_object = o_ptr->is_artifact();
207         is_unpickable_object |= r_ptr->kind_flags.has_any_of(flg_monster_kind);
208         is_unpickable_object |= !r_ptr->resistance_flags.has_all_of(flgr) && r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_ALL);
209         monster_pickup_object(player_ptr, turn_flags_ptr, m_idx, o_ptr, is_unpickable_object, ny, nx, m_name, o_name, this_o_idx);
210     }
211 }
212
213 /*!
214  * @brief モンスターが盗みや拾いで確保していたアイテムを全てドロップさせる / Drop all items carried by a monster
215  * @param player_ptr プレイヤーへの参照ポインタ
216  * @param m_ptr モンスター参照ポインタ
217  */
218 void monster_drop_carried_objects(PlayerType *player_ptr, MonsterEntity *m_ptr)
219 {
220     for (auto it = m_ptr->hold_o_idx_list.begin(); it != m_ptr->hold_o_idx_list.end();) {
221         ItemEntity forge;
222         ItemEntity *o_ptr;
223         ItemEntity *q_ptr;
224         const OBJECT_IDX this_o_idx = *it++;
225         o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
226         q_ptr = &forge;
227         q_ptr->copy_from(o_ptr);
228         q_ptr->held_m_idx = 0;
229         delete_object_idx(player_ptr, this_o_idx);
230         (void)drop_near(player_ptr, q_ptr, -1, m_ptr->fy, m_ptr->fx);
231     }
232
233     m_ptr->hold_o_idx_list.clear();
234 }