OSDN Git Service

Merge pull request #2013 from sikabane-works/release/3.0.0Alpha51
[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, HIT_POINT dam, AttributeType typ)
42 {
43     grid_type *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         processed_list.insert(this_o_idx);
57
58         object_type *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         auto flags = object_flags(o_ptr);
68         bool is_artifact = o_ptr->is_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             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             break;
89         }
90         case AttributeType::FIRE: {
91             if (BreakerFire().hates(o_ptr)) {
92                 do_kill = true;
93                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
94                 if (flags.has(TR_IGNORE_FIRE))
95                     ignore = true;
96             }
97
98             break;
99         }
100         case AttributeType::COLD: {
101             if (BreakerCold().hates(o_ptr)) {
102                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
103                 do_kill = true;
104                 if (flags.has(TR_IGNORE_COLD))
105                     ignore = true;
106             }
107
108             break;
109         }
110         case AttributeType::PLASMA: {
111             if (BreakerFire().hates(o_ptr)) {
112                 do_kill = true;
113                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
114                 if (flags.has(TR_IGNORE_FIRE))
115                     ignore = true;
116             }
117
118             if (BreakerElec().hates(o_ptr)) {
119                 ignore = false;
120                 do_kill = true;
121                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
122                 if (flags.has(TR_IGNORE_ELEC))
123                     ignore = true;
124             }
125
126             break;
127         }
128         case AttributeType::METEOR: {
129             if (BreakerFire().hates(o_ptr)) {
130                 do_kill = true;
131                 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
132                 if (flags.has(TR_IGNORE_FIRE))
133                     ignore = true;
134             }
135
136             if (BreakerCold().hates(o_ptr)) {
137                 ignore = false;
138                 do_kill = true;
139                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
140                 if (flags.has(TR_IGNORE_COLD))
141                     ignore = true;
142             }
143
144             break;
145         }
146         case AttributeType::ICE:
147         case AttributeType::SHARDS:
148         case AttributeType::FORCE:
149         case AttributeType::SOUND: {
150             if (BreakerCold().hates(o_ptr)) {
151                 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
152                 do_kill = true;
153             }
154
155             break;
156         }
157         case AttributeType::MANA:
158         case AttributeType::SEEKER:
159         case AttributeType::SUPER_RAY: {
160             do_kill = true;
161             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
162             break;
163         }
164         case AttributeType::DISINTEGRATE: {
165             do_kill = true;
166             note_kill = _("蒸発してしまった!", (plural ? " evaporate!" : " evaporates!"));
167             break;
168         }
169         case AttributeType::CHAOS: {
170             do_kill = true;
171             note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
172             if (flags.has(TR_RES_CHAOS))
173                 ignore = true;
174             else if ((o_ptr->tval == ItemKindType::SCROLL) && (o_ptr->sval == SV_SCROLL_CHAOS))
175                 ignore = true;
176             break;
177         }
178         case AttributeType::HOLY_FIRE:
179         case AttributeType::HELL_FIRE: {
180             if (o_ptr->is_cursed()) {
181                 do_kill = true;
182                 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
183             }
184
185             break;
186         }
187         case AttributeType::VOID_MAGIC: {
188             do_kill = true;
189             note_kill = _("消滅してしまった!", (plural ? " vanish!" : " vanishes!"));
190             break;
191         }
192         case AttributeType::IDENTIFY: {
193             identify_item(player_ptr, o_ptr);
194             autopick_alter_item(player_ptr, (-this_o_idx), false);
195             break;
196         }
197         case AttributeType::KILL_TRAP:
198         case AttributeType::KILL_DOOR: {
199             if (o_ptr->tval != ItemKindType::CHEST)
200                 break;
201             if (o_ptr->pval <= 0)
202                 break;
203
204             o_ptr->pval = (0 - o_ptr->pval);
205             object_known(o_ptr);
206             if (known && (o_ptr->marked & OM_FOUND)) {
207                 msg_print(_("カチッと音がした!", "Click!"));
208                 is_item_affected = true;
209             }
210
211             break;
212         }
213         case AttributeType::ANIM_DEAD: {
214             if (o_ptr->tval != ItemKindType::CORPSE)
215                 break;
216
217             BIT_FLAGS mode = 0L;
218             if (!who || is_pet(&player_ptr->current_floor_ptr->m_list[who]))
219                 mode |= PM_FORCE_PET;
220
221             for (int i = 0; i < o_ptr->number; i++) {
222                 if (((o_ptr->sval == SV_CORPSE) && (randint1(100) > 80)) || ((o_ptr->sval == SV_SKELETON) && (randint1(100) > 60))) {
223                     if (!note_kill) {
224                         note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
225                     }
226
227                     continue;
228                 } else if (summon_named_creature(player_ptr, who, y, x, o_ptr->pval, mode)) {
229                     note_kill = _("生き返った。", " revived.");
230                 } else if (!note_kill) {
231                     note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
232                 }
233             }
234
235             do_kill = true;
236             is_item_affected = true;
237             break;
238         }
239         default:
240             break;
241         }
242
243         if (!do_kill)
244             continue;
245
246         GAME_TEXT o_name[MAX_NLEN];
247         if (known && (o_ptr->marked & OM_FOUND)) {
248             is_item_affected = true;
249             describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
250         }
251
252         if ((is_artifact || ignore)) {
253             if (known && (o_ptr->marked & OM_FOUND))
254                 msg_format(_("%sは影響を受けない!", (plural ? "The %s are unaffected!" : "The %s is unaffected!")), o_name);
255
256             continue;
257         }
258
259         if (known && (o_ptr->marked & OM_FOUND) && note_kill)
260             msg_format(_("%sは%s", "The %s%s"), o_name, note_kill);
261
262         KIND_OBJECT_IDX k_idx = o_ptr->k_idx;
263         bool is_potion = o_ptr->is_potion();
264         delete_object_idx(player_ptr, this_o_idx);
265         if (is_potion) {
266             (void)potion_smash_effect(player_ptr, who, y, x, k_idx);
267
268             // 薬の破壊効果によりリストの次のアイテムが破壊された可能性があるのでリストの最初から処理をやり直す
269             // 処理済みのアイテムは processed_list に登録されており、スキップされる
270             it = g_ptr->o_idx_list.begin();
271         }
272
273         lite_spot(player_ptr, y, x);
274     }
275
276     return is_item_affected;
277 }