2 * @brief モンスターが移動した結果、床のアイテムに重なった時の処理と、モンスターがアイテムを落とす処理
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>
36 * @brief オブジェクトのフラグを更新する
38 static void update_object_flags(const TrFlags &flags, EnumClassFlagGroup<MonsterKindType> &flg_monster_kind, EnumClassFlagGroup<MonsterResistanceType> &flgr)
40 if (flags.has(TR_SLAY_DRAGON)) {
41 flg_monster_kind.set(MonsterKindType::DRAGON);
43 if (flags.has(TR_KILL_DRAGON)) {
44 flg_monster_kind.set(MonsterKindType::DRAGON);
46 if (flags.has(TR_SLAY_TROLL)) {
47 flg_monster_kind.set(MonsterKindType::TROLL);
49 if (flags.has(TR_KILL_TROLL)) {
50 flg_monster_kind.set(MonsterKindType::TROLL);
52 if (flags.has(TR_SLAY_GIANT)) {
53 flg_monster_kind.set(MonsterKindType::GIANT);
55 if (flags.has(TR_KILL_GIANT)) {
56 flg_monster_kind.set(MonsterKindType::GIANT);
58 if (flags.has(TR_SLAY_ORC)) {
59 flg_monster_kind.set(MonsterKindType::ORC);
61 if (flags.has(TR_KILL_ORC)) {
62 flg_monster_kind.set(MonsterKindType::ORC);
64 if (flags.has(TR_SLAY_DEMON)) {
65 flg_monster_kind.set(MonsterKindType::DEMON);
67 if (flags.has(TR_KILL_DEMON)) {
68 flg_monster_kind.set(MonsterKindType::DEMON);
70 if (flags.has(TR_SLAY_UNDEAD)) {
71 flg_monster_kind.set(MonsterKindType::UNDEAD);
73 if (flags.has(TR_KILL_UNDEAD)) {
74 flg_monster_kind.set(MonsterKindType::UNDEAD);
76 if (flags.has(TR_SLAY_ANIMAL)) {
77 flg_monster_kind.set(MonsterKindType::ANIMAL);
79 if (flags.has(TR_KILL_ANIMAL)) {
80 flg_monster_kind.set(MonsterKindType::ANIMAL);
82 if (flags.has(TR_SLAY_EVIL)) {
83 flg_monster_kind.set(MonsterKindType::EVIL);
85 if (flags.has(TR_KILL_EVIL)) {
86 flg_monster_kind.set(MonsterKindType::EVIL);
88 if (flags.has(TR_SLAY_GOOD)) {
89 flg_monster_kind.set(MonsterKindType::GOOD);
91 if (flags.has(TR_KILL_GOOD)) {
92 flg_monster_kind.set(MonsterKindType::GOOD);
94 if (flags.has(TR_SLAY_HUMAN)) {
95 flg_monster_kind.set(MonsterKindType::HUMAN);
97 if (flags.has(TR_KILL_HUMAN)) {
98 flg_monster_kind.set(MonsterKindType::HUMAN);
100 if (flags.has(TR_BRAND_ACID)) {
101 flgr.set(MonsterResistanceType::IMMUNE_ACID);
103 if (flags.has(TR_BRAND_ELEC)) {
104 flgr.set(MonsterResistanceType::IMMUNE_ELEC);
106 if (flags.has(TR_BRAND_FIRE)) {
107 flgr.set(MonsterResistanceType::IMMUNE_FIRE);
109 if (flags.has(TR_BRAND_COLD)) {
110 flgr.set(MonsterResistanceType::IMMUNE_COLD);
112 if (flags.has(TR_BRAND_POIS)) {
113 flgr.set(MonsterResistanceType::IMMUNE_POISON);
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
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)
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());
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());
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);
163 if (monster.is_pet()) {
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());
172 delete_object_idx(player_ptr, this_o_idx);
176 * @brief モンスターの移動に伴うオブジェクト処理 (アイテム破壊等)
177 * @param player_ptr プレイヤーへの参照ポインタ
178 * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
179 * @param m_idx モンスターID
180 * @param ny 移動後の、モンスターのY座標
181 * @param nx 移動後の、モンスターのX座標
183 void update_object_by_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx)
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];
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)) {
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);
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);
215 * @brief モンスターが盗みや拾いで確保していたアイテムを全てドロップさせる / Drop all items carried by a monster
216 * @param player_ptr プレイヤーへの参照ポインタ
217 * @param m_ptr モンスター参照ポインタ
219 void monster_drop_carried_objects(PlayerType *player_ptr, MonsterEntity *m_ptr)
221 for (auto it = m_ptr->hold_o_idx_list.begin(); it != m_ptr->hold_o_idx_list.end();) {
225 const OBJECT_IDX this_o_idx = *it++;
226 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
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);
234 m_ptr->hold_o_idx_list.clear();