OSDN Git Service

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