OSDN Git Service

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