OSDN Git Service

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