OSDN Git Service

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