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"
7 #include "monster-floor/monster-summon.h"
8 #include "monster-floor/place-monster-types.h"
9 #include "monster/monster-info.h"
10 #include "monster/monster-util.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-mark-types.h"
15 #include "spell-kind/spells-perception.h"
16 #include "sv-definition/sv-other-types.h"
17 #include "sv-definition/sv-scroll-types.h"
18 #include "system/floor-type-definition.h"
19 #include "system/grid-type-definition.h"
20 #include "system/item-entity.h"
21 #include "system/monster-entity.h"
22 #include "system/player-type-definition.h"
23 #include "util/bit-flags-calculator.h"
24 #include "view/display-messages.h"
28 * @brief 汎用的なビーム/ボルト/ボール系によるアイテムオブジェクトへの効果処理 / Handle a beam/bolt/ball causing damage to a monster.
29 * @param player_ptr プレイヤーへの参照ポインタ
30 * @param src_idx 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
31 * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
32 * @param y 目標Y座標 / Target y location (or location to travel "towards")
33 * @param x 目標X座標 / Target x location (or location to travel "towards")
34 * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
35 * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
36 * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
38 bool affect_item(PlayerType *player_ptr, MONSTER_IDX src_idx, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
40 const auto &floor = *player_ptr->current_floor_ptr;
41 const Pos2D pos(y, x);
42 const auto &grid = floor.get_grid(pos);
44 auto is_item_affected = false;
45 const auto known = grid.has_los();
46 src_idx = is_monster(src_idx) ? src_idx : 0;
47 dam = (dam + r) / (r + 1);
48 std::set<OBJECT_IDX> processed_list;
49 for (auto it = grid.o_idx_list.begin(); it != grid.o_idx_list.end();) {
50 const OBJECT_IDX this_o_idx = *it++;
52 if (auto pit = processed_list.find(this_o_idx); pit != processed_list.end()) {
56 processed_list.insert(this_o_idx);
58 auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
61 concptr note_kill = nullptr;
65 bool plural = (o_ptr->number > 1);
67 const auto flags = o_ptr->get_flags();
68 bool is_fixed_or_random_artifact = o_ptr->is_fixed_or_random_artifact();
70 case AttributeType::ACID: {
71 if (BreakerAcid().hates(o_ptr)) {
73 note_kill = _("融けてしまった!", (plural ? " melt!" : " melts!"));
74 if (flags.has(TR_IGNORE_ACID)) {
81 case AttributeType::ELEC: {
82 if (BreakerElec().hates(o_ptr)) {
84 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
85 if (flags.has(TR_IGNORE_ELEC)) {
92 case AttributeType::FIRE: {
93 if (BreakerFire().hates(o_ptr)) {
95 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
96 if (flags.has(TR_IGNORE_FIRE)) {
103 case AttributeType::COLD: {
104 if (BreakerCold().hates(o_ptr)) {
105 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
107 if (flags.has(TR_IGNORE_COLD)) {
114 case AttributeType::PLASMA: {
115 if (BreakerFire().hates(o_ptr)) {
117 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
118 if (flags.has(TR_IGNORE_FIRE)) {
123 if (BreakerElec().hates(o_ptr)) {
126 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
127 if (flags.has(TR_IGNORE_ELEC)) {
134 case AttributeType::METEOR: {
135 if (BreakerFire().hates(o_ptr)) {
137 note_kill = _("燃えてしまった!", (plural ? " burn up!" : " burns up!"));
138 if (flags.has(TR_IGNORE_FIRE)) {
143 if (BreakerCold().hates(o_ptr)) {
146 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
147 if (flags.has(TR_IGNORE_COLD)) {
154 case AttributeType::ICE:
155 case AttributeType::SHARDS:
156 case AttributeType::FORCE:
157 case AttributeType::SOUND: {
158 if (BreakerCold().hates(o_ptr)) {
159 note_kill = _("砕け散ってしまった!", (plural ? " shatter!" : " shatters!"));
165 case AttributeType::MANA:
166 case AttributeType::SEEKER:
167 case AttributeType::SUPER_RAY: {
169 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
172 case AttributeType::DISINTEGRATE: {
174 note_kill = _("蒸発してしまった!", (plural ? " evaporate!" : " evaporates!"));
177 case AttributeType::CHAOS: {
179 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
180 if (flags.has(TR_RES_CHAOS)) {
182 } else if (o_ptr->bi_key == BaseitemKey(ItemKindType::SCROLL, SV_SCROLL_CHAOS)) {
187 case AttributeType::HOLY_FIRE:
188 case AttributeType::HELL_FIRE: {
189 if (o_ptr->is_cursed()) {
191 note_kill = _("壊れてしまった!", (plural ? " are destroyed!" : " is destroyed!"));
196 case AttributeType::VOID_MAGIC: {
198 note_kill = _("消滅してしまった!", (plural ? " vanish!" : " vanishes!"));
201 case AttributeType::IDENTIFY: {
202 identify_item(player_ptr, o_ptr);
203 autopick_alter_item(player_ptr, (-this_o_idx), false);
206 case AttributeType::KILL_TRAP:
207 case AttributeType::KILL_DOOR: {
208 if (o_ptr->bi_key.tval() != ItemKindType::CHEST) {
212 if (o_ptr->pval <= 0) {
216 o_ptr->pval = (0 - o_ptr->pval);
217 o_ptr->mark_as_known();
218 if (known && o_ptr->marked.has(OmType::FOUND)) {
219 msg_print(_("カチッと音がした!", "Click!"));
220 is_item_affected = true;
225 case AttributeType::ANIM_DEAD: {
226 if (o_ptr->bi_key.tval() != ItemKindType::CORPSE) {
231 if (is_monster(src_idx) || player_ptr->current_floor_ptr->m_list[src_idx].is_pet()) {
232 mode |= PM_FORCE_PET;
235 for (int i = 0; i < o_ptr->number; i++) {
236 auto corpse_r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
237 const auto sval = *o_ptr->bi_key.sval();
238 if (((sval == SV_CORPSE) && (randint1(100) > 80)) || ((sval == SV_SKELETON) && (randint1(100) > 60))) {
240 note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
244 } else if (summon_named_creature(player_ptr, src_idx, y, x, corpse_r_idx, mode)) {
245 note_kill = _("生き返った。", " revived.");
246 } else if (!note_kill) {
247 note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
252 is_item_affected = true;
263 std::string item_name("");
264 if (known && o_ptr->marked.has(OmType::FOUND)) {
265 is_item_affected = true;
266 item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
269 if ((is_fixed_or_random_artifact || ignore)) {
270 if (known && o_ptr->marked.has(OmType::FOUND)) {
271 msg_format(_("%sは影響を受けない!", (plural ? "The %s are unaffected!" : "The %s is unaffected!")), item_name.data());
277 if (known && o_ptr->marked.has(OmType::FOUND) && note_kill) {
278 msg_format(_("%sは%s", "The %s%s"), item_name.data(), note_kill);
281 const auto bi_id = o_ptr->bi_id;
282 const auto is_potion = o_ptr->is_potion();
283 delete_object_idx(player_ptr, this_o_idx);
285 (void)potion_smash_effect(player_ptr, src_idx, y, x, bi_id);
287 // 薬の破壊効果によりリストの次のアイテムが破壊された可能性があるのでリストの最初から処理をやり直す
288 // 処理済みのアイテムは processed_list に登録されており、スキップされる
289 it = grid.o_idx_list.begin();
292 lite_spot(player_ptr, y, x);
295 return is_item_affected;