OSDN Git Service

9b845208e69b2617e936f440a9bfaa9af8a1bf52
[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 "spell/spell-types.h"
19 #include "sv-definition/sv-other-types.h"
20 #include "sv-definition/sv-scroll-types.h"
21 #include "system/floor-type-definition.h"
22 #include "system/grid-type-definition.h"
23 #include "system/monster-type-definition.h"
24 #include "system/object-type-definition.h"
25 #include "system/player-type-definition.h"
26 #include "util/bit-flags-calculator.h"
27 #include "view/display-messages.h"
28
29 #include <set>
30
31 /*!
32  * @brief 汎用的なビーム/ボルト/ボール系によるアイテムオブジェクトへの効果処理 / Handle a beam/bolt/ball causing damage to a monster.
33  * @param player_ptr プレイヤーへの参照ポインタ
34  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
35  * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
36  * @param y 目標Y座標 / Target y location (or location to travel "towards")
37  * @param x 目標X座標 / Target x location (or location to travel "towards")
38  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
39  * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
40  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
41  */
42 bool affect_item(player_type *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, HIT_POINT dam, EFFECT_ID typ)
43 {
44     grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
45
46     bool is_item_affected = false;
47     bool known = player_has_los_bold(player_ptr, y, x);
48     who = who ? who : 0;
49     dam = (dam + r) / (r + 1);
50     std::set<OBJECT_IDX> processed_list;
51     for (auto it = g_ptr->o_idx_list.begin(); it != g_ptr->o_idx_list.end();) {
52         const OBJECT_IDX this_o_idx = *it++;
53
54         if (auto pit = processed_list.find(this_o_idx); pit != processed_list.end())
55             continue;
56
57         processed_list.insert(this_o_idx);
58
59         object_type *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 GF_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             break;
80         }
81         case GF_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             break;
90         }
91         case GF_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             break;
100         }
101         case GF_COLD: {
102             if (BreakerCold().hates(o_ptr)) {
103                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
104                 do_kill = true;
105                 if (flags.has(TR_IGNORE_COLD))
106                     ignore = true;
107             }
108
109             break;
110         }
111         case GF_PLASMA: {
112             if (BreakerFire().hates(o_ptr)) {
113                 do_kill = true;
114                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
115                 if (flags.has(TR_IGNORE_FIRE))
116                     ignore = true;
117             }
118
119             if (BreakerElec().hates(o_ptr)) {
120                 ignore = false;
121                 do_kill = true;
122                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
123                 if (flags.has(TR_IGNORE_ELEC))
124                     ignore = true;
125             }
126
127             break;
128         }
129         case GF_METEOR: {
130             if (BreakerFire().hates(o_ptr)) {
131                 do_kill = true;
132                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
133                 if (flags.has(TR_IGNORE_FIRE))
134                     ignore = true;
135             }
136
137             if (BreakerCold().hates(o_ptr)) {
138                 ignore = false;
139                 do_kill = true;
140                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
141                 if (flags.has(TR_IGNORE_COLD))
142                     ignore = true;
143             }
144
145             break;
146         }
147         case GF_ICE:
148         case GF_SHARDS:
149         case GF_FORCE:
150         case GF_SOUND: {
151             if (BreakerCold().hates(o_ptr)) {
152                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
153                 do_kill = true;
154             }
155
156             break;
157         }
158         case GF_MANA:
159         case GF_SEEKER:
160         case GF_SUPER_RAY: {
161             do_kill = true;
162             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
163             break;
164         }
165         case GF_DISINTEGRATE: {
166             do_kill = true;
167             note_kill = _("蒸発してしまった!", (plural ? " evaporate!" : " evaporates!"));
168             break;
169         }
170         case GF_CHAOS: {
171             do_kill = true;
172             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
173             if (flags.has(TR_RES_CHAOS))
174                 ignore = true;
175             else if ((o_ptr->tval == ItemKindType::SCROLL) && (o_ptr->sval == SV_SCROLL_CHAOS))
176                 ignore = true;
177             break;
178         }
179         case GF_HOLY_FIRE:
180         case GF_HELL_FIRE: {
181             if (o_ptr->is_cursed()) {
182                 do_kill = true;
183                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
184             }
185
186             break;
187         }
188         case GF_VOID: {
189             do_kill = true;
190             note_kill = _("消滅してしまった!", (plural ? " vanish!" : " vanishes!"));
191             break;
192         }
193         case GF_IDENTIFY: {
194             identify_item(player_ptr, o_ptr);
195             autopick_alter_item(player_ptr, (-this_o_idx), false);
196             break;
197         }
198         case GF_KILL_TRAP:
199         case GF_KILL_DOOR: {
200             if (o_ptr->tval != ItemKindType::CHEST)
201                 break;
202             if (o_ptr->pval <= 0)
203                 break;
204
205             o_ptr->pval = (0 - o_ptr->pval);
206             object_known(o_ptr);
207             if (known && (o_ptr->marked & OM_FOUND)) {
208                 msg_print(_("カチッと音がした!", "Click!"));
209                 is_item_affected = true;
210             }
211
212             break;
213         }
214         case GF_ANIM_DEAD: {
215             if (o_ptr->tval != ItemKindType::CORPSE)
216                 break;
217
218             BIT_FLAGS mode = 0L;
219             if (!who || is_pet(&player_ptr->current_floor_ptr->m_list[who]))
220                 mode |= PM_FORCE_PET;
221
222             for (int i = 0; i < o_ptr->number; i++) {
223                 if (((o_ptr->sval == SV_CORPSE) && (randint1(100) > 80)) || ((o_ptr->sval == SV_SKELETON) && (randint1(100) > 60))) {
224                     if (!note_kill) {
225                         note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
226                     }
227
228                     continue;
229                 } else if (summon_named_creature(player_ptr, who, y, x, o_ptr->pval, mode)) {
230                     note_kill = _("生き返った。", " revived.");
231                 } else if (!note_kill) {
232                     note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
233                 }
234             }
235
236             do_kill = true;
237             is_item_affected = true;
238             break;
239         }
240         }
241
242         if (!do_kill)
243             continue;
244
245         GAME_TEXT o_name[MAX_NLEN];
246         if (known && (o_ptr->marked & OM_FOUND)) {
247             is_item_affected = true;
248             describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
249         }
250
251         if ((is_artifact || ignore)) {
252             if (known && (o_ptr->marked & OM_FOUND))
253                 msg_format(_("%sは影響を受けない!", (plural ? "The %s are unaffected!" : "The %s is unaffected!")), o_name);
254
255             continue;
256         }
257
258         if (known && (o_ptr->marked & OM_FOUND) && note_kill)
259             msg_format(_("%sは%s", "The %s%s"), o_name, note_kill);
260
261         KIND_OBJECT_IDX k_idx = o_ptr->k_idx;
262         bool is_potion = o_ptr->is_potion();
263         delete_object_idx(player_ptr, this_o_idx);
264         if (is_potion) {
265             (void)potion_smash_effect(player_ptr, who, y, x, k_idx);
266
267             // 薬の破壊効果によりリストの次のアイテムが破壊された可能性があるのでリストの最初から処理をやり直す
268             // 処理済みのアイテムは processed_list に登録されており、スキップされる
269             it = g_ptr->o_idx_list.begin();
270         }
271
272         lite_spot(player_ptr, y, x);
273     }
274
275     return is_item_affected;
276 }