OSDN Git Service

[Refactor] #2666 player_has_los_bold() をFloorType のオブジェクトメソッドhas_los() に繰り込んだ
[hengbandforosx/hengbandosx.git] / src / effect / effect-item.cpp
1 #include "effect/effect-item.h"
2 #include "autopick/autopick.h"
3 #include "flavor/flavor-describer.h"
4 #include "flavor/object-flavor-types.h"
5 #include "floor/floor-object.h"
6 #include "grid/grid.h"
7 #include "monster-floor/monster-summon.h"
8 #include "monster-floor/place-monster-types.h"
9 #include "monster/monster-info.h"
10 #include "object-enchant/tr-types.h"
11 #include "object-hook/hook-expendable.h"
12 #include "object/object-broken.h"
13 #include "object/object-mark-types.h"
14 #include "perception/object-perception.h"
15 #include "spell-kind/spells-perception.h"
16 #include "sv-definition/sv-other-types.h"
17 #include "sv-definition/sv-scroll-types.h"
18 #include "system/floor-type-definition.h"
19 #include "system/grid-type-definition.h"
20 #include "system/item-entity.h"
21 #include "system/monster-entity.h"
22 #include "system/player-type-definition.h"
23 #include "util/bit-flags-calculator.h"
24 #include "view/display-messages.h"
25 #include <set>
26
27 /*!
28  * @brief 汎用的なビーム/ボルト/ボール系によるアイテムオブジェクトへの効果処理 / Handle a beam/bolt/ball causing damage to a monster.
29  * @param player_ptr プレイヤーへの参照ポインタ
30  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
31  * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
32  * @param y 目標Y座標 / Target y location (or location to travel "towards")
33  * @param x 目標X座標 / Target x location (or location to travel "towards")
34  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
35  * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
36  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
37  */
38 bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
39 {
40     const auto &floor = *player_ptr->current_floor_ptr;
41     const Pos2D pos(y, x);
42     const auto &grid = floor.get_grid(pos);
43
44     auto is_item_affected = false;
45     const auto known = grid.has_los();
46     who = who ? who : 0;
47     dam = (dam + r) / (r + 1);
48     std::set<OBJECT_IDX> processed_list;
49     for (auto it = grid.o_idx_list.begin(); it != grid.o_idx_list.end();) {
50         const OBJECT_IDX this_o_idx = *it++;
51
52         if (auto pit = processed_list.find(this_o_idx); pit != processed_list.end()) {
53             continue;
54         }
55
56         processed_list.insert(this_o_idx);
57
58         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
59         bool ignore = false;
60         bool do_kill = false;
61         concptr note_kill = nullptr;
62
63 #ifdef JP
64 #else
65         bool plural = (o_ptr->number > 1);
66 #endif
67         const auto flags = o_ptr->get_flags();
68         bool is_fixed_or_random_artifact = o_ptr->is_fixed_or_random_artifact();
69         switch (typ) {
70         case AttributeType::ACID: {
71             if (BreakerAcid().hates(o_ptr)) {
72                 do_kill = true;
73                 note_kill = _("融けてしまった!", (plural ? " melt!" : " melts!"));
74                 if (flags.has(TR_IGNORE_ACID)) {
75                     ignore = true;
76                 }
77             }
78
79             break;
80         }
81         case AttributeType::ELEC: {
82             if (BreakerElec().hates(o_ptr)) {
83                 do_kill = true;
84                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
85                 if (flags.has(TR_IGNORE_ELEC)) {
86                     ignore = true;
87                 }
88             }
89
90             break;
91         }
92         case AttributeType::FIRE: {
93             if (BreakerFire().hates(o_ptr)) {
94                 do_kill = true;
95                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
96                 if (flags.has(TR_IGNORE_FIRE)) {
97                     ignore = true;
98                 }
99             }
100
101             break;
102         }
103         case AttributeType::COLD: {
104             if (BreakerCold().hates(o_ptr)) {
105                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
106                 do_kill = true;
107                 if (flags.has(TR_IGNORE_COLD)) {
108                     ignore = true;
109                 }
110             }
111
112             break;
113         }
114         case AttributeType::PLASMA: {
115             if (BreakerFire().hates(o_ptr)) {
116                 do_kill = true;
117                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
118                 if (flags.has(TR_IGNORE_FIRE)) {
119                     ignore = true;
120                 }
121             }
122
123             if (BreakerElec().hates(o_ptr)) {
124                 ignore = false;
125                 do_kill = true;
126                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
127                 if (flags.has(TR_IGNORE_ELEC)) {
128                     ignore = true;
129                 }
130             }
131
132             break;
133         }
134         case AttributeType::METEOR: {
135             if (BreakerFire().hates(o_ptr)) {
136                 do_kill = true;
137                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
138                 if (flags.has(TR_IGNORE_FIRE)) {
139                     ignore = true;
140                 }
141             }
142
143             if (BreakerCold().hates(o_ptr)) {
144                 ignore = false;
145                 do_kill = true;
146                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
147                 if (flags.has(TR_IGNORE_COLD)) {
148                     ignore = true;
149                 }
150             }
151
152             break;
153         }
154         case AttributeType::ICE:
155         case AttributeType::SHARDS:
156         case AttributeType::FORCE:
157         case AttributeType::SOUND: {
158             if (BreakerCold().hates(o_ptr)) {
159                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
160                 do_kill = true;
161             }
162
163             break;
164         }
165         case AttributeType::MANA:
166         case AttributeType::SEEKER:
167         case AttributeType::SUPER_RAY: {
168             do_kill = true;
169             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
170             break;
171         }
172         case AttributeType::DISINTEGRATE: {
173             do_kill = true;
174             note_kill = _("蒸発してしまった!", (plural ? " evaporate!" : " evaporates!"));
175             break;
176         }
177         case AttributeType::CHAOS: {
178             do_kill = true;
179             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
180             if (flags.has(TR_RES_CHAOS)) {
181                 ignore = true;
182             } else if (o_ptr->bi_key == BaseitemKey(ItemKindType::SCROLL, SV_SCROLL_CHAOS)) {
183                 ignore = true;
184             }
185             break;
186         }
187         case AttributeType::HOLY_FIRE:
188         case AttributeType::HELL_FIRE: {
189             if (o_ptr->is_cursed()) {
190                 do_kill = true;
191                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
192             }
193
194             break;
195         }
196         case AttributeType::VOID_MAGIC: {
197             do_kill = true;
198             note_kill = _("消滅してしまった!", (plural ? " vanish!" : " vanishes!"));
199             break;
200         }
201         case AttributeType::IDENTIFY: {
202             identify_item(player_ptr, o_ptr);
203             autopick_alter_item(player_ptr, (-this_o_idx), false);
204             break;
205         }
206         case AttributeType::KILL_TRAP:
207         case AttributeType::KILL_DOOR: {
208             if (o_ptr->bi_key.tval() != ItemKindType::CHEST) {
209                 break;
210             }
211
212             if (o_ptr->pval <= 0) {
213                 break;
214             }
215
216             o_ptr->pval = (0 - o_ptr->pval);
217             object_known(o_ptr);
218             if (known && o_ptr->marked.has(OmType::FOUND)) {
219                 msg_print(_("カチッと音がした!", "Click!"));
220                 is_item_affected = true;
221             }
222
223             break;
224         }
225         case AttributeType::ANIM_DEAD: {
226             if (o_ptr->bi_key.tval() != ItemKindType::CORPSE) {
227                 break;
228             }
229
230             BIT_FLAGS mode = 0L;
231             if (!who || player_ptr->current_floor_ptr->m_list[who].is_pet()) {
232                 mode |= PM_FORCE_PET;
233             }
234
235             for (int i = 0; i < o_ptr->number; i++) {
236                 auto corpse_r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
237                 const auto sval = o_ptr->bi_key.sval().value();
238                 if (((sval == SV_CORPSE) && (randint1(100) > 80)) || ((sval == SV_SKELETON) && (randint1(100) > 60))) {
239                     if (!note_kill) {
240                         note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
241                     }
242
243                     continue;
244                 } else if (summon_named_creature(player_ptr, who, y, x, corpse_r_idx, mode)) {
245                     note_kill = _("生き返った。", " revived.");
246                 } else if (!note_kill) {
247                     note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
248                 }
249             }
250
251             do_kill = true;
252             is_item_affected = true;
253             break;
254         }
255         default:
256             break;
257         }
258
259         if (!do_kill) {
260             continue;
261         }
262
263         std::string item_name("");
264         if (known && o_ptr->marked.has(OmType::FOUND)) {
265             is_item_affected = true;
266             item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
267         }
268
269         if ((is_fixed_or_random_artifact || ignore)) {
270             if (known && o_ptr->marked.has(OmType::FOUND)) {
271                 msg_format(_("%sは影響を受けない!", (plural ? "The %s are unaffected!" : "The %s is unaffected!")), item_name.data());
272             }
273
274             continue;
275         }
276
277         if (known && o_ptr->marked.has(OmType::FOUND) && note_kill) {
278             msg_format(_("%sは%s", "The %s%s"), item_name.data(), note_kill);
279         }
280
281         const auto bi_id = o_ptr->bi_id;
282         const auto is_potion = o_ptr->is_potion();
283         delete_object_idx(player_ptr, this_o_idx);
284         if (is_potion) {
285             (void)potion_smash_effect(player_ptr, who, y, x, bi_id);
286
287             // 薬の破壊効果によりリストの次のアイテムが破壊された可能性があるのでリストの最初から処理をやり直す
288             // 処理済みのアイテムは processed_list に登録されており、スキップされる
289             it = grid.o_idx_list.begin();
290         }
291
292         lite_spot(player_ptr, y, x);
293     }
294
295     return is_item_affected;
296 }